summaryrefslogtreecommitdiff
path: root/home
diff options
context:
space:
mode:
authorPikalaxALT <pikalaxalt@gmail.com>2018-06-02 21:26:20 -0400
committerPikalaxALT <pikalaxalt@gmail.com>2018-06-02 21:26:20 -0400
commit04883f4bf9fa6c0bf935f1aac95d5d48abe3bb30 (patch)
tree3ff95e7bbb62d0decfb9e2cba9e3d54f61013706 /home
parent956d010d59ad225bea768aec172ccb56977b1775 (diff)
parent5fb7140613d6ea00ec1964fde18418c6257c2e27 (diff)
Merge branch 'master' into build_more_roms
Diffstat (limited to 'home')
-rw-r--r--home/audio.asm247
-rw-r--r--home/bankswitch.asm6
-rw-r--r--home/clear_sprites.asm32
-rw-r--r--home/copy.asm149
-rw-r--r--home/copy2.asm28
-rw-r--r--home/copy_tilemap.asm24
-rw-r--r--home/delay.asm28
-rw-r--r--home/farcall.asm62
-rw-r--r--home/init.asm221
-rw-r--r--home/interrupts.asm14
-rwxr-xr-xhome/items.asm145
-rw-r--r--home/joypad.asm285
-rw-r--r--home/lcd.asm120
-rw-r--r--home/names.asm23
-rw-r--r--home/oam_dma.asm30
-rw-r--r--home/pic.asm40
-rw-r--r--home/pokemon.asm28
-rw-r--r--home/predef.asm72
-rw-r--r--home/print_bcd.asm113
-rw-r--r--home/print_hex.asm42
-rw-r--r--home/print_num.asm252
-rw-r--r--home/serial.asm87
-rw-r--r--home/sram.asm28
-rw-r--r--home/text.asm368
-rw-r--r--home/unknown.asm32
-rw-r--r--home/vblank.asm315
-rw-r--r--home/vcopy.asm616
27 files changed, 2761 insertions, 646 deletions
diff --git a/home/audio.asm b/home/audio.asm
index ede88d4..bf3a6c5 100644
--- a/home/audio.asm
+++ b/home/audio.asm
@@ -7,143 +7,136 @@ SECTION "Audio interface", ROM0[$3C83]
endc
DisableAudio:: ; 3cbf
- push hl
- push de
- push bc
- push af
- ldh a, [hROMBank]
- push af
- ld a, BANK(_DisableAudio)
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- call _DisableAudio
- pop af
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- pop af
- pop bc
- pop de
- pop hl
- ret
-
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(_DisableAudio)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _DisableAudio
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
UpdateSound:: ; 3cdb
- push hl
- push de
- push bc
- push af
- ldh a, [hROMBank]
- push af
- ld a, BANK(_UpdateSound)
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- call _UpdateSound
- pop af
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- pop af
- pop bc
- pop de
- pop hl
- ret
-
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(_UpdateSound)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _UpdateSound
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
_LoadMusicByte:: ; 3cf7
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- ld a, [de]
- push af
- ld a, BANK(_UpdateSound)
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- pop af
- ret
-
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ ld a, [de]
+ push af
+ ld a, BANK(_UpdateSound)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ ret
PlayMusic:: ; 3d07
- push hl
- push de
- push bc
- push af
- ldh a, [hROMBank]
- push af
- ld a, BANK(_PlayMusic)
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- call _PlayMusic
- pop af
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- pop af
- pop bc
- pop de
- pop hl
- ret
-
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(_PlayMusic)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _PlayMusic
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
PlayCryHeader:: ; 3d23
- push hl
- push de
- push bc
- push af
- ldh a, [hROMBank]
- push af
-
- ld a, BANK(CryHeaders)
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- ld hl, CryHeaders
-REPT 6
- add hl, de
-ENDR
- ld e, [hl]
- inc hl
- ld d, [hl]
- inc hl
- ld a, [hli]
- ld [wCryPitch], a
- ld a, [hli]
- ld [wCryPitch + 1], a
- ld a, [hli]
- ld [wCryLength], a
- ld a, [hl]
- ld [wCryLength + 1], a
-
- ld a, BANK(_PlayCryHeader)
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- call _PlayCryHeader
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+
+ ld a, BANK(CryHeaders)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ ld hl, CryHeaders
+rept 6
+ add hl, de
+endr
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld a, [hli]
+ ld [wCryPitch], a
+ ld a, [hli]
+ ld [wCryPitch + 1], a
+ ld a, [hli]
+ ld [wCryLength], a
+ ld a, [hl]
+ ld [wCryLength + 1], a
+
+ ld a, BANK(_PlayCryHeader)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _PlayCryHeader
- pop af
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- pop af
- pop bc
- pop de
- pop hl
- ret
-
-
-
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
PlaySFX:: ; 3d63
- push hl
- push de
- push bc
- push af
- ldh a, [hROMBank]
- push af
- ld a, BANK(_PlaySFX)
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- call _PlaySFX
- pop af
- ld [MBC3RomBank], a ; Unsafe
- ldh [hROMBank], a
- pop af
- pop bc
- pop de
- pop hl
- ret
+ push hl
+ push de
+ push bc
+ push af
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(_PlaySFX)
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ call _PlaySFX
+ pop af
+ ld [MBC3RomBank], a ; Unsafe
+ ldh [hROMBank], a
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
WaitPlaySFX:: ; 3d7f
diff --git a/home/bankswitch.asm b/home/bankswitch.asm
index 574fa64..278013c 100644
--- a/home/bankswitch.asm
+++ b/home/bankswitch.asm
@@ -9,6 +9,6 @@ endc
; Moved to a rst vector in final US releases (not sure about JP)
; All rst vectors are unused at this point in development
Bankswitch:: ; 32c2
- ldh [hROMBank], a
- ld [MBC3RomBank], a
- ret
+ ldh [hROMBank], a
+ ld [MBC3RomBank], a
+ ret
diff --git a/home/clear_sprites.asm b/home/clear_sprites.asm
index 90e8f38..489b375 100644
--- a/home/clear_sprites.asm
+++ b/home/clear_sprites.asm
@@ -7,23 +7,23 @@ SECTION "Sprite clearing", ROM0[$32A0]
endc
ClearSprites:: ; 32dc
- ld hl, wVirtualOAM
- ld b, wVirtualOAMEnd - wVirtualOAM
- xor a
+ ld hl, wVirtualOAM
+ ld b, wVirtualOAMEnd - wVirtualOAM
+ xor a
.loop
- ld [hli], a
- dec b
- jr nz, .loop
- ret
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
HideSprites:: ; 32e7
- ld hl, wVirtualOAM
- ld de, SPRITEOAMSTRUCT_LENGTH
- ld b, NUM_SPRITE_OAM_STRUCTS
- ld a, $A0
+ ld hl, wVirtualOAM
+ ld de, SPRITEOAMSTRUCT_LENGTH
+ ld b, NUM_SPRITE_OAM_STRUCTS
+ ld a, SPRITEOAMSTRUCT_LENGTH * NUM_SPRITE_OAM_STRUCTS
.loop
- ld [hl], a
- add hl, de
- dec b
- jr nz, .loop
- ret
+ ld [hl], a
+ add hl, de
+ dec b
+ jr nz, .loop
+ ret
diff --git a/home/copy.asm b/home/copy.asm
index 757da0d..c916cbd 100644
--- a/home/copy.asm
+++ b/home/copy.asm
@@ -6,72 +6,109 @@ else
SECTION "Copy functions", ROM0[$32BB]
endc
-; Copy bc bytes from a:hl to de.
FarCopyBytes:: ; 32f7
- ld [wBuffer], a
- ldh a, [hROMBank]
- push af
- ld a, [wBuffer]
- call Bankswitch
- call CopyBytes
- pop af
- jp Bankswitch
+; Copy bc bytes from a:hl to de.
+ ld [wBuffer], a
+ ldh a, [hROMBank]
+ push af
+ ld a, [wBuffer]
+ call Bankswitch
+ call CopyBytes
+ pop af
+ jp Bankswitch
-; Copy bc bytes from hl to de
CopyBytes:: ; 330a
- ld a, b
- and a
- jr z, CopyBytesSmall
- ld a, c
- and a
- jr z, .next
- inc b
+; Copy bc bytes from hl to de
+ ld a, b
+ and a
+ jr z, CopyBytesSmall
+ ld a, c
+ and a
+ jr z, .next
+ inc b
.next
- call CopyBytesSmall
- dec b
- jr nz, .next
- ret
+ call CopyBytesSmall
+ dec b
+ jr nz, .next
+ ret
-; Copy c bytes from hl to de
CopyBytesSmall:: ; 331a
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, CopyBytesSmall
- ret
-
+; Copy c bytes from hl to de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, CopyBytesSmall
+ ret
GetFarByte:: ; 3321
- ld [wBuffer], a
- ldh a, [hROMBank]
- push af
- ld a, [wBuffer]
- call Bankswitch
- ld a, [hl]
- ld [wBuffer], a
- pop af
- call Bankswitch
- ld a, [wBuffer]
- ret
-
+ ld [wBuffer], a
+ ldh a, [hROMBank]
+ push af
+ ld a, [wBuffer]
+ call Bankswitch
+ ld a, [hl]
+ ld [wBuffer], a
+ pop af
+ call Bankswitch
+ ld a, [wBuffer]
+ ret
ByteFill:: ; 3339
- push af
- ld a, b
- and a
- jr z, .small_fill
- ld a, c
- and a
- jr z, .start_filling
+ push af
+ ld a, b
+ and a
+ jr z, .small_fill
+ ld a, c
+ and a
+ jr z, .start_filling
.small_fill
- inc b
+ inc b
.start_filling
- pop af
+ pop af
.loop
- ld [hli], a
- dec c
- jr nz, .loop
- dec b
- jr nz, .loop
- ret
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ dec b
+ jr nz, .loop
+ ret
+
+UncompressSpriteFromDE::
+; Decompress pic at a:de.
+ ld hl, wSpriteInputPtr
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ jp UncompressSpriteData
+
+BackUpTilesToBuffer:: ; 3355
+ hlcoord 0, 0
+ decoord 0, 0, wTileMapBackup
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ jp CopyBytes
+
+ReloadTilesFromBuffer:: ; 3361
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 0, 0, wTileMapBackup
+ decoord 0, 0
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ call CopyBytes
+ ld a, 1
+ ldh [hBGMapMode], a
+ ret
+
+CopyStringToCD31::
+; copies a string from [de] to [wcd31]
+ ld hl, wcd31
+ ; fallthrough
+
+CopyString::
+; copies a string from [de] to [hl]
+ ld a, [de]
+ inc de
+ ld [hli], a
+ cp "@"
+ jr nz, CopyString
+ ret
diff --git a/home/copy2.asm b/home/copy2.asm
index 27abf08..0a0ee54 100644
--- a/home/copy2.asm
+++ b/home/copy2.asm
@@ -2,9 +2,9 @@ INCLUDE "constants.asm"
SECTION "Video Copy functions", ROM0[$0D2A]
+FarCopyData: ; d2a (0:d2a)
; Identical to FarCopyBytes except for tail call optimization
; Copy bc 2bpp bytes from a:hl to de.
-FarCopyData: ; d2a (0:d2a)
ld [wBuffer], a
ldh a, [hROMBank]
push af
@@ -15,8 +15,8 @@ FarCopyData: ; d2a (0:d2a)
call Bankswitch
ret
-; Copy and expand bc 1bpp bytes from a:hl to de.
FarCopyDataDouble: ; d3e (0:d3e)
+; Copy and expand bc 1bpp bytes from a:hl to de.
ld [wBuffer], a
ldh a, [hROMBank]
push af
@@ -49,10 +49,10 @@ FarCopyDataDouble: ; d3e (0:d3e)
call Bankswitch
ret
+CopyVideoData:: ; d68 (0:d68)
; Wait for the next VBlank, then copy c 2bpp
; tiles from b:de to hl, 8 tiles at a time.
; This takes c/8 frames.
-CopyVideoData:: ; d68 (0:d68)
ldh a, [hBGMapMode]
push af
xor a ; disable auto-transfer while copying
@@ -71,7 +71,7 @@ CopyVideoData:: ; d68 (0:d68)
ld [wVBCopyDst + 1], a
.loop
ld a, c
- cp $08
+ cp $8
jr nc, .keepgoing
ld [wVBCopySize], a
call DelayFrame
@@ -81,18 +81,18 @@ CopyVideoData:: ; d68 (0:d68)
ldh [hBGMapMode], a
ret
.keepgoing
- ld a, $08
+ ld a, $8
ld [wVBCopySize], a
call DelayFrame
ld a, c
- sub $08
+ sub $8
ld c, a
jr .loop
+CopyVideoDataDouble:: ; da6 (0:da6)
; Wait for the next VBlank, then copy c 1bpp
; tiles from b:de to hl, 8 tiles at a time.
; This takes c/8 frames.
-CopyVideoDataDouble:: ; da6 (0:da6)
ldh a, [hBGMapMode]
push af
xor a
@@ -111,7 +111,7 @@ CopyVideoDataDouble:: ; da6 (0:da6)
ld [wVBCopyDoubleDst + 1], a
.loop
ld a, c
- cp $08
+ cp $8
jr nc, .keepgoing
ld [wVBCopyDoubleSize], a
call DelayFrame
@@ -121,18 +121,18 @@ CopyVideoDataDouble:: ; da6 (0:da6)
ldh [hBGMapMode], a
ret
.keepgoing
- ld a, $08
+ ld a, $8
ld [wVBCopyDoubleSize], a
call DelayFrame
ld a, c
- sub $08
+ sub $8
ld c, a
jr .loop
+CopyVideoDataOptimized:: ; de4 (0:de4)
; Copy c 2bpp tiles from b:de to hl in VRAM
; using VBlank service or direct copy in
; case LCD is off
-CopyVideoDataOptimized:: ; de4 (0:de4)
ldh a, [rLCDC]
bit rLCDC_ENABLE, a
jp nz, CopyVideoData ; copy video data during vblank while screen is on
@@ -152,10 +152,10 @@ CopyVideoDataOptimized:: ; de4 (0:de4)
pop af
jp FarCopyData
+CopyVideoDataDoubleOptimized: ; dff (0:dff)
; Copy c 1bpp tiles from b:de to hl in VRAM
; using VBlank service or direct copy in
; case LCD is off
-CopyVideoDataDoubleOptimized: ; dff (0:dff)
ldh a, [rLCDC]
bit rLCDC_ENABLE, a
jp nz, CopyVideoDataDouble
@@ -164,7 +164,7 @@ CopyVideoDataDoubleOptimized: ; dff (0:dff)
ld e, l
ld a, b
push af
- ld h, $00
+ ld h, 0
ld l, c
add hl, hl
add hl, hl
@@ -174,4 +174,4 @@ CopyVideoDataDoubleOptimized: ; dff (0:dff)
pop af
pop hl
jp FarCopyDataDouble
-; 0xe18 \ No newline at end of file
+; 0xe18
diff --git a/home/copy_tilemap.asm b/home/copy_tilemap.asm
deleted file mode 100644
index 27c33c0..0000000
--- a/home/copy_tilemap.asm
+++ /dev/null
@@ -1,24 +0,0 @@
-INCLUDE "constants.asm"
-
-if DEBUG
-SECTION "Tilemap copy/restore funcs", ROM0[$3355]
-else
-SECTION "Tilemap copy/restore funcs", ROM0[$3319]
-endc
-
-BackUpTilesToBuffer:: ; 3355
- hlcoord 0, 0
- decoord 0, 0, wTileMapBackup
- ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
- jp CopyBytes
-
-ReloadTilesFromBuffer:: ; 3361
- xor a
- ldh [hBGMapMode], a
- hlcoord 0, 0, wTileMapBackup
- decoord 0, 0
- ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
- call CopyBytes
- ld a, 1
- ldh [hBGMapMode], a
- ret
diff --git a/home/delay.asm b/home/delay.asm
index dc3ad40..286cc0c 100644
--- a/home/delay.asm
+++ b/home/delay.asm
@@ -4,23 +4,19 @@ SECTION "Delay", ROM0[$0317]
DelayFrame::
; Wait for one frame
- ld a, 1
- ld [wVBlankOccurred], a
-
-; Wait for the next VBlank, halting to conserve battery
+ ld a, 1
+ ld [wVBlankOccurred], a
.halt
- halt ; rgbasm adds a nop after this instruction by default
- ld a, [wVBlankOccurred]
- and a
- jr nz, .halt
-
- ret
-
+; Wait for the next VBlank, halting to conserve battery
+ halt ; rgbasm adds a nop after this instruction by default
+ ld a, [wVBlankOccurred]
+ and a
+ jr nz, .halt
+ ret
DelayFrames::
; Wait c frames
- call DelayFrame
- dec c
- jr nz, DelayFrames
-
- ret
+ call DelayFrame
+ dec c
+ jr nz, DelayFrames
+ ret
diff --git a/home/farcall.asm b/home/farcall.asm
index 32fcce5..3fcf37f 100644
--- a/home/farcall.asm
+++ b/home/farcall.asm
@@ -7,36 +7,36 @@ SECTION "FarCall", ROM0[$2F6C]
endc
FarCall_hl:: ; 2fa8
- push af
- ld a, b
- ld [wFarCallBCBuffer], a
- ld a, c
- ld [wFarCallBCBuffer + 1], a
- pop af
- ld b, a
- ldh a, [hROMBank]
- push af
- ld a, b
- call Bankswitch
- ld bc, .return
- push bc
- push hl
- ld a, [wFarCallBCBuffer]
- ld b, a
- ld a, [wFarCallBCBuffer + 1]
- ld c, a
- ret
+ push af
+ ld a, b
+ ld [wFarCallBCBuffer], a
+ ld a, c
+ ld [wFarCallBCBuffer + 1], a
+ pop af
+ ld b, a
+ ldh a, [hROMBank]
+ push af
+ ld a, b
+ call Bankswitch
+ ld bc, .return
+ push bc
+ push hl
+ ld a, [wFarCallBCBuffer]
+ ld b, a
+ ld a, [wFarCallBCBuffer + 1]
+ ld c, a
+ ret
.return
- ld a, b
- ld [wFarCallBCBuffer], a
- ld a, c
- ld [wFarCallBCBuffer + 1], a
- pop bc
- ld a, b
- call Bankswitch
- ld a, [wFarCallBCBuffer]
- ld b, a
- ld a, [wFarCallBCBuffer + 1]
- ld c, a
- ret
+ ld a, b
+ ld [wFarCallBCBuffer], a
+ ld a, c
+ ld [wFarCallBCBuffer + 1], a
+ pop bc
+ ld a, b
+ call Bankswitch
+ ld a, [wFarCallBCBuffer]
+ ld b, a
+ ld a, [wFarCallBCBuffer + 1]
+ ld c, a
+ ret
diff --git a/home/init.asm b/home/init.asm
index 5498b35..ef4b745 100644
--- a/home/init.asm
+++ b/home/init.asm
@@ -1,8 +1,8 @@
INCLUDE "constants.asm"
SECTION "Entry point", ROM0[$100]
- nop
- jp Init
+ nop
+ jp Init
SECTION "Global check value", ROM0[$14E]
; The ROM has an incorrect global check, so set it here
@@ -25,121 +25,122 @@ endc
SECTION "Init", ROM0[$52F]
Init: ; 052f
- di
- xor a
- ld [rIF], a
- ld [rIE], a
- ld [rSCX], a
- ld [rSCY], a
- ld [rSB], a
- ld [rSC], a
- ld [rWX], a
- ld [rWY], a
- ld [rBGP], a
- ld [rOBP0], a
- ld [rOBP1], a
- ld [rTMA], a
- ld [rTAC], a
- ld [wcc38], a ; Useless, since WRAM gets cleared right after
- ld a, 1 << rTAC_ON | rTAC_4096_HZ
- ld [rTAC], a
- ld a, 1 << rLCDC_ENABLE
- ld [rLCDC], a
- call DisableLCD
-
- ld sp, wStackBottom
- call ClearVRAM
- ld hl, WRAM0_Begin
- ld bc, WRAM1_End - WRAM0_Begin
+ di
+ xor a
+ ld [rIF], a
+ ld [rIE], a
+ ld [rSCX], a
+ ld [rSCY], a
+ ld [rSB], a
+ ld [rSC], a
+ ld [rWX], a
+ ld [rWY], a
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld [rOBP1], a
+ ld [rTMA], a
+ ld [rTAC], a
+ ld [wcc38], a ; Useless, since WRAM gets cleared right after
+ ld a, 1 << rTAC_ON | rTAC_4096_HZ
+ ld [rTAC], a
+ ld a, 1 << rLCDC_ENABLE
+ ld [rLCDC], a
+ call DisableLCD
+
+ ld sp, wStackBottom
+ call ClearVRAM
+ ld hl, WRAM0_Begin
+ ld bc, WRAM1_End - WRAM0_Begin
.ByteFill ; 0565
- ld [hl], 0
- inc hl
- dec bc
- ld a, b
- or c
- jr nz, .ByteFill
- ld hl, HRAM_Begin
- ld bc, HRAM_End - HRAM_Begin
- call ByteFill
- call ClearSprites
-
- ld a, BANK(WriteOAMDMACodeToHRAM)
- call Bankswitch
- call WriteOAMDMACodeToHRAM
-
- xor a
- ldh [hMapAnims], a
- ldh [hSCX], a
- ldh [hSCY], a
- ldh [rJOYP], a
- ld a, 1 << rSTAT_HBLANK
- ld [rSTAT], a
- ld a, SCREEN_HEIGHT_PX
- ldh [hWY], a
- ld [rWY], a
- ld a, 7
- ldh [hWX], a
- ld [rWX], a
-
- ld a, $FF
- ldh [hLinkPlayerNumber], a
- ld h, HIGH($9800)
- call BlankBGMap
- ld h, HIGH($9C00)
- call BlankBGMap
- ld a, LCDC_DEFAULT
- ld [rLCDC], a
-
- call DisableAudio
- call _2007
- ; predef ???
- ld a, $4B ; TODO: add predefs so the line above can be uncommented
- call Predef
- ld a, $1F
- ld [rIE], a
- ld a, HIGH($9C00)
- ldh [hBGMapAddress + 1], a
- xor a
- ldh [hBGMapAddress], a
-
- call DisableLCD
- call ClearVRAM
- ld a, LCDC_DEFAULT
- ld [rLCDC], a
- ei
-
- ld a, SRAM_ENABLE
- ld [MBC3SRamEnable], a
- ld a, RTC_DH
- ld [MBC3SRamBank], a
- xor a
- ld [SRAM_Begin], a
- ld a, 0 ; Useless
- ld [MBC3LatchClock], a
- ld [MBC3SRamEnable], a
- jp GameInit
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .ByteFill
+ ld hl, HRAM_Begin
+ ld bc, HRAM_End - HRAM_Begin
+ call ByteFill
+ call ClearSprites
+
+ ld a, BANK(WriteOAMDMACodeToHRAM)
+ call Bankswitch
+ call WriteOAMDMACodeToHRAM
+
+ xor a
+ ldh [hMapAnims], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ldh [rJOYP], a
+ ld a, 1 << rSTAT_HBLANK
+ ld [rSTAT], a
+ ld a, SCREEN_HEIGHT_PX
+ ldh [hWY], a
+ ld [rWY], a
+ ld a, 7
+ ldh [hWX], a
+ ld [rWX], a
+
+ ld a, $ff
+ ldh [hLinkPlayerNumber], a
+ ld h, HIGH($9800)
+ call BlankBGMap
+ ld h, HIGH($9C00)
+ call BlankBGMap
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+
+ call DisableAudio
+ call _2007
+ ; predef ???
+ ld a, $4B ; TODO: add predefs so the line above can be uncommented
+ call Predef
+ ld a, $1F
+ ld [rIE], a
+ ld a, HIGH($9C00)
+ ldh [hBGMapAddress + 1], a
+ xor a
+ ldh [hBGMapAddress], a
+
+ call DisableLCD
+ call ClearVRAM
+ ld a, LCDC_DEFAULT
+ ld [rLCDC], a
+ ei
+
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ ld a, RTC_DH
+ ld [MBC3SRamBank], a
+ xor a
+ ld [SRAM_Begin], a
+ ld a, 0 ; Useless
+ ld [MBC3LatchClock], a
+ ld [MBC3SRamEnable], a
+ jp GameInit
ClearVRAM: ; 05e6
- ld hl, VRAM_Begin
- ld bc, VRAM_End - VRAM_Begin
- xor a
- call ByteFill
- ret
+ ld hl, VRAM_Begin
+ ld bc, VRAM_End - VRAM_Begin
+ xor a
+ call ByteFill
+ ret
BlankBGMap:
- ld a, $7F
- jr _FillBGMap
+ ld a, $7f
+ jr _FillBGMap
FillBGMap:
- ld a, l
+ ld a, l
+ ; fallthrough
_FillBGMap:
- ld de, $400
- ld l, e
+ ld de, BG_MAP_WIDTH * BG_MAP_HEIGHT
+ ld l, e
.loop
- ld [hli], a
- dec e
- jr nz, .loop
- dec d
- jr nz, .loop
- ret
+ ld [hli], a
+ dec e
+ jr nz, .loop
+ dec d
+ jr nz, .loop
+ ret
diff --git a/home/interrupts.asm b/home/interrupts.asm
index b7800f1..f9d8ba1 100644
--- a/home/interrupts.asm
+++ b/home/interrupts.asm
@@ -1,28 +1,28 @@
INCLUDE "constants.asm"
SECTION "VBlank interrupt vector", ROM0[$040]
- jp VBlank
+ jp VBlank
SECTION "LCD interrupt vector", ROM0[$048]
- jp LCD
+ jp LCD
SECTION "Timer interrupt vector", ROM0[$050]
- jp TimerDummy
+ jp TimerDummy
SECTION "Serial interrupt vector", ROM0[$058]
- jp Serial
+ jp Serial
SECTION "Joypad interrupt vector", ROM0[$060]
- jp JoypadDummy
+ jp JoypadDummy
SECTION "Timer dummy interrupt", ROM0[$42A]
TimerDummy: ; 042a
- reti
+ reti
SECTION "Joypad dummy interrupt", ROM0[$7F7]
JoypadDummy: ; 07f7
- reti
+ reti
diff --git a/home/items.asm b/home/items.asm
new file mode 100755
index 0000000..496b685
--- /dev/null
+++ b/home/items.asm
@@ -0,0 +1,145 @@
+INCLUDE "constants.asm"
+
+if DEBUG
+SECTION "AddItemToInventory", ROM0[$3259]
+else
+SECTION "AddItemToInventory", ROM0[$321D]
+endc
+
+AddItemToInventory:: ; 3259
+; function to add an item (in varying quantities) to the player's bag or PC box
+; INPUT:
+; HL = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wcd76] = item ID
+; [wItemQuantity] = item quantity
+; sets carry flag if successful, unsets carry flag if unsuccessful
+ push bc
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(AddItemToInventory_)
+ call Bankswitch
+ push hl
+ push de
+ call AddItemToInventory_
+ pop de
+ pop hl
+ pop bc
+ ld a, b
+ call Bankswitch
+ pop bc
+ ret
+
+if DEBUG
+SECTION "GiveItem", ROM0[$366C]
+else
+SECTION "GiveItem", ROM0[$3630]
+endc
+
+GiveItem::
+; Give player quantity c of item b,
+; and copy the item's name to wcf4b.
+; Return carry on success.
+ ld a, b
+ ld [wce37], a
+ ld [wcd76], a
+ ld a, c
+ ld [wItemQuantity], a
+ ld hl, wNumBagItems
+ call AddItemToInventory
+ ret nc
+ call GetItemName
+ call CopyStringToCD31
+ scf
+ ret
+
+if DEBUG
+SECTION "GetItemName", ROM0[$376F]
+else
+SECTION "GetItemName", ROM0[$3733]
+endc
+
+GetItemName:: ; 376F
+; given an item ID at [wce37], store the name of the item into a string
+; starting at wcd26
+ push hl
+ push bc
+ ld a, [wce37]
+ cp ITEM_HM01_RED
+ jr nc, .machine
+
+ ld [wcb5b], a
+ ld a, ITEM_NAME
+ ld [wNameCategory], a
+ call GetName
+ jr .finish
+
+.machine
+ call GetMachineName
+.finish
+ ld de, wcd26 ; pointer to where item name is stored in RAM
+ pop bc
+ pop hl
+ ret
+
+if DEBUG
+SECTION "GetMachineName", ROM0[$378E]
+else
+SECTION "GetMachineName", ROM0[$3752]
+endc
+
+GetMachineName::
+; copies the name of the TM/HM in [wce37] to wcd26
+ push hl
+ push de
+ push bc
+ ld a, [wce37]
+ push af
+ cp ITEM_TM01_RED
+ jr nc, .WriteTM
+; if HM, then write "HM" and add 5 to the item ID, so we can reuse the
+; TM printing code
+ add 5
+ ld [wce37], a
+ ld hl, HiddenPrefix
+ ld bc, 6
+ jr .WriteMachinePrefix
+.WriteTM
+ ld hl, TechnicalPrefix
+ ld bc, 5
+.WriteMachinePrefix
+ ld de, wcd26
+ call CopyBytes
+; now get the machine number and convert it to text
+ ld a, [wce37]
+ sub ITEM_TM01_RED - 1
+ ld b, "0"
+.FirstDigit
+ sub 10
+ jr c, .SecondDigit
+ inc b
+ jr .FirstDigit
+.SecondDigit
+ add 10
+ push af
+ ld a, b
+ ld [de], a
+ inc de
+ pop af
+ ld b, "0"
+ add b
+ ld [de], a
+ inc de
+ ld a, "@"
+ ld [de], a
+ pop af
+ ld [wce37], a
+ pop bc
+ pop de
+ pop hl
+ ret
+
+TechnicalPrefix:
+ db "わざマシン@"
+
+HiddenPrefix:
+ db "ひでんマシン@"
diff --git a/home/joypad.asm b/home/joypad.asm
new file mode 100644
index 0000000..e0740f2
--- /dev/null
+++ b/home/joypad.asm
@@ -0,0 +1,285 @@
+INCLUDE "constants.asm"
+
+SECTION "Joypad functions", ROM0[$07FE]
+
+Joypad:: ; 7fe (0:7fe)
+; Read the joypad register and translate it to something more
+; workable for use in-game. There are 8 buttons, so we can use
+; one byte to contain all player input.
+
+; Updates:
+
+; hJoypadUp: released this frame (delta)
+; hJoypadDown: pressed this frame (delta)
+; hJoypadState: currently pressed
+; hJoypadSum: pressed so far
+ ld a, [$d4ab]
+ and $d0
+ ret nz
+ ld a, 1 << 5 ; select direction keys
+ ldh [rJOYP], a
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ cpl
+ and $0f
+ swap a
+ ld b, a
+ ld a, 1 << 4 ; select button keys
+ ldh [rJOYP], a
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ cpl
+ and $0f
+ or b
+ ld b, a
+ ld a, (1 << 5 | 1 << 4) ; port reset
+ ldh [rJOYP], a
+ ldh a, [hJoypadState]
+ ld e, a
+ xor b
+ ld d, a
+ and e
+ ldh [hJoypadUp], a
+ ld a, d
+ and b
+ ldh [hJoypadDown], a
+ ld c, a
+ ldh a, [hJoypadSum]
+ or c
+ ldh [hJoypadSum], a
+ ld a, b
+ ldh [hJoypadState], a
+ ldh [hJoypadState2], a
+ ; Soft-Reset by holding A+B+SELECT+START
+ and (A_BUTTON | B_BUTTON | SELECT | START)
+ cp (A_BUTTON | B_BUTTON | SELECT | START)
+ jp z, Reset
+ ret
+
+GetJoypad:: ; 84a (0:84a)
+; Update mirror joypad input from hJoypadState (real input)
+
+; hJoyReleased, hJoyDown and hJoyState are synchronized
+; copies of their hJoypad* counterparts.
+
+; bit 0 A
+; 1 B
+; 2 SELECT
+; 3 START
+; 4 RIGHT
+; 5 LEFT
+; 6 UP
+; 7 DOWN
+ push af
+ push hl
+ push de
+ ld hl, wJoypadFlags
+ set 6, [hl] ; mutex
+ ld hl, hJoypadDown
+ ld de, hJoyDown
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld hl, wJoypadFlags
+ res 6, [hl]
+ pop de
+ pop hl
+ pop af
+ ret
+
+JoyTitleScreenInput:: ; 869 (0:869)
+; Check if any of the following conditions
+; is met for c frames
+; - B, Select and Up keys are pressed in same frame
+; - A is pressed
+; - START is pressed
+;
+; Inputs: c - number of frames to check for
+; Return: carry set if condition met, else reset
+.loop
+ call DelayFrame
+ push bc
+ call GetJoypadDebounced
+ pop bc
+ ldh a, [hJoyState]
+ cp (D_UP | SELECT | B_BUTTON)
+ jr z, .done
+ ldh a, [hJoySum]
+ and (START | A_BUTTON)
+ jr nz, .done
+ dec c
+ jr nz, .loop
+ and a
+ ret
+.done
+ scf
+ ret
+
+GetJoypadDebounced:: ; 884 (0:884)
+; Update hJoySum joypad input from either hJoyDown or
+; hJoyState depending on hJoyDebounceSrc.
+; hJoyState is only updated every 5 frames and
+; the update is delayed by 15 frames after any button
+; press.
+ call GetJoypad
+ ldh a, [hJoyDebounceSrc]
+ and a
+ ldh a, [hJoyDown]
+ jr z, .joyDownSrc
+.joyStateSrc
+ ldh a, [hJoyState]
+.joyDownSrc
+ ldh [hJoySum], a
+ ldh a, [hJoyDown]
+ and a
+ jr z, .sampleAfterPress
+ ld a, $0f
+ ld [wVBlankJoyFrameCounter], a
+ ret
+.sampleAfterPress
+ ld a, [wVBlankJoyFrameCounter]
+ and a
+ jr z, .sampleRegular
+ xor a
+ ldh [hJoySum], a
+ ret
+.sampleRegular
+ ld a, $05
+ ld [wVBlankJoyFrameCounter], a
+ ret
+; 0x8ad
+
+TextboxWaitPressAorB_BlinkCursor: ; 8ad (0:8ad)
+; Show a blinking cursor in the lower right-hand
+; corner of a textbox and wait until A or B is
+; pressed.
+;
+; CAUTION: The cursor has to be shown when calling
+; this function or no cursor will be shown at all.
+; Waiting on button presses is unaffected by this.
+ ldh a, [hSpriteWidth] ; hTextBoxCursorBlinkInterval is shared with
+ push af ; hSpriteWidth and hSpriteHeight, so we need
+ ldh a, [hSpriteHeight] ; to back them up
+ push af
+ xor a
+ ldh [hTextBoxCursorBlinkInterval], a
+ ld a, $06
+ ldh [hTextBoxCursorBlinkInterval + 1], a ; initially, 0x600 iterations
+.loop
+ push hl
+ coord hl, (TEXTBOX_WIDTH - 2), (TEXTBOX_Y + TEXTBOX_HEIGHT - 1)
+ call TextboxBlinkCursor
+ pop hl
+ call GetJoypadDebounced
+ ldh a, [hJoySum]
+ and (A_BUTTON | B_BUTTON)
+ jr z, .loop
+ pop af
+ ldh [hSpriteHeight], a
+ pop af
+ ldh [hSpriteWidth], a
+ ret
+
+ButtonSound:: ; 8d2 (0:8d2)
+ ld a, [wLinkMode]
+ cp $03
+ jr z, .link
+ call WaitAorB_BlinkCursor
+ push de
+ ld de, $5
+ call PlaySFX
+ pop de
+ ret
+.link
+ ld c, $41
+ jp DelayFrames
+
+WaitAorB_BlinkCursor:: ; 8ea (0:8ea)
+.loop
+ call BlinkCursor
+ call GetJoypadDebounced
+ ldh a, [hJoySum]
+ and (A_BUTTON | B_BUTTON)
+ ret nz
+ call RTC
+ call UpdateTimeOfDayPalettes
+ ld a, $01
+ ldh [hBGMapMode], a
+ call DelayFrame
+ jr .loop
+
+BlinkCursor: ; 904 (0:904)
+; Show a blinking cursor in the lower right-hand
+; corner of the screen
+; Will toggle between cursor and blank every
+; 16 frames.
+ ldh a, [hVBlankCounter]
+ and $10
+ jr z, .cursor_off
+ ld a, "▼"
+ jr .save_cursor_state
+.cursor_off
+ ld a, " "
+.save_cursor_state
+ ldcoord_a (SCREEN_WIDTH - 2), (SCREEN_HEIGHT - 1)
+ ret
+
+TextboxBlinkCursor:: ; 914 (0:914)
+; Show a blinking cursor at the specified position
+; that toggles between down arrow and horizontal textbox
+; frame tile.
+; hl - address of cursor
+; hTextBoxCursorBlinkInterval - initial delay between toggling
+; subsequent delays will be 0x6FF
+; calls of this function
+; CAUTION: if the cursor is not shown initially, even initial
+; hTextBoxCursorBlinkInterval values will cause no cursor
+; to be shown at all.
+ ld a, [hl]
+ ld b, a
+ ld a, "▼"
+ cp b
+ jr nz, .showCursorCountdown
+.showTextboxFrameCountdown
+ ldh a, [hTextBoxCursorBlinkInterval]
+ dec a
+ ldh [hTextBoxCursorBlinkInterval], a
+ ret nz
+ ldh a, [hTextBoxCursorBlinkInterval + 1]
+ dec a
+ ldh [hTextBoxCursorBlinkInterval + 1], a
+ ret nz
+ ld a, "─"
+ ld [hl], a
+ ld a, $ff
+ ldh [hTextBoxCursorBlinkInterval], a
+ ld a, $06
+ ldh [hTextBoxCursorBlinkInterval + 1], a ; reset to 0x6FF iterations
+ ret
+.showCursorCountdown
+ ldh a, [hTextBoxCursorBlinkInterval]
+ and a
+ ret z
+ dec a
+ ldh [hTextBoxCursorBlinkInterval], a
+ ret nz
+ dec a
+ ldh [hTextBoxCursorBlinkInterval], a
+ ldh a, [hTextBoxCursorBlinkInterval + 1]
+ dec a
+ ldh [hTextBoxCursorBlinkInterval + 1], a
+ ret nz
+ ld a, $06
+ ldh [hTextBoxCursorBlinkInterval + 1], a ; reset to 0x6FF iterations
+ ld a, "▼"
+ ld [hl], a
+ ret
diff --git a/home/lcd.asm b/home/lcd.asm
index 6641f05..e915806 100644
--- a/home/lcd.asm
+++ b/home/lcd.asm
@@ -3,78 +3,78 @@ INCLUDE "constants.asm"
SECTION "LCD functions", ROM0[$3AE]
LCD:: ; 03ae
- push af
- ldh a, [hLCDCPointer]
- and a
- jr z, .done
- push hl
- rla
- jr c, .try_hide_sprites
- ld a, [rLY]
- ld l, a
- ld h, HIGH(wLYOverrides)
- ld h, [hl]
- ldh a, [hLCDCPointer]
- ld l, a
- ld a, h
- ld h, $FF
- ld [hl], a
- pop hl
- pop af
- reti
+ push af
+ ldh a, [hLCDCPointer]
+ and a
+ jr z, .done
+ push hl
+ rla
+ jr c, .try_hide_sprites
+ ld a, [rLY]
+ ld l, a
+ ld h, HIGH(wLYOverrides)
+ ld h, [hl]
+ ldh a, [hLCDCPointer]
+ ld l, a
+ ld a, h
+ ld h, $FF
+ ld [hl], a
+ pop hl
+ pop af
+ reti
.try_hide_sprites
- ld a, [rLY]
- cp $80
- jr nz, .dont_hide
- ld hl, rLCDC
- res 1, [hl]
+ ld a, [rLY]
+ cp $80
+ jr nz, .dont_hide
+ ld hl, rLCDC
+ res 1, [hl]
.dont_hide
- pop hl
- pop af
- reti
+ pop hl
+ pop af
+ reti
- ; Seems unused?
- ldh a, [hSCX]
- ld [rSCX], a
- ldh a, [hSCY]
- ld [rSCY], a
- pop hl
+ ; Seems unused?
+ ldh a, [hSCX]
+ ld [rSCX], a
+ ldh a, [hSCY]
+ ld [rSCY], a
+ pop hl
.done
- pop af
- reti
+ pop af
+ reti
; 0:3e1
; TODO: can this be done using `sine_table`?
- db 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 3, 3, 2, 2, 1, 0, -1, -2, -2, -3, -3, -4, -4, -4, -4, -4, -3, -3, -2, -2, -1
+ db 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 3, 3, 2, 2, 1, 0, -1, -2, -2, -3, -3, -4, -4, -4, -4, -4, -3, -3, -2, -2, -1
DisableLCD:: ; 0401
- ld a, [rLCDC]
- bit 7, a
- ret z
- xor a
- ld [rIF], a
- ld a, [rIE]
- ld b, a
- res 0, a
- ld [rIE], a
+ ld a, [rLCDC]
+ bit 7, a
+ ret z
+ xor a
+ ld [rIF], a
+ ld a, [rIE]
+ ld b, a
+ res 0, a
+ ld [rIE], a
.wait
- ld a, [rLY]
- cp LY_VBLANK + 1
- jr nz, .wait
- ld a, [rLCDC]
- and $7F ; Shut LCD down
- ld [rLCDC], a
- xor a
- ld [rIF], a
- ld a, b
- ld [rIE], a
- ret
+ ld a, [rLY]
+ cp LY_VBLANK + 1
+ jr nz, .wait
+ ld a, [rLCDC]
+ and $7f ; Shut LCD down
+ ld [rLCDC], a
+ xor a
+ ld [rIF], a
+ ld a, b
+ ld [rIE], a
+ ret
EnableLCD:: ; 0423
- ld a, [rLCDC]
- set 7, a
- ld [rLCDC], a
- ret
+ ld a, [rLCDC]
+ set 7, a
+ ld [rLCDC], a
+ ret
diff --git a/home/names.asm b/home/names.asm
new file mode 100644
index 0000000..7ce5767
--- /dev/null
+++ b/home/names.asm
@@ -0,0 +1,23 @@
+INCLUDE "constants.asm"
+
+if DEBUG
+SECTION "GetNthString", ROM0[$3732]
+else
+SECTION "GetNthString", ROM0[$36F6]
+endc
+
+GetNthString::
+; Return the address of the ath string starting from hl.
+ and a
+ ret z
+ push bc
+ ld b, a
+ ld c, "@"
+.readChar:
+ ld a, [hli]
+ cp c
+ jr nz, .readChar
+ dec b
+ jr nz, .readChar
+ pop bc
+ ret
diff --git a/home/oam_dma.asm b/home/oam_dma.asm
index d76df89..42ecaaf 100644
--- a/home/oam_dma.asm
+++ b/home/oam_dma.asm
@@ -3,23 +3,23 @@ INCLUDE "constants.asm"
SECTION "OAM DMA", ROMX[$4153],BANK[1]
WriteOAMDMACodeToHRAM:: ; 4153
- ld c, LOW(hOAMDMA)
- ld b, .OAMDMAEnd - .OAMDMA
- ld hl, .OAMDMA
+ ld c, LOW(hOAMDMA)
+ ld b, .OAMDMAEnd - .OAMDMA
+ ld hl, .OAMDMA
.loop
- ld a, [hli]
- ld [$ff00+c], a
- inc c
- dec b
- jr nz, .loop
- ret
+ ld a, [hli]
+ ld [$ff00+c], a
+ inc c
+ dec b
+ jr nz, .loop
+ ret
.OAMDMA ; 4161
- ld a, HIGH(wVirtualOAM)
- ldh [rDMA], a
- ld a, $28
+ ld a, HIGH(wVirtualOAM)
+ ldh [rDMA], a
+ ld a, $28
.wait
- dec a
- jr nz, .wait
- ret
+ dec a
+ jr nz, .wait
+ ret
.OAMDMAEnd ; 416b
diff --git a/home/pic.asm b/home/pic.asm
index 60dd6a3..04cf7bb 100644
--- a/home/pic.asm
+++ b/home/pic.asm
@@ -2,9 +2,9 @@ INCLUDE "constants.asm"
SECTION "Decompression Functions", ROM0[$095E]
+UncompressSpriteData:: ; 95e (0:95e)
; bankswitches and runs _UncompressSpriteData
; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr
-UncompressSpriteData:: ; 95e (0:95e)
ld b, a
ldh a, [hROMBank]
push af
@@ -18,11 +18,11 @@ UncompressSpriteData:: ; 95e (0:95e)
call Bankswitch
ret
-; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
_UncompressSpriteData:: ; 976 (0:976)
+; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
ld hl, sSpriteBuffer1
- ld c, (2*SPRITEBUFFERSIZE) % $100
- ld b, (2*SPRITEBUFFERSIZE) / $100
+ ld c, (2 * SPRITEBUFFERSIZE) % $100
+ ld b, (2 * SPRITEBUFFERSIZE) / $100
xor a
call ByteFill
ld a, $01 ; next call to ReadNextInputBit will read byte
@@ -51,12 +51,12 @@ _UncompressSpriteData:: ; 976 (0:976)
ld [wSpriteLoadFlags], a ; initialite bit1 to 0 and bit0 to the first input bit
; this will load two chunks of data to sSpriteBuffer1 and sSpriteBuffer2
; bit 0 decides in which one the first chunk is placed
- ; fall through
+ ; fallthrough
+UncompressSpriteDataLoop::
; uncompresses a chunk from the sprite input data stream (pointed to at wSpriteInputPtr) into sSpriteBuffer1 or sSpriteBuffer2
; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards
; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack
-UncompressSpriteDataLoop::
ld hl, sSpriteBuffer1
ld a, [wSpriteLoadFlags]
bit 0, a
@@ -143,10 +143,10 @@ UncompressSpriteDataLoop::
jr nz, .writeZerosLoop
jr .readNextInput
+MoveToNextBufferPosition:: ; a34 (0:a34)
; moves output pointer to next position
; also cancels the calling function if the all output is done (by removing the return pointer from stack)
; and calls postprocessing functions according to the unpack mode
-MoveToNextBufferPosition:: ; a34 (0:a34)
ld a, [wSpriteHeight]
ld b, a
ld a, [wSpriteCurPosY]
@@ -206,8 +206,8 @@ MoveToNextBufferPosition:: ; a34 (0:a34)
.done
jp UnpackSprite
-; writes 2 bits (from a) to the output buffer (pointed to from wSpriteOutputPtr)
WriteSpriteBitsToBuffer:: ; aa5 (0:aa5)
+; writes 2 bits (from a) to the output buffer (pointed to from wSpriteOutputPtr)
ld e, a
ld a, [wSpriteOutputBitOffset]
and a
@@ -234,8 +234,8 @@ WriteSpriteBitsToBuffer:: ; aa5 (0:aa5)
ld [hl], a
ret
-; reads next bit from input stream and returns it in a
ReadNextInputBit:: ; acc (0:acc)
+; reads next bit from input stream and returns it in a
ld a, [wSpriteInputBitCounter]
dec a
jr nz, .curByteHasMoreBitsToRead
@@ -250,8 +250,8 @@ ReadNextInputBit:: ; acc (0:acc)
and $01
ret
-; reads next byte from input stream and returns it in a
ReadNextInputByte: ; ae7 (0:ae7)
+; reads next byte from input stream and returns it in a
ld a, [wSpriteInputPtr]
ld l, a
ld a, [wSpriteInputPtr + 1]
@@ -265,8 +265,8 @@ ReadNextInputByte: ; ae7 (0:ae7)
ld a, b
ret
-; the nth item is 2^n - 1
LengthEncodingOffsetList::
+; the nth item is 2^n - 1
dw %0000000000000001
dw %0000000000000011
dw %0000000000000111
@@ -284,8 +284,8 @@ LengthEncodingOffsetList::
dw %0111111111111111
dw %1111111111111111
-; unpacks the sprite data depending on the unpack mode
UnpackSprite:: ; b1b (0:b1b)
+; unpacks the sprite data depending on the unpack mode
ld a, [wSpriteUnpackMode]
cp $02
jp z, UnpackSpriteMode2
@@ -294,11 +294,11 @@ UnpackSprite:: ; b1b (0:b1b)
ld hl, sSpriteBuffer1
call SpriteDifferentialDecode
ld hl, sSpriteBuffer2
- ; fall through
+ ; fallthrough
+SpriteDifferentialDecode::
; decodes differential encoded sprite data
; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0).
-SpriteDifferentialDecode::
xor a
ld [wSpriteCurPosX], a
ld [wSpriteCurPosY], a
@@ -382,8 +382,8 @@ SpriteDifferentialDecode::
ld [wSpriteCurPosY], a
ret
-; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1)
DifferentialDecodeNybble:: ; bc9 (0:bc9)
+; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1)
srl a ; c=a%2, a/=2
ld c, $00
jr nc, .evenNumber
@@ -462,8 +462,8 @@ DecodeNybble1TableFlipped::
dn $e, $6
dn $2, $a
-; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differentially decoded beforehand.
XorSpriteChunks:: ; c23 (0:c23)
+; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differentially decoded beforehand.
xor a
ld [wSpriteCurPosX], a
ld [wSpriteCurPosY], a
@@ -527,8 +527,8 @@ XorSpriteChunks:: ; c23 (0:c23)
ld [wSpriteCurPosX], a
ret
-; reverses the bits in the nybble given in register a
ReverseNybble:: ; c93 (0:c93)
+; reverses the bits in the nybble given in register a
ld de, NybbleReverseTable
add e
ld e, a
@@ -538,8 +538,8 @@ ReverseNybble:: ; c93 (0:c93)
ld a, [de]
ret
-; resets sprite buffer pointers to buffer 1 and 2, depending on wSpriteLoadFlags
ResetSpriteBufferPointers:: ; c9d (0:c9d)
+; resets sprite buffer pointers to buffer 1 and 2, depending on wSpriteLoadFlags
ld a, [wSpriteLoadFlags]
bit 0, a
jr nz, .buffer2Selected
@@ -564,8 +564,8 @@ ResetSpriteBufferPointers:: ; c9d (0:c9d)
NybbleReverseTable::
db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f
-; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differentially decoded beforehand.
UnpackSpriteMode2:: ; cd3 (0:cd3)
+; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differentially decoded beforehand.
call ResetSpriteBufferPointers
ld a, [wSpriteFlipped]
push af
@@ -581,8 +581,8 @@ UnpackSpriteMode2:: ; cd3 (0:cd3)
ld [wSpriteFlipped], a
jp XorSpriteChunks
-; stores hl into the output pointers
StoreSpriteOutputPointer:: ; cf3 (0:cf3)
+; stores hl into the output pointers
ld a, l
ld [wSpriteOutputPtr], a
ld [wSpriteOutputPtrCached], a
diff --git a/home/pokemon.asm b/home/pokemon.asm
index 1f51f8e..f990393 100644
--- a/home/pokemon.asm
+++ b/home/pokemon.asm
@@ -5,10 +5,10 @@ SECTION "3A4B", ROM0[$3A4B]
else
SECTION "3A4B", ROM0[$3A0F]
endc
+GetMonHeader:: ; 3a4b (0:3a4b)
; copies the base stat data of a pokemon to wMonHeader
; INPUT:
; [wcb5b] = pokemon ID in dex order
-GetMonHeader:: ; 3a4b (0:3a4b)
push bc
push de
push hl
@@ -29,7 +29,7 @@ GetMonHeader:: ; 3a4b (0:3a4b)
jr .done
.egg
ld de, EggPicFront
- ld b, $55 ; egg sprite dimension
+ ln b, 5, 5 ; egg sprite dimension
ld hl, wMonHSpriteDim
ld [hl], b
ld hl, wMonHFrontSprite
@@ -53,10 +53,10 @@ else
SECTION "3AED", ROM0[$3AB1]
endc
+UncompressMonSprite:: ; 3aed (0:3aed)
; Uncompresses the front or back sprite of the specified mon
; assumes the corresponding mon header is already loaded
; hl contains offset to sprite pointer ($b for front or $d for back)
-UncompressMonSprite:: ; 3aed (0:3aed)
ld a, [wMonDexIndex]
and a
ret z
@@ -104,12 +104,12 @@ UncompressMonSprite:: ; 3aed (0:3aed)
ld a, BANK(AnnonPics)
jp UncompressSpriteData
-; Uncompress Pokémon Front Srite for
+LoadMonFrontSprite:: ; 3b3f
+; Uncompress Pokémon Front Sprite for
; mon currently loaded in wMonHeader
; to 0x9000
; de: destination location
; returns the sprite dimension in c
-LoadMonFrontSprite:: ; 3b3f
push de
ld hl, wMonHFrontSprite - wMonHeader
call UncompressMonSprite
@@ -117,13 +117,13 @@ LoadMonFrontSprite:: ; 3b3f
ld a, [hl]
ld c, a
pop de
- ; fall through
-
+ ; fallthrough
+
+LoadUncompressedSpriteData:: ; 3b4c (0:3b4c)
; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram
; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers
; de: destination location
; a,c: sprite dimensions (in tiles of 8x8 each)
-LoadUncompressedSpriteData:: ; 3b4c (0:3b4c)
push de
and $0f
ldh [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
@@ -172,15 +172,15 @@ LoadUncompressedSpriteData:: ; 3b4c (0:3b4c)
call InterlaceMergeSpriteBuffers
ret
-; fills the sprite buffer (pointed to in hl) with zeros
ZeroSpriteBuffer:: ; 3ba1 (0:3ba1)
+; fills the sprite buffer (pointed to in hl) with zeros
ld bc, SPRITEBUFFERSIZE
xor a
jp ByteFill
+AlignSpriteDataCentered:: ; 3ba8 (0:3ba8)
; copies and aligns the sprite data properly inside the sprite buffer
; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area
-AlignSpriteDataCentered:: ; 3ba8 (0:3ba8)
ldh a, [hSpriteOffset]
ld c, a
ld b, $00
@@ -206,28 +206,28 @@ AlignSpriteDataCentered:: ; 3ba8 (0:3ba8)
jr nz, .columnLoop
ret
+InterlaceMergeSpriteBuffers:: ; 3bc6 (0:3bc6)
; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2
; in the resulting sprite, the rows of the two source sprites are interlaced
; de: output address
-InterlaceMergeSpriteBuffers:: ; 3bc6 (0:3bc6)
ld a, $00
call OpenSRAM
push de
call _InterlaceMergeSpriteBuffers
pop hl
ld de, sSpriteBuffer1
- ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
+ ld c, (2 * SPRITEBUFFERSIZE) / 16 ; $31, number of 16 byte chunks to be copied
ldh a, [hROMBank]
ld b, a
call CopyVideoDataOptimized
call CloseSRAM
ret
+_InterlaceMergeSpriteBuffers:: ; 3bdf (0:3bdf)
; actual implementation of InterlaceMergeSpriteBuffers
; sprite flipping is now done during interlace merge loop
; and not as second loop after regular interlace merge
; to save time
-_InterlaceMergeSpriteBuffers:: ; 3bdf (0:3bdf)
ld a, [wSpriteFlipped]
and a
jr nz, .flipped
@@ -271,7 +271,7 @@ _InterlaceMergeSpriteBuffers:: ; 3bdf (0:3bdf)
ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
- ld a, SPRITEBUFFERSIZE/2 ; $c4
+ ld a, SPRITEBUFFERSIZE / 2 ; $c4
ldh [hSpriteInterlaceCounter], a
.interlaceLoopFlipped
ld a, [de]
diff --git a/home/predef.asm b/home/predef.asm
index a9ff091..e6d5019 100644
--- a/home/predef.asm
+++ b/home/predef.asm
@@ -7,43 +7,43 @@ SECTION "Predef", ROM0[$2FA2]
endc
Predef:: ; 2fde
- ld [wPredefID], a
- ldh a, [hROMBank]
- push af
- ld a, BANK(GetPredefPointer)
- call Bankswitch
- call GetPredefPointer
- call Bankswitch
- ld hl, .return
- push hl
- push de
- jr .get_regs
+ ld [wPredefID], a
+ ldh a, [hROMBank]
+ push af
+ ld a, BANK(GetPredefPointer)
+ call Bankswitch
+ call GetPredefPointer
+ call Bankswitch
+ ld hl, .return
+ push hl
+ push de
+ jr .get_regs
.return
- ld a, h
- ld [wPredefHL], a
- ld a, l
- ld [wPredefHL + 1], a
- pop hl
- ld a, h ; Could have used `pop af` instead
- call Bankswitch
- ld a, [wPredefHL]
- ld h, a
- ld a, [wPredefHL + 1]
- ld l, a
- ret
+ ld a, h
+ ld [wPredefHL], a
+ ld a, l
+ ld [wPredefHL + 1], a
+ pop hl
+ ld a, h ; Could have used `pop af` instead
+ call Bankswitch
+ ld a, [wPredefHL]
+ ld h, a
+ ld a, [wPredefHL + 1]
+ ld l, a
+ ret
.get_regs
- ld a, [wPredefHL]
- ld h, a
- ld a, [wPredefHL + 1]
- ld l, a
- ld a, [wPredefDE]
- ld d, a
- ld a, [wPredefDE + 1]
- ld e, a
- ld a, [wPredefBC]
- ld b, a
- ld a, [wPredefBC + 1]
- ld c, a
- ret
+ ld a, [wPredefHL]
+ ld h, a
+ ld a, [wPredefHL + 1]
+ ld l, a
+ ld a, [wPredefDE]
+ ld d, a
+ ld a, [wPredefDE + 1]
+ ld e, a
+ ld a, [wPredefBC]
+ ld b, a
+ ld a, [wPredefBC + 1]
+ ld c, a
+ ret
diff --git a/home/print_bcd.asm b/home/print_bcd.asm
new file mode 100644
index 0000000..4f647ff
--- /dev/null
+++ b/home/print_bcd.asm
@@ -0,0 +1,113 @@
+INCLUDE "constants.asm"
+
+if DEBUG
+SECTION "BCD Finalize", ROM0[$33a3]
+else
+SECTION "BCD Finalize", ROM0[$3367]
+endc
+
+PrintLetterDelay:: ; 33a3 (0:33a3)
+ ld a, [wce5f]
+ bit 4, a
+ ret nz
+ ld a, [wTextBoxFlags]
+ bit 1, a
+ ret z
+ push hl
+ push de
+ push bc
+ ld a, [wTextBoxFlags]
+ bit 0, a
+ jr z, .waitOneFrame
+ ld a, [wce5f]
+ and $07
+ jr .initFrameCnt
+.waitOneFrame
+ ld a, $01
+.initFrameCnt
+ ld [wVBlankJoyFrameCounter], a
+.checkButtons
+ call GetJoypad
+ ldh a, [hJoyState]
+.checkAButton
+ bit 0, a ; is the A button pressed?
+ jr z, .checkBButton
+ jr .endWait
+.checkBButton
+ bit 1, a ; is the B button pressed?
+ jr z, .buttonsNotPressed
+.endWait
+ call DelayFrame
+ jr .done
+.buttonsNotPressed ; if neither A nor B is pressed
+ ld a, [wVBlankJoyFrameCounter]
+ and a
+ jr nz, .checkButtons
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+; 0x33e3
+
+if DEBUG
+SECTION "BCD Functions", ROM0[$3AB2]
+else
+SECTION "BCD Functions", ROM0[$3A76]
+endc
+
+; function to print a BCD (Binary-coded decimal) number
+; de = address of BCD number
+; hl = destination address
+; c = flags and length
+; bit 7: if set, do not print leading zeroes
+; if unset, print leading zeroes
+; bit 6: if set, left-align the string (do not pad empty digits with spaces)
+; if unset, right-align the string
+; bits 0-5: length of BCD number in bytes
+; Note that bits 5 and 7 are modified during execution. The above reflects
+; their meaning at the beginning of the functions's execution.
+PrintBCDNumber:: ; 3ab2 (0:3ab2)
+ ld b, c ; save flags in b
+ res 7, c
+ res 6, c ; c now holds the length
+.loop
+ ld a, [de]
+ swap a
+ call PrintBCDDigit
+ ld a, [de]
+ call PrintBCDDigit
+ inc de
+ dec c
+ jr nz, .loop
+ bit 7, b ; were any non-zero digits printed?
+ jr z, .done
+.numberEqualsZero ; if every digit of the BCD number is zero
+ bit 6, b
+ jr nz, .skipRightAlignmentAdjustment
+ dec hl ; if the string is right-aligned, it needs
+.skipRightAlignmentAdjustment ;to be moved back one space
+ ld [hl], "0"
+ call PrintLetterDelay
+ inc hl
+.done
+ ret
+
+PrintBCDDigit:: ; 3ad5 (0:3ad5)
+ and $0f
+ and a
+ jr z, .zeroDigit
+ res 7, b ; unset 7 to indicate that a nonzero
+.outputDigit ; digit has been reached
+ add "0"
+ ld [hli], a
+ jp PrintLetterDelay
+.zeroDigit
+ bit 7, b ; either printing leading zeroes or
+ jr z, .outputDigit ; already reached a nonzero digit?
+ bit 6, b
+ ret nz ; left-align, don't pad with space
+ ld a, " "
+ ld [hli], a
+ ret
+; 0x3aed \ No newline at end of file
diff --git a/home/print_hex.asm b/home/print_hex.asm
new file mode 100644
index 0000000..993e210
--- /dev/null
+++ b/home/print_hex.asm
@@ -0,0 +1,42 @@
+INCLUDE "constants.asm"
+
+if DEBUG
+SECTION "Print Hexadecimal functions", ROM0[$3597]
+else
+SECTION "Print Hexadecimal functions", ROM0[$355B]
+endc
+
+PrintHexBytes: ; 3597 (0:3597)
+.loop
+ push bc
+ call PrintHexByte
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+PrintHexByte:: ; 35a0 (0:35a0)
+ ld a, [de]
+ swap a
+ and $0f
+ call PrintHexDigit
+ ld [hli], a
+ ld a, [de]
+ and $0f
+ call PrintHexDigit
+ ld [hli], a
+ inc de
+ ret
+
+PrintHexDigit: ; 35b2 (0:35b2)
+ ld bc, .hexDigitTable
+ add c
+ ld c, a
+ ld a, $00
+ adc b
+ ld b, a
+ ld a, [bc]
+ ret
+
+.hexDigitTable:
+ db "0123456789ABCDEF"
diff --git a/home/print_num.asm b/home/print_num.asm
new file mode 100644
index 0000000..3ae1c10
--- /dev/null
+++ b/home/print_num.asm
@@ -0,0 +1,252 @@
+INCLUDE "constants.asm"
+
+if DEBUG
+SECTION "Number Printing Functions", ROM0[$3460]
+else
+SECTION "Number Printing Functions", ROM0[$3424]
+endc
+
+PrintNumber:: ; 3460 (0:3460)
+; function to print a number
+; de = address of number in little-endian format
+; hl = destination address
+; b = flags and length
+; bit 7: if set, do not print leading zeroes
+; if unset, print leading zeroes
+; bit 6: if set, left-align the string (do not pad empty digits with spaces)
+; if unset, right-align the string
+; bits 0-5: length of number in bytes
+; 01 - 1 byte
+; 02 - 2 bytes
+; <> - 3 bytes
+; c = number of digits from 2 to 7
+; For 1-digit numbers, add the value to char "0"
+; instead of calling PrintNumber.
+; This function works as follow
+; There are three temporary registers
+; - hPrintNumDividend,
+; - hPrintNumDivisor,
+; - hPrintNumTemp
+; All are three bytes long and organized in big-endian order.
+; To produce digits, PrintNumber is going to
+; 1. Store Input in hPrintNumDividend
+; 1a. Init hPrintNumLeadingDigit to zero (no prior leading digit)
+; 2. Repeatedly call .PrintDigit for required digits 7 thru 3:
+; 2a. Store divisor in hPrintNumDivisor
+; 2b. Divide dividend by divisor to get digit
+; 2c. hPrintNumTemp is used, because dividend < divisor might
+; not be immediately visible in byte-wise division
+; 2d. Update hPrintNumLeadingDigit in case digit > 0
+; 3. Perform the same operations for two digits as byte-wide operations
+; as opposed to three-byte-wide operations
+; 4. Check if at least one non-zero digit was printed, else print zero.
+; 5. Done.
+ push bc
+ xor a
+ ldh [hPrintNumLeadingDigit], a
+ ldh [hPrintNumDividend], a
+ ldh [hPrintNumDividend + 1], a
+ ld a, b
+ and $0f
+ cp $01
+ jr z, .byte
+ cp $02
+ jr z, .word
+ ld a, [de]
+ ldh [hPrintNumDividend], a
+ inc de
+ ld a, [de]
+ ldh [hPrintNumDividend + 1], a
+ inc de
+ ld a, [de]
+ ldh [hPrintNumDividend + 2], a
+ jr .start
+.word
+ ld a, [de]
+ ldh [hPrintNumDividend + 1], a
+ inc de
+ ld a, [de]
+ ldh [hPrintNumDividend + 2], a
+ jr .start
+.byte
+ ld a, [de]
+ ldh [hPrintNumDividend + 2], a
+.start
+ push de
+ ld d, b
+ ld a, c
+ ld b, a
+ xor a
+ ld c, a
+ ld a, b
+ cp $02
+ jr z, .two_digits
+ cp $03
+ jr z, .three_digits
+ cp $04
+ jr z, .four_digits
+ cp $05
+ jr z, .five_digits
+ cp $06
+ jr z, .six_digits
+.seven_digits
+ ld a, 1000000 / $10000 % $100
+ ldh [hPrintNumDivisor], a
+ ld a, 1000000 / $100 % $100
+ ldh [hPrintNumDivisor + 1], a
+ ld a, 1000000 % $100
+ ldh [hPrintNumDivisor + 2], a
+ call .PrintDigit
+ call .AdvancePointer
+.six_digits
+ ld a, 100000 / $10000 % $100
+ ldh [hPrintNumDivisor], a
+ ld a, 100000 / $100 % $100
+ ldh [hPrintNumDivisor + 1], a
+ ld a, 100000 % $100
+ ldh [hPrintNumDivisor + 2], a
+ call .PrintDigit
+ call .AdvancePointer
+.five_digits
+ xor a
+ ldh [hPrintNumDivisor], a
+ ld a, 10000 / $100
+ ldh [hPrintNumDivisor + 1], a
+ ld a, 10000 % $100
+ ldh [hPrintNumDivisor + 2], a
+ call .PrintDigit
+ call .AdvancePointer
+.four_digits
+ xor a
+ ldh [hPrintNumDivisor], a
+ ld a, 1000 / $100
+ ldh [hPrintNumDivisor + 1], a
+ ld a, 1000 % $100
+ ldh [hPrintNumDivisor + 2], a
+ call .PrintDigit
+ call .AdvancePointer
+.three_digits
+ xor a
+ ldh [hPrintNumDivisor], a
+ xor a
+ ldh [hPrintNumDivisor + 1], a
+ ld a, 100
+ ldh [hPrintNumDivisor + 2], a
+ call .PrintDigit
+ call .AdvancePointer
+.two_digits
+ ld c, $00
+ ldh a, [hPrintNumDividend + 2]
+.mod_10
+ cp $0a
+ jr c, .modded_10
+ sub $0a
+ inc c
+ jr .mod_10
+.modded_10
+ ld b, a
+ ldh a, [hPrintNumLeadingDigit]
+ or c
+ ldh [hPrintNumLeadingDigit], a
+ jr nz, .LeadingNonZero
+ call .PrintLeadingZero
+ jr .PrintLeastSignificantDigit
+.LeadingNonZero
+ ld a, "0"
+ add c
+ ld [hl], a
+.PrintLeastSignificantDigit
+ call .AdvancePointer
+ ld a, "0"
+ add b
+ ld [hli], a
+ pop de
+ pop bc
+ ret
+
+.PrintDigit: ; 3525 (0:3525)
+ ld c, $00
+.loop
+ ldh a, [hPrintNumDivisor]
+ ld b, a
+ ldh a, [hPrintNumDividend]
+ ldh [hPrintNumTemp], a ; store high byte in case dividend < divisor
+ cp b ; in subsequent bytes
+ jr c, .DividendLessThanDivisor ; dividend < divisor --> the digit is zero
+ sub b
+ ldh [hPrintNumDividend], a
+ ldh a, [hPrintNumDivisor + 1]
+ ld b, a
+ ldh a, [hPrintNumDividend + 1]
+ ldh [hPrintNumTemp + 1], a ; store mid byte in case dividend < divisor
+ cp b ; in subsequent byte
+ jr nc, .SubtractMidNoBorrow
+ ldh a, [hPrintNumDividend] ; try to borrow from upper byte
+ or $00
+ jr z, .DividendLessThanDivisorRestoreHigh ; can't borrow, because dividend < divisor
+ dec a
+ ldh [hPrintNumDividend], a
+ ldh a, [hPrintNumDividend + 1]
+.SubtractMidNoBorrow
+ sub b
+ ldh [hPrintNumDividend + 1], a
+ ldh a, [hPrintNumDivisor + 2]
+ ld b, a
+ ldh a, [hPrintNumDividend + 2]
+ ldh [hPrintNumTemp + 2], a ; store low byte in case dividend < divisor, which
+ cp b ; goes unused, because the algorithm doesn't
+ jr nc, .SubtractLoNoBorrow ; clobber hPrintNumDividend + 2 in that case
+ ldh a, [hPrintNumDividend + 1]
+ and a
+ jr nz, .SubtractLoBorrow
+ ldh a, [hPrintNumDividend] ; if mid byte == zero, we need to borrow from high
+ and a
+ jr z, .DividendLessThanDivisorRestoreMid
+.SubtractLoBorrowFromHigh
+ dec a
+ ldh [hPrintNumDividend], a
+ xor a
+.SubtractLoBorrow
+ dec a
+ ldh [hPrintNumDividend + 1], a
+ ldh a, [hPrintNumDividend + 2]
+.SubtractLoNoBorrow
+ sub b
+ ldh [hPrintNumDividend + 2], a
+ inc c
+ jr .loop
+.DividendLessThanDivisorRestoreMid
+ ldh a, [hPrintNumTemp + 1]
+ ldh [hPrintNumDividend + 1], a
+.DividendLessThanDivisorRestoreHigh
+ ldh a, [hPrintNumTemp]
+ ldh [hPrintNumDividend], a
+.DividendLessThanDivisor
+ ldh a, [hPrintNumLeadingDigit]
+ or c
+ jr z, .PrintLeadingZero
+ ld a, "0"
+ add c
+ ld [hl], a
+ ldh [hPrintNumLeadingDigit], a
+ ret
+.PrintLeadingZero:
+; prints a leading zero unless they are turned off in the flags
+ bit 7, d
+ ret z
+ ld [hl], "0"
+ ret
+
+.AdvancePointer: ; 3589 (0:3589)
+; increments the pointer unless leading zeroes are not being printed,
+; the number is left-aligned, and no nonzero digits have been printed yet
+ bit 7, d ; print leading zeroes?
+ jr nz, .inc
+ bit 6, d ; left alignment or right alignment?
+ jr z, .inc
+ ldh a, [hPrintNumLeadingDigit]
+ and a
+ ret z ; don't advance if leading digit is zero
+.inc
+ inc hl
+ ret
diff --git a/home/serial.asm b/home/serial.asm
index 61510b0..48d6832 100644
--- a/home/serial.asm
+++ b/home/serial.asm
@@ -3,53 +3,52 @@ INCLUDE "constants.asm"
SECTION "Serial handler", ROM0[$602]
Serial::
- push af
- push bc
- push de
- push hl
- ldh a, [hLinkPlayerNumber]
- inc a
- jr z, .init_player_number
+ push af
+ push bc
+ push de
+ push hl
+ ldh a, [hLinkPlayerNumber]
+ inc a
+ jr z, .init_player_number
- ld a, [rSB]
- ldh [hSerialReceive], a
- ldh a, [hSerialSend]
- ld [rSB], a
- ldh a, [hLinkPlayerNumber]
- cp 2
- jr z, .done
- ld a, 1 << rSC_ON
- ld [rSC], a
- jr .done
+ ld a, [rSB]
+ ldh [hSerialReceive], a
+ ldh a, [hSerialSend]
+ ld [rSB], a
+ ldh a, [hLinkPlayerNumber]
+ cp 2
+ jr z, .done
+ ld a, 1 << rSC_ON
+ ld [rSC], a
+ jr .done
.init_player_number
- ld a, [rSB]
- ldh [hSerialReceive], a
- ldh [hLinkPlayerNumber], a
- cp 2
- jr z, .master
- xor a
- ld [rSB], a
- ld a, 3
- ld [rDIV], a
+ ld a, [rSB]
+ ldh [hSerialReceive], a
+ ldh [hLinkPlayerNumber], a
+ cp 2
+ jr z, .master
+ xor a
+ ld [rSB], a
+ ld a, 3
+ ld [rDIV], a
.wait
- ld a, [rDIV]
- bit 7, a
- jr nz, .wait
- ld a, 1 << rSC_ON
- ld [rSC], a
- jr .done
+ ld a, [rDIV]
+ bit 7, a
+ jr nz, .wait
+ ld a, 1 << rSC_ON
+ ld [rSC], a
+ jr .done
.master
- xor a
- ld [rSB], a
-
+ xor a
+ ld [rSB], a
.done
- ld a, 1
- ldh [hSerialReceived], a
- ld a, SERIAL_NO_DATA_BYTE
- ldh [hSerialSend], a
- pop hl
- pop de
- pop bc
- pop af
- reti
+ ld a, 1
+ ldh [hSerialReceived], a
+ ld a, SERIAL_NO_DATA_BYTE
+ ldh [hSerialSend], a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
diff --git a/home/sram.asm b/home/sram.asm
index 03d4411..87f2335 100644
--- a/home/sram.asm
+++ b/home/sram.asm
@@ -7,19 +7,19 @@ SECTION "SRAM functions", ROM0[$326B]
endc
OpenSRAM:: ; 32a7
- push af
- ld a, 1
- ld [MBC3LatchClock], a
- ld a, SRAM_ENABLE
- ld [MBC3SRamEnable], a
- pop af
- ld [MBC3SRamBank], a
- ret
+ push af
+ ld a, 1
+ ld [MBC3LatchClock], a
+ ld a, SRAM_ENABLE
+ ld [MBC3SRamEnable], a
+ pop af
+ ld [MBC3SRamBank], a
+ ret
CloseSRAM:: ; 32b7
- push af
- ld a, SRAM_DISABLE
- ld [MBC3LatchClock], a
- ld [MBC3SRamEnable], a
- pop af
- ret
+ push af
+ ld a, SRAM_DISABLE
+ ld [MBC3LatchClock], a
+ ld [MBC3SRamEnable], a
+ pop af
+ ret
diff --git a/home/text.asm b/home/text.asm
new file mode 100644
index 0000000..83bbd42
--- /dev/null
+++ b/home/text.asm
@@ -0,0 +1,368 @@
+INCLUDE "constants.asm"
+
+SECTION "Text Commands", ROM0[$107e]
+
+ScrollTextUpOneLine:: ; 107e (0:107e)
+; move both rows of text in the normal text box up one row
+; always called twice in a row
+; first time, copy the two rows of text to the "in between" rows that are usually emtpy
+; second time, copy the bottom row of text into the top row of text
+ coord hl, TEXTBOX_X, TEXTBOX_INNERY ; top row of text
+ coord de, TEXTBOX_X, TEXTBOX_INNERY - 1 ; empty line above text
+ ld b, TEXTBOX_WIDTH * 3
+.copyText
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .copyText
+ coord hl, TEXTBOX_INNERX, TEXTBOX_INNERY + 2
+ ld a, " "
+ ld b, TEXTBOX_INNERW
+.clearText
+ ld [hli], a
+ dec b
+ jr nz, .clearText
+ ld b, $05 ; wait five frames
+.waitFrame
+ call DelayFrame
+ dec b
+ jr nz, .waitFrame
+ ret
+
+ProtectedWaitBGMap:: ; 10a0 (0:10a0)
+ push bc
+ call WaitBGMap
+ pop bc
+ ret
+
+TextCommandProcessor:: ; 10a6 (0:10a6)
+; Process a string of text commands
+; at hl and write text to bc
+ ld a, [wTextBoxFlags]
+ push af
+ set 1, a
+ ld [wTextBoxFlags], a
+ ld a, c
+ ld [wTextDest], a
+ ld a, b
+ ld [wTextDest + 1], a
+ ; fall through
+
+NextTextCommand:: ; 10b7 (0:10b7)
+ ld a, [hli]
+ cp "@" ; terminator
+ jr nz, .doTextCommand
+ pop af
+ ld [wTextBoxFlags], a
+ ret
+.doTextCommand
+ push hl
+ ld hl, TextCommands
+ push bc
+ add a
+ ld b, $00
+ ld c, a
+ add hl, bc
+ pop bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+Text_TX_BOX:: ; 10d0 (0:10d0)
+; TX_BOX
+; draw a box
+; little endian
+; [$04][addr][height][width]
+ pop hl
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+ push hl
+ ld h, d
+ ld l, e
+ call DrawTextBox
+ pop hl
+ jr NextTextCommand
+
+Text_TX:: ; 10e2 (0:10e2)
+; TX
+; write text until "@"
+; [$00]["...@"]
+ pop hl
+ ld d, h
+ ld e, l
+ ld h, b
+ ld l, c
+ call PlaceString
+ ld h, d
+ ld l, e
+ inc hl
+ jr NextTextCommand
+
+Text_TX_RAM:: ; 10ef (0:10ef)
+; text_from_ram
+; write text from a ram address
+; little endian
+; [$01][addr]
+ pop hl
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ push hl
+ ld h, b
+ ld l, c
+ call PlaceString
+ pop hl
+ jr NextTextCommand
+
+Text_TX_BCD:: ; 10fd (0:10fd)
+; TX_BCD
+; write bcd from address, typically ram
+; [$02][addr][flags]
+; flags: see PrintBCDNumber
+ pop hl
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ push hl
+ ld h, b
+ ld l, c
+ ld c, a
+ call PrintBCDNumber
+ ld b, h
+ ld c, l
+ pop hl
+ jr NextTextCommand
+
+Text_TX_MOVE:: ; 110f (0:110f)
+; TX_MOVE
+; move to a new tile
+; [$03][addr]
+ pop hl
+ ld a, [hli]
+ ld [wTextDest], a
+ ld c, a
+ ld a, [hli]
+ ld [wTextDest + 1], a
+ ld b, a
+ jp NextTextCommand
+
+Text_TX_LOW:: ; 111d (0:111d)
+; TX_LOW
+; write text at (1,16)
+; [$05]
+ pop hl
+ coord bc, TEXTBOX_INNERX, TEXTBOX_INNERY + 2
+ jp NextTextCommand
+; 0x1124
+
+Text_WAIT_BUTTON:: ; 1124 (0:1124)
+; TX_WAITBUTTON
+; wait for button press
+; show arrow
+; [06]
+ ld a, [wLinkMode]
+ cp $03
+ jp z, Text_TX_LINK_WAIT_BUTTON
+ ld a, "▼"
+ ldcoord_a TEXTBOX_WIDTH - 2, TEXTBOX_Y + TEXTBOX_HEIGHT - 1
+ push bc
+ call ButtonSound
+ pop bc
+ ld a, "─"
+ ldcoord_a TEXTBOX_WIDTH - 2, TEXTBOX_Y + TEXTBOX_HEIGHT - 1
+ pop hl
+ jp NextTextCommand
+
+Text_TX_SCROLL:: ; 113f (0:113f)
+; TX_SCROLL
+; pushes text up two lines and sets the BC cursor to the border tile
+; below the first character column of the text box.
+; [07]
+ ld a, "─"
+ ldcoord_a TEXTBOX_WIDTH - 2, TEXTBOX_Y + TEXTBOX_HEIGHT - 1
+ call ScrollTextUpOneLine
+ call ScrollTextUpOneLine
+ pop hl
+ coord bc, TEXTBOX_INNERX, TEXTBOX_INNERY + 2
+ jp NextTextCommand
+
+Text_START_ASM:: ; 1151 (0:1151)
+; TX_ASM
+; Executes code following this command.
+; Text processing is resumed upon returning.
+; [08][asm...ret]
+ pop hl
+ ld de, NextTextCommand
+ push de
+ jp hl
+
+Text_TX_NUM:: ; 1157 (0:1157)
+; TX_NUM
+; [$09][addr][hi:bytes lo:digits]
+ pop hl
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ push hl
+ ld h, b
+ ld l, c
+ ld b, a
+ and $0f
+ ld c, a
+ ld a, b
+ and $f0
+ swap a
+ set 6, a
+ ld b, a
+ call PrintNumber
+ ld b, h
+ ld c, l
+ pop hl
+ jp NextTextCommand
+; 0x1175
+
+Text_TX_EXIT: ; 1175 (0:1175)
+; TX_EXIT
+; [$0A]
+ push bc
+ call GetJoypad
+ ldh a, [hJoyState]
+ and (A_BUTTON | B_BUTTON)
+ jr nz, .done
+ ld c, 30
+ call DelayFrames
+.done
+ pop bc
+ pop hl
+ jp NextTextCommand
+; 0x1189
+
+Text_PlaySound:: ; 1189 (0:1189)
+; Text_PlaySound
+; [0B|0E..13] Play Sound Effects
+; [14..16] Play Pokémon Cries
+ pop hl
+ push bc
+ dec hl
+ ld a, [hli]
+ ld b, a
+ push hl
+ ld hl, .soundTable
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .found
+ inc hl
+ inc hl
+ jr .loop
+.found
+ cp $14
+ jr z, .playCry
+ cp $15
+ jr z, .playCry
+ cp $16
+ jr z, .playCry
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call PlaySFX
+ call WaitSFX
+ pop de
+ pop hl
+ pop bc
+ jp NextTextCommand
+.playCry
+ push de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ call PlayCry
+ pop de
+ pop hl
+ pop bc
+ jp NextTextCommand
+
+.soundTable:
+ dbw TX_SOUND_0B, $0063
+ dbw TX_SOUND_12, $006B
+ dbw TX_SOUND_0E, $0066
+ dbw TX_SOUND_0F, $0067
+ dbw TX_SOUND_10, $0068
+ dbw TX_SOUND_11, $0069
+ dbw TX_SOUND_13, $0027
+ dbw TX_CRY_14, MON_NIDORINA ; or MON_LEAFY?
+ dbw TX_CRY_15, MON_PIGEOT
+ dbw TX_CRY_16, MON_JUGON
+
+Text_TX_DOTS: ; 11e1 (0:11e1)
+ pop hl
+ ld a, [hli]
+ ld d, a
+ push hl
+ ld h, b
+ ld l, c
+.loop
+ ld a, "…"
+ ld [hli], a
+ push de
+ call GetJoypad
+ pop de
+ ldh a, [hJoyState]
+ and (A_BUTTON | B_BUTTON)
+ jr nz, .next
+ ld c, 10
+ call DelayFrames
+.next
+ dec d
+ jr nz, .loop
+ ld b, h
+ ld c, l
+ pop hl
+ jp NextTextCommand
+
+Text_TX_LINK_WAIT_BUTTON:: ; 1203 (0:1203)
+ push bc
+ call ButtonSound
+ pop bc
+ pop hl
+ jp NextTextCommand
+; 0x120c
+
+TextCommands:: ; 120c
+ dw Text_TX
+ dw Text_TX_RAM
+ dw Text_TX_BCD
+ dw Text_TX_MOVE
+ dw Text_TX_BOX
+ dw Text_TX_LOW
+ dw Text_WAIT_BUTTON
+ dw Text_TX_SCROLL
+ dw Text_START_ASM
+ dw Text_TX_NUM
+ dw Text_TX_EXIT
+ dw Text_PlaySound
+ dw Text_TX_DOTS
+ dw Text_TX_LINK_WAIT_BUTTON
+ dw Text_PlaySound
+ dw Text_PlaySound
+ dw Text_PlaySound
+ dw Text_PlaySound
+ dw Text_PlaySound
+ dw Text_PlaySound
+ dw Text_PlaySound
+ dw Text_PlaySound
+ dw Text_PlaySound
diff --git a/home/unknown.asm b/home/unknown.asm
index c216f62..5b9a6e1 100644
--- a/home/unknown.asm
+++ b/home/unknown.asm
@@ -7,10 +7,10 @@ SECTION "Empty function", ROM0[$2F5B]
endc
InexplicablyEmptyFunction:: ; 2f97
-REPT 16
- nop
-ENDR
- ret
+rept 16
+ nop
+endr
+ ret
; TODO:
@@ -21,14 +21,14 @@ ENDR
SECTION "Unknown functions", ROM0[$1FF4]
_1FF4:: ; 1ff4
- ld a, BANK(s0_a600)
- call OpenSRAM
- ld hl, s0_a600 ; TODO: label this.
- ld bc, 7
- xor a
- call ByteFill
- call CloseSRAM
- ret
+ ld a, BANK(s0_a600)
+ call OpenSRAM
+ ld hl, s0_a600 ; TODO: label this.
+ ld bc, 7
+ xor a
+ call ByteFill
+ call CloseSRAM
+ ret
_2007:: ; 2007
ld a, BANK(s0_a600)
@@ -65,13 +65,13 @@ if DEBUG
._209e:
endc
- ld hl, hHours
+ ld hl, hRTCHours
ld de, wcbd2
call _20DC
- ld hl, hMinutes
+ ld hl, hRTCMinutes
ld de, wcbd2 + 3
call _20DC
- ldh a, [hDays]
+ ldh a, [hRTCDays]
and 7
add $71 ; Sunday
ld [wcbd2 + 6], a
@@ -79,7 +79,7 @@ endc
ld [wcbd2 + 9], a
inc a ; mobile
ld [wcbd2 + 11], a
- ldh a, [hSeconds]
+ ldh a, [hRTCSeconds]
and 1
ret z
ld a, $70 ; :
diff --git a/home/vblank.asm b/home/vblank.asm
index 334cef4..33bbd40 100644
--- a/home/vblank.asm
+++ b/home/vblank.asm
@@ -3,29 +3,298 @@ INCLUDE "constants.asm"
SECTION "VBlank handler", ROM0[$150]
VBlank:: ; 0150
- push af
- push bc
- push de
- push hl
- ldh a, [hVBlank]
- and 3
- ld e, a
- ld d, 0
- ld hl, .blanks
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, .return
- push de
- jp hl
+ push af
+ push bc
+ push de
+ push hl
+ ldh a, [hVBlank]
+ and 3
+ ld e, a
+ ld d, 0
+ ld hl, .blanks
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .return
+ push de
+ jp hl
.return
- pop hl
- pop de
- pop bc
- pop af
- reti
+ pop hl
+ pop de
+ pop bc
+ pop af
+ reti
.blanks
- ; TODO
+ dw VBlank0
+ dw VBlank1
+ dw VBlank2
+ dw VBlank3
+
+VBlank0:: ; 175 (0:175)
+; rng
+; scx, scy, wy, wx
+; bg map
+; row/column redraw
+; copy 2bpp
+; copy 1bpp
+; animate tileset
+; copy far 2bpp
+; enable oam sprites
+; oam
+; joypad
+; sound / serial / lcd_stat
+ ldh a, [hVBlankCounter]
+ inc a
+ ldh [hVBlankCounter], a
+ bit 0, a
+ jr nz, .even_frame
+ ldh a, [hRTCRandom]
+ ld b, a
+ ldh a, [rLY]
+ adc b
+.even_frame
+ ; advance random variables
+ ld b, a
+ ldh a, [hRandomAdd]
+ adc b
+ ldh [hRandomAdd], a
+ ld b, a
+ ldh a, [hRandomSub]
+ sbc b
+ ldh [hRandomSub], a
+ ldh a, [hRTCSeconds]
+ ldh [hRTCRandom], a
+ ldh a, [hROMBank]
+ ld [wVBlankSavedROMBank], a
+ ldh a, [hSCX]
+ ldh [rSCX], a
+ ldh a, [hSCY]
+ ldh [rSCY], a
+ ld a, [wDisableVBlankWYUpdate]
+ and a
+ jr nz, .ok
+ ldh a, [hWY]
+ ldh [rWY], a
+ ldh a, [hWX]
+ ldh [rWX], a
+.ok
+ call AutoBgMapTransfer
+ call RedrawRowOrColumn
+ call VBlankCopy
+ call VBlankCopyDouble
+ call AnimateTileset
+ call VBlankCopyFar
+ call EnableSprites
+ call hOAMDMA
+ xor a
+ ld [wVBlankOccurred], a
+ ld a, [wVBlankJoyFrameCounter]
+ and a
+ jr z, .skipDec
+ dec a
+ ld [wVBlankJoyFrameCounter], a
+.skipDec
+ call Joypad
+ xor a
+ ldh [rIF], a
+ ld a, (1 << SERIAL | 1 << LCD_STAT)
+ ldh [rIE], a
+ ld a, (1 << LCD_STAT)
+ ldh [rIF], a
+ ei
+ call UpdateSound
+ ld a, [wVBlankSavedROMBank]
+ call Bankswitch
+ di
+ xor a
+ ldh [rIF], a
+ ld a, (1 << JOYPAD | 1 << SERIAL | 1 << TIMER | 1 << LCD_STAT | 1 << VBLANK)
+ ldh [rIE], a
+ ret
+
+VBlank1:: ; 1f6 (0:1f6)
+; Simple VBlank
+;
+; scx, scy
+; dmg pals
+; bg map
+; copy 2bpp
+; oam
+; sound / lcd_stat
+; no counters!
+ ldh a, [hROMBank]
+ ld [wVBlankSavedROMBank], a
+ ldh a, [hSCX]
+ ldh [rSCX], a
+ ldh a, [hSCY]
+ ldh [rSCY], a
+ ld a, [wBGP]
+ ldh [rBGP], a
+ ld a, [wOBP0]
+ ldh [rOBP0], a
+ ld a, [wOBP1]
+ ldh [rOBP1], a
+ call AutoBgMapTransfer
+ call VBlankCopy
+ ld a, [wDisableVBlankOAMUpdate]
+ and a
+ jr nz, .skip_oam
+ call hOAMDMA
+.skip_oam
+ xor a
+ ld [wVBlankOccurred], a
+ xor a
+ ldh [rIF], a
+ ld a, (1 << LCD_STAT)
+ ldh [rIE], a
+ ldh [rIF], a
+ ei
+ call UpdateSound
+ ld a, [wVBlankSavedROMBank]
+ call Bankswitch
+ di
+ xor a
+ ldh [rIF], a
+ ld a, (1 << JOYPAD | 1 << SERIAL | 1 << TIMER | 1 << LCD_STAT | 1 << VBLANK)
+ ldh [rIE], a
+ ret
+
+VBlank2:: ; 241 (0:241)
+; rng
+; scx, scy, wy, wx
+; joypad
+; bg map
+; row/column redraw
+; copy 2bpp
+; copy 1bpp
+; copy far 2bpp
+; oam
+; sound
+ ldh a, [hVBlankCounter]
+ inc a
+ ldh [hVBlankCounter], a
+ bit 0, a
+ jr nz, .even_frame
+ ldh a, [rLY]
+.even_frame
+ ; advance random variables
+ ld b, a
+ ldh a, [hRandomAdd]
+ adc b
+ ldh [hRandomAdd], a
+ ld b, a
+ ldh a, [hRandomSub]
+ sbc b
+ ldh [hRandomSub], a
+ call Joypad
+ ldh a, [hROMBank]
+ ld [wVBlankSavedROMBank], a
+ ldh a, [hSCX]
+ ldh [rSCX], a
+ ldh a, [hSCY]
+ ldh [rSCY], a
+ ld a, [wDisableVBlankWYUpdate]
+ and a
+ jr nz, .ok
+ ldh a, [hWY]
+ ldh [rWY], a
+ ldh a, [hWX]
+ ldh [rWX], a
+.ok
+ call AutoBgMapTransfer
+ call RedrawRowOrColumn
+ call VBlankCopy
+ call VBlankCopyDouble
+ call VBlankCopyFar
+ call hOAMDMA
+ xor a
+ ld [wVBlankOccurred], a
+ ld a, [wVBlankJoyFrameCounter]
+ and a
+ jr z, .skipDec
+ dec a
+ ld [wVBlankJoyFrameCounter], a
+.skipDec
+ call UpdateSound
+ ld a, [wVBlankSavedROMBank]
+ call Bankswitch
+ ret
+
+VBlank3:: ; 2a0 (0:2a0)
+; rng
+; joypad
+; scx, scy, wy, wx
+; bg map
+; row/column redraw
+; copy 2bpp
+; copy 1bpp
+; animate tileset
+; copy far 2bpp
+; enable oam sprites
+; oam
+; sound / lcd_stat
+ ldh a, [hVBlankCounter]
+ inc a
+ ldh [hVBlankCounter], a
+ bit 0, a
+ jr nz, .even_frame
+ ldh a, [rLY]
+.even_frame
+ ld b, a
+ ldh a, [hRandomAdd]
+ adc b
+ ldh [hRandomAdd], a
+ ld b, a
+ ldh a, [hRandomSub]
+ sbc b
+ ldh [hRandomSub], a
+ call Joypad
+ ldh a, [hROMBank]
+ ld [wVBlankSavedROMBank], a
+ ldh a, [hSCX]
+ ldh [rSCX], a
+ ldh a, [hSCY]
+ ldh [rSCY], a
+ ld a, [wDisableVBlankWYUpdate]
+ and a
+ jr nz, .ok
+ ldh a, [hWY]
+ ldh [rWY], a
+ ldh a, [hWX]
+ ldh [rWX], a
+.ok
+ call AutoBgMapTransfer
+ call RedrawRowOrColumn
+ call VBlankCopy
+ call VBlankCopyDouble
+ call AnimateTileset
+ call VBlankCopyFar
+ call EnableSprites
+ call hOAMDMA
+ xor a
+ ld [wVBlankOccurred], a
+ ld a, [wVBlankJoyFrameCounter]
+ and a
+ jr z, .skipDec
+ dec a
+ ld [wVBlankJoyFrameCounter], a
+.skipDec
+ xor a
+ ldh [rIF], a
+ ld a, (1 << LCD_STAT)
+ ldh [rIE], a
+ ldh [rIF], a
+ ei
+ call UpdateSound
+ ld a, [wVBlankSavedROMBank]
+ call Bankswitch
+ di
+ xor a
+ ldh [rIF], a
+ ld a, (1 << JOYPAD | 1 << SERIAL | 1 << TIMER | 1 << LCD_STAT | 1 << VBLANK)
+ ldh [rIE], a
+ ret
+; 0x317
diff --git a/home/vcopy.asm b/home/vcopy.asm
new file mode 100644
index 0000000..a453da5
--- /dev/null
+++ b/home/vcopy.asm
@@ -0,0 +1,616 @@
+INCLUDE "constants.asm"
+INCLUDE "vram.asm"
+
+SECTION "Copy Routines used by VBlank ISR", ROM0[$123a]
+
+RedrawRowOrColumn:: ; 123a (0: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
+ 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
+ ; fallthrough (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
+ ; fallthrough
+
+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
+
+VBlankCopyDouble:: ; 1470 (0:1470)
+; 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.
+ 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
+
+VBlankCopy:: ; 14c7 (0:14c7)
+; 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.
+ 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
+
+VBlankCopyFar:: ; 1558 (0:1558)
+; 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.
+ 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