.include "macros.inc" .include "defines.inc" ; All code in this file is position-independent. .if PAL=0 PAL_offset=0 .else PAL_offset=77 .endif line_counter = $93 metatile_counter = $94 left_edge_metatile_index = $58 ; Already found there ;right_edge_metatile_index = $59 vramline_index = $6A metatile_index = $13 ; $10 must not be used y_screen_index = $11 y_screen_line = $15 metatile_ptr = $02 current_metatile = $5C current_screen = $5D .segment "TOWNDOORUPDATER_ANYBANK" ; This module changes the 32x32 metatiles of town-doors at day-night transition ; to open/close doors depending whether it's day or night respectively. TownDoorUpdater: ; If we're in town, check doors! lda $30 bne @rts @is_town: jsr $D15B - PAL_offset ; Just to make sure, reload all level data pointers ; left_edge_metatile_index = CurrentXScrollingPositionPixels_Div256 * 8 ; - 0x60 / 32 + CurrentXScrollingPositionPixels_Mod256 / 32; ;lda $53 ; CurrentXScrollingPositionPixels_Mod256 ;lsr ;lsr ;lsr ;lsr ;lsr ; CurrentXScrollingPositionPixels_Mod256 / 32 ;sta $00 ;lda $54 ; CurrentXScrollingPositionPixels_Div256 ;asl ;asl ;asl ; CurrentXScrollingPositionPixels_Div256 * 8 ;clc ;adc $00 ;sec ;sbc #3 ;sta left_edge_metatile_index ; Incidentally, this is also found at $58 in the RAM, ; as written there by $E72C (that we don't need to call). ; Load the first Y coordinate that is displayed in VRAM. ; y_screen_index = CurrentYScrollingPositionPixels_Div224; ldy $57 ; CurrentYScrollingPositionPixels_Div224 sty y_screen_index ; y_screen_line = CurrentYScrollingPositionPixels_Mod224 / 8; lda $56 ; CurrentYScrollingPositionPixels_Mod224 lsr lsr lsr ; CurrentYScrollingPositionPixels_Mod224 / 8 sta y_screen_line ; Calculate the VRAM coordinate where it is rendered. ; vramline_index = (y_screen_line + y_screen_index * 28) % 30; ; Position-independent code prohibits a look-up-table for multiplication. @mul28_mod30_loop: dey bmi @mul28_mod30_loop_over clc adc #28 cmp #30 bcc @mul28_mod30_loop sbc #30 bcs @mul28_mod30_loop @mul28_mod30_loop_over: sta vramline_index ; for(byte line_counter = 0; line_counter < 30; ++line_counter) // 30 = 240/8 ; { setb line_counter, 30 .byte "TRJ" .byte "BN2" ; .word & .byte TowndoorUpdater_Bank2 @rts: rts .segment "TOWNDOORUPDATER_BANK2" TowndoorUpdater_Bank2: @line_counter_loop: ; byte metatile_index = left_edge_metatile_index; lda left_edge_metatile_index sta metatile_index ; byte current_screen = y_screen_index * CurrentMapWidthInScreens + (metatile_index / 8); ; ; Divide metatile_index by 8, and we get how many screenfuls ; ; we are supposed to be towards the right. lsr lsr lsr sta current_screen ; We are in bank 2, so we can load data from the level-data screens right away. ldy #0 lda ($70),y ; Load number of horizontal screens tay ; Multiply by y_screen_index lda current_screen cpy #0 beq @mul_y_done clc @mul_y_loop: adc y_screen_index dey bpl @mul_y_loop @mul_y_done: asl adc #2 sta current_screen ; *2 + 2 is because each element in screens[] is a word, not a byte, ; and the table is prefixed by two bytes that describe dimensions. ; byte current_metatile = (y_screen_line / 4) * 8 + (metatile_index % 8) + 2; lda metatile_index and #7 sta current_metatile lda y_screen_line asl and #$F8 adc current_metatile sta current_metatile ; const byte* metatile_ptr = GetScreen(current_screen); ldy current_screen lda ($70),y sta metatile_ptr+0 iny lda ($70),y sta metatile_ptr+1 ; for(byte metatile_counter = 0; metatile_counter < 13; ++metatile_counter) ; { setb metatile_counter, 13 @metatile_counter_loop: ; Load the metatile_number: ldy current_metatile lda (metatile_ptr),y bmi @change_metatile @metatile_change_over: ; Proceed to next map metatile inc current_metatile inc metatile_index ; metatile_index & 7 == 0 ? lda #7 bit metatile_index beq @go_next_screen @didnt_go_next_screen: ; } dec metatile_counter bne @metatile_counter_loop ; Proceed to next VRAM line ; if(++vramline_index == 30) vramline_index = 0; ldx vramline_index inx cpx #30 bne @didnt_wrap_vramline_index ldx #0 @didnt_wrap_vramline_index: stx vramline_index ; if(++y_screen_line == 4*7) { y_screen_line = 0; ++y_screen_index; } ldx y_screen_line inx cpx #4*7 bne @didnt_wrap_screen inc y_screen_index ldx #0 @didnt_wrap_screen: stx y_screen_line ; } dec line_counter bne @line_counter_loop ; All done rts @go_next_screen: ; Yes, go next screen ; current_metatile &= 0xF8 ; Remove the % 8 part lda current_metatile and #$F8 sta current_metatile ; ++metatile_ptr = GetScreen(++current_screen); ldy current_screen; ; Add two, not one, because each element is a word, not a byte. iny iny sty current_screen lda ($70),y sta metatile_ptr+0 iny lda ($70),y sta metatile_ptr+1 bne @didnt_go_next_screen @change_metatile: ; Change metatile and #$7F ;ldy IsNightTime ;bne @got_changed_metatile cmp #$20 lda #0 adc #$43 @got_changed_metatile: ;lda #$36 ;clc ;adc y_screen_line sta $62 .byte "TRA" ; jsr Trampoline .byte "BN4" ; .word & .byte OneMetaTileUpdater ldx PPUsendQueueHead cpx #$61 bcc @metatile_change_over @too_much: rts ; Too much .segment "TOWNDOORUPDATER_BANK4" OneMetaTileUpdater: ; Calculate VRAM address. ; Low 5 bits: ((metatile_index * 4) & 0x1F) ; Next 5 bits: + (vramline_index * 0x20) ; Next 1 bit: + (metatile_index & 8) * (0x400 / 8) ; And then + 0x2000; ; ; This is very much similar to what $EB35 does, but our variables ; have a slightly different meaning... lda metatile_index asl asl and #$1F sta $5E setb $5F, $20/4 lda vramline_index .repeat 3 asl .endrepeat .repeat 2 asl rol $5F .endrepeat ora $5E sta $5E lda metatile_index lsr and #4 ; Convert 8 into $4, which means $400 ora $5F sta $5F lda y_screen_line and #3 sta $10 ; Second part of $EA57 jsr $EA69 - PAL_offset ; Load_MetaTile_ParticularTileStoreTo16_and_0F09 using _this_ tile ;^ $16 = Metatiletable + nmetatiles ; $0F:$09 = $16 + $62 * 16 ; ; Reads $62 = metatile number ; Reads $63,$64 = pointer to metatile table ; Writes Y,C,A ; Writes $16,$17 = pointer to the beginning of metatile data in the table ; Writes $09,$0F = pointer to the beginning of the data for _this_ metatile ; Load a row of tiles (4 tiles) jsr $E7F4 - PAL_offset ; Load_MetaTile_ParticularRowPointerStoreTo16 ;^ $16 = $0F:$09 + $10*4 ; ; Reads $10 = Tile-line index into the metatile ; Reads $09,$0F = pointer to the beginning of the data for _this_ metatile ; Writes C,A ; Writes $16,$17 = pointer to _this_ metatile's _this_ row ; Load attribute byte @N = 4 .if 0 ldx PPUsendQueueHead lda #1 sta PPUsendQueue+0,x sta PPUsendQueue+5 + 0,x lda $61 sta PPUsendQueue+1,x lda $60 sta PPUsendQueue+2,x ldy $62 iny lda ($63),y sta PPUsendQueue+3,x lda #$FF sta PPUsendQueue+4,x sta PPUsendQueue+5 + 7,x txa clc adc #5 tax .else ldx PPUsendQueueHead lda #1 sta PPUsendQueue + 0,x lda #$FF sta PPUsendQueue + 3 + @N,x .endif lda $5F sta PPUsendQueue+1,x lda $5E sta PPUsendQueue+2,x ldy #0 .repeat @N, I lda ($16),y ;lda $62 sta PPUsendQueue+3 + I,x iny .endrepeat txa clc adc #(4 + @N) sta PPUsendQueueHead rts Mul28table: .repeat 5, I .byte 28*I .endrepeat |