diff options
Diffstat (limited to 'home/vcopy.asm')
-rw-r--r-- | home/vcopy.asm | 615 |
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 |