summaryrefslogtreecommitdiff
path: root/home/vcopy.asm
diff options
context:
space:
mode:
Diffstat (limited to 'home/vcopy.asm')
-rw-r--r--home/vcopy.asm615
1 files changed, 615 insertions, 0 deletions
diff --git a/home/vcopy.asm b/home/vcopy.asm
new file mode 100644
index 0000000..bfcaa7c
--- /dev/null
+++ b/home/vcopy.asm
@@ -0,0 +1,615 @@
+INCLUDE "constants.asm"
+INCLUDE "vram.asm"
+
+SECTION "Copy Routines used by VBlank ISR", ROM0[$123a]
+
+; This function redraws a BG row of height 2 or a BG column of width 2.
+; One of its main uses is redrawing the row or column that will be exposed upon
+; scrolling the BG when the player takes a step. Redrawing only the exposed
+; row or column is more efficient than redrawing the entire screen.
+; However, this function is also called repeatedly to redraw the whole screen
+; when necessary. It is also used in trade animation and elevator code.
+; This also implements the flashlight drawing distance effect, which takes
+; multiple frames in either direction to complete
+RedrawRowOrColumn:: ; 123a (0:123a)
+ ldh a, [hRedrawRowOrColumnMode]
+ and a
+ ret z
+ cp $03
+ jr nc, .flashlight_effect
+ ld b, a
+ xor a
+ ldh [hRedrawRowOrColumnMode], a
+ dec b
+ jr nz, .redrawRow
+.redrawColumn
+ ld hl, wRedrawRowOrColumnSrcTiles
+ ldh a, [hRedrawRowOrColumnDest]
+ ld e, a
+ ldh a, [hRedrawRowOrColumnDest + 1]
+ ld d, a
+ ld c, SCREEN_HEIGHT
+.col_loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld a, BG_MAP_WIDTH - 1
+ add e
+ ld e, a
+ jr nc, .noCarry
+ inc d
+.noCarry
+; the following 4 lines wrap us from bottom to top if necessary
+ ld a, d
+ and HIGH(vBGMap1 - vBGMap0 - $01)
+ or HIGH(vBGMap0)
+ ld d, a
+ dec c
+ jr nz, .col_loop
+ xor a
+ ldh [hRedrawRowOrColumnMode], a
+ ret
+.redrawRow
+ ld hl, wRedrawRowOrColumnSrcTiles
+ ldh a, [hRedrawRowOrColumnDest]
+ ld e, a
+ ldh a, [hRedrawRowOrColumnDest + 1]
+ ld d, a
+ push de
+ call .DrawHalf
+ pop de
+ ld a, BG_MAP_WIDTH ; width of VRAM background map
+ add e
+ ld e, a
+ ; fall through and draw lower half
+
+.DrawHalf
+ ld c, SCREEN_WIDTH / 2
+.row_loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld a, e
+ inc a
+; the following 6 lines wrap us from the right edge to the left edge if necessary
+ and BG_MAP_WIDTH - 1 ; mask lower address bits
+ ld b, a
+ ld a, e
+ and ($FF ^ (BG_MAP_WIDTH - 1)) ; mask upper address bits
+ or b
+ ld e, a
+ dec c
+ jr nz, .row_loop
+ ret
+.flashlight_effect
+ dec a
+ dec a
+ dec a
+ ld c, a
+ ld b, $00
+ ld hl, .flashlight_effect_table
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+.flashlight_effect_table
+ dw RedrawFlashlightRow0 ; $1310
+ dw RedrawFlashlightRow0 ; $1310
+ dw RedrawFlashlightColumn0 ; $12C3
+ dw RedrawFlashlightColumn0 ; $12C3
+ dw RedrawFlashlightRow1 ; $1329
+ dw RedrawFlashlightRow1 ; $1329
+ dw RedrawFlashlightColumn1 ; $12DC
+ dw RedrawFlashlightColumn1 ; $12DC
+ dw RedrawFlashlightRow2 ; $1335
+ dw RedrawFlashlightRow2 ; $1335
+ dw RedrawFlashlightColumn2 ; $12E8
+ dw RedrawFlashlightColumn2 ; $12E8
+ dw RedrawFlashlightRow3 ; $134E
+ dw RedrawFlashlightRow3 ; $134E
+ dw RedrawFlashlightColumn3 ; $1301
+ dw RedrawFlashlightColumn3 ; $1301
+
+RedrawFlashlightColumn0:: ; 12c3 (0:12c3)
+ ldh a, [hSCX]
+ and $07
+ ret nz ; wait till we moved one complete tile in X
+ ld a, [wRedrawFlashlightDst0]
+ ld e, a
+ ld a, [wRedrawFlashlightDst0 + 1]
+ ld d, a
+ ld a, [wRedrawFlashlightSrc0]
+ ld l, a
+ ld a, [wRedrawFlashlightSrc0 + 1]
+ ld h, a
+ call _RedrawFlashlightColumn
+ ret
+
+RedrawFlashlightColumn1:: ; 12dc (0:12dc)
+ ld a, [wRedrawFlashlightBlackDst0]
+ ld e, a
+ ld a, [wRedrawFlashlightBlackDst0 + 1]
+ ld d, a
+ call _RedrawFlashlightColumnBlack
+ ret
+; 0x12e8
+
+RedrawFlashlightColumn2:: ; 12e8 (0:12e8)
+ ldh a, [hSCX]
+ and $0f
+ ret nz ; wait till we moved two complete tiles in X
+ ld a, [wRedrawFlashlightDst1]
+ ld e, a
+ ld a, [wRedrawFlashlightDst1 + 1]
+ ld d, a
+ ld a, [wRedrawFlashlightSrc1]
+ ld l, a
+ ld a, [wRedrawFlashlightSrc1 + 1]
+ ld h, a
+ call _RedrawFlashlightColumn
+ ret
+
+RedrawFlashlightColumn3:: ; 1301 (0:1301)
+ ld a, [wRedrawFlashlightBlackDst1]
+ ld e, a
+ ld a, [wRedrawFlashlightBlackDst1 + 1]
+ ld d, a
+ call _RedrawFlashlightColumnBlack
+ xor a
+ ldh [hRedrawRowOrColumnMode], a ; end flashlight redraw
+ ret
+
+RedrawFlashlightRow0:: ; 1310 (0:1310)
+ ldh a, [hSCY]
+ and $07
+ ret nz ; wait till we moved one complete tile in Y
+ ld a, [wRedrawFlashlightDst0]
+ ld e, a
+ ld a, [wRedrawFlashlightDst0 + 1]
+ ld d, a
+ ld a, [wRedrawFlashlightSrc0]
+ ld l, a
+ ld a, [wRedrawFlashlightSrc0 + 1]
+ ld h, a
+ call _RedrawFlashlightRow
+ ret
+
+RedrawFlashlightRow1:: ; 1329 (0:1329)
+ ld a, [wRedrawFlashlightBlackDst0]
+ ld e, a
+ ld a, [wRedrawFlashlightBlackDst0 + 1]
+ ld d, a
+ call _RedrawFlashlightRowBlack
+ ret
+; 0x12e8
+
+RedrawFlashlightRow2:: ; 1335 (0:1335)
+ ldh a, [hSCY]
+ and $0f
+ ret nz ; wait till we moved two complete tiles in Y
+ ld a, [wRedrawFlashlightDst1]
+ ld e, a
+ ld a, [wRedrawFlashlightDst1 + 1]
+ ld d, a
+ ld a, [wRedrawFlashlightSrc1]
+ ld l, a
+ ld a, [wRedrawFlashlightSrc1 + 1]
+ ld h, a
+ call _RedrawFlashlightRow
+ ret
+
+RedrawFlashlightRow3:: ; 134e (0:134e)
+ ld a, [wRedrawFlashlightBlackDst1]
+ ld e, a
+ ld a, [wRedrawFlashlightBlackDst1 + 1]
+ ld d, a
+ call _RedrawFlashlightRowBlack
+ xor a
+ ldh [hRedrawRowOrColumnMode], a ; end flashlight redraw
+ ret
+
+_RedrawFlashlightColumn:: ; 135d (0:135d)
+ ld a, [wRedrawFlashlightWidthHeight]
+ add a
+ ld c, a
+.loop
+ ld a, [hli]
+ ld [de], a
+ ld a, SCREEN_WIDTH - 1
+ add l
+ ld l, a
+ jr nc, .noCarryScreen
+ inc h
+.noCarryScreen
+ ld a, BG_MAP_WIDTH
+ add e
+ ld e, a
+ jr nc, .noCarryBG
+ inc d
+.noCarryBG
+; the following 4 lines wrap us from bottom to top if necessary
+ ld a, d
+ and HIGH(vBGMap1 - vBGMap0 - $01)
+ or HIGH(vBGMap0)
+ ld d, a
+ dec c
+ jr nz, .loop
+ ldh a, [hRedrawRowOrColumnMode]
+ add $04 ; inc by 4, because flashlight redraw
+ ldh [hRedrawRowOrColumnMode], a ; has four directions
+ ret
+
+_RedrawFlashlightRow:: ; 1382 (0:1382)
+ ld a, [wRedrawFlashlightWidthHeight]
+ ld c, a
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld a, e
+ inc a
+; the following 6 lines wrap us from the right edge to the left edge if necessary
+ and BG_MAP_WIDTH - 1 ; mask lower address bits
+ ld b, a
+ ld a, e
+ and ($FF ^ (BG_MAP_WIDTH - 1)) ; mask upper address bits
+ or b
+ ld e, a
+ dec c
+ jr nz, .loop
+ ldh a, [hRedrawRowOrColumnMode]
+ add $04 ; inc by 4, because flashlight redraw
+ ldh [hRedrawRowOrColumnMode], a ; has four directions
+ ret
+
+_RedrawFlashlightColumnBlack:: ; 139f (0:139f)
+ ld l, e
+ ld h, d
+ ld b, "■"
+ ld de, BG_MAP_WIDTH
+ ld a, [wRedrawFlashlightWidthHeight]
+ add a
+ ld c, a
+.loop
+ ld [hl], b
+ add hl, de
+; the following 4 lines wrap us from bottom to top if necessary
+ ld a, h
+ and HIGH(vBGMap1 - vBGMap0 - $01)
+ or HIGH(vBGMap0)
+ ld h, a
+ dec c
+ jr nz, .loop
+ ldh a, [hRedrawRowOrColumnMode]
+ add $04 ; inc by 4, because flashlight redraw
+ ldh [hRedrawRowOrColumnMode], a ; has four directions
+ ret
+
+_RedrawFlashlightRowBlack:: ; 13bd (0:13bd)
+ ld l, e
+ ld h, d
+ ld b, "■"
+ ld a, [wRedrawFlashlightWidthHeight]
+ ld c, a
+.loop
+ ld [hl], b
+ inc hl
+ ld [hl], b
+ ld a, l
+ inc a
+; the following 6 lines wrap us from the right edge to the left edge if necessary
+ and BG_MAP_WIDTH - 1 ; mask lower address bits
+ ld d, a
+ ld a, l
+ and ($FF ^ (BG_MAP_WIDTH - 1)) ; mask upper address bits
+ or d
+ ld l, a
+ dec c
+ jr nz, .loop
+ ldh a, [hRedrawRowOrColumnMode]
+ add $04 ; inc by 4, because flashlight redraw
+ ldh [hRedrawRowOrColumnMode], a ; has four directions
+ ret
+
+WaitForAutoBgMapTransfer:: ; 13dc (0:13dc)
+.loop
+ ldh a, [hBGMapMode]
+ and a
+ ret z
+ ldh a, [hBGMapTransferPosition]
+ and a
+ jr z, .done
+ call DelayFrame
+ jr .loop
+.done
+ xor a
+ ldh [hBGMapMode], a
+ ret
+
+; This function automatically transfers tile number data from the tile map at
+; wTileMap to VRAM during V-blank. Note that it only transfers one third of the
+; background per V-blank. It cycles through which third it draws.
+; This transfer is turned off when walking around the map, but is turned
+; on when talking to sprites, battling, using menus, etc. This is because
+; the above function, RedrawRowOrColumn, is used when walking to
+; improve efficiency.
+AutoBgMapTransfer:: ; 13ee (0:13ee)
+ ldh a, [hBGMapMode]
+ and a
+ ret z
+ ld [hSPTemp], sp
+ ldh a, [hBGMapTransferPosition]
+ and a
+ jr z, .transferTopThird
+ dec a
+ jr z, .transferMiddleThird
+.transferBottomThird
+ coord hl, 0, 12
+ ld sp, hl
+ ldh a, [hBGMapAddress + 1]
+ ld h, a
+ ldh a, [hBGMapAddress]
+ ld l, a
+ ld de, 12 * BG_MAP_WIDTH
+ add hl, de
+ xor a
+ jr .doTransfer
+.transferTopThird
+ coord hl, 0, 0
+ ld sp, hl
+ ldh a, [hBGMapAddress + 1]
+ ld h, a
+ ldh a, [hBGMapAddress]
+ ld l, a
+ ld a, $01
+ jr .doTransfer
+.transferMiddleThird
+ coord hl, 0, 6
+ ld sp, hl
+ ldh a, [hBGMapAddress + 1]
+ ld h, a
+ ldh a, [hBGMapAddress]
+ ld l, a
+ ld de, 6 * BG_MAP_WIDTH
+ add hl, de
+ ld a, $02
+.doTransfer
+ ldh [hBGMapTransferPosition], a
+ ld a, $06 ; 6 rows of SCREEN_WIDTH each
+ ; fall through
+
+TransferBgRows:: ; 1430 (0:1430)
+ ld bc, BG_MAP_WIDTH - SCREEN_WIDTH + 1
+.loop
+
+ rept SCREEN_WIDTH / 2 - 1 ; two bytes per pop minus last block
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ endr
+
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ add hl, bc
+ dec a
+ jr nz, .loop
+ ldh a, [hSPTemp]
+ ld l, a
+ ldh a, [hSPTemp + 1]
+ ld h, a
+ ld sp, hl
+ ret
+
+; Copy [wVBCopyDoubleSize] 1bpp tiles
+; from wVBCopyDoubleSrc to wVBCopyDoubleDst.
+; wVBCopyDoubleDst must be aligned to 0x10 bytes.
+
+; While we're here, convert to 2bpp.
+; The process is straightforward:
+; copy each byte twice.
+VBlankCopyDouble:: ; 1470 (0:1470)
+ ld a, [wVBCopyDoubleSize]
+ and a
+ ret z
+ ld [hSPTemp], sp
+ ld hl, wVBCopyDoubleSrc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld sp, hl
+ ld hl, wVBCopyDoubleDst
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wVBCopyDoubleSize]
+ ld b, a
+ xor a
+ ld [wVBCopyDoubleSize], a
+.loop
+
+ rept 16/4 - 1 ; 16 bytes per 2bpp tile at 2 bytes per pop
+ pop de ; copied twice minus last block
+ ld [hl], e
+ inc l
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ ld [hl], d
+ inc l
+ endr
+
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ ld [hl], d
+ inc hl
+ dec b
+ jr nz, .loop
+ ld a, l
+ ld [wVBCopyDoubleDst], a
+ ld a, h
+ ld [wVBCopyDoubleDst + 1], a
+ ld [wVBCopyDoubleSrc], sp
+ ldh a, [hSPTemp]
+ ld l, a
+ ldh a, [hSPTemp + 1]
+ ld h, a
+ ld sp, hl
+ ret
+
+; Copy 16 * [wVBCopySize] bytes
+; from wVBCopySrc to wVBCopyDst.
+; wVBCopyDst must be aligned to 0x10 bytes.
+
+; Source and destination addresses are updated,
+; so transfer can continue in subsequent calls.
+VBlankCopy:: ; 14c7 (0:14c7)
+ ld a, [wVBCopySize]
+ and a
+ ret z
+ ld [hSPTemp], sp
+ ld hl, wVBCopySrc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld sp, hl
+ ld hl, wVBCopyDst
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wVBCopySize]
+ ld b, a
+ xor a
+ ld [wVBCopySize], a
+.loop
+
+ rept 16/2 - 1 ; 16 bytes per transfer at 2 bytes per pop
+ pop de ; minus last block
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ endr
+
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc hl
+ dec b
+ jr nz, .loop
+ ld a, l
+ ld [wVBCopyDst], a
+ ld a, h
+ ld [wVBCopyDst + 1], a
+ ld [wVBCopySrc], sp
+ ldh a, [hSPTemp]
+ ld l, a
+ ldh a, [hSPTemp + 1]
+ ld h, a
+ ld sp, hl
+ ret
+
+AnimateTileset:: ; 1522 (0:1522)
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(AnimateTilesetImpl)
+ call Bankswitch
+ call AnimateTilesetImpl
+ pop af
+ jp Bankswitch
+; 0x1531
+
+EnableSprites:: ; 1531 (0:1531)
+ nop
+ ld hl, rLCDC
+ set rLCDC_SPRITES_ENABLE, [hl]
+ ret
+; 0x1538
+
+Function_1538: ; 1538 (0:1538)
+ ld a, [$d14f]
+ bit 0, a
+ ret z
+ bit 7, a
+ ret nz
+ bit 2, a
+ res 2, a
+ ret z
+ ld [$d14f], a
+ ld [hSPTemp], sp
+ ld hl, $cbd2
+ ld sp, hl
+ ld hl, $9c20
+ ld a, $01
+ jp TransferBgRows
+
+; Copy 0x10 * [wVBCopyFarSize] bytes
+; from wVBCopyFarSrcBank::wVBCopyFarSrc to wVBCopyFarDst.
+; wVBCopyFarDst must be aligned to 0x10 bytes.
+
+; Source and destination addresses are updated,
+; so transfer can continue in subsequent calls.
+VBlankCopyFar:: ; 1558 (0:1558)
+ ld a, [wVBCopyFarSize]
+ and a
+ ret z
+ ld a, [wVBCopyFarSrcBank]
+ call Bankswitch
+ ld [hSPTemp], sp
+ ld hl, wVBCopyFarSrc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld sp, hl
+ ld hl, wVBCopyFarDst
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wVBCopyFarSize]
+ ld b, a
+ xor a
+ ld [wVBCopyFarSize], a
+.loop
+ rept 16/2 - 1 ; 16 bytes per transfer at 2 bytes per pop
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc l
+ endr
+
+ pop de
+ ld [hl], e
+ inc l
+ ld [hl], d
+ inc hl
+ dec b
+ jr nz, .loop
+ ld [wVBCopyFarSrc], sp
+ ld sp, hl
+ ld [wVBCopyFarDst], sp
+ ldh a, [hSPTemp]
+ ld l, a
+ ldh a, [hSPTemp + 1]
+ ld h, a
+ ld sp, hl
+ ret
+; 0x15b5