.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