aboutsummaryrefslogtreecommitdiffstats
path: root/home
diff options
context:
space:
mode:
authordannye <33dannye@gmail.com>2020-11-04 00:06:44 -0600
committerdannye <33dannye@gmail.com>2020-11-04 00:06:44 -0600
commit5647ca687b92954dcf37a6ea6bfbc9a341c32de4 (patch)
treedde1937a1bfdb3a835f4155e1c2eb8f1aaf86f63 /home
parentMerge pull request #55 from Deokishisu/patch-1 (diff)
downloadpokeyellow-5647ca687b92954dcf37a6ea6bfbc9a341c32de4.tar.gz
pokeyellow-5647ca687b92954dcf37a6ea6bfbc9a341c32de4.tar.xz
pokeyellow-5647ca687b92954dcf37a6ea6bfbc9a341c32de4.zip
Sync with pokered
Diffstat (limited to 'home')
-rw-r--r--home/array.asm21
-rw-r--r--home/array2.asm47
-rw-r--r--home/audio.asm10
-rw-r--r--home/bankswitch.asm15
-rw-r--r--home/clear_sprites.asm21
-rw-r--r--home/compare.asm11
-rw-r--r--home/copy.asm50
-rw-r--r--home/copy2.asm68
-rw-r--r--home/copy_string.asm13
-rw-r--r--home/count_set_bits.asm24
-rw-r--r--home/delay.asm32
-rw-r--r--home/fade.asm18
-rw-r--r--home/fade_audio.asm46
-rw-r--r--home/give.asm26
-rw-r--r--home/header.asm81
-rw-r--r--home/hidden_objects.asm35
-rw-r--r--home/init.asm80
-rw-r--r--home/inventory.asm38
-rw-r--r--home/item.asm49
-rw-r--r--home/item_price.asm39
-rw-r--r--home/joypad.asm5
-rw-r--r--home/joypad2.asm100
-rw-r--r--home/lcd.asm25
-rw-r--r--home/lcdc.asm6
-rw-r--r--home/list_menu.asm523
-rw-r--r--home/load_font.asm47
-rw-r--r--home/map_objects.asm322
-rw-r--r--home/math.asm33
-rw-r--r--home/money.asm15
-rw-r--r--home/move_mon.asm239
-rw-r--r--home/names.asm141
-rw-r--r--home/names2.asm92
-rw-r--r--home/npc_movement.asm52
-rw-r--r--home/oam.asm36
-rw-r--r--home/overworld.asm371
-rw-r--r--home/overworld_text.asm31
-rw-r--r--home/palettes.asm63
-rw-r--r--home/pathfinding.asm65
-rw-r--r--home/pics.asm198
-rwxr-xr-xhome/pikachu.asm6
-rw-r--r--home/play_time.asm10
-rw-r--r--home/pokemon.asm474
-rw-r--r--home/predef.asm4
-rw-r--r--home/predef_text.asm28
-rw-r--r--home/print_bcd.asm77
-rw-r--r--home/print_num.asm219
-rw-r--r--home/print_text.asm45
-rw-r--r--home/random.asm12
-rw-r--r--home/reload_sprites.asm19
-rw-r--r--home/reload_tiles.asm67
-rw-r--r--home/reset_player_sprite.asm21
-rw-r--r--home/serial.asm98
-rw-r--r--home/start.asm10
-rwxr-xr-xhome/start_menu.asm84
-rw-r--r--home/text.asm519
-rw-r--r--home/text_script.asm225
-rw-r--r--home/textbox.asm7
-rw-r--r--home/tilemap.asm45
-rw-r--r--home/trainers.asm426
-rw-r--r--home/trainers2.asm54
-rw-r--r--home/uncompress.asm (renamed from home/pic.asm)8
-rw-r--r--home/update_sprites.asm15
-rw-r--r--home/vblank.asm38
-rw-r--r--home/vcopy.asm150
-rw-r--r--home/window.asm292
-rw-r--r--home/yes_no.asm40
66 files changed, 5338 insertions, 743 deletions
diff --git a/home/array.asm b/home/array.asm
new file mode 100644
index 00000000..256c58e1
--- /dev/null
+++ b/home/array.asm
@@ -0,0 +1,21 @@
+; skips a text entries, each of size NAME_LENGTH (like trainer name, OT name, rival name, ...)
+; hl: base pointer, will be incremented by NAME_LENGTH * a
+SkipFixedLengthTextEntries::
+ and a
+ ret z
+ ld bc, NAME_LENGTH
+.skipLoop
+ add hl, bc
+ dec a
+ jr nz, .skipLoop
+ ret
+
+AddNTimes::
+; add bc to hl a times
+ and a
+ ret z
+.loop
+ add hl, bc
+ dec a
+ jr nz, .loop
+ ret
diff --git a/home/array2.asm b/home/array2.asm
new file mode 100644
index 00000000..f4ed8389
--- /dev/null
+++ b/home/array2.asm
@@ -0,0 +1,47 @@
+CallFunctionInTable::
+; Call function a in jumptable hl.
+; de is not preserved.
+ push hl
+ push de
+ push bc
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .returnAddress
+ push de
+ jp hl
+.returnAddress
+ pop bc
+ pop de
+ pop hl
+ ret
+
+IsInArray::
+; Search an array at hl for the value in a.
+; Entry size is de bytes.
+; Return count b and carry if found.
+ ld b, 0
+
+IsInRestOfArray::
+ ld c, a
+.loop
+ ld a, [hl]
+ cp -1
+ jr z, .notfound
+ cp c
+ jr z, .found
+ inc b
+ add hl, de
+ jr .loop
+
+.notfound
+ and a
+ ret
+
+.found
+ scf
+ ret
diff --git a/home/audio.asm b/home/audio.asm
index fa7020ee..bf2537a7 100644
--- a/home/audio.asm
+++ b/home/audio.asm
@@ -93,7 +93,7 @@ UpdateMusicCTimes::
.loop
push bc
push hl
- callba Audio1_UpdateMusic
+ farcall Audio1_UpdateMusic
pop hl
pop bc
dec c
@@ -144,11 +144,11 @@ Func_2223::
ld [wChannelSoundIDs + Ch6], a
ld [wChannelSoundIDs + Ch7], a
ld [wChannelSoundIDs + Ch8], a
- ld [rNR10], a
+ ldh [rNR10], a
ret
StopAllMusic::
- ld a, $FF
+ ld a, SFX_STOP_ALL_MUSIC
ld [wNewSoundID], a
; plays music specified by a. If value is $ff, music is stopped
PlaySound::
@@ -200,7 +200,7 @@ PlaySound::
ret
GetNextMusicByte::
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, [wAudioROMBank]
call BankswitchCommon
@@ -256,7 +256,7 @@ StopAllAudio::
ret
DetermineAudioFunction::
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, [wAudioROMBank]
call BankswitchCommon
diff --git a/home/bankswitch.asm b/home/bankswitch.asm
new file mode 100644
index 00000000..3e85e955
--- /dev/null
+++ b/home/bankswitch.asm
@@ -0,0 +1,15 @@
+BankswitchHome::
+; switches to bank # in a
+; Only use this when in the home bank!
+ ld [wBankswitchHomeTemp], a
+ ldh a, [hLoadedROMBank]
+ ld [wBankswitchHomeSavedROMBank], a
+ ld a, [wBankswitchHomeTemp]
+ call BankswitchCommon
+ ret
+
+BankswitchBack::
+; returns from BankswitchHome
+ ld a, [wBankswitchHomeSavedROMBank]
+ call BankswitchCommon
+ ret
diff --git a/home/clear_sprites.asm b/home/clear_sprites.asm
new file mode 100644
index 00000000..34f4b4ec
--- /dev/null
+++ b/home/clear_sprites.asm
@@ -0,0 +1,21 @@
+ClearSprites::
+ xor a
+ ld hl, wOAMBuffer
+ ld b, 40 * 4
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+HideSprites::
+ ld a, 160
+ ld hl, wOAMBuffer
+ ld de, 4
+ ld b, 40
+.loop
+ ld [hl], a
+ add hl, de
+ dec b
+ jr nz, .loop
+ ret
diff --git a/home/compare.asm b/home/compare.asm
new file mode 100644
index 00000000..e2da7857
--- /dev/null
+++ b/home/compare.asm
@@ -0,0 +1,11 @@
+; Compare strings, c bytes in length, at de and hl.
+; Often used to compare big endian numbers in battle calculations.
+StringCmp::
+ ld a, [de]
+ cp [hl]
+ ret nz
+ inc de
+ inc hl
+ dec c
+ jr nz, StringCmp
+ ret
diff --git a/home/copy.asm b/home/copy.asm
index d2228405..b239d951 100644
--- a/home/copy.asm
+++ b/home/copy.asm
@@ -1,7 +1,7 @@
FarCopyData::
; Copy bc bytes from a:hl to de.
ld [wFarCopyDataSavedROMBank], a
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, [wFarCopyDataSavedROMBank]
call BankswitchCommon
@@ -12,17 +12,17 @@ FarCopyData::
CopyData::
; Copy bc bytes from hl to de.
- ld a,b
+ ld a, b
and a
jr z, .copybytes
- ld a,c
+ ld a, c
and a ; is lower byte 0
jr z, .loop
inc b ; if not, increment b as there are <$100 bytes to copy
.loop
call .copybytes
dec b
- jr nz,.loop
+ jr nz, .loop
ret
.copybytes
@@ -34,41 +34,41 @@ CopyData::
ret
CopyVideoDataAlternate::
- ld a, [rLCDC]
- bit 7,a ; LCD enabled?
+ ldh a, [rLCDC]
+ bit 7, a ; LCD enabled?
jp nz, CopyVideoData ; if yes, then copy video data
push hl
- ld h,d
- ld l,e
+ ld h, d
+ ld l, e
pop de
- ld a,b ; save bank
+ ld a, b ; save bank
push af
swap c
- ld a,$f
+ ld a, $f
and c
- ld b,a
- ld a,$f0
+ ld b, a
+ ld a, $f0
and c
- ld c,a
+ ld c, a
pop af
jp FarCopyData
CopyVideoDataDoubleAlternate::
- ld a, [rLCDC]
- bit 7,a ; LCD enabled?
+ ldh a, [rLCDC]
+ bit 7, a ; LCD enabled?
jp nz, CopyVideoDataDouble ; if yes, then copy video data
push de
- ld d,h
- ld e,l
- ld a,b
+ ld d, h
+ ld e, l
+ ld a, b
push af ; save bank to switch to
- ld h,$0
- ld l,c
- add hl,hl ; get raw length of bytes to copy
- add hl,hl
- add hl,hl
- ld b,h
- ld c,l
+ ld h, $0
+ ld l, c
+ add hl, hl ; get raw length of bytes to copy
+ add hl, hl
+ add hl, hl
+ ld b, h
+ ld c, l
pop af
pop hl
jp FarCopyDataDouble
diff --git a/home/copy2.asm b/home/copy2.asm
index c14112bb..bff26570 100644
--- a/home/copy2.asm
+++ b/home/copy2.asm
@@ -2,7 +2,7 @@ FarCopyDataDouble::
; Expand bc bytes of 1bpp image data
; from a:de to 2bpp data at hl.
ld [wFarCopyDataSavedROMBank], a
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, [wFarCopyDataSavedROMBank]
call BankswitchCommon
@@ -38,26 +38,26 @@ CopyVideoData::
; tiles from b:de to hl, 8 tiles at a time.
; This takes c/8 frames.
- ld a, [H_AUTOBGTRANSFERENABLED]
+ ldh a, [hAutoBGTransferEnabled]
push af
xor a ; disable auto-transfer while copying
- ld [H_AUTOBGTRANSFERENABLED], a
+ ldh [hAutoBGTransferEnabled], a
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, b
call BankswitchCommon
ld a, e
- ld [H_VBCOPYSRC], a
+ ldh [hVBlankCopySource], a
ld a, d
- ld [H_VBCOPYSRC + 1], a
+ ldh [hVBlankCopySource + 1], a
ld a, l
- ld [H_VBCOPYDEST], a
+ ldh [hVBlankCopyDest], a
ld a, h
- ld [H_VBCOPYDEST + 1], a
+ ldh [hVBlankCopyDest + 1], a
.loop
ld a, c
@@ -65,17 +65,17 @@ CopyVideoData::
jr nc, .keepgoing
.done
- ld [H_VBCOPYSIZE], a
+ ldh [hVBlankCopySize], a
call DelayFrame
pop af
call BankswitchCommon
pop af
- ld [H_AUTOBGTRANSFERENABLED], a
+ ldh [hAutoBGTransferEnabled], a
ret
.keepgoing
ld a, 8
- ld [H_VBCOPYSIZE], a
+ ldh [hVBlankCopySize], a
call DelayFrame
ld a, c
sub 8
@@ -86,25 +86,25 @@ CopyVideoDataDouble::
; 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.
- ld a, [H_AUTOBGTRANSFERENABLED]
+ ldh a, [hAutoBGTransferEnabled]
push af
xor a ; disable auto-transfer while copying
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, [H_LOADEDROMBANK]
+ ldh [hAutoBGTransferEnabled], a
+ ldh a, [hLoadedROMBank]
push af
ld a, b
call BankswitchCommon
ld a, e
- ld [H_VBCOPYDOUBLESRC], a
+ ldh [hVBlankCopyDoubleSource], a
ld a, d
- ld [H_VBCOPYDOUBLESRC + 1], a
+ ldh [hVBlankCopyDoubleSource + 1], a
ld a, l
- ld [H_VBCOPYDOUBLEDEST], a
+ ldh [hVBlankCopyDoubleDest], a
ld a, h
- ld [H_VBCOPYDOUBLEDEST + 1], a
+ ldh [hVBlankCopyDoubleDest + 1], a
.loop
ld a, c
@@ -112,17 +112,17 @@ CopyVideoDataDouble::
jr nc, .keepgoing
.done
- ld [H_VBCOPYDOUBLESIZE], a
+ ldh [hVBlankCopyDoubleSize], a
call DelayFrame
pop af
call BankswitchCommon
pop af
- ld [H_AUTOBGTRANSFERENABLED], a
+ ldh [hAutoBGTransferEnabled], a
ret
.keepgoing
ld a, 8
- ld [H_VBCOPYDOUBLESIZE], a
+ ldh [hVBlankCopyDoubleSize], a
call DelayFrame
ld a, c
sub 8
@@ -131,10 +131,10 @@ CopyVideoDataDouble::
FillMemory::
push af
- ld a,b
+ ld a, b
and a
jr z, .eightbitcopyamount
- ld a,c
+ ld a, c
and a
jr z, .mulitpleof0x100
.eightbitcopyamount
@@ -142,7 +142,7 @@ FillMemory::
.mulitpleof0x100
pop af
.loop
- ld [hli],a
+ ld [hli], a
dec c
jr nz, .loop
dec b
@@ -154,7 +154,7 @@ GetFarByte::
; and return it in a
push bc
ld b, a
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, b
call BankswitchCommon
@@ -190,32 +190,32 @@ CopyScreenTileBufferToVRAM::
ld c, 6
ld hl, $600 * 0
- coord de, 0, 6 * 0
+ decoord 0, 6 * 0
call .setup
call DelayFrame
ld hl, $600 * 1
- coord de, 0, 6 * 1
+ decoord 0, 6 * 1
call .setup
call DelayFrame
ld hl, $600 * 2
- coord de, 0, 6 * 2
+ decoord 0, 6 * 2
call .setup
jp DelayFrame
.setup
ld a, d
- ld [H_VBCOPYBGSRC+1], a
+ ldh [hVBlankCopyBGSource+1], a
call GetRowColAddressBgMap
ld a, l
- ld [H_VBCOPYBGDEST], a
+ ldh [hVBlankCopyBGDest], a
ld a, h
- ld [H_VBCOPYBGDEST+1], a
+ ldh [hVBlankCopyBGDest+1], a
ld a, c
- ld [H_VBCOPYBGNUMROWS], a
+ ldh [hVBlankCopyBGNumRows], a
ld a, e
- ld [H_VBCOPYBGSRC], a
+ ldh [hVBlankCopyBGSource], a
ret
ClearScreen::
@@ -223,7 +223,7 @@ ClearScreen::
; for the bg map to update.
ld bc, 20 * 18
inc b
- coord hl, 0, 0
+ hlcoord 0, 0
ld a, " "
.loop
ld [hli], a
diff --git a/home/copy_string.asm b/home/copy_string.asm
new file mode 100644
index 00000000..7f86e501
--- /dev/null
+++ b/home/copy_string.asm
@@ -0,0 +1,13 @@
+; copies a string from [de] to [wcf4b]
+CopyStringToCF4B::
+ ld hl, wcf4b
+ ; fall through
+
+; copies a string from [de] to [hl]
+CopyString::
+ ld a, [de]
+ inc de
+ ld [hli], a
+ cp "@"
+ jr nz, CopyString
+ ret
diff --git a/home/count_set_bits.asm b/home/count_set_bits.asm
new file mode 100644
index 00000000..73f7fa9c
--- /dev/null
+++ b/home/count_set_bits.asm
@@ -0,0 +1,24 @@
+; function to count how many bits are set in a string of bytes
+; INPUT:
+; hl = address of string of bytes
+; b = length of string of bytes
+; OUTPUT:
+; [wNumSetBits] = number of set bits
+CountSetBits::
+ ld c, 0
+.loop
+ ld a, [hli]
+ ld e, a
+ ld d, 8
+.innerLoop ; count how many bits are set in the current byte
+ srl e
+ ld a, 0
+ adc c
+ ld c, a
+ dec d
+ jr nz, .innerLoop
+ dec b
+ jr nz, .loop
+ ld a, c
+ ld [wNumSetBits], a
+ ret
diff --git a/home/delay.asm b/home/delay.asm
new file mode 100644
index 00000000..eba865c2
--- /dev/null
+++ b/home/delay.asm
@@ -0,0 +1,32 @@
+DelayFrames::
+; wait c frames
+ call DelayFrame
+ dec c
+ jr nz, DelayFrames
+ ret
+
+PlaySoundWaitForCurrent::
+ push af
+ call WaitForSoundToFinish
+ pop af
+ jp PlaySound
+
+; Wait for sound to finish playing
+WaitForSoundToFinish::
+ ld a, [wLowHealthAlarm]
+ and $80
+ ret nz
+ push hl
+.waitLoop
+ ld hl, wChannelSoundIDs + Ch5
+ xor a
+ or [hl]
+ inc hl
+ or [hl]
+ inc hl
+ inc hl
+ or [hl]
+ and a
+ jr nz, .waitLoop
+ pop hl
+ ret
diff --git a/home/fade.asm b/home/fade.asm
index 1259f92b..f38878b1 100644
--- a/home/fade.asm
+++ b/home/fade.asm
@@ -11,11 +11,11 @@ LoadGBPal::
dec h
.ok
ld a, [hli]
- ld [rBGP], a
+ ldh [rBGP], a
ld a, [hli]
- ld [rOBP0], a
+ ldh [rOBP0], a
ld a, [hli]
- ld [rOBP1], a
+ ldh [rOBP1], a
call UpdateGBCPal_BGP
call UpdateGBCPal_OBP0
call UpdateGBCPal_OBP1
@@ -32,11 +32,11 @@ GBFadeOutToWhite::
GBFadeIncCommon:
ld a, [hli]
- ld [rBGP], a
+ ldh [rBGP], a
ld a, [hli]
- ld [rOBP0], a
+ ldh [rOBP0], a
ld a, [hli]
- ld [rOBP1], a
+ ldh [rOBP1], a
call UpdateGBCPal_BGP
call UpdateGBCPal_OBP0
call UpdateGBCPal_OBP1
@@ -57,11 +57,11 @@ GBFadeInFromWhite::
GBFadeDecCommon:
ld a, [hld]
- ld [rOBP1], a
+ ldh [rOBP1], a
ld a, [hld]
- ld [rOBP0], a
+ ldh [rOBP0], a
ld a, [hld]
- ld [rBGP], a
+ ldh [rBGP], a
call UpdateGBCPal_BGP
call UpdateGBCPal_OBP0
call UpdateGBCPal_OBP1
diff --git a/home/fade_audio.asm b/home/fade_audio.asm
new file mode 100644
index 00000000..f4e77c3f
--- /dev/null
+++ b/home/fade_audio.asm
@@ -0,0 +1,46 @@
+FadeOutAudio::
+ ld a, [wAudioFadeOutControl]
+ and a ; currently fading out audio?
+ jr nz, .fadingOut
+ ld a, [wd72c]
+ bit 1, a
+ ret nz
+ ld a, $77
+ ldh [rNR50], a
+ ret
+.fadingOut
+ ld a, [wAudioFadeOutCounter]
+ and a
+ jr z, .counterReachedZero
+ dec a
+ ld [wAudioFadeOutCounter], a
+ ret
+.counterReachedZero
+ ld a, [wAudioFadeOutCounterReloadValue]
+ ld [wAudioFadeOutCounter], a
+ ldh a, [rNR50]
+ and a ; has the volume reached 0?
+ jr z, .fadeOutComplete
+ ld b, a
+ and $f
+ dec a
+ ld c, a
+ ld a, b
+ and $f0
+ swap a
+ dec a
+ swap a
+ or c
+ ldh [rNR50], a
+ ret
+.fadeOutComplete
+ ld a, [wAudioFadeOutControl]
+ ld b, a
+ xor a
+ ld [wAudioFadeOutControl], a
+ call StopAllMusic
+ ld a, [wAudioSavedROMBank]
+ ld [wAudioROMBank], a
+ ld a, b
+ ld [wNewSoundID], a
+ jp PlaySound
diff --git a/home/give.asm b/home/give.asm
new file mode 100644
index 00000000..cbfd0310
--- /dev/null
+++ b/home/give.asm
@@ -0,0 +1,26 @@
+GiveItem::
+; Give player quantity c of item b,
+; and copy the item's name to wcf4b.
+; Return carry on success.
+ ld a, b
+ ld [wd11e], a
+ ld [wcf91], a
+ ld a, c
+ ld [wItemQuantity], a
+ ld hl, wNumBagItems
+ call AddItemToInventory
+ ret nc
+ call GetItemName
+ call CopyStringToCF4B
+ scf
+ ret
+
+GivePokemon::
+; Give the player monster b at level c.
+ ld a, b
+ ld [wcf91], a
+ ld a, c
+ ld [wCurEnemyLVL], a
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ farjp _GivePokemon
diff --git a/home/header.asm b/home/header.asm
new file mode 100644
index 00000000..671f29b1
--- /dev/null
+++ b/home/header.asm
@@ -0,0 +1,81 @@
+; rst vectors (unused)
+
+SECTION "rst0", ROM0[$0000]
+ rst $38
+
+ ds $08 - @, 0 ; unused
+
+SECTION "rst8", ROM0[$0008]
+ rst $38
+
+ ds $10 - @, 0 ; unused
+
+SECTION "rst10", ROM0[$0010]
+ rst $38
+
+ ds $18 - @, 0 ; unused
+
+SECTION "rst18", ROM0[$0018]
+ rst $38
+
+ ds $20 - @, 0 ; unused
+
+SECTION "rst20", ROM0[$0020]
+ rst $38
+
+ ds $28 - @, 0 ; unused
+
+SECTION "rst28", ROM0[$0028]
+ rst $38
+
+ ds $30 - @, 0 ; unused
+
+SECTION "rst30", ROM0[$0030]
+ rst $38
+
+ ds $38 - @, 0 ; unused
+
+SECTION "rst38", ROM0[$0038]
+ rst $38
+
+ ds $40 - @, 0 ; unused
+
+
+; Game Boy hardware interrupts
+
+SECTION "vblank", ROM0[$0040]
+ jp VBlank
+
+ ds $48 - @, 0 ; unused
+
+SECTION "lcd", ROM0[$0048]
+ jp LCDC
+
+ ds $50 - @, 0 ; unused
+
+SECTION "timer", ROM0[$0050]
+ jp Timer
+
+ ds $58 - @, 0 ; unused
+
+SECTION "serial", ROM0[$0058]
+ jp Serial
+
+ ds $60 - @, 0 ; unused
+
+SECTION "joypad", ROM0[$0060]
+ reti
+
+
+SECTION "Header", ROM0[$0100]
+
+Start::
+; Nintendo requires all Game Boy ROMs to begin with a nop ($00) and a jp ($C3)
+; to the starting address.
+ nop
+ jp _Start
+
+; The Game Boy cartridge header data is patched over by rgbfix.
+; This makes sure it doesn't get used for anything else.
+
+ ds $0150 - @
diff --git a/home/hidden_objects.asm b/home/hidden_objects.asm
new file mode 100644
index 00000000..40c49c3e
--- /dev/null
+++ b/home/hidden_objects.asm
@@ -0,0 +1,35 @@
+UpdateCinnabarGymGateTileBlocks::
+ farcall UpdateCinnabarGymGateTileBlocks_
+ ret
+
+CheckForHiddenObjectOrBookshelfOrCardKeyDoor::
+ ldh a, [hLoadedROMBank]
+ push af
+ ldh a, [hJoyHeld]
+ bit 0, a ; A button
+ jr z, .nothingFound
+; A button is pressed
+ callbs CheckForHiddenObject
+ ldh a, [hDidntFindAnyHiddenObject]
+ and a
+ jr nz, .hiddenObjectNotFound
+ xor a
+ ldh [hItemAlreadyFound], a
+ ld a, [wHiddenObjectFunctionRomBank]
+ call BankswitchCommon
+ call JumpToAddress
+ ldh a, [hItemAlreadyFound]
+ jr .done
+.hiddenObjectNotFound
+ predef GetTileAndCoordsInFrontOfPlayer
+ farcall PrintBookshelfText
+ ldh a, [hFFDB]
+ and a
+ jr z, .done
+.nothingFound
+ ld a, $ff
+.done
+ ldh [hItemAlreadyFound], a
+ pop af
+ call BankswitchCommon
+ ret
diff --git a/home/init.asm b/home/init.asm
index a2f7f786..878f329a 100644
--- a/home/init.asm
+++ b/home/init.asm
@@ -21,28 +21,28 @@ rLCDC_DEFAULT EQU %11100011
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 [rTMA], a
- ld [rTAC], a
- ld [rBGP], a
- ld [rOBP0], a
- ld [rOBP1], a
+ ldh [rIF], a
+ ldh [rIE], a
+ ldh [rSCX], a
+ ldh [rSCY], a
+ ldh [rSB], a
+ ldh [rSC], a
+ ldh [rWX], a
+ ldh [rWY], a
+ ldh [rTMA], a
+ ldh [rTAC], a
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
ld a, rLCDC_ENABLE_MASK
- ld [rLCDC], a
+ ldh [rLCDC], a
call DisableLCD
ld sp, wStack
- ld hl, $c000 ; start of WRAM
- ld bc, $2000 ; size of WRAM
+ ld hl, WRAM0_Begin
+ ld bc, WRAM1_End - WRAM0_Begin
.loop
ld [hl], 0
inc hl
@@ -53,46 +53,46 @@ rLCDC_DEFAULT EQU %11100011
call ClearVram
- ld hl, $ff80
- ld bc, $fffe - $ff80
+ ld hl, HRAM_Begin
+ ld bc, HRAM_End - HRAM_Begin - 1
call FillMemory
call ClearSprites
- ld a, Bank(WriteDMACodeToHRAM)
- ld [H_LOADEDROMBANK], a
+ ld a, BANK(WriteDMACodeToHRAM)
+ ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call WriteDMACodeToHRAM
xor a
- ld [hTilesetType], a
- ld [rSTAT], a
- ld [hSCX], a
- ld [hSCY], a
- ld [rIF], a
+ ldh [hTilesetType], a
+ ldh [rSTAT], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ldh [rIF], a
ld [wc0f3], a
ld [wc0f4], a
ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL
- ld [rIE], a
+ ldh [rIE], a
ld a, 144 ; move the window off-screen
- ld [hWY], a
- ld [rWY], a
+ ldh [hWY], a
+ ldh [rWY], a
ld a, 7
- ld [rWX], a
+ ldh [rWX], a
ld a, CONNECTION_NOT_ESTABLISHED
- ld [hSerialConnectionStatus], a
+ ldh [hSerialConnectionStatus], a
- ld h, vBGMap0 / $100
+ ld h, HIGH(vBGMap0)
call ClearBgMap
- ld h, vBGMap1 / $100
+ ld h, HIGH(vBGMap1)
call ClearBgMap
ld a, rLCDC_DEFAULT
- ld [rLCDC], a
+ ldh [rLCDC], a
ld a, 16
- ld [hSoftReset], a
+ ldh [hSoftReset], a
call StopAllSounds
ei
@@ -103,9 +103,9 @@ rLCDC_DEFAULT EQU %11100011
ld [wAudioROMBank], a
ld [wAudioSavedROMBank], a
ld a, $9c
- ld [H_AUTOBGTRANSFERDEST + 1], a
+ ldh [hAutoBGTransferDest + 1], a
xor a
- ld [H_AUTOBGTRANSFERDEST], a
+ ldh [hAutoBGTransferDest], a
dec a
ld [wUpdateSpritesEnabled], a
@@ -116,13 +116,13 @@ rLCDC_DEFAULT EQU %11100011
call GBPalNormal
call ClearSprites
ld a, rLCDC_DEFAULT
- ld [rLCDC], a
+ ldh [rLCDC], a
jp SetDefaultNamesBeforeTitlescreen
-ClearVram:
- ld hl, $8000
- ld bc, $2000
+ClearVram::
+ ld hl, VRAM_Begin
+ ld bc, VRAM_End - VRAM_Begin
xor a
jp FillMemory
diff --git a/home/inventory.asm b/home/inventory.asm
new file mode 100644
index 00000000..1100666f
--- /dev/null
+++ b/home/inventory.asm
@@ -0,0 +1,38 @@
+; subtracts the amount the player paid from their money
+; OUTPUT: carry = 0(success) or 1(fail because there is not enough money)
+SubtractAmountPaidFromMoney::
+ farjp SubtractAmountPaidFromMoney_
+
+; adds the amount the player sold to their money
+AddAmountSoldToMoney::
+ ld de, wPlayerMoney + 2
+ ld hl, hMoney + 2 ; total price of items
+ ld c, 3 ; length of money in bytes
+ predef AddBCDPredef ; add total price to money
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; redraw money text box
+ ld a, SFX_PURCHASE
+ call PlaySoundWaitForCurrent
+ jp WaitForSoundToFinish
+
+; function to remove an item (in varying quantities) from the player's bag or PC box
+; INPUT:
+; HL = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wWhichPokemon] = index (within the inventory) of the item to remove
+; [wItemQuantity] = quantity to remove
+RemoveItemFromInventory::
+ homecall RemoveItemFromInventory_
+ ret
+
+; 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)
+; [wcf91] = item ID
+; [wItemQuantity] = item quantity
+; sets carry flag if successful, unsets carry flag if unsuccessful
+AddItemToInventory::
+ push bc
+ homecall_sf AddItemToInventory_
+ pop bc
+ ret
diff --git a/home/item.asm b/home/item.asm
new file mode 100644
index 00000000..f27d46f4
--- /dev/null
+++ b/home/item.asm
@@ -0,0 +1,49 @@
+; uses an item
+; UseItem is used with dummy items to perform certain other functions as well
+; INPUT:
+; [wcf91] = item ID
+; OUTPUT:
+; [wActionResultOrTookBattleTurn] = success
+; 00: unsuccessful
+; 01: successful
+; 02: not able to be used right now, no extra menu displayed (only certain items use this)
+UseItem::
+ farjp UseItem_
+
+; confirms the item toss and then tosses the item
+; INPUT:
+; hl = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wcf91] = item ID
+; [wWhichPokemon] = index of item within inventory
+; [wItemQuantity] = quantity to toss
+; OUTPUT:
+; clears carry flag if the item is tossed, sets carry flag if not
+TossItem::
+ ldh a, [hLoadedROMBank]
+ push af
+ ld a, BANK(TossItem_)
+ ldh [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ call TossItem_
+ pop de
+ ld a, d
+ ldh [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
+
+; checks if an item is a key item
+; INPUT:
+; [wcf91] = item ID
+; OUTPUT:
+; [wIsKeyItem] = result
+; 00: item is not key item
+; 01: item is key item
+IsKeyItem::
+ push hl
+ push de
+ push bc
+ farcall IsKeyItem_
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/home/item_price.asm b/home/item_price.asm
new file mode 100644
index 00000000..d8c2068e
--- /dev/null
+++ b/home/item_price.asm
@@ -0,0 +1,39 @@
+GetItemPrice::
+; Stores item's price as BCD at hItemPrice (3 bytes)
+; Input: [wcf91] = item id
+ ldh a, [hLoadedROMBank]
+ push af
+ ld a, [wListMenuID]
+ cp MOVESLISTMENU
+ ld a, BANK(ItemPrices)
+ jr nz, .ok
+ ld a, $f ; hardcoded Bank
+.ok
+ call BankswitchCommon
+ ld hl, wItemPrices
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wcf91] ; a contains item id
+ cp HM01
+ jr nc, .getTMPrice
+ ld bc, $3
+.loop
+ add hl, bc
+ dec a
+ jr nz, .loop
+ dec hl
+ ld a, [hld]
+ ldh [hItemPrice + 2], a
+ ld a, [hld]
+ ldh [hItemPrice + 1], a
+ ld a, [hl]
+ ldh [hItemPrice], a
+ jr .done
+.getTMPrice
+ callbs GetMachinePrice
+.done
+ ld de, hItemPrice
+ pop af
+ call BankswitchCommon
+ ret
diff --git a/home/joypad.asm b/home/joypad.asm
new file mode 100644
index 00000000..15f10fe2
--- /dev/null
+++ b/home/joypad.asm
@@ -0,0 +1,5 @@
+Joypad::
+ homecall_jump _Joypad
+
+ReadJoypad::
+ homecall_jump ReadJoypad_
diff --git a/home/joypad2.asm b/home/joypad2.asm
new file mode 100644
index 00000000..30f9f788
--- /dev/null
+++ b/home/joypad2.asm
@@ -0,0 +1,100 @@
+; this function is used when lower button sensitivity is wanted (e.g. menus)
+; OUTPUT: [hJoy5] = pressed buttons in usual format
+; there are two flags that control its functionality, [hJoy6] and [hJoy7]
+; there are essentially three modes of operation
+; 1. Get newly pressed buttons only
+; ([hJoy7] == 0, [hJoy6] == any)
+; Just copies [hJoyPressed] to [hJoy5].
+; 2. Get currently pressed buttons at low sample rate with delay
+; ([hJoy7] == 1, [hJoy6] != 0)
+; If the user holds down buttons for more than half a second,
+; report buttons as being pressed up to 12 times per second thereafter.
+; If the user holds down buttons for less than half a second,
+; report only one button press.
+; 3. Same as 2, but report no buttons as pressed if A or B is held down.
+; ([hJoy7] == 1, [hJoy6] == 0)
+JoypadLowSensitivity::
+ call Joypad
+ ldh a, [hJoy7] ; flag
+ and a ; get all currently pressed buttons or only newly pressed buttons?
+ ldh a, [hJoyPressed] ; newly pressed buttons
+ jr z, .storeButtonState
+ ldh a, [hJoyHeld] ; all currently pressed buttons
+.storeButtonState
+ ldh [hJoy5], a
+ ldh a, [hJoyPressed] ; newly pressed buttons
+ and a ; have any buttons been newly pressed since last check?
+ jr z, .noNewlyPressedButtons
+.newlyPressedButtons
+ ld a, 30 ; half a second delay
+ ldh [hFrameCounter], a
+ ret
+.noNewlyPressedButtons
+ ldh a, [hFrameCounter]
+ and a ; is the delay over?
+ jr z, .delayOver
+.delayNotOver
+ xor a
+ ldh [hJoy5], a ; report no buttons as pressed
+ ret
+.delayOver
+; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed
+ ldh a, [hJoyHeld]
+ and A_BUTTON | B_BUTTON
+ jr z, .setShortDelay
+ ldh a, [hJoy6] ; flag
+ and a
+ jr nz, .setShortDelay
+ xor a
+ ldh [hJoy5], a
+.setShortDelay
+ ld a, 5 ; 1/12 of a second delay
+ ldh [hFrameCounter], a
+ ret
+
+WaitForTextScrollButtonPress::
+ ldh a, [hDownArrowBlinkCount1]
+ push af
+ ldh a, [hDownArrowBlinkCount2]
+ push af
+ xor a
+ ldh [hDownArrowBlinkCount1], a
+ ld a, $6
+ ldh [hDownArrowBlinkCount2], a
+.loop
+ push hl
+ ld a, [wTownMapSpriteBlinkingEnabled]
+ and a
+ jr z, .skipAnimation
+ push de
+ push bc
+ callfar TownMapSpriteBlinkingAnimation
+ pop bc
+ pop de
+.skipAnimation
+ hlcoord 18, 16
+ call HandleDownArrowBlinkTiming
+ pop hl
+ call JoypadLowSensitivity
+ predef CableClub_Run
+ ldh a, [hJoy5]
+ and A_BUTTON | B_BUTTON
+ jr z, .loop
+ pop af
+ ldh [hDownArrowBlinkCount2], a
+ pop af
+ ldh [hDownArrowBlinkCount1], a
+ ret
+
+; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect
+ManualTextScroll::
+ ld a, [wLinkState]
+ cp LINK_STATE_BATTLING
+ jr z, .inLinkBattle
+ call WaitForTextScrollButtonPress
+ call WaitForSoundToFinish
+ ld a, SFX_PRESS_AB
+ jp PlaySound
+.inLinkBattle
+ ld c, 65
+ jp DelayFrames
diff --git a/home/lcd.asm b/home/lcd.asm
new file mode 100644
index 00000000..72fc70ed
--- /dev/null
+++ b/home/lcd.asm
@@ -0,0 +1,25 @@
+DisableLCD::
+ xor a
+ ldh [rIF], a
+ ldh a, [rIE]
+ ld b, a
+ res 0, a
+ ldh [rIE], a
+
+.wait
+ ldh a, [rLY]
+ cp LY_VBLANK
+ jr nz, .wait
+
+ ldh a, [rLCDC]
+ and $ff ^ rLCDC_ENABLE_MASK
+ ldh [rLCDC], a
+ ld a, b
+ ldh [rIE], a
+ ret
+
+EnableLCD::
+ ldh a, [rLCDC]
+ set rLCDC_ENABLE, a
+ ldh [rLCDC], a
+ ret
diff --git a/home/lcdc.asm b/home/lcdc.asm
index 6172dd0d..dd3fb2fb 100644
--- a/home/lcdc.asm
+++ b/home/lcdc.asm
@@ -1,15 +1,15 @@
LCDC::
push af
- ld a, [hLCDCPointer] ; doubles as enabling byte
+ ldh a, [hLCDCPointer] ; doubles as enabling byte
and a
jr z, .noLCDCInterrupt
push hl
; [C700 + [rLY]] --> [FF00 + [hLCDCPointer]]
- ld a, [rLY]
+ ldh a, [rLY]
ld l, a
ld h, wLYOverrides / $100
ld h, [hl] ; h != not part of pointer
- ld a, [hLCDCPointer]
+ ldh a, [hLCDCPointer]
ld l, a
ld a, h
ld h, $ff
diff --git a/home/list_menu.asm b/home/list_menu.asm
new file mode 100644
index 00000000..f0480460
--- /dev/null
+++ b/home/list_menu.asm
@@ -0,0 +1,523 @@
+; INPUT:
+; [wListMenuID] = list menu ID
+; [wListPointer] = address of the list (2 bytes)
+DisplayListMenuID::
+ xor a
+ ldh [hAutoBGTransferEnabled], a ; disable auto-transfer
+ ld a, 1
+ ldh [hJoy7], a ; joypad state update flag
+ ld a, [wBattleType]
+ and a ; is it the Old Man battle?
+ jr nz, .specialBattleType
+ ld a, $01 ; hardcoded bank
+ jr .bankswitch
+.specialBattleType ; Old Man battle
+ ld a, BANK(DisplayBattleMenu)
+.bankswitch
+ call BankswitchHome
+ ld hl, wd730
+ set 6, [hl] ; turn off letter printing delay
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ ld [wListCount], a
+ ld a, [wListPointer]
+ ld l, a
+ ld a, [wListPointer + 1]
+ ld h, a ; hl = address of the list
+ ld a, [hl] ; the first byte is the number of entries in the list
+ ld [wListCount], a
+ ld a, LIST_MENU_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; draw the menu text box
+ call UpdateSprites ; disable sprites behind the text box
+; the code up to .skipMovingSprites appears to be useless
+ hlcoord 4, 2 ; coordinates of upper left corner of menu text box
+ lb de, 9, 14 ; height and width of menu text box
+ ld a, [wListMenuID]
+ and a ; PCPOKEMONLISTMENU?
+ jr nz, .skipMovingSprites
+ call UpdateSprites
+.skipMovingSprites
+ ld a, 1 ; max menu item ID is 1 if the list has less than 2 entries
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld a, [wListCount]
+ cp 2 ; does the list have less than 2 entries?
+ jr c, .setMenuVariables
+ ld a, 2 ; max menu item ID is 2 if the list has at least 2 entries
+.setMenuVariables
+ ld [wMaxMenuItem], a
+ ld a, 4
+ ld [wTopMenuItemY], a
+ ld a, 5
+ ld [wTopMenuItemX], a
+ ld a, A_BUTTON | B_BUTTON | SELECT
+ ld [wMenuWatchedKeys], a
+ ld c, 10
+ call DelayFrames
+
+DisplayListMenuIDLoop::
+ xor a
+ ldh [hAutoBGTransferEnabled], a ; disable transfer
+ call PrintListMenuEntries
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a ; enable transfer
+ call Delay3
+ ld a, [wBattleType]
+ and a ; is it the Old Man battle?
+ jr z, .notOldManBattle
+.oldManBattle
+ ld a, "▶"
+ ldcoord_a 5, 4 ; place menu cursor in front of first menu entry
+ ld c, 20
+ call DelayFrames
+ xor a
+ ld [wCurrentMenuItem], a
+ hlcoord 5, 4
+ ld a, l
+ ld [wMenuCursorLocation], a
+ ld a, h
+ ld [wMenuCursorLocation + 1], a
+ jr .buttonAPressed
+.notOldManBattle
+ call LoadGBPal
+ call HandleMenuInput
+ push af
+ call PlaceMenuCursor
+ pop af
+ bit 0, a ; was the A button pressed?
+ jp z, .checkOtherKeys
+.buttonAPressed
+ ld a, [wCurrentMenuItem]
+ call PlaceUnfilledArrowMenuCursor
+
+; pointless because both values are overwritten before they are read
+ ld a, $01
+ ld [wMenuExitMethod], a
+ ld [wChosenMenuItem], a
+
+ xor a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld a, [wCurrentMenuItem]
+ ld c, a
+ ld a, [wListScrollOffset]
+ add c
+ ld c, a
+ ld a, [wListCount]
+ and a ; is the list empty?
+ jp z, ExitListMenu ; if so, exit the menu
+ dec a
+ cp c ; did the player select Cancel?
+ jp c, ExitListMenu ; if so, exit the menu
+ ld a, c
+ ld [wWhichPokemon], a
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ jr nz, .skipMultiplying
+; if it's an item menu
+ sla c ; item entries are 2 bytes long, so multiply by 2
+.skipMultiplying
+ ld a, [wListPointer]
+ ld l, a
+ ld a, [wListPointer + 1]
+ ld h, a
+ inc hl ; hl = beginning of list entries
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wcf91], a
+ ld a, [wListMenuID]
+ and a ; PCPOKEMONLISTMENU?
+ jr z, .pokemonList
+ push hl
+ call GetItemPrice
+ pop hl
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ jr nz, .skipGettingQuantity
+; if it's an item menu
+ inc hl
+ ld a, [hl] ; a = item quantity
+ ld [wMaxItemQuantity], a
+.skipGettingQuantity
+ ld a, [wcf91]
+ ld [wd0b5], a
+ ld a, BANK(ItemNames)
+ ld [wPredefBank], a
+ call GetName
+ jr .storeChosenEntry
+.pokemonList
+ ld hl, wPartyCount
+ ld a, [wListPointer]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld hl, wPartyMonNicks
+ jr z, .getPokemonName
+ ld hl, wBoxMonNicks ; box pokemon names
+.getPokemonName
+ ld a, [wWhichPokemon]
+ call GetPartyMonName
+.storeChosenEntry ; store the menu entry that the player chose and return
+ ld de, wcd6d
+ call CopyStringToCF4B ; copy name to wcf4b
+ ld a, CHOSE_MENU_ITEM
+ ld [wMenuExitMethod], a
+ ld a, [wCurrentMenuItem]
+ ld [wChosenMenuItem], a
+ xor a
+ ldh [hJoy7], a ; joypad state update flag
+ ld hl, wd730
+ res 6, [hl] ; turn on letter printing delay
+ jp BankswitchBack
+.checkOtherKeys ; check B, SELECT, Up, and Down keys
+ bit 1, a ; was the B button pressed?
+ jp nz, ExitListMenu ; if so, exit the menu
+ bit 2, a ; was the select button pressed?
+ jp nz, HandleItemListSwapping ; if so, allow the player to swap menu entries
+ ld b, a
+ bit 7, b ; was Down pressed?
+ ld hl, wListScrollOffset
+ jr z, .upPressed
+.downPressed
+ ld a, [hl]
+ add 3
+ ld b, a
+ ld a, [wListCount]
+ cp b ; will going down scroll past the Cancel button?
+ jp c, DisplayListMenuIDLoop
+ inc [hl] ; if not, go down
+ jp DisplayListMenuIDLoop
+.upPressed
+ ld a, [hl]
+ and a
+ jp z, DisplayListMenuIDLoop
+ dec [hl]
+ jp DisplayListMenuIDLoop
+
+DisplayChooseQuantityMenu::
+; text box dimensions/coordinates for just quantity
+ hlcoord 15, 9
+ lb bc, 1, 3 ; height and width
+ ld a, [wListMenuID]
+ cp PRICEDITEMLISTMENU
+ jr nz, .drawTextBox
+; text box dimensions/coordinates for quantity and price
+ hlcoord 7, 9
+ lb bc, 1, 11 ; height and width
+.drawTextBox
+ call TextBoxBorder
+ hlcoord 16, 10
+ ld a, [wListMenuID]
+ cp PRICEDITEMLISTMENU
+ jr nz, .printInitialQuantity
+ hlcoord 8, 10
+.printInitialQuantity
+ ld de, InitialQuantityText
+ call PlaceString
+ xor a
+ ld [wItemQuantity], a ; initialize current quantity to 0
+ jp .incrementQuantity
+.waitForKeyPressLoop
+ call JoypadLowSensitivity
+ ldh a, [hJoyPressed] ; newly pressed buttons
+ bit 0, a ; was the A button pressed?
+ jp nz, .buttonAPressed
+ bit 1, a ; was the B button pressed?
+ jp nz, .buttonBPressed
+ bit 6, a ; was Up pressed?
+ jr nz, .incrementQuantity
+ bit 7, a ; was Down pressed?
+ jr nz, .decrementQuantity
+ jr .waitForKeyPressLoop
+.incrementQuantity
+ ld a, [wMaxItemQuantity]
+ inc a
+ ld b, a
+ ld hl, wItemQuantity ; current quantity
+ inc [hl]
+ ld a, [hl]
+ cp b
+ jr nz, .handleNewQuantity
+; wrap to 1 if the player goes above the max quantity
+ ld a, 1
+ ld [hl], a
+ jr .handleNewQuantity
+.decrementQuantity
+ ld hl, wItemQuantity ; current quantity
+ dec [hl]
+ jr nz, .handleNewQuantity
+; wrap to the max quantity if the player goes below 1
+ ld a, [wMaxItemQuantity]
+ ld [hl], a
+.handleNewQuantity
+ hlcoord 17, 10
+ ld a, [wListMenuID]
+ cp PRICEDITEMLISTMENU
+ jr nz, .printQuantity
+.printPrice
+ ld c, $03
+ ld a, [wItemQuantity]
+ ld b, a
+ ld hl, hMoney ; total price
+; initialize total price to 0
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+.addLoop ; loop to multiply the individual price by the quantity to get the total price
+ ld de, hMoney + 2
+ ld hl, hItemPrice + 2
+ push bc
+ predef AddBCDPredef ; add the individual price to the current sum
+ pop bc
+ dec b
+ jr nz, .addLoop
+ ldh a, [hHalveItemPrices]
+ and a ; should the price be halved (for selling items)?
+ jr z, .skipHalvingPrice
+ xor a
+ ldh [hDivideBCDDivisor], a
+ ldh [hDivideBCDDivisor + 1], a
+ ld a, $02
+ ldh [hDivideBCDDivisor + 2], a
+ predef DivideBCDPredef3 ; halves the price
+; store the halved price
+ ldh a, [hDivideBCDQuotient]
+ ldh [hMoney], a
+ ldh a, [hDivideBCDQuotient + 1]
+ ldh [hMoney + 1], a
+ ldh a, [hDivideBCDQuotient + 2]
+ ldh [hMoney + 2], a
+.skipHalvingPrice
+ hlcoord 12, 10
+ ld de, SpacesBetweenQuantityAndPriceText
+ call PlaceString
+ ld de, hMoney ; total price
+ ld c, $a3
+ call PrintBCDNumber
+ hlcoord 9, 10
+.printQuantity
+ ld de, wItemQuantity ; current quantity
+ lb bc, LEADING_ZEROES | 1, 2 ; 1 byte, 2 digits
+ call PrintNumber
+ jp .waitForKeyPressLoop
+.buttonAPressed ; the player chose to make the transaction
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ ret
+.buttonBPressed ; the player chose to cancel the transaction
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ ld a, $ff
+ ret
+
+InitialQuantityText::
+ db "×01@"
+
+SpacesBetweenQuantityAndPriceText::
+ db " @"
+
+ExitListMenu::
+ ld a, [wCurrentMenuItem]
+ ld [wChosenMenuItem], a
+ ld a, CANCELLED_MENU
+ ld [wMenuExitMethod], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ xor a
+ ldh [hJoy7], a
+ ld hl, wd730
+ res 6, [hl]
+ call BankswitchBack
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ scf
+ ret
+
+PrintListMenuEntries::
+ hlcoord 5, 3
+ lb bc, 9, 14
+ call ClearScreenArea
+ ld a, [wListPointer]
+ ld e, a
+ ld a, [wListPointer + 1]
+ ld d, a
+ inc de ; de = beginning of list entries
+ ld a, [wListScrollOffset]
+ ld c, a
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ ld a, c
+ jr nz, .skipMultiplying
+; if it's an item menu
+; item entries are 2 bytes long, so multiply by 2
+ add a
+ sla c
+.skipMultiplying
+ add e
+ ld e, a
+ jr nc, .noCarry
+ inc d
+.noCarry
+ hlcoord 6, 4 ; coordinates of first list entry name
+ ld b, 4 ; print 4 names
+.loop
+ ld a, b
+ ld [wWhichPokemon], a
+ ld a, [de]
+ ld [wd11e], a
+ cp $ff
+ jp z, .printCancelMenuItem
+ push bc
+ push de
+ push hl
+ push hl
+ push de
+ ld a, [wListMenuID]
+ and a ; PCPOKEMONLISTMENU?
+ jr z, .pokemonPCMenu
+ cp MOVESLISTMENU
+ jr z, .movesMenu
+.itemMenu
+ call GetItemName
+ jr .placeNameString
+.pokemonPCMenu
+ push hl
+ ld hl, wPartyCount
+ ld a, [wListPointer]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld hl, wPartyMonNicks
+ jr z, .getPokemonName
+ ld hl, wBoxMonNicks ; box pokemon names
+.getPokemonName
+ ld a, [wWhichPokemon]
+ ld b, a
+ ld a, 4
+ sub b
+ ld b, a
+ ld a, [wListScrollOffset]
+ add b
+ call GetPartyMonName
+ pop hl
+ jr .placeNameString
+.movesMenu
+ call GetMoveName
+.placeNameString
+ call PlaceString
+ pop de
+ pop hl
+ ld a, [wPrintItemPrices]
+ and a ; should prices be printed?
+ jr z, .skipPrintingItemPrice
+.printItemPrice
+ push hl
+ ld a, [de]
+ ld de, ItemPrices
+ ld [wcf91], a
+ call GetItemPrice ; get price
+ pop hl
+ ld bc, SCREEN_WIDTH + 5 ; 1 row down and 5 columns right
+ add hl, bc
+ ld c, $a3 ; no leading zeroes, right-aligned, print currency symbol, 3 bytes
+ call PrintBCDNumber
+.skipPrintingItemPrice
+ ld a, [wListMenuID]
+ and a ; PCPOKEMONLISTMENU?
+ jr nz, .skipPrintingPokemonLevel
+.printPokemonLevel
+ ld a, [wd11e]
+ push af
+ push hl
+ ld hl, wPartyCount
+ ld a, [wListPointer]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld a, PLAYER_PARTY_DATA
+ jr z, .next
+ ld a, BOX_DATA
+.next
+ ld [wMonDataLocation], a
+ ld hl, wWhichPokemon
+ ld a, [hl]
+ ld b, a
+ ld a, $04
+ sub b
+ ld b, a
+ ld a, [wListScrollOffset]
+ add b
+ ld [hl], a
+ call LoadMonData
+ ld a, [wMonDataLocation]
+ and a ; is it a list of party pokemon or box pokemon?
+ jr z, .skipCopyingLevel
+.copyLevel
+ ld a, [wLoadedMonBoxLevel]
+ ld [wLoadedMonLevel], a
+.skipCopyingLevel
+ pop hl
+ ld bc, $1c
+ add hl, bc
+ call PrintLevel
+ pop af
+ ld [wd11e], a
+.skipPrintingPokemonLevel
+ pop hl
+ pop de
+ inc de
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ jr nz, .nextListEntry
+.printItemQuantity
+ ld a, [wd11e]
+ ld [wcf91], a
+ call IsKeyItem ; check if item is unsellable
+ ld a, [wIsKeyItem]
+ and a ; is the item unsellable?
+ jr nz, .skipPrintingItemQuantity ; if so, don't print the quantity
+ push hl
+ ld bc, SCREEN_WIDTH + 8 ; 1 row down and 8 columns right
+ add hl, bc
+ ld a, "×"
+ ld [hli], a
+ ld a, [wd11e]
+ push af
+ ld a, [de]
+ ld [wMaxItemQuantity], a
+ push de
+ ld de, wd11e
+ ld [de], a
+ lb bc, 1, 2
+ call PrintNumber
+ pop de
+ pop af
+ ld [wd11e], a
+ pop hl
+.skipPrintingItemQuantity
+ inc de
+ pop bc
+ inc c
+ push bc
+ inc c
+ ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
+ and a ; is an item being swapped?
+ jr z, .nextListEntry
+ add a
+ cp c ; is it this item?
+ jr nz, .nextListEntry
+ dec hl
+ ld a, "▷"
+ ld [hli], a
+.nextListEntry
+ ld bc, 2 * SCREEN_WIDTH ; 2 rows
+ add hl, bc
+ pop bc
+ inc c
+ dec b
+ jp nz, .loop
+ ld bc, -8
+ add hl, bc
+ ld a, "▼"
+ ld [hl], a
+ ret
+.printCancelMenuItem
+ ld de, ListMenuCancelText
+ jp PlaceString
+
+ListMenuCancelText::
+ db "CANCEL@"
diff --git a/home/load_font.asm b/home/load_font.asm
new file mode 100644
index 00000000..8ed0f0a7
--- /dev/null
+++ b/home/load_font.asm
@@ -0,0 +1,47 @@
+LoadFontTilePatterns::
+ ldh a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, FontGraphics
+ ld de, vFont
+ ld bc, FontGraphicsEnd - FontGraphics
+ ld a, BANK(FontGraphics)
+ jp FarCopyDataDouble ; if LCD is off, transfer all at once
+.on
+ ld de, FontGraphics
+ ld hl, vFont
+ lb bc, BANK(FontGraphics), (FontGraphicsEnd - FontGraphics) / $8
+ jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
+
+LoadTextBoxTilePatterns::
+ ldh a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, TextBoxGraphics
+ ld de, vChars2 tile $60
+ ld bc, TextBoxGraphicsEnd - TextBoxGraphics
+ ld a, BANK(TextBoxGraphics)
+ jp FarCopyData ; if LCD is off, transfer all at once
+.on
+ ld de, TextBoxGraphics
+ ld hl, vChars2 tile $60
+ lb bc, BANK(TextBoxGraphics), (TextBoxGraphicsEnd - TextBoxGraphics) / $10
+ jp CopyVideoData ; if LCD is on, transfer during V-blank
+
+LoadHpBarAndStatusTilePatterns::
+ ldh a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, HpBarAndStatusGraphics
+ ld de, vChars2 tile $62
+ ld bc, HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics
+ ld a, BANK(HpBarAndStatusGraphics)
+ jp FarCopyData ; if LCD is off, transfer all at once
+.on
+ ld de, HpBarAndStatusGraphics
+ ld hl, vChars2 tile $62
+ lb bc, BANK(HpBarAndStatusGraphics), (HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics) / $10
+ jp CopyVideoData ; if LCD is on, transfer during V-blank
diff --git a/home/map_objects.asm b/home/map_objects.asm
new file mode 100644
index 00000000..51206cc5
--- /dev/null
+++ b/home/map_objects.asm
@@ -0,0 +1,322 @@
+; checks if the player's coordinates match an arrow movement tile's coordinates
+; and if so, decodes the RLE movement data
+; b = player Y
+; c = player X
+DecodeArrowMovementRLE::
+ ld a, [hli]
+ cp $ff
+ ret z ; no match in the list
+ cp b
+ jr nz, .nextArrowMovementTileEntry1
+ ld a, [hli]
+ cp c
+ jr nz, .nextArrowMovementTileEntry2
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ ld hl, wSimulatedJoypadStatesEnd
+ call DecodeRLEList
+ dec a
+ ld [wSimulatedJoypadStatesIndex], a
+ ret
+.nextArrowMovementTileEntry1
+ inc hl
+.nextArrowMovementTileEntry2
+ inc hl
+ inc hl
+ jr DecodeArrowMovementRLE
+
+TextScript_ItemStoragePC::
+ call SaveScreenTilesToBuffer2
+ ld b, BANK(PlayerPC)
+ ld hl, PlayerPC
+ jr bankswitchAndContinue
+
+TextScript_BillsPC::
+ call SaveScreenTilesToBuffer2
+ ld b, BANK(BillsPC_)
+ ld hl, BillsPC_
+ jr bankswitchAndContinue
+
+TextScript_GameCornerPrizeMenu::
+; XXX find a better name for this function
+; special_F7
+ ld b, BANK(CeladonPrizeMenu)
+ ld hl, CeladonPrizeMenu
+bankswitchAndContinue::
+ call Bankswitch
+ jp HoldTextDisplayOpen ; continue to main text-engine function
+
+TextScript_PokemonCenterPC::
+ ld b, BANK(ActivatePC)
+ ld hl, ActivatePC
+ jr bankswitchAndContinue
+
+StartSimulatingJoypadStates::
+ xor a
+ ld [wOverrideSimulatedJoypadStatesMask], a
+ ld [wSpritePlayerStateData2MovementByte1], a
+ ld hl, wd730
+ set 7, [hl]
+ ret
+
+IsItemInBag::
+; given an item_id in b
+; set zero flag if item isn't in player's bag
+; else reset zero flag
+; related to Pokémon Tower and ghosts
+ predef GetQuantityOfItemInBag
+ ld a, b
+ and a
+ ret
+
+IsSurfingPikachuInParty::
+; set bit 6 of wd472 if true
+; also calls Func_3467, which is a bankswitch to IsStarterPikachuInOurParty
+ ld a, [wd472]
+ and $3f
+ ld [wd472], a
+ ld hl, wPartyMon1
+ ld c, PARTY_LENGTH
+ ld b, SURF
+.loop
+ ld a, [hl]
+ cp PIKACHU
+ jr nz, .notPikachu
+ push hl
+ ld de, $8
+ add hl, de
+ ld a, [hli]
+ cp b ; does pikachu have surf as one of its moves
+ jr z, .hasSurf
+ ld a, [hli]
+ cp b
+ jr z, .hasSurf
+ ld a, [hli]
+ cp b
+ jr z, .hasSurf
+ ld a, [hli]
+ cp b
+ jr nz, .noSurf
+.hasSurf
+ ld a, [wd472]
+ set 6, a
+ ld [wd472], a
+.noSurf
+ pop hl
+.notPikachu
+ ld de, wPartyMon2 - wPartyMon1
+ add hl, de
+ dec c
+ jr nz, .loop
+ call Func_3467
+ ret
+
+Func_3467::
+ push hl
+ push bc
+ callfar IsStarterPikachuInOurParty
+ pop bc
+ pop hl
+ ret nc
+ ld a, [wd472]
+ set 7, a
+ ld [wd472], a
+ ret
+
+DisplayPokedex::
+ ld [wd11e], a
+ farjp _DisplayPokedex
+
+SetSpriteFacingDirectionAndDelay::
+ call SetSpriteFacingDirection
+ ld c, 6
+ jp DelayFrames
+
+SetSpriteFacingDirection::
+ ld a, SPRITESTATEDATA1_FACINGDIRECTION
+ ldh [hSpriteDataOffset], a
+ call GetPointerWithinSpriteStateData1
+ ldh a, [hSpriteFacingDirection]
+ ld [hl], a
+ ret
+
+SetSpriteImageIndexAfterSettingFacingDirection::
+ ld de, SPRITESTATEDATA1_IMAGEINDEX - SPRITESTATEDATA1_FACINGDIRECTION
+ add hl, de
+ ld [hl], a
+ ret
+
+SpriteFunc_34a1::
+ ldh a, [hSpriteIndex]
+ swap a
+ add $e
+ ld l, a
+ ld h, $c2
+ ld c, [hl]
+ dec c
+ swap c
+ ldh a, [hSpriteOffset]
+ add c
+ ld c, a
+ ldh a, [hSpriteHeight]
+ swap a
+ add $2
+ ld l, a
+ dec h
+ ld [hl], c
+ ret
+
+; tests if the player's coordinates are in a specified array
+; INPUT:
+; hl = address of array
+; OUTPUT:
+; [wCoordIndex] = if there is match, the matching array index
+; sets carry if the coordinates are in the array, clears carry if not
+ArePlayerCoordsInArray::
+ ld a, [wYCoord]
+ ld b, a
+ ld a, [wXCoord]
+ ld c, a
+ ; fallthrough
+
+CheckCoords::
+ xor a
+ ld [wCoordIndex], a
+.loop
+ ld a, [hli]
+ cp $ff ; reached terminator?
+ jr z, .notInArray
+ push hl
+ ld hl, wCoordIndex
+ inc [hl]
+ pop hl
+.compareYCoord
+ cp b
+ jr z, .compareXCoord
+ inc hl
+ jr .loop
+.compareXCoord
+ ld a, [hli]
+ cp c
+ jr nz, .loop
+.inArray
+ scf
+ ret
+.notInArray
+ and a
+ ret
+
+; tests if a boulder's coordinates are in a specified array
+; INPUT:
+; hl = address of array
+; [hSpriteIndex] = index of boulder sprite
+; OUTPUT:
+; [wCoordIndex] = if there is match, the matching array index
+; sets carry if the coordinates are in the array, clears carry if not
+CheckBoulderCoords::
+ push hl
+ ld hl, wSpritePlayerStateData2MapY
+ ldh a, [hSpriteIndex]
+ swap a
+ ld d, $0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ sub $4 ; because sprite coordinates are offset by 4
+ ld b, a
+ ld a, [hl]
+ sub $4 ; because sprite coordinates are offset by 4
+ ld c, a
+ pop hl
+ jp CheckCoords
+
+GetPointerWithinSpriteStateData1::
+ ld h, HIGH(wSpriteStateData1)
+ jr _GetPointerWithinSpriteStateData
+
+GetPointerWithinSpriteStateData2::
+ ld h, HIGH(wSpriteStateData2)
+
+_GetPointerWithinSpriteStateData:
+ ldh a, [hSpriteDataOffset]
+ ld b, a
+ ldh a, [hSpriteIndex]
+ swap a
+ add b
+ ld l, a
+ ret
+
+; decodes a $ff-terminated RLEncoded list
+; each entry is a pair of bytes <byte value> <repetitions>
+; the final $ff will be replicated in the output list and a contains the number of bytes written
+; de: input list
+; hl: output list
+DecodeRLEList::
+ xor a
+ ld [wRLEByteCount], a ; count written bytes here
+.listLoop
+ ld a, [de]
+ cp $ff
+ jr z, .endOfList
+ ldh [hRLEByteValue], a ; store byte value to be written
+ inc de
+ ld a, [de]
+ ld b, $0
+ ld c, a ; number of bytes to be written
+ ld a, [wRLEByteCount]
+ add c
+ ld [wRLEByteCount], a ; update total number of written bytes
+ ldh a, [hRLEByteValue]
+ call FillMemory ; write a c-times to output
+ inc de
+ jr .listLoop
+.endOfList
+ ld a, $ff
+ ld [hl], a ; write final $ff
+ ld a, [wRLEByteCount]
+ inc a ; include sentinel in counting
+ ret
+
+; sets movement byte 1 for sprite [hSpriteIndex] to $FE and byte 2 to [hSpriteMovementByte2]
+SetSpriteMovementBytesToFE::
+ push hl
+ call GetSpriteMovementByte1Pointer
+ ld [hl], $fe
+ call GetSpriteMovementByte2Pointer
+ ldh a, [hSpriteMovementByte2]
+ ld [hl], a
+ pop hl
+ ret
+
+; sets both movement bytes for sprite [hSpriteIndex] to $FF
+SetSpriteMovementBytesToFF::
+ push hl
+ call GetSpriteMovementByte1Pointer
+ ld [hl], $FF
+ call GetSpriteMovementByte2Pointer
+ ld [hl], $FF ; prevent person from walking?
+ pop hl
+ ret
+
+; returns the sprite movement byte 1 pointer for sprite [hSpriteIndex] in hl
+GetSpriteMovementByte1Pointer::
+ ld h, $C2
+ ldh a, [hSpriteIndex]
+ swap a
+ add 6
+ ld l, a
+ ret
+
+; returns the sprite movement byte 2 pointer for sprite [hSpriteIndex] in hl
+GetSpriteMovementByte2Pointer::
+ push de
+ ld hl, wMapSpriteData
+ ldh a, [hSpriteIndex]
+ dec a
+ add a
+ ld e, a
+ ld d, 0
+ add hl, de
+ pop de
+ ret
diff --git a/home/math.asm b/home/math.asm
new file mode 100644
index 00000000..59eda606
--- /dev/null
+++ b/home/math.asm
@@ -0,0 +1,33 @@
+; function to do multiplication
+; all values are big endian
+; INPUT
+; FF96-FF98 = multiplicand
+; FF99 = multiplier
+; OUTPUT
+; FF95-FF98 = product
+Multiply::
+ push hl
+ push bc
+ callfar _Multiply
+ pop bc
+ pop hl
+ ret
+
+; function to do division
+; all values are big endian
+; INPUT
+; FF95-FF98 = dividend
+; FF99 = divisor
+; b = number of bytes in the dividend (starting from FF95)
+; OUTPUT
+; FF95-FF98 = quotient
+; FF99 = remainder
+Divide::
+ push hl
+ push de
+ push bc
+ homecall _Divide
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/home/money.asm b/home/money.asm
new file mode 100644
index 00000000..a62835ea
--- /dev/null
+++ b/home/money.asm
@@ -0,0 +1,15 @@
+HasEnoughMoney::
+; Check if the player has at least as much
+; money as the 3-byte BCD value at hMoney.
+ ld de, wPlayerMoney
+ ld hl, hMoney
+ ld c, 3
+ jp StringCmp
+
+HasEnoughCoins::
+; Check if the player has at least as many
+; coins as the 2-byte BCD value at hCoins.
+ ld de, wPlayerCoins
+ ld hl, hCoins
+ ld c, 2
+ jp StringCmp
diff --git a/home/move_mon.asm b/home/move_mon.asm
new file mode 100644
index 00000000..c766fbd5
--- /dev/null
+++ b/home/move_mon.asm
@@ -0,0 +1,239 @@
+; Copies [hl, bc) to [de, de + bc - hl).
+; In other words, the source data is from hl up to but not including bc,
+; and the destination is de.
+CopyDataUntil::
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, h
+ cp b
+ jr nz, CopyDataUntil
+ ld a, l
+ cp c
+ jr nz, CopyDataUntil
+ ret
+
+; Function to remove a pokemon from the party or the current box.
+; wWhichPokemon determines the pokemon.
+; [wRemoveMonFromBox] == 0 specifies the party.
+; [wRemoveMonFromBox] != 0 specifies the current box.
+RemovePokemon::
+ jpfar _RemovePokemon
+
+AddPartyMon::
+ push hl
+ push de
+ push bc
+ farcall _AddPartyMon
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; calculates all 5 stats of current mon and writes them to [de]
+CalcStats::
+ ld c, $0
+.statsLoop
+ inc c
+ call CalcStat
+ ldh a, [hMultiplicand+1]
+ ld [de], a
+ inc de
+ ldh a, [hMultiplicand+2]
+ ld [de], a
+ inc de
+ ld a, c
+ cp NUM_STATS
+ jr nz, .statsLoop
+ ret
+
+; calculates stat c of current mon
+; c: stat to calc (HP=1,Atk=2,Def=3,Spd=4,Spc=5)
+; b: consider stat exp?
+; hl: base ptr to stat exp values ([hl + 2*c - 1] and [hl + 2*c])
+CalcStat::
+ push hl
+ push de
+ push bc
+ ld a, b
+ ld d, a
+ push hl
+ ld hl, wMonHeader
+ ld b, $0
+ add hl, bc
+ ld a, [hl] ; read base value of stat
+ ld e, a
+ pop hl
+ push hl
+ sla c
+ ld a, d
+ and a
+ jr z, .statExpDone ; consider stat exp?
+ add hl, bc ; skip to corresponding stat exp value
+.statExpLoop ; calculates ceil(Sqrt(stat exp)) in b
+ xor a
+ ldh [hMultiplicand], a
+ ldh [hMultiplicand+1], a
+ inc b ; increment current stat exp bonus
+ ld a, b
+ cp $ff
+ jr z, .statExpDone
+ ldh [hMultiplicand+2], a
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, [hld]
+ ld d, a
+ ldh a, [hProduct + 3]
+ sub d
+ ld a, [hli]
+ ld d, a
+ ldh a, [hProduct + 2]
+ sbc d ; test if (current stat exp bonus)^2 < stat exp
+ jr c, .statExpLoop
+.statExpDone
+ srl c
+ pop hl
+ push bc
+ ld bc, wPartyMon1DVs - (wPartyMon1HPExp - 1) ; also wEnemyMonDVs - wEnemyMonHP
+ add hl, bc
+ pop bc
+ ld a, c
+ cp $2
+ jr z, .getAttackIV
+ cp $3
+ jr z, .getDefenseIV
+ cp $4
+ jr z, .getSpeedIV
+ cp $5
+ jr z, .getSpecialIV
+.getHpIV
+ push bc
+ ld a, [hl] ; Atk IV
+ swap a
+ and $1
+ sla a
+ sla a
+ sla a
+ ld b, a
+ ld a, [hli] ; Def IV
+ and $1
+ sla a
+ sla a
+ add b
+ ld b, a
+ ld a, [hl] ; Spd IV
+ swap a
+ and $1
+ sla a
+ add b
+ ld b, a
+ ld a, [hl] ; Spc IV
+ and $1
+ add b ; HP IV: LSB of the other 4 IVs
+ pop bc
+ jr .calcStatFromIV
+.getAttackIV
+ ld a, [hl]
+ swap a
+ and $f
+ jr .calcStatFromIV
+.getDefenseIV
+ ld a, [hl]
+ and $f
+ jr .calcStatFromIV
+.getSpeedIV
+ inc hl
+ ld a, [hl]
+ swap a
+ and $f
+ jr .calcStatFromIV
+.getSpecialIV
+ inc hl
+ ld a, [hl]
+ and $f
+.calcStatFromIV
+ ld d, $0
+ add e
+ ld e, a
+ jr nc, .noCarry
+ inc d ; de = Base + IV
+.noCarry
+ sla e
+ rl d ; de = (Base + IV) * 2
+ srl b
+ srl b ; b = ceil(Sqrt(stat exp)) / 4
+ ld a, b
+ add e
+ jr nc, .noCarry2
+ inc d ; de = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4
+.noCarry2
+ ldh [hMultiplicand+2], a
+ ld a, d
+ ldh [hMultiplicand+1], a
+ xor a
+ ldh [hMultiplicand], a
+ ld a, [wCurEnemyLVL]
+ ldh [hMultiplier], a
+ call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level
+ ldh a, [hMultiplicand]
+ ldh [hDividend], a
+ ldh a, [hMultiplicand+1]
+ ldh [hDividend+1], a
+ ldh a, [hMultiplicand+2]
+ ldh [hDividend+2], a
+ ld a, $64
+ ldh [hDivisor], a
+ ld a, $3
+ ld b, a
+ call Divide ; (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100
+ ld a, c
+ cp $1
+ ld a, 5 ; + 5 for non-HP stat
+ jr nz, .notHPStat
+ ld a, [wCurEnemyLVL]
+ ld b, a
+ ldh a, [hMultiplicand+2]
+ add b
+ ldh [hMultiplicand+2], a
+ jr nc, .noCarry3
+ ldh a, [hMultiplicand+1]
+ inc a
+ ldh [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level
+.noCarry3
+ ld a, 10 ; +10 for HP stat
+.notHPStat
+ ld b, a
+ ldh a, [hMultiplicand+2]
+ add b
+ ldh [hMultiplicand+2], a
+ jr nc, .noCarry4
+ ldh a, [hMultiplicand+1]
+ inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5
+ ldh [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10
+.noCarry4
+ ldh a, [hMultiplicand+1] ; check for overflow (>999)
+ cp HIGH(MAX_STAT_VALUE) + 1
+ jr nc, .overflow
+ cp HIGH(MAX_STAT_VALUE)
+ jr c, .noOverflow
+ ldh a, [hMultiplicand+2]
+ cp LOW(MAX_STAT_VALUE) + 1
+ jr c, .noOverflow
+.overflow
+ ld a, HIGH(MAX_STAT_VALUE) ; overflow: cap at 999
+ ldh [hMultiplicand+1], a
+ ld a, LOW(MAX_STAT_VALUE)
+ ldh [hMultiplicand+2], a
+.noOverflow
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AddEnemyMonToPlayerParty::
+ homecall_sf _AddEnemyMonToPlayerParty
+ ret
+
+MoveMon::
+ homecall_sf _MoveMon
+ ret
diff --git a/home/names.asm b/home/names.asm
new file mode 100644
index 00000000..f7751fa0
--- /dev/null
+++ b/home/names.asm
@@ -0,0 +1,141 @@
+GetMonName::
+ push hl
+ ldh a, [hLoadedROMBank]
+ push af
+ ld a, BANK(MonsterNames)
+ ldh [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ld a, [wd11e]
+ dec a
+ ld hl, MonsterNames
+ ld c, 10
+ ld b, 0
+ call AddNTimes
+ ld de, wcd6d
+ push de
+ ld bc, 10
+ call CopyData
+ ld hl, wcd6d + 10
+ ld [hl], "@"
+ pop de
+ pop af
+ ldh [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ pop hl
+ ret
+
+GetItemName::
+; given an item ID at [wd11e], store the name of the item into a string
+; starting at wcd6d
+ push hl
+ push bc
+ ld a, [wd11e]
+ cp HM01 ; is this a TM/HM?
+ jr nc, .Machine
+
+ ld [wd0b5], a
+ ld a, ITEM_NAME
+ ld [wNameListType], a
+ ld a, BANK(ItemNames)
+ ld [wPredefBank], a
+ call GetName
+ jr .Finish
+
+.Machine
+ call GetMachineName
+.Finish
+ ld de, wcd6d ; pointer to where item name is stored in RAM
+ pop bc
+ pop hl
+ ret
+
+GetMachineName::
+; copies the name of the TM/HM in [wd11e] to wcd6d
+ push hl
+ push de
+ push bc
+ ld a, [wd11e]
+ push af
+ cp TM01 ; is this a TM? [not HM]
+ jr nc, .WriteTM
+; if HM, then write "HM" and add NUM_HMS to the item ID, so we can reuse the
+; TM printing code
+ add NUM_HMS
+ ld [wd11e], a
+ ld hl, HiddenPrefix ; points to "HM"
+ ld bc, 2
+ jr .WriteMachinePrefix
+.WriteTM
+ ld hl, TechnicalPrefix ; points to "TM"
+ ld bc, 2
+.WriteMachinePrefix
+ ld de, wcd6d
+ call CopyData
+
+; now get the machine number and convert it to text
+ ld a, [wd11e]
+ sub TM01 - 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 [wd11e], a
+ pop bc
+ pop de
+ pop hl
+ ret
+
+TechnicalPrefix::
+ db "TM"
+HiddenPrefix::
+ db "HM"
+
+; sets carry if item is HM, clears carry if item is not HM
+; Input: a = item ID
+IsItemHM::
+ cp HM01
+ jr c, .notHM
+ cp TM01
+ ret
+.notHM
+ and a
+ ret
+
+; sets carry if move is an HM, clears carry if move is not an HM
+; Input: a = move ID
+IsMoveHM::
+ ld hl, HMMoves
+ ld de, 1
+ jp IsInArray
+
+HMMoves::
+INCLUDE "data/moves/hm_moves.asm"
+
+GetMoveName::
+ push hl
+ ld a, MOVE_NAME
+ ld [wNameListType], a
+ ld a, [wd11e]
+ ld [wd0b5], a
+ ld a, BANK(MoveNames)
+ ld [wPredefBank], a
+ call GetName
+ ld de, wcd6d ; pointer to where move name is stored in RAM
+ pop hl
+ ret
diff --git a/home/names2.asm b/home/names2.asm
new file mode 100644
index 00000000..9c8ca00c
--- /dev/null
+++ b/home/names2.asm
@@ -0,0 +1,92 @@
+NamePointers::
+; entries correspond to *_NAME constants
+ dw MonsterNames
+ dw MoveNames
+ dw UnusedBadgeNames
+ dw ItemNames
+ dw wPartyMonOT ; player's OT names list
+ dw wEnemyMonOT ; enemy's OT names list
+ dw TrainerNames
+
+GetName::
+; arguments:
+; [wd0b5] = which name
+; [wNameListType] = which list
+; [wPredefBank] = bank of list
+;
+; returns pointer to name in de
+ ld a, [wd0b5]
+ ld [wd11e], a
+
+ ; TM names are separate from item names.
+ ; BUG: This applies to all names instead of just items.
+ cp HM01
+ jp nc, GetMachineName
+
+ ldh a, [hLoadedROMBank]
+ push af
+ push hl
+ push bc
+ push de
+ ld a, [wNameListType] ;List3759_entrySelector
+ dec a
+ jr nz, .otherEntries
+ ;1 = MON_NAMES
+ call GetMonName
+ ld hl, NAME_LENGTH
+ add hl, de
+ ld e, l
+ ld d, h
+ jr .gotPtr
+.otherEntries
+ ;2-7 = OTHER ENTRIES
+ ld a, [wPredefBank]
+ call BankswitchCommon
+ ld a, [wNameListType] ;VariousNames' entryID
+ dec a
+ add a
+ ld d, 0
+ ld e, a
+ jr nc, .skip
+ inc d
+.skip
+ ld hl, NamePointers
+ add hl, de
+ ld a, [hli]
+ ldh [hSwapTemp + 1], a
+ ld a, [hl]
+ ldh [hSwapTemp], a
+ ldh a, [hSwapTemp]
+ ld h, a
+ ldh a, [hSwapTemp + 1]
+ ld l, a
+ ld a, [wd0b5]
+ ld b, a
+ ld c, 0
+.nextName
+ ld d, h
+ ld e, l
+.nextChar
+ ld a, [hli]
+ cp "@"
+ jr nz, .nextChar
+ inc c ;entry counter
+ ld a, b ;wanted entry
+ cp c
+ jr nz, .nextName
+ ld h, d
+ ld l, e
+ ld de, wcd6d
+ ld bc, $14
+ call CopyData
+.gotPtr
+ ld a, e
+ ld [wUnusedCF8D], a
+ ld a, d
+ ld [wUnusedCF8D + 1], a
+ pop de
+ pop bc
+ pop hl
+ pop af
+ call BankswitchCommon
+ ret
diff --git a/home/npc_movement.asm b/home/npc_movement.asm
new file mode 100644
index 00000000..200d3983
--- /dev/null
+++ b/home/npc_movement.asm
@@ -0,0 +1,52 @@
+; not zero if an NPC movement script is running, the player character is
+; automatically stepping down from a door, or joypad states are being simulated
+IsPlayerCharacterBeingControlledByGame::
+ ld a, [wNPCMovementScriptPointerTableNum]
+ and a
+ ret nz
+ ld a, [wd736]
+ bit 1, a ; currently stepping down from door bit
+ ret nz
+ ld a, [wd730]
+ and $80
+ ret
+
+RunNPCMovementScript::
+ ld hl, wd736
+ bit 0, [hl]
+ res 0, [hl]
+ jr nz, .playerStepOutFromDoor
+ ld a, [wNPCMovementScriptPointerTableNum]
+ and a
+ ret z
+ dec a
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, .NPCMovementScriptPointerTables
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ldh a, [hLoadedROMBank]
+ push af
+ ld a, [wNPCMovementScriptBank]
+ call BankswitchCommon
+ ld a, [wNPCMovementScriptFunctionNum]
+ call CallFunctionInTable
+ pop af
+ call BankswitchCommon
+ ret
+
+.NPCMovementScriptPointerTables
+ dw PalletMovementScriptPointerTable
+ dw PewterMuseumGuyMovementScriptPointerTable
+ dw PewterGymGuyMovementScriptPointerTable
+.playerStepOutFromDoor
+ farjp PlayerStepOutFromDoor
+
+EndNPCMovementScript::
+ farjp _EndNPCMovementScript
+
+DebugPressedOrHeldB::
+ ret
diff --git a/home/oam.asm b/home/oam.asm
new file mode 100644
index 00000000..8a940d97
--- /dev/null
+++ b/home/oam.asm
@@ -0,0 +1,36 @@
+; INPUT:
+; a = oam block index (each block is 4 oam entries)
+; b = Y coordinate of upper left corner of sprite
+; c = X coordinate of upper left corner of sprite
+; de = base address of 4 tile number and attribute pairs
+WriteOAMBlock::
+ ld h, HIGH(wOAMBuffer)
+ swap a ; multiply by 16
+ ld l, a
+ call .writeOneEntry ; upper left
+ push bc
+ ld a, 8
+ add c
+ ld c, a
+ call .writeOneEntry ; upper right
+ pop bc
+ ld a, 8
+ add b
+ ld b, a
+ call .writeOneEntry ; lower left
+ ld a, 8
+ add c
+ ld c, a
+ ; lower right
+.writeOneEntry
+ ld [hl], b ; Y coordinate
+ inc hl
+ ld [hl], c ; X coordinate
+ inc hl
+ ld a, [de] ; tile number
+ inc de
+ ld [hli], a
+ ld a, [de] ; attribute
+ inc de
+ ld [hli], a
+ ret
diff --git a/home/overworld.asm b/home/overworld.asm
index 8608cbfe..0cd63cf7 100644
--- a/home/overworld.asm
+++ b/home/overworld.asm
@@ -3,7 +3,7 @@ EnterMap::
ld a, $ff
ld [wJoyIgnore], a
call LoadMapData
- callba ClearVariablesOnEnterMap
+ farcall ClearVariablesOnEnterMap
ld hl, wd72c
bit 0, [hl] ; has the player already made 3 steps since the last battle?
jr z, .skipGivingThreeStepsOfNoRandomBattles
@@ -19,7 +19,7 @@ EnterMap::
ld a, [hl]
and 1 << 4 | 1 << 3 ; fly warp or dungeon warp
jr z, .didNotEnterUsingFlyWarpOrDungeonWarp
- callba EnterMapAnim
+ farcall EnterMapAnim
call UpdateSprites
ld hl, wd732
res 3, [hl]
@@ -27,7 +27,7 @@ EnterMap::
res 4, [hl]
.didNotEnterUsingFlyWarpOrDungeonWarp
call IsSurfingPikachuInParty
- callba CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road
+ farcall CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road
ld hl, wd732
bit 4, [hl]
res 4, [hl]
@@ -51,7 +51,7 @@ OverworldLoopLessDelay::
and a
jp nz, .moveAhead ; if the player sprite has not yet completed the walking animation
call JoypadOverworld ; get joypad state (which is possibly simulated)
- callba SafariZoneCheck
+ farcall SafariZoneCheck
ld a, [wSafariZoneGameOver]
and a
jp nz, WarpFound2
@@ -68,16 +68,16 @@ OverworldLoopLessDelay::
ld a, [wd730]
bit 7, a ; are we simulating button presses?
jr z, .notSimulating
- ld a, [hJoyHeld]
+ ldh a, [hJoyHeld]
jr .checkIfStartIsPressed
.notSimulating
- ld a, [hJoyPressed]
+ ldh a, [hJoyPressed]
.checkIfStartIsPressed
bit 3, a ; start button
jr z, .startButtonNotPressed
; if START is pressed
- xor a
- ld [hSpriteIndexOrTextID], a ; start menu text ID
+ xor a ; TEXT_START_MENU
+ ldh [hSpriteIndexOrTextID], a
jp .displayDialogue
.startButtonNotPressed
bit 0, a ; A button
@@ -89,14 +89,14 @@ OverworldLoopLessDelay::
call IsPlayerCharacterBeingControlledByGame
jr nz, .checkForOpponent
call CheckForHiddenObjectOrBookshelfOrCardKeyDoor
- ld a, [$ffeb]
+ ldh a, [hItemAlreadyFound]
and a
jp z, OverworldLoop ; jump if a hidden object or bookshelf was found, but not if a card key door was found
xor a
ld [wd436], a ; new yellow address
call IsSpriteOrSignInFrontOfPlayer
call Func_0ffe
- ld a, [hSpriteIndexOrTextID]
+ ldh a, [hSpriteIndexOrTextID]
and a
jp z, OverworldLoop
.displayDialogue
@@ -107,7 +107,7 @@ OverworldLoopLessDelay::
jr nz, .checkForOpponent
bit 0, a
jr nz, .checkForOpponent
- aCoord 8, 9
+ lda_coord 8, 9
ld [wTilePlayerStandingOn], a ; unused?
call DisplayTextID ; display either the start menu or the NPC/sign text
ld a, [wEnteringCableClub]
@@ -141,11 +141,11 @@ OverworldLoopLessDelay::
jp OverworldLoop
.checkIfDownButtonIsPressed
- ld a, [hJoyHeld] ; current joypad state
+ ldh a, [hJoyHeld] ; current joypad state
bit 7, a ; down button
jr z, .checkIfUpButtonIsPressed
ld a, 1
- ld [wSpriteStateData1 + 3], a ; delta Y
+ ld [wSpritePlayerStateData1YStepVector], a
ld a, PLAYER_DIR_DOWN
jr .handleDirectionButtonPress
@@ -153,7 +153,7 @@ OverworldLoopLessDelay::
bit 6, a ; up button
jr z, .checkIfLeftButtonIsPressed
ld a, -1
- ld [wSpriteStateData1 + 3], a ; delta Y
+ ld [wSpritePlayerStateData1YStepVector], a
ld a, PLAYER_DIR_UP
jr .handleDirectionButtonPress
@@ -161,7 +161,7 @@ OverworldLoopLessDelay::
bit 5, a ; left button
jr z, .checkIfRightButtonIsPressed
ld a, -1
- ld [wSpriteStateData1 + 5], a ; delta X
+ ld [wSpritePlayerStateData1XStepVector], a
ld a, PLAYER_DIR_LEFT
jr .handleDirectionButtonPress
@@ -169,7 +169,7 @@ OverworldLoopLessDelay::
bit 4, a ; right button
jr z, .noDirectionButtonsPressed
ld a, 1
- ld [wSpriteStateData1 + 5], a ; delta X
+ ld [wSpritePlayerStateData1XStepVector], a
ld a, 1
.handleDirectionButtonPress
@@ -228,7 +228,7 @@ OverworldLoopLessDelay::
.noCollision
ld a, $08
ld [wWalkCounter], a
- callab Func_fcc08
+ callfar Func_fcc08
jr .moveAhead2
.moveAhead
@@ -249,7 +249,7 @@ OverworldLoopLessDelay::
call StepCountCheck
CheckEvent EVENT_IN_SAFARI_ZONE ; in the safari zone?
jr z, .notSafariZone
- callba SafariZoneCheckSteps
+ farcall SafariZoneCheckSteps
ld a, [wSafariZoneGameOver]
and a
jp nz, WarpFound2
@@ -275,7 +275,7 @@ OverworldLoopLessDelay::
set 5, [hl]
set 6, [hl]
xor a
- ld [hJoyHeld], a
+ ldh [hJoyHeld], a
ld a, [wCurMap]
cp CINNABAR_GYM
jr nz, .notCinnabarGym
@@ -286,7 +286,7 @@ OverworldLoopLessDelay::
ld a, [wCurMap]
cp OAKS_LAB
jp z, .noFaintCheck ; no blacking out if the player lost to the rival in Oak's lab
- callab AnyPartyAlive
+ callfar AnyPartyAlive
ld a, d
and a
jr z, AllPokemonFainted
@@ -330,7 +330,7 @@ NewBattle::
ld a, [wd72e]
bit 4, a
jr nz, .noBattle
- jpba InitBattle
+ farjp InitBattle
.noBattle
and a
ret
@@ -349,7 +349,7 @@ DoBikeSpeedup::
ld a, [wCurMap]
cp ROUTE_17 ; Cycling Road
jr nz, .goFaster
- ld a, [hJoyHeld]
+ ldh a, [hJoyHeld]
and D_UP | D_LEFT | D_RIGHT
ret nz
.goFaster
@@ -381,7 +381,7 @@ CheckWarpsNoCollisionLoop::
push bc
ld hl, wd736
set 2, [hl] ; standing on warp flag
- callba IsPlayerStandingOnDoorTileOrWarpTile
+ farcall IsPlayerStandingOnDoorTileOrWarpTile
pop bc
pop hl
jr c, WarpFound1 ; jump if standing on door or warp
@@ -400,7 +400,7 @@ CheckWarpsNoCollisionLoop::
call Joypad
pop bc
pop de
- ld a, [hJoyHeld]
+ ldh a, [hJoyHeld]
and D_DOWN | D_UP | D_LEFT | D_RIGHT
jr z, CheckWarpsNoCollisionRetry2 ; if directional buttons aren't being pressed, do not pass through the warp
jr WarpFound1
@@ -435,7 +435,7 @@ CheckWarpsCollision::
ld a, [hli]
ld [wDestinationWarpID], a
ld a, [hl]
- ld [hWarpDestinationMap], a
+ ldh [hWarpDestinationMap], a
jr WarpFound2
.retry1
inc hl
@@ -450,7 +450,7 @@ WarpFound1::
ld a, [hli]
ld [wDestinationWarpID], a
ld a, [hli]
- ld [hWarpDestinationMap], a
+ ldh [hWarpDestinationMap], a
WarpFound2::
ld a, [wNumberOfWarps]
@@ -465,7 +465,7 @@ WarpFound2::
ld [wLastMap], a
ld a, [wCurMapWidth]
ld [wUnusedD366], a ; not read
- ld a, [hWarpDestinationMap]
+ ldh a, [hWarpDestinationMap]
ld [wCurMap], a
cp ROCK_TUNNEL_1F
jr nz, .notRockTunnel
@@ -473,19 +473,19 @@ WarpFound2::
ld [wMapPalOffset], a
call GBFadeOutToBlack
.notRockTunnel
- callab SetPikachuSpawnOutside
+ callfar SetPikachuSpawnOutside
call PlayMapChangeSound
jr .done
; for maps that can have the 0xFF destination map, which means to return to the outside map
; not all these maps are necessarily indoors, though
.indoorMaps
- ld a, [hWarpDestinationMap] ; destination map
- cp $ff
+ ldh a, [hWarpDestinationMap] ; destination map
+ cp LAST_MAP
jr z, .goBackOutside
; if not going back to the previous map
ld [wCurMap], a
- callba IsPlayerStandingOnWarpPadOrHole
+ farcall IsPlayerStandingOnWarpPadOrHole
ld a, [wStandingOnWarpPadOrHole]
dec a ; is the player on a warp pad?
jr nz, .notWarpPad
@@ -500,11 +500,11 @@ WarpFound2::
ld hl, wd736
res 0, [hl]
res 1, [hl]
- callab SetPikachuSpawnWarpPad
+ callfar SetPikachuSpawnWarpPad
jr .done
.goBackOutside
- callab SetPikachuSpawnBackOutside
+ callfar SetPikachuSpawnBackOutside
ld a, [wLastMap]
ld [wCurMap], a
call PlayMapChangeSound
@@ -654,7 +654,7 @@ CheckMapConnections::
ld b, SET_PAL_OVERWORLD
call RunPaletteCommand
; Since the sprite set shouldn't change, this will just update VRAM slots at
-; $C2XE without loading any tile patterns.
+; x#SPRITESTATEDATA2_IMAGEBASEOFFSET without loading any tile patterns.
call InitMapSprites
call LoadTileBlockMap
jp OverworldLoopLessDelay
@@ -669,7 +669,7 @@ PlayMapChangeSound::
jr z, .didNotGoThroughDoor
cp CEMETERY
jr z, .didNotGoThroughDoor
- aCoord 8, 8 ; upper left tile of the 4x4 square the player's sprite is standing on
+ lda_coord 8, 8 ; upper left tile of the 4x4 square the player's sprite is standing on
cp $0b ; door tile in tileset 0
jr nz, .didNotGoThroughDoor
ld a, SFX_GO_INSIDE
@@ -728,7 +728,7 @@ ExtraWarpCheck::
jp Bankswitch
MapEntryAfterBattle::
- callba IsPlayerStandingOnWarp ; for enabling warp testing after collisions
+ farcall IsPlayerStandingOnWarp ; for enabling warp testing after collisions
ld a, [wMapPalOffset]
and a
jp z, GBFadeInFromWhite
@@ -744,7 +744,7 @@ HandleBlackOut::
ld hl, wd72e
res 5, [hl]
switchbank SpecialWarpIn ; also Bank(SpecialEnterMap)
- callab ResetStatusAndHalveMoneyOnBlackout
+ callfar ResetStatusAndHalveMoneyOnBlackout
call SpecialWarpIn
call PlayDefaultMusicFadeOutCurrent
jp SpecialEnterMap
@@ -774,7 +774,7 @@ HandleFlyWarpOrDungeonWarp::
jp SpecialEnterMap
LeaveMapAnim::
- jpba _LeaveMapAnim
+ farjp _LeaveMapAnim
Func_07c4::
ld a, [wWalkBikeSurfState]
@@ -799,7 +799,7 @@ LoadPlayerSpriteGraphics::
dec a
jr z, .ridingBike
- ld a, [hTilesetType]
+ ldh a, [hTilesetType]
and a
jr nz, .determineGraphics
jr .startWalking
@@ -853,7 +853,7 @@ IsBikeRidingAllowed::
scf
ret
-INCLUDE "data/bike_riding_tilesets.asm"
+INCLUDE "data/tilesets/bike_riding_tilesets.asm"
; load the tile pattern data of the current tileset into VRAM
LoadTilesetTilePatternData::
@@ -878,9 +878,9 @@ LoadTileBlockMap::
; a 3-byte border at the edges of the map is kept so that there is space for map connections
ld hl, wOverworldMap
ld a, [wCurMapWidth]
- ld [hMapWidth], a
+ ldh [hMapWidth], a
add MAP_BORDER * 2 ; east and west
- ld [hMapStride], a ; map width + border
+ ldh [hMapStride], a ; map width + border
ld b, 0
ld c, a
; make space for north border (next 3 lines)
@@ -897,7 +897,7 @@ LoadTileBlockMap::
ld b, a
.rowLoop ; copy one row each iteration
push hl
- ld a, [hMapWidth] ; map width (without border)
+ ldh a, [hMapWidth] ; map width (without border)
ld c, a
.rowInnerLoop
ld a, [de]
@@ -907,7 +907,7 @@ LoadTileBlockMap::
jr nz, .rowInnerLoop
; add the map width plus the border to the base address of the current row to get the next row's address
pop hl
- ld a, [hMapStride] ; map width + border
+ ldh a, [hMapStride] ; map width + border
add l
ld l, a
jr nc, .noCarry
@@ -929,9 +929,9 @@ LoadTileBlockMap::
ld a, [wNorthConnectionStripDest + 1]
ld d, a
ld a, [wNorthConnectionStripWidth]
- ld [hNorthSouthConnectionStripWidth], a
+ ldh [hNorthSouthConnectionStripWidth], a
ld a, [wNorthConnectedMapWidth]
- ld [hNorthSouthConnectedMapWidth], a
+ ldh [hNorthSouthConnectedMapWidth], a
call LoadNorthSouthConnectionsTileMap
.southConnection
ld a, [wMapConn2Ptr]
@@ -947,9 +947,9 @@ LoadTileBlockMap::
ld a, [wSouthConnectionStripDest + 1]
ld d, a
ld a, [wSouthConnectionStripWidth]
- ld [hNorthSouthConnectionStripWidth], a
+ ldh [hNorthSouthConnectionStripWidth], a
ld a, [wSouthConnectedMapWidth]
- ld [hNorthSouthConnectedMapWidth], a
+ ldh [hNorthSouthConnectedMapWidth], a
call LoadNorthSouthConnectionsTileMap
.westConnection
ld a, [wMapConn3Ptr]
@@ -967,7 +967,7 @@ LoadTileBlockMap::
ld a, [wWestConnectionStripHeight]
ld b, a
ld a, [wWestConnectedMapWidth]
- ld [hEastWestConnectedMapWidth], a
+ ldh [hEastWestConnectedMapWidth], a
call LoadEastWestConnectionsTileMap
.eastConnection
ld a, [wMapConn4Ptr]
@@ -985,7 +985,7 @@ LoadTileBlockMap::
ld a, [wEastConnectionStripHeight]
ld b, a
ld a, [wEastConnectedMapWidth]
- ld [hEastWestConnectedMapWidth], a
+ ldh [hEastWestConnectedMapWidth], a
call LoadEastWestConnectionsTileMap
.done
ret
@@ -995,7 +995,7 @@ LoadNorthSouthConnectionsTileMap::
.loop
push de
push hl
- ld a, [hNorthSouthConnectionStripWidth]
+ ldh a, [hNorthSouthConnectionStripWidth]
ld b, a
.innerLoop
ld a, [hli]
@@ -1005,7 +1005,7 @@ LoadNorthSouthConnectionsTileMap::
jr nz, .innerLoop
pop hl
pop de
- ld a, [hNorthSouthConnectedMapWidth]
+ ldh a, [hNorthSouthConnectedMapWidth]
add l
ld l, a
jr nc, .noCarry1
@@ -1034,7 +1034,7 @@ LoadEastWestConnectionsTileMap::
jr nz, .innerLoop
pop de
pop hl
- ld a, [hEastWestConnectedMapWidth]
+ ldh a, [hEastWestConnectedMapWidth]
add l
ld l, a
jr nc, .noCarry1
@@ -1055,7 +1055,7 @@ LoadEastWestConnectionsTileMap::
; if so, carry is set. otherwise, carry is cleared
IsSpriteOrSignInFrontOfPlayer::
xor a
- ld [hSpriteIndexOrTextID], a
+ ldh [hSpriteIndexOrTextID], a
ld a, [wNumSigns]
and a
jr z, .extendRangeOverCounter
@@ -1081,7 +1081,7 @@ IsSpriteInFrontOfPlayer::
ld d, $10 ; talking range in pixels (normal range)
IsSpriteInFrontOfPlayer2::
lb bc, $3c, $40 ; Y and X position of player sprite
- ld a, [wSpritePlayerStateData1FacingDirection] ; direction the player is facing
+ ld a, [wSpritePlayerStateData1FacingDirection]
.checkIfPlayerFacingUp
cp SPRITE_FACING_UP
jr nz, .checkIfPlayerFacingDown
@@ -1120,7 +1120,7 @@ IsSpriteInFrontOfPlayer2::
ld a, PLAYER_DIR_LEFT
.doneCheckingDirection
ld [wPlayerDirection], a
- ld hl, wSpriteStateData1 + $10
+ ld hl, wSprite01StateData1
; yellow does not have the "if sprites are existant" check
ld e, $01
ld d, $f
@@ -1157,11 +1157,11 @@ IsSpriteInFrontOfPlayer2::
ld a, l
and $f0
inc a
- ld l, a ; hl = $c1x1
+ ld l, a ; hl = x#SPRITESTATEDATA1_MOVEMENTSTATUS
set 7, [hl] ; set flag to make the sprite face the player
ld a, e
- ld [hSpriteIndexOrTextID], a
- ld a, [hSpriteIndexOrTextID] ; possible useless read because a already has the value of the read address
+ ldh [hSpriteIndexOrTextID], a
+ ldh a, [hSpriteIndexOrTextID] ; possible useless read because a already has the value of the read address
cp $f
jr nz, .dontwritetowd436
ld a, $FF
@@ -1197,7 +1197,7 @@ SignLoop::
dec c
add hl, bc
ld a, [hl]
- ld [hSpriteIndexOrTextID], a ; store sign text ID
+ ldh [hSpriteIndexOrTextID], a ; store sign text ID
pop bc
pop hl
scf
@@ -1221,16 +1221,16 @@ CollisionCheckOnLand::
jr nz, .noCollision ; no collisions when the player's movements are being controlled by the game
ld a, [wPlayerDirection] ; the direction that the player is trying to go in
ld d, a
- ld a, [wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
+ ld a, [wSpritePlayerStateData1CollisionData]
and d ; check if a sprite is in the direction the player is trying to go
nop ; ??? why is this in the code
jr nz, .collision
xor a
- ld [hSpriteIndexOrTextID], a
+ ldh [hSpriteIndexOrTextID], a
call IsSpriteInFrontOfPlayer ; check for sprite collisions again? when does the above check fail to detect a sprite collision?
jr nc, .asm_0a5c
res 7, [hl]
- ld a, [hSpriteIndexOrTextID]
+ ldh a, [hSpriteIndexOrTextID]
and a ; was there a sprite collision?
jr z, .asm_0a5c
; if no sprite collision
@@ -1238,7 +1238,7 @@ CollisionCheckOnLand::
jr nz, .collision
call CheckPikachuFollowingPlayer
jr nz, .collision
- ld a, [hJoyHeld]
+ ldh a, [hJoyHeld]
and $2
jr nz, .asm_0a5c
ld hl, wd435
@@ -1284,7 +1284,7 @@ CheckForJumpingAndTilePairCollisions::
predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player
push de
push bc
- callba HandleLedges ; check if the player is trying to jump a ledge
+ farcall HandleLedges ; check if the player is trying to jump a ledge
pop bc
pop de
pop hl
@@ -1295,7 +1295,7 @@ CheckForJumpingAndTilePairCollisions::
; if not jumping
CheckForTilePairCollisions2::
- aCoord 8, 9 ; tile the player is on
+ lda_coord 8, 9 ; tile the player is on
ld [wTilePlayerStandingOn], a
CheckForTilePairCollisions::
@@ -1343,34 +1343,11 @@ CheckForTilePairCollisions::
and a
ret
-; FORMAT: tileset number, tile 1, tile 2
-; terminated by 0xFF
-; these entries indicate that the player may not cross between tile 1 and tile 2
-; it's mainly used to simulate differences in elevation
-
-TilePairCollisionsLand::
- db CAVERN, $20, $05
- db CAVERN, $41, $05
- db FOREST, $30, $2E
- db CAVERN, $2A, $05
- db CAVERN, $05, $21
- db FOREST, $52, $2E
- db FOREST, $55, $2E
- db FOREST, $56, $2E
- db FOREST, $20, $2E
- db FOREST, $5E, $2E
- db FOREST, $5F, $2E
- db $FF
-
-TilePairCollisionsWater::
- db FOREST, $14, $2E
- db FOREST, $48, $2E
- db CAVERN, $14, $05
- db $FF
+INCLUDE "data/tilesets/pair_collision_tile_ids.asm"
; this builds a tile map from the tile block map based on the current X/Y coordinates of the player's character
LoadCurrentMapView::
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, [wTilesetBank] ; tile data ROM bank
call BankswitchCommon ; switch to ROM bank that contains tile data
@@ -1421,21 +1398,21 @@ LoadCurrentMapView::
dec b
jr nz, .rowLoop
ld hl, wTileMapBackup
- ld bc, $0000
+ ld bc, $0
.adjustForYCoordWithinTileBlock
ld a, [wYBlockCoord]
and a
jr z, .adjustForXCoordWithinTileBlock
- ld bc, $0030
+ ld bc, $30
add hl, bc
.adjustForXCoordWithinTileBlock
ld a, [wXBlockCoord]
and a
jr z, .copyToVisibleAreaBuffer
- ld bc, $0002
+ ld bc, $2
add hl, bc
.copyToVisibleAreaBuffer
- coord de, 0, 0 ; base address for the tiles that are directly transferred to VRAM during V-blank
+ decoord 0, 0 ; base address for the tiles that are directly transferred to VRAM during V-blank
ld b, SCREEN_HEIGHT
.rowLoop2
ld c, SCREEN_WIDTH
@@ -1473,14 +1450,14 @@ AdvancePlayerSprite::
; the portion of the map that was newly exposed due to the player's movement
ScheduleNorthRowRedraw::
- coord hl, 0, 0
+ hlcoord 0, 0
call CopyToRedrawRowOrColumnSrcTiles
ld a, [wMapViewVRAMPointer]
- ld [hRedrawRowOrColumnDest], a
+ ldh [hRedrawRowOrColumnDest], a
ld a, [wMapViewVRAMPointer + 1]
- ld [hRedrawRowOrColumnDest + 1], a
+ ldh [hRedrawRowOrColumnDest + 1], a
ld a, REDRAW_ROW
- ld [hRedrawRowOrColumnMode], a
+ ldh [hRedrawRowOrColumnMode], a
ret
CopyToRedrawRowOrColumnSrcTiles::
@@ -1495,26 +1472,26 @@ CopyToRedrawRowOrColumnSrcTiles::
ret
ScheduleSouthRowRedraw::
- coord hl, 0, 16
+ hlcoord 0, 16
call CopyToRedrawRowOrColumnSrcTiles
ld a, [wMapViewVRAMPointer]
ld l, a
ld a, [wMapViewVRAMPointer + 1]
ld h, a
- ld bc, $0200
+ ld bc, $200
add hl, bc
ld a, h
and $03
or $98
- ld [hRedrawRowOrColumnDest + 1], a
+ ldh [hRedrawRowOrColumnDest + 1], a
ld a, l
- ld [hRedrawRowOrColumnDest], a
+ ldh [hRedrawRowOrColumnDest], a
ld a, REDRAW_ROW
- ld [hRedrawRowOrColumnMode], a
+ ldh [hRedrawRowOrColumnMode], a
ret
ScheduleEastColumnRedraw::
- coord hl, 18, 0
+ hlcoord 18, 0
call ScheduleColumnRedrawHelper
ld a, [wMapViewVRAMPointer]
ld c, a
@@ -1524,11 +1501,11 @@ ScheduleEastColumnRedraw::
add 18
and $1f
or b
- ld [hRedrawRowOrColumnDest], a
+ ldh [hRedrawRowOrColumnDest], a
ld a, [wMapViewVRAMPointer + 1]
- ld [hRedrawRowOrColumnDest + 1], a
+ ldh [hRedrawRowOrColumnDest + 1], a
ld a, REDRAW_COL
- ld [hRedrawRowOrColumnMode], a
+ ldh [hRedrawRowOrColumnMode], a
ret
ScheduleColumnRedrawHelper::
@@ -1552,14 +1529,14 @@ ScheduleColumnRedrawHelper::
ret
ScheduleWestColumnRedraw::
- coord hl, 0, 0
+ hlcoord 0, 0
call ScheduleColumnRedrawHelper
ld a, [wMapViewVRAMPointer]
- ld [hRedrawRowOrColumnDest], a
+ ldh [hRedrawRowOrColumnDest], a
ld a, [wMapViewVRAMPointer + 1]
- ld [hRedrawRowOrColumnDest + 1], a
+ ldh [hRedrawRowOrColumnDest + 1], a
ld a, REDRAW_COL
- ld [hRedrawRowOrColumnMode], a
+ ldh [hRedrawRowOrColumnMode], a
ret
; function to write the tiles that make up a tile block to memory
@@ -1597,7 +1574,7 @@ DrawTileBlock::
ld a, [de]
ld [hl], a
inc de
- ld bc, $0015
+ ld bc, $15
add hl, bc
pop bc
dec c
@@ -1607,8 +1584,8 @@ DrawTileBlock::
; function to update joypad state and simulate button presses
JoypadOverworld::
xor a
- ld [wSpriteStateData1 + 3], a
- ld [wSpriteStateData1 + 5], a
+ ld [wSpritePlayerStateData1YStepVector], a
+ ld [wSpritePlayerStateData1XStepVector], a
call RunMapScript
call Joypad
call ForceBikeDown
@@ -1622,11 +1599,11 @@ ForceBikeDown::
ld a, [wCurMap]
cp ROUTE_17 ; Cycling Road
ret nz
- ld a, [hJoyHeld]
+ ldh a, [hJoyHeld]
and D_DOWN | D_UP | D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON
ret nz
ld a, D_DOWN
- ld [hJoyHeld], a ; on the cycling road, if there isn't a trainer and the player isn't pressing buttons, simulate a down press
+ ldh [hJoyHeld], a ; on the cycling road, if there isn't a trainer and the player isn't pressing buttons, simulate a down press
ret
AreInputsSimulated::
@@ -1634,18 +1611,18 @@ AreInputsSimulated::
bit 7, a
ret z
; if simulating button presses
- ld a, [hJoyHeld]
+ ldh a, [hJoyHeld]
ld b, a
ld a, [wOverrideSimulatedJoypadStatesMask] ; bit mask for button presses that override simulated ones
and b
ret nz ; return if the simulated button presses are overridden
call GetSimulatedInput
jr nc, .doneSimulating
- ld [hJoyHeld], a ; store simulated button press in joypad state
+ ldh [hJoyHeld], a ; store simulated button press in joypad state
and a
ret nz
- ld [hJoyPressed], a
- ld [hJoyReleased], a
+ ldh [hJoyPressed], a
+ ldh [hJoyReleased], a
ret
; if done simulating button presses
@@ -1655,7 +1632,7 @@ AreInputsSimulated::
ld [wSimulatedJoypadStatesIndex], a
ld [wSimulatedJoypadStatesEnd], a
ld [wJoyIgnore], a
- ld [hJoyHeld], a
+ ldh [hJoyHeld], a
ld hl, wd736
ld a, [hl]
and $f8
@@ -1694,14 +1671,14 @@ CollisionCheckOnWater::
jp nz, .noCollision ; return and clear carry if button presses are being simulated
ld a, [wPlayerDirection] ; the direction that the player is trying to go in
ld d, a
- ld a, [wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
+ ld a, [wSpritePlayerStateData1CollisionData]
and d ; check if a sprite is in the direction the player is trying to go
jr nz, .collision
ld hl, TilePairCollisionsWater
call CheckForJumpingAndTilePairCollisions
jr c, .collision
predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player (puts it in c and [wTileInFrontOfPlayer])
- callab IsNextTileShoreOrWater
+ callfar IsNextTileShoreOrWater
jr c, .noCollision
ld a, [wTileInFrontOfPlayer] ; tile in front of player
ld c, a
@@ -1742,11 +1719,11 @@ RunMapScript::
push hl
push de
push bc
- callba TryPushingBoulder
+ farcall TryPushingBoulder
ld a, [wFlags_0xcd60]
bit 1, a ; play boulder dust animation
jr z, .afterBoulderEffect
- callba DoBoulderDustAnimation
+ farcall DoBoulderDustAnimation
.afterBoulderEffect
pop bc
pop de
@@ -1795,8 +1772,9 @@ LoadSurfingPlayerSpriteGraphics::
jr LoadPlayerSpriteGraphicsCommon
LoadBikePlayerSpriteGraphics::
- ld b, BANK(RedCyclingSprite)
- ld de, RedCyclingSprite
+ ld b, BANK(RedBikeSprite)
+ ld de, RedBikeSprite
+
LoadPlayerSpriteGraphicsCommon::
ld hl, vNPCSprites
push de
@@ -1819,12 +1797,12 @@ LoadPlayerSpriteGraphicsCommon::
; function to load data from the map header
LoadMapHeader::
- callba MarkTownVisitedAndLoadMissableObjects
+ farcall MarkTownVisitedAndLoadMissableObjects
jr asm_0dbd
Func_0db5:: ; XXX
- callba LoadUnusedBluesHouseMissableObjectData
-asm_0dbd
+ farcall LoadUnusedBluesHouseMissableObjectData
+asm_0dbd:
ld a, [wCurMapTileset]
ld [wUnusedD119], a
ld a, [wCurMap]
@@ -1833,7 +1811,7 @@ asm_0dbd
ld b, a
res 7, a
ld [wCurMapTileset], a
- ld [hPreviousTileset], a
+ ldh [hPreviousTileset], a
bit 7, b
ret nz
call GetMapHeaderPointer
@@ -1921,9 +1899,9 @@ asm_0dbd
ld a, [wd72e]
bit 5, a ; did a battle happen immediately before this?
jr nz, .skip_pika_spawn
- callab SchedulePikachuSpawnForAfterText
+ callfar SchedulePikachuSpawnForAfterText
.skip_pika_spawn
- callab LoadWildData
+ callfar LoadWildData
pop hl ; restore hl from before going to the warp/sign/sprite data (this value was saved for seemingly no purpose)
ld a, [wCurMapHeight] ; map height in 4x4 tile blocks
add a ; double it
@@ -1934,7 +1912,7 @@ asm_0dbd
ld a, [wCurMap]
ld c, a
ld b, $00
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
switchbank MapSongBanks
ld hl, MapSongBanks
@@ -1982,7 +1960,7 @@ CopySignData::
; function to load map data
LoadMapData::
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
call DisableLCD
call ResetMapVariables
@@ -2017,7 +1995,7 @@ LoadScreenRelatedData::
ret
ReloadMapAfterSurfingMinigame::
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
call DisableLCD
call ResetMapVariables
@@ -2034,7 +2012,7 @@ ReloadMapAfterSurfingMinigame::
jr asm_0f4d
ReloadMapAfterPrinter::
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, [wCurMap]
call SwitchToMapRomBank
@@ -2042,7 +2020,7 @@ ReloadMapAfterPrinter::
pop af
call BankswitchCommon
asm_0f4d:
- jpab SetMapSpecificScriptFlagsOnMapReload
+ jpfar SetMapSpecificScriptFlagsOnMapReload
ret ; useless?
ResetMapVariables::
@@ -2050,8 +2028,8 @@ ResetMapVariables::
ld [wMapViewVRAMPointer + 1], a
xor a
ld [wMapViewVRAMPointer], a
- ld [hSCY], a
- ld [hSCX], a
+ ldh [hSCY], a
+ ldh [hSCX], a
ld [wWalkCounter], a
ld [wUnusedD119], a
ld [wSpriteSetID], a
@@ -2094,16 +2072,16 @@ SwitchToMapRomBank::
ld hl, MapHeaderBanks
add hl, bc
ld a, [hl]
- ld [$ffe8], a ; save map ROM bank
+ ldh [hMapROMBank], a ; save map ROM bank
call BankswitchBack
- ld a, [$ffe8]
+ ldh a, [hMapROMBank]
call BankswitchCommon
pop bc
pop hl
ret
GetMapHeaderPointer::
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
switchbank MapHeaderPointers
push de
@@ -2146,17 +2124,17 @@ HandleMidJump::
ld a, [wd736]
bit 6, a ; jumping down a ledge?
ret z
- callba _HandleMidJump
+ farcall _HandleMidJump
ret
IsSpinning::
ld a, [wd736]
bit 7, a
ret z ; no spinning
- jpba LoadSpinnerArrowTiles ; spin while moving
+ farjp LoadSpinnerArrowTiles ; spin while moving
Func_0ffe::
- jpab IsPlayerTalkingToPikachu
+ jpfar IsPlayerTalkingToPikachu
InitSprites::
ld a, [hli]
@@ -2178,27 +2156,27 @@ InitSprites::
ret z ; don't copy sprite data if not
ld b, a
ld c, $0
- ld de, wSpriteStateData1 + $10
+ ld de, wSprite01StateData1
; copy sprite stuff?
.loadSpriteLoop
ld a, [hli]
- ld [de], a ; store picture ID at C1X0
+ ld [de], a ; x#SPRITESTATEDATA1_PICTUREID
inc d
ld a, e
add $4
ld e, a
ld a, [hli]
- ld [de], a ; store Y position at C2X4
+ ld [de], a ; x#SPRITESTATEDATA2_MAPY
inc e
ld a, [hli]
- ld [de], a ; store X position at C2X5
+ ld [de], a ; x#SPRITESTATEDATA2_MAPX
inc e
ld a, [hli]
- ld [de], a ; store movement byte 1 at C2X6
+ ld [de], a ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
ld a, [hli]
- ld [$ff8d], a ; save movement byte 2
+ ldh [hLoadSpriteTemp1], a ; save movement byte 2
ld a, [hli]
- ld [$ff8e], a ; save text ID and flags byte
+ ldh [hLoadSpriteTemp2], a ; save text ID and flags byte
push bc
call LoadSprite
pop bc
@@ -2213,10 +2191,10 @@ InitSprites::
ret
ZeroSpriteStateData::
-; zero C110-C1EF and C210-C2EF
-; C1F0-C1FF and C2F0-C2FF is used for Pikachu
- ld hl, wSpriteStateData1 + $10
- ld de, wSpriteStateData2 + $10
+; zero out sprite state data for sprites 01-14
+; sprite 15 is used for Pikachu
+ ld hl, wSprite01StateData1
+ ld de, wSprite01StateData2
xor a
ld b, 14 * $10
.loop
@@ -2228,8 +2206,8 @@ ZeroSpriteStateData::
ret
DisableRegularSprites::
-; initialize all C100-C1FF sprite entries to disabled (other than player's and pikachu)
- ld hl, wSpriteStateData1 + 1 * $10 + 2
+; disable SPRITESTATEDATA1_IMAGEINDEX (set to $ff) for sprites 01-14
+ ld hl, wSprite01StateData1ImageIndex
ld de, $10
ld c, $e
.loop
@@ -2244,16 +2222,16 @@ LoadSprite::
ld b, $0
ld hl, wMapSpriteData
add hl, bc
- ld a, [$ff8d]
+ ldh a, [hLoadSpriteTemp1]
ld [hli], a ; store movement byte 2 in byte 0 of sprite entry
- ld a, [$ff8e]
+ ldh a, [hLoadSpriteTemp2]
ld [hl], a ; this appears pointless, since the value is overwritten immediately after
- ld a, [$ff8e]
- ld [$ff8d], a
+ ldh a, [hLoadSpriteTemp2]
+ ldh [hLoadSpriteTemp1], a
and $3f
ld [hl], a ; store text ID in byte 1 of sprite entry
pop hl
- ld a, [$ff8d]
+ ldh a, [hLoadSpriteTemp1]
bit 6, a
jr nz, .trainerSprite
bit 7, a
@@ -2271,28 +2249,79 @@ LoadSprite::
.trainerSprite
ld a, [hli]
- ld [$ff8d], a ; save trainer class
+ ldh [hLoadSpriteTemp1], a ; save trainer class
ld a, [hli]
- ld [$ff8e], a ; save trainer number (within class)
+ ldh [hLoadSpriteTemp2], a ; save trainer number (within class)
push hl
ld hl, wMapSpriteExtraData
add hl, bc
- ld a, [$ff8d]
+ ldh a, [hLoadSpriteTemp1]
ld [hli], a ; store trainer class in byte 0 of the entry
- ld a, [$ff8e]
+ ldh a, [hLoadSpriteTemp2]
ld [hl], a ; store trainer number in byte 1 of the entry
pop hl
ret
.itemBallSprite
ld a, [hli]
- ld [$ff8d], a ; save item number
+ ldh [hLoadSpriteTemp1], a ; save item number
push hl
ld hl, wMapSpriteExtraData
add hl, bc
- ld a, [$ff8d]
+ ldh a, [hLoadSpriteTemp1]
ld [hli], a ; store item number in byte 0 of the entry
xor a
ld [hl], a ; zero byte 1, since it is not used
pop hl
ret
+
+CheckForUserInterruption::
+; Return carry if Up+Select+B, Start or A are pressed in c frames.
+; Used only in the intro and title screen.
+ call DelayFrame
+
+ push bc
+ call JoypadLowSensitivity
+ pop bc
+
+ ldh a, [hJoyHeld]
+ cp D_UP + SELECT + B_BUTTON
+ jr z, .input
+
+ ldh a, [hJoy5]
+ and START | A_BUTTON
+ jr nz, .input
+
+ dec c
+ jr nz, CheckForUserInterruption
+
+ and a
+ ret
+
+.input
+ scf
+ ret
+
+; function to load position data for destination warp when switching maps
+; INPUT:
+; a = ID of destination warp within destination map
+LoadDestinationWarpPosition::
+ ld b, a
+ ldh a, [hLoadedROMBank]
+ push af
+ ld a, [wPredefParentBank]
+ ldh [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ld a, b
+ add a
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld bc, 4
+ ld de, wCurrentTileBlockMapViewPointer
+ call CopyData
+ pop af
+ ldh [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
diff --git a/home/overworld_text.asm b/home/overworld_text.asm
new file mode 100644
index 00000000..7ea23fe4
--- /dev/null
+++ b/home/overworld_text.asm
@@ -0,0 +1,31 @@
+TextScriptEndingText::
+ text_end
+
+TextScriptEnd::
+ ld hl, TextScriptEndingText
+ ret
+
+ExclamationText::
+ text_far _ExclamationText
+ text_end
+
+GroundRoseText::
+ text_far _GroundRoseText
+ text_end
+
+BoulderText::
+ text_far _BoulderText
+ text_end
+
+MartSignText::
+ text_far _MartSignText
+ text_end
+
+PokeCenterSignText::
+ text_far _PokeCenterSignText
+ text_end
+
+PickUpItemText::
+ text_asm
+ predef PickUpItem
+ jp TextScriptEnd
diff --git a/home/palettes.asm b/home/palettes.asm
new file mode 100644
index 00000000..3b944a03
--- /dev/null
+++ b/home/palettes.asm
@@ -0,0 +1,63 @@
+RestoreScreenTilesAndReloadTilePatterns::
+ call ClearSprites
+ ld a, $1
+ ld [wUpdateSpritesEnabled], a
+ call ReloadMapSpriteTilePatterns
+ call LoadScreenTilesFromBuffer2
+ call LoadTextBoxTilePatterns
+ call RunDefaultPaletteCommand
+ jr Delay3
+
+GBPalWhiteOutWithDelay3::
+ call GBPalWhiteOut
+
+Delay3::
+; The bg map is updated each frame in thirds.
+; Wait three frames to let the bg map fully update.
+ ld c, 3
+ jp DelayFrames
+
+GBPalNormal::
+; Reset BGP and OBP0.
+ ld a, %11100100 ; 3210
+ ldh [rBGP], a
+ ld a, %11010000 ; 3100
+ ldh [rOBP0], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+GBPalWhiteOut::
+; White out all palettes.
+ xor a
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+RunDefaultPaletteCommand::
+ ld b, SET_PAL_DEFAULT
+RunPaletteCommand::
+ ld a, [wOnSGB]
+ and a
+ ret z
+ predef_jump _RunPaletteCommand
+
+GetHealthBarColor::
+; Return at hl the palette of
+; an HP bar e pixels long.
+ ld a, e
+ cp 27
+ ld d, 0 ; green
+ jr nc, .gotColor
+ cp 10
+ inc d ; yellow
+ jr nc, .gotColor
+ inc d ; red
+.gotColor
+ ld [hl], d
+ ret
diff --git a/home/pathfinding.asm b/home/pathfinding.asm
new file mode 100644
index 00000000..53f98847
--- /dev/null
+++ b/home/pathfinding.asm
@@ -0,0 +1,65 @@
+; calculates the difference |a-b|, setting carry flag if a<b
+CalcDifference::
+ sub b
+ ret nc
+ cpl
+ add $1
+ scf
+ ret
+
+MoveSprite::
+; move the sprite [hSpriteIndex] with the movement pointed to by de
+; actually only copies the movement data to wNPCMovementDirections for later
+ call SetSpriteMovementBytesToFF
+MoveSprite_::
+ push hl
+ push bc
+ call GetSpriteMovementByte1Pointer
+ xor a
+ ld [hl], a
+ ld hl, wNPCMovementDirections
+ ld c, 0
+
+.loop
+ ld a, [de]
+ ld [hli], a
+ inc de
+ inc c
+ cp -1 ; have we reached the end of the movement data?
+ jr nz, .loop
+
+ ld a, c
+ ld [wNPCNumScriptedSteps], a ; number of steps taken
+
+ pop bc
+ ld hl, wd730
+ set 0, [hl]
+ pop hl
+ xor a
+ ld [wOverrideSimulatedJoypadStatesMask], a
+ ld [wSimulatedJoypadStatesEnd], a
+ dec a
+ ld [wJoyIgnore], a
+ ld [wWastedByteCD3A], a
+ ret
+
+; divides [hDividend2] by [hDivisor2] and stores the quotient in [hQuotient2]
+DivideBytes::
+ push hl
+ ld hl, hQuotient2
+ xor a
+ ld [hld], a
+ ld a, [hld]
+ and a
+ jr z, .done
+ ld a, [hli]
+.loop
+ sub [hl]
+ jr c, .done
+ inc hl
+ inc [hl]
+ dec hl
+ jr .loop
+.done
+ pop hl
+ ret
diff --git a/home/pics.asm b/home/pics.asm
new file mode 100644
index 00000000..f3b3f1b5
--- /dev/null
+++ b/home/pics.asm
@@ -0,0 +1,198 @@
+; 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::
+ ld bc, wMonHeader
+ add hl, bc
+ ld a, [hli]
+ ld [wSpriteInputPtr], a ; fetch sprite input pointer
+ ld a, [hl]
+ ld [wSpriteInputPtr+1], a
+; define (by index number) the bank that a pokemon's image is in
+; index = Mew, bank 1
+; index = Kabutops fossil, bank $B
+; index < $1F, bank 9
+; $1F ≤ index < $4A, bank $A
+; $4A ≤ index < $74, bank $B
+; $74 ≤ index < $99, bank $C
+; $99 ≤ index, bank $D
+ ld a, [wcf91] ; XXX name for this ram location
+ ld b, a
+ ;cp MEW
+ ;ld a, BANK(MewPicFront)
+ ;jr z, .GotBank
+ ;ld a, b
+ cp FOSSIL_KABUTOPS
+ ld a, BANK(FossilKabutopsPic)
+ jr z, .GotBank
+ ld a, b
+ cp TANGELA + 1
+ ld a, BANK(TangelaPicFront)
+ jr c, .GotBank
+ ld a, b
+ cp MOLTRES + 1
+ ld a, BANK(MoltresPicFront)
+ jr c, .GotBank
+ ld a, b
+ cp BEEDRILL + 2
+ ld a, BANK(BeedrillPicFront)
+ jr c, .GotBank
+ ld a, b
+ cp STARMIE + 1
+ ld a, BANK(StarmiePicFront)
+ jr c, .GotBank
+ ld a, BANK(VictreebelPicFront)
+.GotBank
+ jp UncompressSpriteData
+
+; de: destination location
+LoadMonFrontSprite::
+ push de
+ ld hl, wMonHFrontSprite - wMonHeader
+ call UncompressMonSprite
+ ld hl, wMonHSpriteDim
+ ld a, [hli]
+ ld c, a
+ pop de
+ ; fall through
+
+; 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::
+ push de
+ and $f
+ ldh [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
+ ld b, a
+ ld a, $7
+ sub b ; 7-w
+ inc a ; 8-w
+ srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up)
+ ld b, a
+ add a
+ add a
+ add a
+ sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles)
+ ldh [hSpriteOffset], a
+ ld a, c
+ swap a
+ and $f
+ ld b, a
+ add a
+ add a
+ add a ; 8*tiles is height in bytes
+ ldh [hSpriteHeight], a
+ ld a, $7
+ sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
+ ld b, a
+ ldh a, [hSpriteOffset]
+ add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles)
+ add a
+ add a
+ add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes)
+ ldh [hSpriteOffset], a
+ ld a, $0
+ call SwitchSRAMBankAndLatchClockData
+ ld hl, sSpriteBuffer0
+ call ZeroSpriteBuffer ; zero buffer 0
+ ld de, sSpriteBuffer1
+ ld hl, sSpriteBuffer0
+ call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
+ ld hl, sSpriteBuffer1
+ call ZeroSpriteBuffer ; zero buffer 1
+ ld de, sSpriteBuffer2
+ ld hl, sSpriteBuffer1
+ call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
+ call PrepareRTCDataAndDisableSRAM
+ pop de
+ jp InterlaceMergeSpriteBuffers
+
+; 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::
+ ldh a, [hSpriteOffset]
+ ld b, $0
+ ld c, a
+ add hl, bc
+ ldh a, [hSpriteWidth]
+.columnLoop
+ push af
+ push hl
+ ldh a, [hSpriteHeight]
+ ld c, a
+.columnInnerLoop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .columnInnerLoop
+ pop hl
+ ld bc, 7*8 ; 7 tiles
+ add hl, bc ; advance one full column
+ pop af
+ dec a
+ jr nz, .columnLoop
+ ret
+
+; fills the sprite buffer (pointed to in hl) with zeros
+ZeroSpriteBuffer::
+ ld bc, SPRITEBUFFERSIZE
+.nextByteLoop
+ xor a
+ ld [hli], a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .nextByteLoop
+ ret
+
+; 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::
+ ld a, $0
+ call SwitchSRAMBankAndLatchClockData
+ push de
+ 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
+ ldh [hSpriteInterlaceCounter], a
+.interlaceLoop
+ ld a, [de]
+ dec de
+ ld [hld], a ; write byte of source 2
+ ld a, [bc]
+ dec bc
+ ld [hld], a ; write byte of source 1
+ ld a, [de]
+ dec de
+ ld [hld], a ; write byte of source 2
+ ld a, [bc]
+ dec bc
+ ld [hld], a ; write byte of source 1
+ ldh a, [hSpriteInterlaceCounter]
+ dec a
+ ldh [hSpriteInterlaceCounter], a
+ jr nz, .interlaceLoop
+ ld a, [wSpriteFlipped]
+ and a
+ jr z, .notFlipped
+ ld bc, 2*SPRITEBUFFERSIZE
+ ld hl, sSpriteBuffer1
+.swapLoop
+ swap [hl] ; if flipped swap nybbles in all bytes
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .swapLoop
+.notFlipped
+ pop hl
+ ld de, sSpriteBuffer1
+ ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
+ ldh a, [hLoadedROMBank]
+ ld b, a
+ call CopyVideoData
+ jp PrepareRTCDataAndDisableSRAM
diff --git a/home/pikachu.asm b/home/pikachu.asm
index 336c80b3..c276b3d4 100755
--- a/home/pikachu.asm
+++ b/home/pikachu.asm
@@ -55,7 +55,7 @@ SpawnPikachu::
ld a, [hl]
dec a
swap a
- ld [hTilePlayerStandingOn], a
+ ldh [hTilePlayerStandingOn], a
homecall SpawnPikachu_ ; 3f:46d5
ret
@@ -83,7 +83,7 @@ Pikachu_IsInArray::
GetPikachuMovementScriptByte::
push hl
push bc
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, [wPikachuMovementScriptBank]
call BankswitchCommon
@@ -105,7 +105,7 @@ GetPikachuMovementScriptByte::
ret
ApplyPikachuMovementData::
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
ld b, a
push af
callbs ApplyPikachuMovementData_
diff --git a/home/play_time.asm b/home/play_time.asm
index 47b2a690..d6c95fbd 100644
--- a/home/play_time.asm
+++ b/home/play_time.asm
@@ -1,10 +1,10 @@
-TrackPlayTime:
+TrackPlayTime::
call CountDownIgnoreInputBitReset
ld hl, wd47a
bit 0, [hl]
jr nz, .maxIGT
- ld a,[wd732]
- bit 0,a
+ ld a, [wd732]
+ bit 0, a
ret z
ld a, [wPlayTimeMaxed]
and a
@@ -66,6 +66,6 @@ CountDownIgnoreInputBitReset:
ld [wd730], a
ret z
xor a
- ld [hJoyPressed], a
- ld [hJoyHeld], a
+ ldh [hJoyPressed], a
+ ldh [hJoyHeld], a
ret
diff --git a/home/pokemon.asm b/home/pokemon.asm
new file mode 100644
index 00000000..3e08906f
--- /dev/null
+++ b/home/pokemon.asm
@@ -0,0 +1,474 @@
+DrawHPBar::
+; Draw an HP bar d tiles long, and fill it to e pixels.
+; If c is nonzero, show at least a sliver regardless.
+; The right end of the bar changes with [wHPBarType].
+
+ push hl
+ push de
+ ;push bc
+
+ ; Left
+ ld a, $71 ; "HP:"
+ ld [hli], a
+ ld a, $62
+ ld [hli], a
+
+ push hl
+
+ ; Middle
+ ld a, $63 ; empty
+.draw
+ ld [hli], a
+ dec d
+ jr nz, .draw
+
+ ; Right
+ ld a, [wHPBarType]
+ dec a
+ ld a, $6d ; status screen and battle
+ jr z, .ok
+ dec a ; pokemon menu
+.ok
+ ld [hl], a
+
+ pop hl
+
+ ld a, e
+ and a
+ jr nz, .fill
+
+ ; If c is nonzero, draw a pixel anyway.
+ ld a, c
+ and a
+ jr z, .done
+ ld e, 1
+
+.fill
+ ld a, e
+ sub 8
+ jr c, .partial
+ ld e, a
+ ld a, $6b ; full
+ ld [hli], a
+ ld a, e
+ and a
+ jr z, .done
+ jr .fill
+
+.partial
+ ; Fill remaining pixels at the end if necessary.
+ ld a, $63 ; empty
+ add e
+ ld [hl], a
+.done
+ ;pop bc
+ pop de
+ pop hl
+ ret
+
+
+; loads pokemon data from one of multiple sources to wLoadedMon
+; loads base stats to wMonHeader
+; INPUT:
+; [wWhichPokemon] = index of pokemon within party/box
+; [wMonDataLocation] = source
+; 00: player's party
+; 01: enemy's party
+; 02: current box
+; 03: daycare
+; OUTPUT:
+; [wcf91] = pokemon ID
+; wLoadedMon = base address of pokemon data
+; wMonHeader = base address of base stats
+LoadMonData::
+ jpfar LoadMonData_
+
+OverwritewMoves::
+; Write c to [wMoves + b]. Unused.
+ ld hl, wMoves
+ ld e, b
+ ld d, 0
+ add hl, de
+ ld a, c
+ ld [hl], a
+ ret
+
+LoadFlippedFrontSpriteByMonIndex::
+ ld a, 1
+ ld [wSpriteFlipped], a
+
+LoadFrontSpriteByMonIndex::
+ push hl
+ ld a, [wd11e]
+ push af
+ ld a, [wcf91]
+ ld [wd11e], a
+ predef IndexToPokedex
+ ld hl, wd11e
+ ld a, [hl]
+ pop bc
+ ld [hl], b
+ and a
+ pop hl
+ jr z, .invalidDexNumber ; dex #0 invalid
+ cp NUM_POKEMON + 1
+ jr c, .validDexNumber ; dex >#151 invalid
+.invalidDexNumber
+ ld a, RHYDON ; $1
+ ld [wcf91], a
+ ret
+.validDexNumber
+ push hl
+ ld de, vFrontPic
+ call LoadMonFrontSprite
+ pop hl
+ ldh a, [hLoadedROMBank]
+ push af
+ switchbank CopyUncompressedPicToHL
+ xor a
+ ldh [hStartTileID], a
+ call CopyUncompressedPicToHL
+ xor a
+ ld [wSpriteFlipped], a
+ pop af
+ jp BankswitchCommon
+
+
+PlayCry::
+; Play monster a's cry.
+ push bc
+ ld b, a
+ ld a, [wLowHealthAlarm]
+ push af
+ xor a
+ ld [wLowHealthAlarm], a
+ ld a, b
+ call GetCryData
+ call PlaySound
+ call WaitForSoundToFinish
+ pop af
+ ld [wLowHealthAlarm], a
+ pop bc
+ ret
+
+GetCryData::
+; Load cry data for monster a.
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, CryData
+ add hl, bc
+ add hl, bc
+ add hl, bc
+
+ ld a, BANK(CryData)
+ call BankswitchHome
+ ld a, [hli]
+ ld b, a ; cry id
+ ld a, [hli]
+ ld [wFrequencyModifier], a
+ ld a, [hl]
+ ld [wTempoModifier], a
+ call BankswitchBack
+
+ ; Cry headers have 3 channels,
+ ; and start from index CRY_SFX_START,
+ ; so add 3 times the cry id.
+ ld a, b
+ ld c, CRY_SFX_START
+ rlca ; * 2
+ add b
+ add c
+ ret
+
+DisplayPartyMenu::
+ ldh a, [hTilesetType]
+ push af
+ xor a
+ ldh [hTilesetType], a
+ call GBPalWhiteOutWithDelay3
+ call ClearSprites
+ call PartyMenuInit
+ call DrawPartyMenu
+ jp HandlePartyMenuInput
+
+GoBackToPartyMenu::
+ ldh a, [hTilesetType]
+ push af
+ xor a
+ ldh [hTilesetType], a
+ call PartyMenuInit
+ call RedrawPartyMenu
+ jp HandlePartyMenuInput
+
+PartyMenuInit::
+ ld a, 1 ; hardcoded bank
+ call BankswitchHome
+ call LoadHpBarAndStatusTilePatterns
+ ld hl, wd730
+ set 6, [hl] ; turn off letter printing delay
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld hl, wTopMenuItemY
+ inc a
+ ld [hli], a ; top menu item Y
+ xor a
+ ld [hli], a ; top menu item X
+ ld a, [wPartyAndBillsPCSavedMenuItem]
+ push af
+ ld [hli], a ; current menu item ID
+ inc hl
+ ld a, [wPartyCount]
+ and a ; are there more than 0 pokemon in the party?
+ jr z, .storeMaxMenuItemID
+ dec a
+; if party is not empty, the max menu item ID is ([wPartyCount] - 1)
+; otherwise, it is 0
+.storeMaxMenuItemID
+ ld [hli], a ; max menu item ID
+ ld a, [wForcePlayerToChooseMon]
+ and a
+ ld a, A_BUTTON | B_BUTTON
+ jr z, .next
+ xor a
+ ld [wForcePlayerToChooseMon], a
+ inc a ; a = A_BUTTON
+.next
+ ld [hli], a ; menu watched keys
+ pop af
+ ld [hl], a ; old menu item ID
+ ret
+
+HandlePartyMenuInput::
+ ld a, 1
+ ld [wMenuWrappingEnabled], a
+ ld a, $40
+ ld [wPartyMenuAnimMonEnabled], a
+ call HandleMenuInput_
+ push af ; save hJoy5 OR wMenuWrapping enabled, if no inputs were selected within a certain period of time
+ bit 1, a ; was B button pressed?
+ ld a, $0
+ ld [wPartyMenuAnimMonEnabled], a
+ ld a, [wCurrentMenuItem]
+ ld [wPartyAndBillsPCSavedMenuItem], a
+ jr nz, .asm_1258
+ ld a, [wCurrentMenuItem]
+ ld [wWhichPokemon], a
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .asm_1258
+ call CheckPikachuFollowingPlayer
+ jr nz, .asm_128f
+.asm_1258
+ pop af
+ call PlaceUnfilledArrowMenuCursor
+ ld b, a
+ ld hl, wd730
+ res 6, [hl] ; turn on letter printing delay
+ ld a, [wMenuItemToSwap]
+ and a
+ jp nz, .swappingPokemon
+ pop af
+ ldh [hTilesetType], a
+ bit 1, b
+ jr nz, .noPokemonChosen
+ ld a, [wPartyCount]
+ and a
+ jr z, .noPokemonChosen
+ ld a, [wCurrentMenuItem]
+ ld [wWhichPokemon], a
+ ld hl, wPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wcf91], a
+ ld [wBattleMonSpecies2], a
+ call BankswitchBack
+ and a
+ ret
+.asm_128f
+ pop af
+ ld hl, PartyMenuText_12cc
+ call PrintText
+ xor a
+ ld [wMenuItemToSwap], a
+ pop af
+ ldh [hTilesetType], a
+.noPokemonChosen
+ call BankswitchBack
+ scf
+ ret
+.swappingPokemon
+ bit 1, b ; was the B button pressed?
+ jr z, .handleSwap ; if not, handle swapping the pokemon
+.cancelSwap ; if the B button was pressed
+ farcall ErasePartyMenuCursors
+ xor a
+ ld [wMenuItemToSwap], a
+ ld [wPartyMenuTypeOrMessageID], a
+ call RedrawPartyMenu
+ jp HandlePartyMenuInput
+.handleSwap
+ ld a, [wCurrentMenuItem]
+ ld [wWhichPokemon], a
+ farcall SwitchPartyMon
+ jp HandlePartyMenuInput
+
+PartyMenuText_12cc::
+ text_far _SleepingPikachuText1
+ text_end
+
+DrawPartyMenu::
+ ld hl, DrawPartyMenu_
+ jr DrawPartyMenuCommon
+
+RedrawPartyMenu::
+ ld hl, RedrawPartyMenu_
+
+DrawPartyMenuCommon::
+ ld b, BANK(RedrawPartyMenu_)
+ jp Bankswitch
+
+; prints a pokemon's status condition
+; INPUT:
+; de = address of status condition
+; hl = destination address
+PrintStatusCondition::
+ push de
+ dec de
+ dec de ; de = address of current HP
+ ld a, [de]
+ ld b, a
+ dec de
+ ld a, [de]
+ or b ; is the pokemon's HP zero?
+ pop de
+ jr nz, PrintStatusConditionNotFainted
+; if the pokemon's HP is 0, print "FNT"
+ ld a, "F"
+ ld [hli], a
+ ld a, "N"
+ ld [hli], a
+ ld [hl], "T"
+ and a
+ ret
+
+PrintStatusConditionNotFainted::
+ homecall_jump_sf PrintStatusAilment
+
+; function to print pokemon level, leaving off the ":L" if the level is at least 100
+; INPUT:
+; hl = destination address
+; [wLoadedMonLevel] = level
+PrintLevel::
+ ld a, "<LV>" ; ":L" tile ID
+ ld [hli], a
+ ld c, 2 ; number of digits
+ ld a, [wLoadedMonLevel] ; level
+ cp 100
+ jr c, PrintLevelCommon
+; if level at least 100, write over the ":L" tile
+ dec hl
+ inc c ; increment number of digits to 3
+ jr PrintLevelCommon
+
+; prints the level without leaving off ":L" regardless of level
+; INPUT:
+; hl = destination address
+; [wLoadedMonLevel] = level
+PrintLevelFull::
+ ld a, "<LV>" ; ":L" tile ID
+ ld [hli], a
+ ld c, 3 ; number of digits
+ ld a, [wLoadedMonLevel] ; level
+
+PrintLevelCommon::
+ ld [wd11e], a
+ ld de, wd11e
+ ld b, LEFT_ALIGN | 1 ; 1 byte
+ jp PrintNumber
+
+GetwMoves::
+; Unused. Returns the move at index a from wMoves in a
+ ld hl, wMoves
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ret
+
+; copies the base stat data of a pokemon to wMonHeader
+; INPUT:
+; [wd0b5] = pokemon ID
+GetMonHeader::
+ ldh a, [hLoadedROMBank]
+ push af
+ switchbank BaseStats
+ push bc
+ push de
+ push hl
+ ld a, [wd11e]
+ push af
+ ld a, [wd0b5]
+ ld [wd11e], a
+ ld de, FossilKabutopsPic
+ ld b, $66 ; size of Kabutops fossil and Ghost sprites
+ cp FOSSIL_KABUTOPS ; Kabutops fossil
+ jr z, .specialID
+ ld de, GhostPic
+ cp MON_GHOST ; Ghost
+ jr z, .specialID
+ ld de, FossilAerodactylPic
+ ld b, $77 ; size of Aerodactyl fossil sprite
+ cp FOSSIL_AERODACTYL ; Aerodactyl fossil
+ jr z, .specialID
+ ;cp MEW
+ ;jr z, .mew
+ predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number
+ ld a, [wd11e]
+ dec a
+ ld bc, MonBaseStatsEnd - MonBaseStats
+ ld hl, BaseStats
+ call AddNTimes
+ ld de, wMonHeader
+ ld bc, MonBaseStatsEnd - MonBaseStats
+ call CopyData
+ jr .done
+.specialID
+ ld hl, wMonHSpriteDim
+ ld [hl], b ; write sprite dimensions
+ inc hl
+ ld [hl], e ; write front sprite pointer
+ inc hl
+ ld [hl], d
+.done
+ ld a, [wd0b5]
+ ld [wMonHIndex], a
+ pop af
+ ld [wd11e], a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ call BankswitchCommon
+ ret
+
+; copy party pokemon's name to wcd6d
+GetPartyMonName2::
+ ld a, [wWhichPokemon] ; index within party
+ ld hl, wPartyMonNicks
+
+; this is called more often
+GetPartyMonName::
+ push hl
+ push bc
+ call SkipFixedLengthTextEntries ; add NAME_LENGTH to hl, a times
+ ld de, wcd6d
+ push de
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop de
+ pop bc
+ pop hl
+ ret
diff --git a/home/predef.asm b/home/predef.asm
index dfa10772..a0889e0e 100644
--- a/home/predef.asm
+++ b/home/predef.asm
@@ -8,12 +8,12 @@ Predef::
; A hack for LoadDestinationWarpPosition.
; See LoadTilesetHeader (predef $19).
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
ld [wPredefParentBank], a
push af
ld a, BANK(GetPredefPointer)
- ld [H_LOADEDROMBANK], a
+ ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call GetPredefPointer
diff --git a/home/predef_text.asm b/home/predef_text.asm
new file mode 100644
index 00000000..b494a2c8
--- /dev/null
+++ b/home/predef_text.asm
@@ -0,0 +1,28 @@
+PrintPredefTextID::
+ ldh [hSpriteIndexOrTextID], a
+ ld hl, TextPredefs
+ call SetMapTextPointer
+ ld hl, wTextPredefFlag
+ set 0, [hl]
+ call DisplayTextID
+
+RestoreMapTextPointer::
+ ld hl, wMapTextPtr
+ ldh a, [hSavedMapTextPtr]
+ ld [hli], a
+ ldh a, [hSavedMapTextPtr + 1]
+ ld [hl], a
+ ret
+
+SetMapTextPointer::
+ ld a, [wMapTextPtr]
+ ldh [hSavedMapTextPtr], a
+ ld a, [wMapTextPtr + 1]
+ ldh [hSavedMapTextPtr + 1], a
+ ld a, l
+ ld [wMapTextPtr], a
+ ld a, h
+ ld [wMapTextPtr + 1], a
+ ret
+
+INCLUDE "data/text_predef_pointers.asm"
diff --git a/home/print_bcd.asm b/home/print_bcd.asm
new file mode 100644
index 00000000..38aedd3c
--- /dev/null
+++ b/home/print_bcd.asm
@@ -0,0 +1,77 @@
+; 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
+; bit 5: if set, print currency symbol at the beginning of the string
+; if unset, do not print the currency symbol
+; bits 0-4: 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::
+ ld b, c ; save flags in b
+ res 7, c
+ res 6, c
+ res 5, c ; c now holds the length
+ bit 5, b
+ jr z, .loop
+ bit 7, b
+ jr nz, .loop
+ ld [hl], "¥"
+ inc hl
+.loop
+ ld a, [de]
+ swap a
+ call PrintBCDDigit ; print upper digit
+ ld a, [de]
+ call PrintBCDDigit ; print lower digit
+ inc de
+ dec c
+ jr nz, .loop
+ bit 7, b ; were any non-zero digits printed?
+ jr z, .done ; if so, we are done
+.numberEqualsZero ; if every digit of the BCD number is zero
+ bit 6, b ; left or right alignment?
+ jr nz, .skipRightAlignmentAdjustment
+ dec hl ; if the string is right-aligned, it needs to be moved back one space
+.skipRightAlignmentAdjustment
+ bit 5, b
+ jr z, .skipCurrencySymbol
+ ld [hl], "¥"
+ inc hl
+.skipCurrencySymbol
+ ld [hl], "0"
+ call PrintLetterDelay
+ inc hl
+.done
+ ret
+
+PrintBCDDigit::
+ and $f
+ and a
+ jr z, .zeroDigit
+.nonzeroDigit
+ bit 7, b ; have any non-space characters been printed?
+ jr z, .outputDigit
+; if bit 7 is set, then no numbers have been printed yet
+ bit 5, b ; print the currency symbol?
+ jr z, .skipCurrencySymbol
+ ld [hl], "¥"
+ inc hl
+ res 5, b
+.skipCurrencySymbol
+ res 7, b ; unset 7 to indicate that a nonzero digit has been reached
+.outputDigit
+ add "0"
+ ld [hli], a
+ jp PrintLetterDelay
+.zeroDigit
+ bit 7, b ; either printing leading zeroes or already reached a nonzero digit?
+ jr z, .outputDigit ; if so, print a zero digit
+ bit 6, b ; left or right alignment?
+ ret nz
+ inc hl ; if right-aligned, "print" a space by advancing the pointer
+ ret
diff --git a/home/print_num.asm b/home/print_num.asm
new file mode 100644
index 00000000..e2628b1f
--- /dev/null
+++ b/home/print_num.asm
@@ -0,0 +1,219 @@
+PrintNumber::
+; Print the c-digit, b-byte value at de.
+; Allows 2 to 7 digits. For 1-digit numbers, add
+; the value to char "0" instead of calling PrintNumber.
+; Flags LEADING_ZEROES and LEFT_ALIGN can be given
+; in bits 7 and 6 of b respectively.
+ push bc
+ xor a
+ ldh [hPastLeadingZeros], a
+ ldh [hNumToPrint], a
+ ldh [hNumToPrint + 1], a
+ ld a, b
+ and $f
+ cp 1
+ jr z, .byte
+ cp 2
+ jr z, .word
+.long
+ ld a, [de]
+ ldh [hNumToPrint], a
+ inc de
+ ld a, [de]
+ ldh [hNumToPrint + 1], a
+ inc de
+ ld a, [de]
+ ldh [hNumToPrint + 2], a
+ jr .start
+
+.word
+ ld a, [de]
+ ldh [hNumToPrint + 1], a
+ inc de
+ ld a, [de]
+ ldh [hNumToPrint + 2], a
+ jr .start
+
+.byte
+ ld a, [de]
+ ldh [hNumToPrint + 2], a
+
+.start
+ push de
+
+ ld d, b
+ ld a, c
+ ld b, a
+ xor a
+ ld c, a
+ ld a, b
+
+ cp 2
+ jr z, .tens
+ cp 3
+ jr z, .hundreds
+ cp 4
+ jr z, .thousands
+ cp 5
+ jr z, .ten_thousands
+ cp 6
+ jr z, .hundred_thousands
+
+print_digit: MACRO
+
+IF (\1) / $10000
+ ld a, \1 / $10000 % $100
+ELSE
+ xor a
+ENDC
+ ldh [hPowerOf10 + 0], a
+
+IF (\1) / $100
+ ld a, \1 / $100 % $100
+ELSE
+ xor a
+ENDC
+ ldh [hPowerOf10 + 1], a
+
+ ld a, \1 / $1 % $100
+ ldh [hPowerOf10 + 2], a
+
+ call .PrintDigit
+ call .NextDigit
+ENDM
+
+.millions print_digit 1000000
+.hundred_thousands print_digit 100000
+.ten_thousands print_digit 10000
+.thousands print_digit 1000
+.hundreds print_digit 100
+
+.tens
+ ld c, 0
+ ldh a, [hNumToPrint + 2]
+.mod
+ cp 10
+ jr c, .ok
+ sub 10
+ inc c
+ jr .mod
+.ok
+
+ ld b, a
+ ldh a, [hPastLeadingZeros]
+ or c
+ ldh [hPastLeadingZeros], a
+ jr nz, .past
+ call .PrintLeadingZero
+ jr .next
+.past
+ ld a, "0"
+ add c
+ ld [hl], a
+.next
+
+ call .NextDigit
+.ones
+ ld a, "0"
+ add b
+ ld [hli], a
+ pop de
+ dec de
+ pop bc
+ ret
+
+.PrintDigit:
+; Divide by the current decimal place.
+; Print the quotient, and keep the modulus.
+ ld c, 0
+.loop
+ ldh a, [hPowerOf10]
+ ld b, a
+ ldh a, [hNumToPrint]
+ ldh [hSavedNumToPrint], a
+ cp b
+ jr c, .underflow0
+ sub b
+ ldh [hNumToPrint], a
+ ldh a, [hPowerOf10 + 1]
+ ld b, a
+ ldh a, [hNumToPrint + 1]
+ ldh [hSavedNumToPrint + 1], a
+ cp b
+ jr nc, .noborrow1
+
+ ldh a, [hNumToPrint]
+ or 0
+ jr z, .underflow1
+ dec a
+ ldh [hNumToPrint], a
+ ldh a, [hNumToPrint + 1]
+.noborrow1
+
+ sub b
+ ldh [hNumToPrint + 1], a
+ ldh a, [hPowerOf10 + 2]
+ ld b, a
+ ldh a, [hNumToPrint + 2]
+ ldh [hSavedNumToPrint + 2], a
+ cp b
+ jr nc, .noborrow2
+
+ ldh a, [hNumToPrint + 1]
+ and a
+ jr nz, .borrowed
+
+ ldh a, [hNumToPrint]
+ and a
+ jr z, .underflow2
+ dec a
+ ldh [hNumToPrint], a
+ xor a
+.borrowed
+
+ dec a
+ ldh [hNumToPrint + 1], a
+ ldh a, [hNumToPrint + 2]
+.noborrow2
+ sub b
+ ldh [hNumToPrint + 2], a
+ inc c
+ jr .loop
+
+.underflow2
+ ldh a, [hSavedNumToPrint + 1]
+ ldh [hNumToPrint + 1], a
+.underflow1
+ ldh a, [hSavedNumToPrint]
+ ldh [hNumToPrint], a
+.underflow0
+ ldh a, [hPastLeadingZeros]
+ or c
+ jr z, .PrintLeadingZero
+
+ ld a, "0"
+ add c
+ ld [hl], a
+ ldh [hPastLeadingZeros], a
+ ret
+
+.PrintLeadingZero:
+ bit BIT_LEADING_ZEROES, d
+ ret z
+ ld [hl], "0"
+ ret
+
+.NextDigit:
+; Increment unless the number is left-aligned,
+; leading zeroes are not printed, and no digits
+; have been printed yet.
+ bit BIT_LEADING_ZEROES, d
+ jr nz, .inc
+ bit BIT_LEFT_ALIGN, d
+ jr z, .inc
+ ldh a, [hPastLeadingZeros]
+ and a
+ ret z
+.inc
+ inc hl
+ ret
diff --git a/home/print_text.asm b/home/print_text.asm
new file mode 100644
index 00000000..049ddfb4
--- /dev/null
+++ b/home/print_text.asm
@@ -0,0 +1,45 @@
+; This function is used to wait a short period after printing a letter to the
+; screen unless the player presses the A/B button or the delay is turned off
+; through the [wd730] or [wLetterPrintingDelayFlags] flags.
+PrintLetterDelay::
+ ld a, [wd730]
+ bit 6, a
+ ret nz
+ ld a, [wLetterPrintingDelayFlags]
+ bit 1, a
+ ret z
+ push hl
+ push de
+ push bc
+ ld a, [wLetterPrintingDelayFlags]
+ bit 0, a
+ jr z, .waitOneFrame
+ ld a, [wOptions]
+ and $f
+ ldh [hFrameCounter], a
+ jr .checkButtons
+.waitOneFrame
+ ld a, 1
+ ldh [hFrameCounter], a
+.checkButtons
+ call Joypad
+ ldh a, [hJoyHeld]
+.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
+ ldh a, [hFrameCounter]
+ and a
+ jr nz, .checkButtons
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/home/random.asm b/home/random.asm
new file mode 100644
index 00000000..33a24425
--- /dev/null
+++ b/home/random.asm
@@ -0,0 +1,12 @@
+Random::
+; Return a random number in a.
+; For battles, use BattleRandom.
+ push hl
+ push de
+ push bc
+ farcall Random_
+ ldh a, [hRandomAdd]
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/home/reload_sprites.asm b/home/reload_sprites.asm
new file mode 100644
index 00000000..63a71d26
--- /dev/null
+++ b/home/reload_sprites.asm
@@ -0,0 +1,19 @@
+; Copy the current map's sprites' tile patterns to VRAM again after they have
+; been overwritten by other tile patterns.
+ReloadMapSpriteTilePatterns::
+ ld hl, wFontLoaded
+ ld a, [hl]
+ push af
+ res 0, [hl]
+ push hl
+ xor a
+ ld [wSpriteSetID], a
+ call DisableLCD
+ call InitMapSprites
+ call EnableLCD
+ pop hl
+ pop af
+ ld [hl], a
+ call LoadPlayerSpriteGraphics
+ call LoadFontTilePatterns
+ jp UpdateSprites
diff --git a/home/reload_tiles.asm b/home/reload_tiles.asm
new file mode 100644
index 00000000..ae9f6544
--- /dev/null
+++ b/home/reload_tiles.asm
@@ -0,0 +1,67 @@
+; reloads text box tile patterns, current map view, and tileset tile patterns
+ReloadMapData::
+ ldh a, [hLoadedROMBank]
+ push af
+ ld a, [wCurMap]
+ call SwitchToMapRomBank
+ call DisableLCD
+ call LoadTextBoxTilePatterns
+ call LoadCurrentMapView
+ call LoadTilesetTilePatternData
+ call EnableLCD
+ pop af
+ call BankswitchCommon
+ ret
+
+; reloads tileset tile patterns
+ReloadTilesetTilePatterns::
+ ldh a, [hLoadedROMBank]
+ push af
+ ld a, [wCurMap]
+ call SwitchToMapRomBank
+ call DisableLCD
+ call LoadTilesetTilePatternData
+ call EnableLCD
+ pop af
+ call BankswitchCommon
+ ret
+
+; shows the town map and lets the player choose a destination to fly to
+ChooseFlyDestination::
+ ld hl, wd72e
+ res 4, [hl]
+ farjp LoadTownMap_Fly
+
+PrinterSerial::
+ homecall PrinterSerial_
+ ret
+
+SerialFunction::
+ ld a, [wPrinterConnectionOpen]
+ bit 0, a
+ ret z
+ ld a, [wPrinterOpcode]
+ and a
+ ret nz
+ ld hl, wOverworldMap + 650
+ inc [hl]
+ ld a, [hl]
+ cp $6
+ ret c
+ xor a
+ ld [hl], a
+ ld a, $0c
+ ld [wPrinterOpcode], a
+ ld a, $88
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ldh [rSC], a
+ ret
+
+; causes the text box to close without waiting for a button press after displaying text
+DisableWaitingAfterTextDisplay::
+ ld a, $01
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ret
diff --git a/home/reset_player_sprite.asm b/home/reset_player_sprite.asm
new file mode 100644
index 00000000..2765d613
--- /dev/null
+++ b/home/reset_player_sprite.asm
@@ -0,0 +1,21 @@
+ResetPlayerSpriteData::
+ ld hl, wSpriteStateData1
+ call ResetPlayerSpriteData_ClearSpriteData
+ ld hl, wSpriteStateData2
+ call ResetPlayerSpriteData_ClearSpriteData
+ ld a, $1
+ ld [wSpritePlayerStateData1PictureID], a
+ ld [wSpritePlayerStateData2ImageBaseOffset], a
+ ld hl, wSpritePlayerStateData1YPixels
+ ld [hl], $3c ; set Y screen pos
+ inc hl
+ inc hl
+ ld [hl], $40 ; set X screen pos
+ ret
+
+; overwrites sprite data with zeroes
+ResetPlayerSpriteData_ClearSpriteData::
+ ld bc, $10
+ xor a
+ call FillMemory
+ ret
diff --git a/home/serial.asm b/home/serial.asm
index 5fe7fb81..ef914933 100644
--- a/home/serial.asm
+++ b/home/serial.asm
@@ -6,46 +6,46 @@ Serial::
ld a, [wPrinterConnectionOpen]
bit 0, a
jp nz, PrinterSerial__
- ld a, [hSerialConnectionStatus]
+ ldh a, [hSerialConnectionStatus]
inc a
jr z, .connectionNotYetEstablished
- ld a, [rSB]
- ld [hSerialReceiveData], a
- ld a, [hSerialSendData]
- ld [rSB], a
- ld a, [hSerialConnectionStatus]
+ ldh a, [rSB]
+ ldh [hSerialReceiveData], a
+ ldh a, [hSerialSendData]
+ ldh [rSB], a
+ ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .done
; using external clock
ld a, START_TRANSFER_EXTERNAL_CLOCK
- ld [rSC], a
+ ldh [rSC], a
jr .done
.connectionNotYetEstablished
- ld a, [rSB]
- ld [hSerialReceiveData], a
- ld [hSerialConnectionStatus], a
+ ldh a, [rSB]
+ ldh [hSerialReceiveData], a
+ ldh [hSerialConnectionStatus], a
cp USING_INTERNAL_CLOCK
jr z, .usingInternalClock
; using external clock
xor a
- ld [rSB], a
+ ldh [rSB], a
ld a, $3
- ld [rDIV], a
+ ldh [rDIV], a
.waitLoop
- ld a, [rDIV]
+ ldh a, [rDIV]
bit 7, a
jr nz, .waitLoop
ld a, START_TRANSFER_EXTERNAL_CLOCK
- ld [rSC], a
+ ldh [rSC], a
jr .done
.usingInternalClock
xor a
- ld [rSB], a
+ ldh [rSB], a
.done
ld a, $1
- ld [hSerialReceivedNewData], a
+ ldh [hSerialReceivedNewData], a
ld a, SERIAL_NO_DATA_BYTE
- ld [hSerialSendData], a
+ ldh [hSerialSendData], a
pop hl
pop de
pop bc
@@ -57,10 +57,10 @@ Serial::
; bc = length of data
Serial_ExchangeBytes::
ld a, 1
- ld [hSerialIgnoringInitialData], a
+ ldh [hSerialIgnoringInitialData], a
.loop
ld a, [hl]
- ld [hSerialSendData], a
+ ldh [hSerialSendData], a
call Serial_ExchangeByte
push bc
ld b, a
@@ -69,7 +69,7 @@ Serial_ExchangeBytes::
.waitLoop
dec a
jr nz, .waitLoop
- ld a, [hSerialIgnoringInitialData]
+ ldh a, [hSerialIgnoringInitialData]
and a
ld a, b
pop bc
@@ -78,7 +78,7 @@ Serial_ExchangeBytes::
cp SERIAL_PREAMBLE_BYTE
jr nz, .loop
xor a
- ld [hSerialIgnoringInitialData], a
+ ldh [hSerialIgnoringInitialData], a
jr .loop
.storeReceivedByte
ld [de], a
@@ -91,17 +91,17 @@ Serial_ExchangeBytes::
Serial_ExchangeByte::
xor a
- ld [hSerialReceivedNewData], a
- ld a, [hSerialConnectionStatus]
+ ldh [hSerialReceivedNewData], a
+ ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr nz, .loop
ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
+ ldh [rSC], a
.loop
- ld a, [hSerialReceivedNewData]
+ ldh a, [hSerialReceivedNewData]
and a
jr nz, .ok
- ld a, [hSerialConnectionStatus]
+ ldh a, [hSerialConnectionStatus]
cp USING_EXTERNAL_CLOCK
jr nz, .doNotIncrementUnknownCounter
call IsUnknownCounterZero
@@ -119,7 +119,7 @@ Serial_ExchangeByte::
jr nz, .loop
jp SetUnknownCounterToFFFF
.doNotIncrementUnknownCounter
- ld a, [rIE]
+ ldh a, [rIE]
and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
cp (1 << SERIAL)
jr nz, .loop
@@ -131,7 +131,7 @@ Serial_ExchangeByte::
dec a
ld [wUnknownSerialCounter2 + 1], a
jr nz, .loop
- ld a, [hSerialConnectionStatus]
+ ldh a, [hSerialConnectionStatus]
cp USING_EXTERNAL_CLOCK
jr z, .ok
ld a, 255
@@ -140,8 +140,8 @@ Serial_ExchangeByte::
jr nz, .waitLoop
.ok
xor a
- ld [hSerialReceivedNewData], a
- ld a, [rIE]
+ ldh [hSerialReceivedNewData], a
+ ldh a, [rIE]
and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
sub (1 << SERIAL)
jr nz, .skipReloadingUnknownCounter2
@@ -149,7 +149,7 @@ Serial_ExchangeByte::
ld a, $50
ld [wUnknownSerialCounter2 + 1], a
.skipReloadingUnknownCounter2
- ld a, [hSerialReceiveData]
+ ldh a, [hSerialReceiveData]
cp SERIAL_NO_DATA_BYTE
ret nz
call IsUnknownCounterZero
@@ -167,13 +167,13 @@ Serial_ExchangeByte::
call IsUnknownCounterZero
jr z, SetUnknownCounterToFFFF
.done
- ld a, [rIE]
+ ldh a, [rIE]
and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
cp (1 << SERIAL)
ld a, SERIAL_NO_DATA_BYTE
ret z
ld a, [hl]
- ld [hSerialSendData], a
+ ldh [hSerialSendData], a
call DelayFrame
jp Serial_ExchangeByte
@@ -206,18 +206,18 @@ Serial_ExchangeLinkMenuSelection::
ld de, wLinkMenuSelectionReceiveBuffer
ld c, 2 ; number of bytes to save
ld a, 1
- ld [hSerialIgnoringInitialData], a
+ ldh [hSerialIgnoringInitialData], a
.loop
call DelayFrame
ld a, [hl]
- ld [hSerialSendData], a
+ ldh [hSerialSendData], a
call Serial_ExchangeByte
ld b, a
inc hl
- ld a, [hSerialIgnoringInitialData]
+ ldh a, [hSerialIgnoringInitialData]
and a
ld a, 0
- ld [hSerialIgnoringInitialData], a
+ ldh [hSerialIgnoringInitialData], a
jr nz, .loop
ld a, b
ld [de], a
@@ -228,7 +228,7 @@ Serial_ExchangeLinkMenuSelection::
Serial_PrintWaitingTextAndSyncAndExchangeNybble::
call SaveScreenTilesToBuffer1
- callab PrintWaitingText
+ callfar PrintWaitingText
call Serial_SyncAndExchangeNybble
jp LoadScreenTilesFromBuffer1
@@ -276,20 +276,20 @@ Serial_ExchangeNybble::
call .doExchange
ld a, [wSerialExchangeNybbleSendData]
add $60
- ld [hSerialSendData], a
- ld a, [hSerialConnectionStatus]
+ ldh [hSerialSendData], a
+ ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr nz, .doExchange
ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
+ ldh [rSC], a
.doExchange
- ld a, [hSerialReceiveData]
+ ldh a, [hSerialReceiveData]
ld [wSerialExchangeNybbleTempReceiveData], a
and $f0
cp $60
ret nz
xor a
- ld [hSerialReceiveData], a
+ ldh [hSerialReceiveData], a
ld a, [wSerialExchangeNybbleTempReceiveData]
and $f
ld [wSerialExchangeNybbleReceiveData], a
@@ -297,21 +297,21 @@ Serial_ExchangeNybble::
Serial_SendZeroByte::
xor a
- ld [hSerialSendData], a
- ld a, [hSerialConnectionStatus]
+ ldh [hSerialSendData], a
+ ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
ret nz
ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
+ ldh [rSC], a
ret
Serial_TryEstablishingExternallyClockedConnection::
ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
- ld [rSB], a
+ ldh [rSB], a
xor a
- ld [hSerialReceiveData], a
+ ldh [hSerialReceiveData], a
ld a, START_TRANSFER_EXTERNAL_CLOCK
- ld [rSC], a
+ ldh [rSC], a
ret
PrinterSerial__::
diff --git a/home/start.asm b/home/start.asm
new file mode 100644
index 00000000..379436ae
--- /dev/null
+++ b/home/start.asm
@@ -0,0 +1,10 @@
+_Start::
+ cp GBC
+ jr z, .gbc
+ xor a
+ jr .ok
+.gbc
+ ld a, 1
+.ok
+ ldh [hGBC], a
+ jp Init
diff --git a/home/start_menu.asm b/home/start_menu.asm
new file mode 100755
index 00000000..bd1b24bf
--- /dev/null
+++ b/home/start_menu.asm
@@ -0,0 +1,84 @@
+DisplayStartMenu::
+ switchbank StartMenu_Pokedex ; also bank for other functions
+ ld a, [wWalkBikeSurfState] ; walking/biking/surfing
+ ld [wWalkBikeSurfStateCopy], a
+ ld a, SFX_START_MENU
+ call PlaySound
+
+RedisplayStartMenu::
+ farcall DrawStartMenu
+RedisplayStartMenu_DoNotDrawStartMenu::
+ farcall PrintSafariZoneSteps ; print Safari Zone info, if in Safari Zone
+ call UpdateSprites
+.loop
+ call HandleMenuInput
+ ld b, a
+.checkIfUpPressed
+ bit 6, a ; was Up pressed?
+ jr z, .checkIfDownPressed
+ ld a, [wCurrentMenuItem] ; menu selection
+ and a
+ jr nz, .loop
+ ld a, [wLastMenuItem]
+ and a
+ jr nz, .loop
+; if the player pressed tried to go past the top item, wrap around to the bottom
+ CheckEvent EVENT_GOT_POKEDEX
+ ld a, 6 ; there are 7 menu items with the pokedex, so the max index is 6
+ jr nz, .wrapMenuItemId
+ dec a ; there are only 6 menu items without the pokedex
+.wrapMenuItemId
+ ld [wCurrentMenuItem], a
+ call EraseMenuCursor
+ jr .loop
+.checkIfDownPressed
+ bit 7, a
+ jr z, .buttonPressed
+; if the player pressed tried to go past the bottom item, wrap around to the top
+ CheckEvent EVENT_GOT_POKEDEX
+ ld a, [wCurrentMenuItem]
+ ld c, 7 ; there are 7 menu items with the pokedex
+ jr nz, .checkIfPastBottom
+ dec c ; there are only 6 menu items without the pokedex
+.checkIfPastBottom
+ cp c
+ jr nz, .loop
+; the player went past the bottom, so wrap to the top
+ xor a
+ ld [wCurrentMenuItem], a
+ call EraseMenuCursor
+ jr .loop
+.buttonPressed ; A, B, or Start button pressed
+ call PlaceUnfilledArrowMenuCursor
+ ld a, [wCurrentMenuItem]
+ ld [wBattleAndStartSavedMenuItem], a ; save current menu selection
+ ld a, b
+ and %00001010 ; was the Start button or B button pressed?
+ jp nz, CloseStartMenu
+ call SaveScreenTilesToBuffer2 ; copy background from wTileMap to wTileMapBackup2
+ CheckEvent EVENT_GOT_POKEDEX
+ ld a, [wCurrentMenuItem]
+ jr nz, .displayMenuItem
+ inc a ; adjust position to account for missing pokedex menu item
+.displayMenuItem
+ cp 0
+ jp z, StartMenu_Pokedex
+ cp 1
+ jp z, StartMenu_Pokemon
+ cp 2
+ jp z, StartMenu_Item
+ cp 3
+ jp z, StartMenu_TrainerInfo
+ cp 4
+ jp z, StartMenu_SaveReset
+ cp 5
+ jp z, StartMenu_Option
+
+; EXIT falls through to here
+CloseStartMenu::
+ call Joypad
+ ldh a, [hJoyPressed]
+ bit 0, a ; was A button newly pressed?
+ jr nz, CloseStartMenu
+ call LoadTextBoxTilePatterns
+ jp CloseTextDisplay
diff --git a/home/text.asm b/home/text.asm
index f78227eb..78d69138 100644
--- a/home/text.asm
+++ b/home/text.asm
@@ -5,9 +5,9 @@ TextBoxBorder::
push hl
ld a, "┌"
ld [hli], a
- inc a ; ─
- call NPlaceChar
- inc a ; ┐
+ inc a ; "─"
+ call .PlaceChars
+ inc a ; "┐"
ld [hl], a
pop hl
@@ -20,7 +20,7 @@ TextBoxBorder::
ld a, "│"
ld [hli], a
ld a, " "
- call NPlaceChar
+ call .PlaceChars
ld [hl], "│"
pop hl
@@ -33,11 +33,11 @@ TextBoxBorder::
ld a, "└"
ld [hli], a
ld a, "─"
- call NPlaceChar
+ call .PlaceChars
ld [hl], "┘"
ret
-NPlaceChar::
+.PlaceChars::
; Place char a c times.
ld d, c
.loop
@@ -48,21 +48,21 @@ NPlaceChar::
PlaceString::
push hl
+
PlaceNextChar::
ld a, [de]
-
cp "@"
- jr nz, Char4ETest
+ jr nz, .NotTerminator
ld b, h
ld c, l
pop hl
ret
-Char4ETest::
- cp $4E ; next
- jr nz, .char4FTest
+.NotTerminator
+ cp "<NEXT>"
+ jr nz, .NotNext
ld bc, 2 * SCREEN_WIDTH
- ld a, [hFlags_0xFFFA]
+ ldh a, [hFlagsFFFA]
bit 2, a
jr z, .ok
ld bc, SCREEN_WIDTH
@@ -70,142 +70,101 @@ Char4ETest::
pop hl
add hl, bc
push hl
- jp PlaceNextChar_inc
+ jp NextChar
-.char4FTest
- cp $4F ; line
- jr nz, .next3
+.NotNext
+ cp "<LINE>"
+ jr nz, .NotLine
pop hl
- coord hl, 1, 16
+ hlcoord 1, 16
push hl
- jp PlaceNextChar_inc
+ jp NextChar
-.next3 ; Check against a dictionary
-dict: macro
-if \1 == 0
- and a
-else
- cp \1
-endc
- jp z, \2
-endm
+.NotLine
- dict $00, Char00 ; error
- dict $4C, Char4C ; autocont
- dict $4B, Char4B ; cont_
- dict $51, Char51 ; para
- dict $49, Char49 ; page
- dict $52, Char52 ; player
- dict $53, Char53 ; rival
- dict $54, Char54 ; POKé
- dict $5B, Char5B ; PC
- dict $5E, Char5E ; ROCKET
- dict $5C, Char5C ; TM
- dict $5D, Char5D ; TRAINER
- dict $55, Char55 ; cont
- dict $56, Char56 ; 6 dots
- dict $57, Char57 ; done
- dict $58, Char58 ; prompt
- dict $4A, Char4A ; PKMN
- dict $5F, Char5F ; dex
- dict $59, Char59 ; TARGET
- dict $5A, Char5A ; USER
+; Check against a dictionary
+ dict "<NULL>", NullChar
+ dict "<SCROLL>", _ContTextNoPause
+ dict "<_CONT>", _ContText
+ dict "<PARA>", Paragraph
+ dict "<PAGE>", PageChar
+ dict "<PLAYER>", PrintPlayerName
+ dict "<RIVAL>", PrintRivalName
+ dict "#", PlacePOKe
+ dict "<PC>", PCChar
+ dict "<ROCKET>", RocketChar
+ dict "<TM>", TMChar
+ dict "<TRAINER>", TrainerChar
+ dict "<CONT>", ContText
+ dict "<……>", SixDotsChar
+ dict "<DONE>", DoneText
+ dict "<PROMPT>", PromptText
+ dict "<PKMN>", PlacePKMN
+ dict "<DEXEND>", PlaceDexEnd
+ dict "<TARGET>", PlaceMoveTargetsName
+ dict "<USER>", PlaceMoveUsersName
ld [hli], a
call PrintLetterDelay
-PlaceNextChar_inc::
+
+NextChar::
inc de
jp PlaceNextChar
-Char00::
+NullChar::
ld b, h
ld c, l
pop hl
- ld de, Char00Text
+ ld de, TextIDErrorText
dec de
ret
-Char00Text:: ; “%d ERROR.”
- TX_FAR _Char00Text
- db "@"
+TextIDErrorText:: ; "[hSpriteIndexOrTextID] ERROR."
+ text_far _TextIDErrorText
+ text_end
-Char52:: ; player’s name
+print_name: MACRO
push de
- ld de, wPlayerName
- jr FinishDTE
+ ld de, \1
+ jr PlaceCommandCharacter
+ENDM
-Char53:: ; rival’s name
- push de
- ld de, wRivalName
- jr FinishDTE
+PrintPlayerName:: print_name wPlayerName
+PrintRivalName:: print_name wRivalName
-Char5D:: ; TRAINER
- push de
- ld de, Char5DText
- jr FinishDTE
-
-Char5C:: ; TM
- push de
- ld de, Char5CText
- jr FinishDTE
+TrainerChar:: print_name TrainerCharText
+TMChar:: print_name TMCharText
+PCChar:: print_name PCCharText
+RocketChar:: print_name RocketCharText
+PlacePOKe:: print_name PlacePOKeText
+SixDotsChar:: print_name SixDotsCharText
+PlacePKMN:: print_name PlacePKMNText
-Char5B:: ; PC
- push de
- ld de, Char5BText
- jr FinishDTE
-
-Char5E:: ; ROCKET
- push de
- ld de, Char5EText
- jr FinishDTE
-
-Char54:: ; POKé
- push de
- ld de, Char54Text
- jr FinishDTE
-
-Char56:: ; ……
- push de
- ld de, Char56Text
- jr FinishDTE
-
-Char4A:: ; PKMN
- push de
- ld de, Char4AText
- jr FinishDTE
-
-Char59::
-; depending on whose turn it is, print
-; enemy active monster’s name, prefixed with “Enemy ”
-; or
-; player active monster’s name
-; (like Char5A but flipped)
- ld a, [H_WHOSETURN]
+PlaceMoveTargetsName::
+ ldh a, [hWhoseTurn]
xor 1
- jr MonsterNameCharsCommon
+ jr PlaceMoveUsersName.place
+
+PlaceMoveUsersName::
+ ldh a, [hWhoseTurn]
-Char5A::
-; depending on whose turn it is, print
-; player active monster’s name
-; or
-; enemy active monster’s name, prefixed with “Enemy ”
- ld a, [H_WHOSETURN]
-MonsterNameCharsCommon::
+.place:
push de
and a
- jr nz, .Enemy
- ld de, wBattleMonNick ; player active monster name
- jr FinishDTE
+ jr nz, .enemy
-.Enemy
- ; print “Enemy ”
- ld de, Char5AText
+ ld de, wBattleMonNick
+ jr PlaceCommandCharacter
+
+.enemy
+ ld de, EnemyText
call PlaceString
ld h, b
ld l, c
- ld de, wEnemyMonNick ; enemy active monster name
+ ld de, wEnemyMonNick
+ ; fallthrough
-FinishDTE::
+PlaceCommandCharacter::
call PlaceString
ld h, b
ld l, c
@@ -213,28 +172,20 @@ FinishDTE::
inc de
jp PlaceNextChar
-Char5CText::
- db "TM@"
-Char5DText::
- db "TRAINER@"
-Char5BText::
- db "PC@"
-Char5EText::
- db "ROCKET@"
-Char54Text::
- db "POKé@"
-Char56Text::
- db "……@"
-Char5AText::
- db "Enemy @"
-Char4AText::
- db $E1, $E2, "@" ; PKMN
+TMCharText:: db "TM@"
+TrainerCharText:: db "TRAINER@"
+PCCharText:: db "PC@"
+RocketCharText:: db "ROCKET@"
+PlacePOKeText:: db "POKé@"
+SixDotsCharText:: db "……@"
+EnemyText:: db "Enemy @"
+PlacePKMNText:: db "<PK><MN>@"
-Char55::
+ContText::
push de
ld b, h
ld c, l
- ld hl, Char55Text
+ ld hl, ContCharText
call TextCommandProcessor
ld h, b
ld l, c
@@ -242,101 +193,99 @@ Char55::
inc de
jp PlaceNextChar
-Char55Text::
-; equivalent to Char4B
- TX_FAR _Char55Text
- db "@"
+ContCharText::
+ text_far _ContCharText
+ text_end
-Char5F::
-; ends a Pokédex entry
+PlaceDexEnd::
ld [hl], "."
pop hl
ret
-Char58:: ; prompt
+PromptText::
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jp z, .ok
ld a, "▼"
- Coorda 18, 16
+ ldcoord_a 18, 16
.ok
call ProtectedDelay3
call ManualTextScroll
ld a, " "
- Coorda 18, 16
-Char57:: ; done
+ ldcoord_a 18, 16
+
+DoneText::
pop hl
- ld de, Char58Text
+ ld de, .stop
dec de
ret
-Char58Text::
- db "@"
+.stop:
+ text_end
-Char51:: ; para
+Paragraph::
push de
ld a, "▼"
- Coorda 18, 16
+ ldcoord_a 18, 16
call ProtectedDelay3
call ManualTextScroll
- coord hl, 1, 13
+ hlcoord 1, 13
lb bc, 4, 18
call ClearScreenArea
ld c, 20
call DelayFrames
pop de
- coord hl, 1, 14
- jp PlaceNextChar_inc
+ hlcoord 1, 14
+ jp NextChar
-Char49::
- ld a, [hFlags_0xFFFA]
+PageChar::
+ ldh a, [hFlagsFFFA]
bit 3, a
- jr z, .Char49
- ld a, $4e
- jp Char4ETest
+ jr z, .pageChar
+ ld a, "<NEXT>"
+ jp PlaceNextChar.NotTerminator
-.Char49
+.pageChar
push de
ld a, "▼"
- Coorda 18, 16
+ ldcoord_a 18, 16
call ProtectedDelay3
call ManualTextScroll
- coord hl, 1, 10
+ hlcoord 1, 10
lb bc, 7, 18
call ClearScreenArea
ld c, 20
call DelayFrames
pop de
pop hl
- coord hl, 1, 11
+ hlcoord 1, 11
push hl
- jp PlaceNextChar_inc
+ jp NextChar
-Char4B::
+_ContText::
ld a, "▼"
- Coorda 18, 16
+ ldcoord_a 18, 16
call ProtectedDelay3
push de
call ManualTextScroll
pop de
ld a, " "
- Coorda 18, 16
- ;fall through
-Char4C::
+ ldcoord_a 18, 16
+_ContTextNoPause::
push de
call ScrollTextUpOneLine
call ScrollTextUpOneLine
- coord hl, 1, 16
+ hlcoord 1, 16
pop de
- jp PlaceNextChar_inc
+ jp NextChar
; 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
ScrollTextUpOneLine::
- coord hl, 0, 14 ; top row of text
- coord de, 0, 13 ; empty line above text
+ hlcoord 0, 14 ; top row of text
+ decoord 0, 13 ; empty line above text
ld b, SCREEN_WIDTH * 3
.copyText
ld a, [hli]
@@ -344,7 +293,7 @@ ScrollTextUpOneLine::
inc de
dec b
jr nz, .copyText
- coord hl, 1, 16
+ hlcoord 1, 16
ld a, " "
ld b, SCREEN_WIDTH - 2
.clearText
@@ -352,7 +301,6 @@ ScrollTextUpOneLine::
dec b
jr nz, .clearText
- ; wait five frames
ld b, 5
.WaitFrame
call DelayFrame
@@ -372,7 +320,7 @@ TextCommandProcessor::
push af
set 1, a
ld e, a
- ld a, [$fff9]
+ ldh a, [hClearLetterPrintingDelayFlags]
xor e
ld [wLetterPrintingDelayFlags], a
ld a, c
@@ -382,18 +330,18 @@ TextCommandProcessor::
NextTextCommand::
ld a, [hli]
- cp "@" ; terminator
- jr nz, .doTextCommand
+ cp TX_END
+ jr nz, .TextCommand
pop af
ld [wLetterPrintingDelayFlags], a
ret
-.doTextCommand
+
+.TextCommand:
push hl
- cp $17
- jp z, TextCommand17
- cp $0e
- jp nc, TextCommand0B ; if a != 0x17 and a >= 0xE, go to command 0xB
-; if a < 0xE, use a jump table
+ cp TX_FAR
+ jp z, TextCommand_FAR
+ cp TX_SOUND_POKEDEX_RATING
+ jp nc, TextCommand_SOUND
ld hl, TextCommandJumpTable
push bc
add a
@@ -406,12 +354,8 @@ NextTextCommand::
ld l, a
jp hl
-; draw box
-; 04AAAABBCC
-; AAAA = address of upper left corner
-; BB = height
-; CC = width
-TextCommand04::
+TextCommand_BOX::
+; draw a box (height, width)
pop hl
ld a, [hli]
ld e, a
@@ -428,9 +372,8 @@ TextCommand04::
pop hl
jr NextTextCommand
-; place string inline
-; 00{string}
-TextCommand00::
+TextCommand_START::
+; write text until "@"
pop hl
ld d, h
ld e, l
@@ -442,10 +385,8 @@ TextCommand00::
inc hl
jr NextTextCommand
-; place string from RAM
-; 01AAAA
-; AAAA = address of string
-TextCommand01::
+TextCommand_RAM::
+; write text from a ram address (little endian)
pop hl
ld a, [hli]
ld e, a
@@ -458,13 +399,8 @@ TextCommand01::
pop hl
jr NextTextCommand
-; print BCD number
-; 02AAAABB
-; AAAA = address of BCD number
-; BB
-; bits 0-4 = length in bytes
-; bits 5-7 = unknown flags
-TextCommand02::
+TextCommand_BCD::
+; write bcd from address, typically ram
pop hl
ld a, [hli]
ld e, a
@@ -481,10 +417,8 @@ TextCommand02::
pop hl
jr NextTextCommand
-; repoint destination address
-; 03AAAA
-; AAAA = new destination address
-TextCommand03::
+TextCommand_MOVE::
+; move to a new tile
pop hl
ld a, [hli]
ld [wTextDest], a
@@ -494,58 +428,47 @@ TextCommand03::
ld b, a
jp NextTextCommand
-; repoint destination to second line of dialogue text box
-; 05
-; (no arguments)
-TextCommand05::
+TextCommand_LOW::
+; write text at (1,16)
pop hl
- coord bc, 1, 16 ; address of second line of dialogue text box
+ bccoord 1, 16 ; second line of dialogue text box
jp NextTextCommand
-; blink arrow and wait for A or B to be pressed
-; 06
-; (no arguments)
-TextCommand06::
+TextCommand_PROMPT_BUTTON::
+; wait for button press; show arrow
ld a, [wLinkState]
cp LINK_STATE_BATTLING
- jp z, TextCommand0D
+ jp z, TextCommand_WAIT_BUTTON
ld a, "▼"
- Coorda 18, 16 ; place down arrow in lower right corner of dialogue text box
+ ldcoord_a 18, 16 ; place down arrow in lower right corner of dialogue text box
push bc
call ManualTextScroll ; blink arrow and wait for A or B to be pressed
pop bc
ld a, " "
- Coorda 18, 16 ; overwrite down arrow with blank space
+ ldcoord_a 18, 16 ; overwrite down arrow with blank space
pop hl
jp NextTextCommand
-; scroll text up one line
-; 07
-; (no arguments)
-TextCommand07::
+TextCommand_SCROLL::
+; pushes text up two lines and sets the BC cursor to the border tile
+; below the first character column of the text box.
ld a, " "
- Coorda 18, 16 ; place blank space in lower right corner of dialogue text box
+ ldcoord_a 18, 16 ; place blank space in lower right corner of dialogue text box
call ScrollTextUpOneLine
call ScrollTextUpOneLine
pop hl
- coord bc, 1, 16 ; address of second line of dialogue text box
+ bccoord 1, 16 ; second line of dialogue text box
jp NextTextCommand
-; execute asm inline
-; 08{code}
-TextCommand08::
+TextCommand_START_ASM::
+; run assembly code
pop hl
ld de, NextTextCommand
- push de ; return address
+ push de
jp hl
-; print decimal number (converted from binary number)
-; 09AAAABB
-; AAAA = address of number
-; BB
-; bits 0-3 = how many digits to display
-; bits 4-7 = how long the number is in bytes
-TextCommand09::
+TextCommand_NUM::
+; print a number
pop hl
ld a, [hli]
ld e, a
@@ -569,45 +492,42 @@ TextCommand09::
pop hl
jp NextTextCommand
-; wait half a second if the user doesn't hold A or B
-; 0A
-; (no arguments)
-TextCommand0A::
+TextCommand_PAUSE::
+; wait for button press or 30 frames
push bc
call Joypad
- ld a, [hJoyHeld]
+ ldh a, [hJoyHeld]
and A_BUTTON | B_BUTTON
- jr nz, .skipDelay
- ld c, 30
+ jr nz, .done
+ ld c, 30 ; half a second
call DelayFrames
-.skipDelay
+.done
pop bc
pop hl
jp NextTextCommand
-; plays sounds
-; this actually handles various command ID's, not just 0B
-; (no arguments)
-TextCommand0B::
+TextCommand_SOUND::
+; play a sound effect from TextCommandSounds
pop hl
push bc
dec hl
ld a, [hli]
- ld b, a ; b = command number that got us here
+ ld b, a ; b = text command number that got us here
push hl
ld hl, TextCommandSounds
.loop
ld a, [hli]
cp b
- jr z, .matchFound
+ jr z, .play
inc hl
jr .loop
-.matchFound
- cp $14
+
+.play
+ cp TX_SOUND_CRY_PIKACHU
jr z, .pokemonCry
- cp $15
+ cp TX_SOUND_CRY_PIDGEOT
jr z, .pokemonCry
- cp $16
+ cp TX_SOUND_CRY_DEWGONG
jr z, .pokemonCry
ld a, [hl]
call PlaySound
@@ -615,6 +535,7 @@ TextCommand0B::
pop hl
pop bc
jp NextTextCommand
+
.pokemonCry
push de
ld a, [hl]
@@ -624,95 +545,95 @@ TextCommand0B::
pop bc
jp NextTextCommand
-; format: text command ID, sound ID or cry ID
TextCommandSounds::
- db $0B, SFX_GET_ITEM_1
- db $12, SFX_TURN_OFF_PC
- db $0E, SFX_POKEDEX_RATING
- db $0F, SFX_GET_ITEM_1
- db $10, SFX_GET_ITEM_2
- db $11, SFX_GET_KEY_ITEM
- db $13, SFX_TRADE_MACHINE
- db $14, PIKACHU ; used in OakSpeech
- db $15, PIDGEOT ; used in SaffronCityText12
- db $16, DEWGONG ; unused?
+ db TX_SOUND_GET_ITEM_1, SFX_GET_ITEM_1 ; actually plays SFX_LEVEL_UP when the battle music engine is loaded
+ db TX_SOUND_CAUGHT_MON, SFX_CAUGHT_MON
+ db TX_SOUND_POKEDEX_RATING, SFX_POKEDEX_RATING ; unused
+ db TX_SOUND_GET_ITEM_1_DUPLICATE, SFX_GET_ITEM_1 ; unused
+ db TX_SOUND_GET_ITEM_2, SFX_GET_ITEM_2
+ db TX_SOUND_GET_KEY_ITEM, SFX_GET_KEY_ITEM
+ db TX_SOUND_DEX_PAGE_ADDED, SFX_DEX_PAGE_ADDED
+ db TX_SOUND_CRY_PIKACHU, PIKACHU ; used in OakSpeech
+ db TX_SOUND_CRY_PIDGEOT, PIDGEOT ; used in SaffronCityText12
+ db TX_SOUND_CRY_DEWGONG, DEWGONG ; unused
-; draw ellipses
-; 0CAA
-; AA = number of ellipses to draw
-TextCommand0C::
+TextCommand_DOTS::
+; wait for button press or 30 frames while printing "…"s
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 Joypad
pop de
- ld a, [hJoyHeld] ; joypad state
+ ldh a, [hJoyHeld] ; joypad state
and A_BUTTON | B_BUTTON
- jr nz, .skipDelay ; if so, skip the delay
+ jr nz, .next ; if so, skip the delay
ld c, 10
call DelayFrames
-.skipDelay
+.next
dec d
jr nz, .loop
+
ld b, h
ld c, l
pop hl
jp NextTextCommand
-; wait for A or B to be pressed
-; 0D
-; (no arguments)
-TextCommand0D::
+TextCommand_WAIT_BUTTON::
+; wait for button press; don't show arrow
push bc
- call ManualTextScroll ; wait for A or B to be pressed
+ call ManualTextScroll
pop bc
pop hl
jp NextTextCommand
-; process text commands in another ROM bank
-; 17AAAABB
-; AAAA = address of text commands
-; BB = bank
-TextCommand17::
+TextCommand_FAR::
+; write text from a different bank (little endian)
pop hl
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
+
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
- ld [H_LOADEDROMBANK], a
+
+ ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
+
push hl
ld l, e
ld h, d
call TextCommandProcessor
pop hl
+
pop af
- ld [H_LOADEDROMBANK], a
+ ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
jp NextTextCommand
TextCommandJumpTable::
- dw TextCommand00
- dw TextCommand01
- dw TextCommand02
- dw TextCommand03
- dw TextCommand04
- dw TextCommand05
- dw TextCommand06
- dw TextCommand07
- dw TextCommand08
- dw TextCommand09
- dw TextCommand0A
- dw TextCommand0B
- dw TextCommand0C
- dw TextCommand0D
+; entries correspond to TX_* constants (see macros/scripts/text.asm)
+ dw TextCommand_START ; TX_START
+ dw TextCommand_RAM ; TX_RAM
+ dw TextCommand_BCD ; TX_BCD
+ dw TextCommand_MOVE ; TX_MOVE
+ dw TextCommand_BOX ; TX_BOX
+ dw TextCommand_LOW ; TX_LOW
+ dw TextCommand_PROMPT_BUTTON ; TX_PROMPT_BUTTON
+ dw TextCommand_SCROLL ; TX_SCROLL
+ dw TextCommand_START_ASM ; TX_START_ASM
+ dw TextCommand_NUM ; TX_NUM
+ dw TextCommand_PAUSE ; TX_PAUSE
+ dw TextCommand_SOUND ; TX_SOUND_GET_ITEM_1 (also handles other TX_SOUND_* commands)
+ dw TextCommand_DOTS ; TX_DOTS
+ dw TextCommand_WAIT_BUTTON ; TX_WAIT_BUTTON
+ ; greater TX_* constants are handled directly by NextTextCommand
diff --git a/home/text_script.asm b/home/text_script.asm
new file mode 100644
index 00000000..1847e23b
--- /dev/null
+++ b/home/text_script.asm
@@ -0,0 +1,225 @@
+; this function is used to display sign messages, sprite dialog, etc.
+; INPUT: [hSpriteIndexOrTextID] = sprite ID or text ID
+DisplayTextID::
+ ldh a, [hLoadedROMBank]
+ push af
+ farcall DisplayTextIDInit ; initialization
+ ld hl, wTextPredefFlag
+ bit 0, [hl]
+ res 0, [hl]
+ jr nz, .skipSwitchToMapBank
+ ld a, [wCurMap]
+ call SwitchToMapRomBank
+.skipSwitchToMapBank
+ ld a, 30 ; half a second
+ ldh [hFrameCounter], a ; used as joypad poll timer
+ ld hl, wMapTextPtr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; hl = map text pointer
+ ld d, $00
+ ldh a, [hSpriteIndexOrTextID] ; text ID
+ ld [wSpriteIndex], a
+
+ dict TEXT_START_MENU, DisplayStartMenu
+ dict TEXT_PIKACHU_ANIM, DisplayPikachuEmotion
+ dict TEXT_SAFARI_GAME_OVER, DisplaySafariGameOverText
+ dict TEXT_MON_FAINTED, DisplayPokemonFaintedText
+ dict TEXT_BLACKED_OUT, DisplayPlayerBlackedOutText
+ dict TEXT_REPEL_WORE_OFF, DisplayRepelWoreOffText
+
+ ld a, [wNumSprites]
+ ld e, a
+ ldh a, [hSpriteIndexOrTextID] ; sprite ID
+ cp e
+ jr z, .spriteHandling
+ jr nc, .skipSpriteHandling
+.spriteHandling
+; get the text ID of the sprite
+ push hl
+ ;push de
+ ;push bc
+ ;farcall UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction)
+ ;pop bc
+ ;pop de
+ ld hl, wMapSpriteData ; NPC text entries
+ ldh a, [hSpriteIndexOrTextID]
+ dec a
+ add a
+ ld e, a
+ ld d, $0
+ add hl, de
+ inc hl
+ ld a, [hl] ; a = text ID of the sprite
+ pop hl
+.skipSpriteHandling
+; look up the address of the text in the map's text entries
+ dec a
+ ld e, a
+ ld d, $0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; hl = address of the text
+ ld a, [hl] ; a = first byte of text
+
+; check first byte of text for special cases
+
+dict2: MACRO
+ cp \1
+ jr nz, .not\@
+ \2
+ jr AfterDisplayingTextID
+.not\@
+ENDM
+
+ dict TX_SCRIPT_MART, DisplayPokemartDialogue
+ dict TX_SCRIPT_POKECENTER_NURSE, DisplayPokemonCenterDialogue
+ dict TX_SCRIPT_PLAYERS_PC, TextScript_ItemStoragePC
+ dict TX_SCRIPT_BILLS_PC, TextScript_BillsPC
+ dict TX_SCRIPT_POKECENTER_PC, TextScript_PokemonCenterPC
+ dict2 TX_SCRIPT_VENDING_MACHINE, farcall VendingMachineMenu
+ dict TX_SCRIPT_PRIZE_VENDOR, TextScript_GameCornerPrizeMenu
+ dict2 TX_SCRIPT_CABLE_CLUB_RECEPTIONIST, callfar CableClubNPC
+
+ call PrintText_NoCreatingTextBox ; display the text
+ ld a, [wDoNotWaitForButtonPressAfterDisplayingText]
+ and a
+ jr nz, HoldTextDisplayOpen
+
+AfterDisplayingTextID::
+ ld a, [wEnteringCableClub]
+ and a
+ jr nz, HoldTextDisplayOpen
+ call WaitForTextScrollButtonPress ; wait for a button press after displaying all the text
+
+; loop to hold the dialogue box open as long as the player keeps holding down the A button
+HoldTextDisplayOpen::
+ call Joypad
+ ldh a, [hJoyHeld]
+ bit 0, a ; is the A button being pressed?
+ jr nz, HoldTextDisplayOpen
+
+CloseTextDisplay::
+ ld a, [wCurMap]
+ call SwitchToMapRomBank
+ ld a, $90
+ ldh [hWY], a ; move the window off the screen
+ call DelayFrame
+ call LoadGBPal
+ xor a
+ ldh [hAutoBGTransferEnabled], a ; disable continuous WRAM to VRAM transfer each V-blank
+; loop to make sprites face the directions they originally faced before the dialogue
+ ld hl, wSprite01StateData2OrigFacingDirection
+ ld c, $0f
+ ld de, $10
+.restoreSpriteFacingDirectionLoop
+ ld a, [hl] ; x#SPRITESTATEDATA2_ORIGFACINGDIRECTION
+ dec h
+ ld [hl], a ; [x#SPRITESTATEDATA1_FACINGDIRECTION]
+ inc h
+ add hl, de
+ dec c
+ jr nz, .restoreSpriteFacingDirectionLoop
+ call InitMapSprites ; reload sprite tile pattern data (since it was partially overwritten by text tile patterns)
+ ld hl, wFontLoaded
+ res 0, [hl]
+ ld a, [wd732]
+ bit 3, a ; used fly warp
+ call z, LoadPlayerSpriteGraphics
+ call LoadCurrentMapView
+ pop af
+ call BankswitchCommon
+ jp UpdateSprites
+
+DisplayPokemartDialogue::
+ push hl
+ ld hl, PokemartGreetingText
+ call PrintText
+ pop hl
+ inc hl
+ call LoadItemList
+ ld a, PRICEDITEMLISTMENU
+ ld [wListMenuID], a
+ homecall DisplayPokemartDialogue_
+ jp AfterDisplayingTextID
+
+PokemartGreetingText::
+ text_far _PokemartGreetingText
+ text_end
+
+LoadItemList::
+ ld a, 1
+ ld [wUpdateSpritesEnabled], a
+ ld a, h
+ ld [wItemListPointer], a
+ ld a, l
+ ld [wItemListPointer + 1], a
+ ld de, wItemList
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ cp $ff
+ jr nz, .loop
+ ret
+
+DisplayPokemonCenterDialogue::
+; zeroing these doesn't appear to serve any purpose
+ xor a
+ ldh [hItemPrice], a
+ ldh [hItemPrice + 1], a
+ ldh [hItemPrice + 2], a
+
+ inc hl
+ homecall DisplayPokemonCenterDialogue_
+ jp AfterDisplayingTextID
+
+DisplaySafariGameOverText::
+ callfar PrintSafariGameOverText
+ jp AfterDisplayingTextID
+
+DisplayPokemonFaintedText::
+ ld hl, PokemonFaintedText
+ call PrintText
+ jp AfterDisplayingTextID
+
+PokemonFaintedText::
+ text_far _PokemonFaintedText
+ text_end
+
+DisplayPlayerBlackedOutText::
+ ld hl, PlayerBlackedOutText
+ call PrintText
+ ld a, [wd732]
+ res 5, a ; reset forced to use bike bit
+ ld [wd732], a
+ CheckEvent EVENT_IN_SAFARI_ZONE
+ jr z, .didnotblackoutinsafari
+ xor a
+ ld [wNumSafariBalls], a
+ ld [wSafariSteps], a
+ ld [wSafariSteps + 1], a
+ EventFlagAddressa EVENT_IN_SAFARI_ZONE
+ ld [wcf0d], a
+ ld [wSafariZoneGateCurScript], a
+.didnotblackoutinsafari
+ jp HoldTextDisplayOpen
+
+PlayerBlackedOutText::
+ text_far _PlayerBlackedOutText
+ text_end
+
+DisplayRepelWoreOffText::
+ ld hl, RepelWoreOffText
+ call PrintText
+ jp AfterDisplayingTextID
+
+RepelWoreOffText::
+ text_far _RepelWoreOffText
+ text_end
+
+DisplayPikachuEmotion::
+ callfar TalkToPikachu
+ jp CloseTextDisplay
diff --git a/home/textbox.asm b/home/textbox.asm
new file mode 100644
index 00000000..f95c72c7
--- /dev/null
+++ b/home/textbox.asm
@@ -0,0 +1,7 @@
+; function to draw various text boxes
+; INPUT:
+; [wTextBoxID] = text box ID
+; b, c = y, x cursor position (TWO_OPTION_MENU only)
+DisplayTextBoxID::
+ homecall_sf DisplayTextBoxID_
+ ret
diff --git a/home/tilemap.asm b/home/tilemap.asm
new file mode 100644
index 00000000..ea247763
--- /dev/null
+++ b/home/tilemap.asm
@@ -0,0 +1,45 @@
+UncompressSpriteFromDE::
+; Decompress pic at a:de.
+ ld hl, wSpriteInputPtr
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ jp UncompressSpriteData
+
+SaveScreenTilesToBuffer2::
+ hlcoord 0, 0
+ ld de, wTileMapBackup2
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ jp CopyData
+
+LoadScreenTilesFromBuffer2::
+ call LoadScreenTilesFromBuffer2DisableBGTransfer
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+; loads screen tiles stored in wTileMapBackup2 but leaves hAutoBGTransferEnabled disabled
+LoadScreenTilesFromBuffer2DisableBGTransfer::
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld hl, wTileMapBackup2
+ decoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ jp CopyData
+
+SaveScreenTilesToBuffer1::
+ hlcoord 0, 0
+ ld de, wTileMapBackup
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ jp CopyData
+
+LoadScreenTilesFromBuffer1::
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld hl, wTileMapBackup
+ decoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ call CopyData
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
+ ret
diff --git a/home/trainers.asm b/home/trainers.asm
new file mode 100644
index 00000000..f407652a
--- /dev/null
+++ b/home/trainers.asm
@@ -0,0 +1,426 @@
+; stores hl in [wTrainerHeaderPtr]
+StoreTrainerHeaderPointer::
+ ld a, h
+ ld [wTrainerHeaderPtr], a
+ ld a, l
+ ld [wTrainerHeaderPtr+1], a
+ ret
+
+; executes the current map script from the function pointer array provided in de.
+; a: map script index to execute (unless overridden by [wd733] bit 4)
+; hl: trainer header pointer
+ExecuteCurMapScriptInTable::
+ push af
+ push de
+ call StoreTrainerHeaderPointer
+ pop hl
+ pop af
+ push hl
+ ld hl, wFlags_D733
+ bit 4, [hl]
+ res 4, [hl]
+ jr z, .useProvidedIndex ; test if map script index was overridden manually
+ ld a, [wCurMapScript]
+.useProvidedIndex
+ pop hl
+ ld [wCurMapScript], a
+ call CallFunctionInTable
+ ld a, [wCurMapScript]
+ ret
+
+LoadGymLeaderAndCityName::
+ push de
+ ld de, wGymCityName
+ ld bc, $11
+ call CopyData ; load city name
+ pop hl
+ ld de, wGymLeaderName
+ ld bc, NAME_LENGTH
+ jp CopyData ; load gym leader name
+
+; reads specific information from trainer header (pointed to at wTrainerHeaderPtr)
+; a: offset in header data
+; 0 -> flag's bit (into wTrainerHeaderFlagBit)
+; 2 -> flag's byte ptr (into hl)
+; 4 -> before battle text (into hl)
+; 6 -> after battle text (into hl)
+; 8 -> end battle text (into hl)
+ReadTrainerHeaderInfo::
+ push de
+ push af
+ ld d, $0
+ ld e, a
+ ld hl, wTrainerHeaderPtr
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+ add hl, de
+ pop af
+ and a
+ jr nz, .nonZeroOffset
+ ld a, [hl]
+ ld [wTrainerHeaderFlagBit], a ; store flag's bit
+ jr .done
+.nonZeroOffset
+ cp $2
+ jr z, .readPointer ; read flag's byte ptr
+ cp $4
+ jr z, .readPointer ; read before battle text
+ cp $6
+ jr z, .readPointer ; read after battle text
+ cp $8
+ jr z, .readPointer ; read end battle text
+ cp $a
+ jr nz, .done
+ ld a, [hli] ; read end battle text (2) but override the result afterwards (XXX why, bug?)
+ ld d, [hl]
+ ld e, a
+ jr .done
+.readPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.done
+ pop de
+ ret
+
+TrainerFlagAction::
+ predef_jump FlagActionPredef
+
+TalkToTrainer::
+ call StoreTrainerHeaderPointer
+ xor a
+ call ReadTrainerHeaderInfo ; read flag's bit
+ ld a, $2
+ call ReadTrainerHeaderInfo ; read flag's byte ptr
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ ld b, FLAG_TEST
+ call TrainerFlagAction ; read trainer's flag
+ ld a, c
+ and a
+ jr z, .trainerNotYetFought ; test trainer's flag
+ ld a, $6
+ call ReadTrainerHeaderInfo ; print after battle text
+ jp PrintText
+.trainerNotYetFought
+ ld a, $4
+ call ReadTrainerHeaderInfo ; print before battle text
+ call PrintText
+ ld a, $a
+ call ReadTrainerHeaderInfo ; (?) does nothing apparently (maybe bug in ReadTrainerHeaderInfo)
+ push de
+ ld a, $8
+ call ReadTrainerHeaderInfo ; read end battle text
+ pop de
+ call SaveEndBattleTextPointers
+ ld hl, wFlags_D733
+ set 4, [hl] ; activate map script index override (index is set below)
+ ld hl, wFlags_0xcd60
+ bit 0, [hl] ; test if player is already engaging the trainer (because the trainer saw the player)
+ ret nz
+; if the player talked to the trainer of his own volition
+ call EngageMapTrainer
+ ld hl, wCurMapScript
+ inc [hl] ; increment map script index before StartTrainerBattle increments it again (next script function is usually EndTrainerBattle)
+ jp StartTrainerBattle
+
+; checks if any trainers are seeing the player and wanting to fight
+CheckFightingMapTrainers::
+ call CheckForEngagingTrainers
+ ld a, [wSpriteIndex]
+ cp $ff
+ jr nz, .trainerEngaging
+.trainerNotEngaging
+ xor a
+ ld [wSpriteIndex], a
+ ld [wTrainerHeaderFlagBit], a
+ ret
+.trainerEngaging
+ ld hl, wFlags_D733
+ set 3, [hl]
+ ld [wEmotionBubbleSpriteIndex], a
+ xor a ; EXCLAMATION_BUBBLE
+ ld [wWhichEmotionBubble], a
+ predef EmotionBubble
+ ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
+ ld [wJoyIgnore], a
+ xor a
+ ldh [hJoyHeld], a
+ call TrainerWalkUpToPlayer_Bank0
+ ld hl, wCurMapScript
+ inc [hl] ; increment map script index (next script function is usually DisplayEnemyTrainerTextAndStartBattle)
+ ret
+
+; display the before battle text after the enemy trainer has walked up to the player's sprite
+DisplayEnemyTrainerTextAndStartBattle::
+ ld a, [wd730]
+ and $1
+ ret nz ; return if the enemy trainer hasn't finished walking to the player's sprite
+ ld [wJoyIgnore], a
+ ld a, [wSpriteIndex]
+ ldh [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ ; fall through
+
+StartTrainerBattle::
+ xor a
+ ld [wJoyIgnore], a
+ call InitBattleEnemyParameters
+ ld hl, wd72d
+ set 6, [hl]
+ set 7, [hl]
+ ld hl, wd72e
+ set 1, [hl]
+ ld hl, wCurMapScript
+ inc [hl] ; increment map script index (next script function is usually EndTrainerBattle)
+ ret
+
+EndTrainerBattle::
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+ set 6, [hl]
+ ld hl, wd72d
+ res 7, [hl]
+ ld hl, wFlags_0xcd60
+ res 0, [hl] ; player is no longer engaged by any trainer
+ ld a, [wIsInBattle]
+ cp $ff
+ jp z, ResetButtonPressedAndMapScript
+ ld a, $2
+ call ReadTrainerHeaderInfo
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ ld b, FLAG_SET
+ call TrainerFlagAction ; flag trainer as fought
+ ld a, [wEnemyMonOrTrainerClass]
+ cp OPP_ID_OFFSET
+ jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite)
+ ld hl, wMissableObjectList
+ ld de, $2
+ ld a, [wSpriteIndex]
+ call IsInArray ; search for sprite ID
+ inc hl
+ ld a, [hl]
+ ld [wMissableObjectIndex], a ; load corresponding missable object index and remove it
+ predef HideObject
+.skipRemoveSprite
+ ld hl, wd730
+ bit 4, [hl]
+ res 4, [hl]
+ ret nz
+
+ResetButtonPressedAndMapScript::
+ xor a
+ ld [wJoyIgnore], a
+ ldh [hJoyHeld], a
+ ldh [hJoyPressed], a
+ ldh [hJoyReleased], a
+ ld [wCurMapScript], a ; reset battle status
+ ret
+
+; calls TrainerWalkUpToPlayer
+TrainerWalkUpToPlayer_Bank0::
+ farjp TrainerWalkUpToPlayer
+
+; sets opponent type and mon set/lvl based on the engaging trainer data
+InitBattleEnemyParameters::
+ ld a, [wEngagedTrainerClass]
+ ld [wCurOpponent], a
+ ld [wEnemyMonOrTrainerClass], a
+ cp OPP_ID_OFFSET
+ ld a, [wEngagedTrainerSet]
+ jr c, .noTrainer
+ ld [wTrainerNo], a
+ ret
+.noTrainer
+ ld [wCurEnemyLVL], a
+ ret
+
+GetSpritePosition1::
+ ld hl, _GetSpritePosition1
+ jr SpritePositionBankswitch
+
+GetSpritePosition2::
+ ld hl, _GetSpritePosition2
+ jr SpritePositionBankswitch
+
+SetSpritePosition1::
+ ld hl, _SetSpritePosition1
+ jr SpritePositionBankswitch
+
+SetSpritePosition2::
+ ld hl, _SetSpritePosition2
+SpritePositionBankswitch::
+ ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2)
+ jp Bankswitch ; indirect jump to one of the four functions
+
+CheckForEngagingTrainers::
+ xor a
+ call ReadTrainerHeaderInfo ; read trainer flag's bit (unused)
+ ld d, h ; store trainer header address in de
+ ld e, l
+.trainerLoop
+ call StoreTrainerHeaderPointer ; set trainer header pointer to current trainer
+ ld a, [de]
+ ld [wSpriteIndex], a ; store trainer flag's bit
+ ld [wTrainerHeaderFlagBit], a
+ cp -1
+ ret z
+ ld a, $2
+ call ReadTrainerHeaderInfo ; read trainer flag's byte ptr
+ ld b, FLAG_TEST
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ call TrainerFlagAction ; read trainer flag
+ ld a, c
+ and a ; has the trainer already been defeated?
+ jr nz, .continue
+ push hl
+ push de
+ push hl
+ xor a
+ call ReadTrainerHeaderInfo ; get trainer header pointer
+ inc hl
+ ld a, [hl] ; read trainer engage distance
+ pop hl
+ ld [wTrainerEngageDistance], a
+ ld a, [wSpriteIndex]
+ swap a
+ ld [wTrainerSpriteOffset], a
+ predef TrainerEngage
+ pop de
+ pop hl
+ ld a, [wTrainerSpriteOffset]
+ and a
+ ret nz ; break if the trainer is engaging
+.continue
+ ld hl, $c
+ add hl, de
+ ld d, h
+ ld e, l
+ jr .trainerLoop
+
+; hl = text if the player wins
+; de = text if the player loses
+SaveEndBattleTextPointers::
+ ldh a, [hLoadedROMBank]
+ ld [wEndBattleTextRomBank], a
+ ld a, h
+ ld [wEndBattleWinTextPointer], a
+ ld a, l
+ ld [wEndBattleWinTextPointer + 1], a
+ ld a, d
+ ld [wEndBattleLoseTextPointer], a
+ ld a, e
+ ld [wEndBattleLoseTextPointer + 1], a
+ ret
+
+; loads data of some trainer on the current map and plays pre-battle music
+; [wSpriteIndex]: sprite ID of trainer who is engaged
+EngageMapTrainer::
+ ld hl, wMapSpriteExtraData
+ ld d, $0
+ ld a, [wSpriteIndex]
+ dec a
+ add a
+ ld e, a
+ add hl, de ; seek to engaged trainer data
+ ld a, [hli] ; load trainer class
+ ld [wEngagedTrainerClass], a
+ ld a, [hl] ; load trainer mon set
+ ld [wEngagedTrainerSet], a
+ jp PlayTrainerMusic
+
+PrintEndBattleText::
+ push hl
+ ld hl, wd72d
+ bit 7, [hl]
+ res 7, [hl]
+ pop hl
+ ret z
+ ldh a, [hLoadedROMBank]
+ push af
+ ld a, [wEndBattleTextRomBank]
+ ldh [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ push hl
+ farcall SaveTrainerName
+ ld hl, TrainerEndBattleText
+ call PrintText
+ pop hl
+ pop af
+ ldh [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ farcall FreezeEnemyTrainerSprite
+ jp WaitForSoundToFinish
+
+GetSavedEndBattleTextPointer::
+ ld a, [wBattleResult]
+ and a
+; won battle
+ jr nz, .lostBattle
+ ld a, [wEndBattleWinTextPointer]
+ ld h, a
+ ld a, [wEndBattleWinTextPointer + 1]
+ ld l, a
+ ret
+.lostBattle
+ ld a, [wEndBattleLoseTextPointer]
+ ld h, a
+ ld a, [wEndBattleLoseTextPointer + 1]
+ ld l, a
+ ret
+
+TrainerEndBattleText::
+ text_far _TrainerNameText
+ text_asm
+ call GetSavedEndBattleTextPointer
+ call TextCommandProcessor
+ jp TextScriptEnd
+
+PlayTrainerMusic::
+ ld a, [wEngagedTrainerClass]
+ cp OPP_RIVAL1
+ ret z
+ cp OPP_RIVAL2
+ ret z
+ cp OPP_RIVAL3
+ ret z
+ ld a, [wGymLeaderNo]
+ and a
+ ret nz
+ xor a
+ ld [wAudioFadeOutControl], a
+ call StopAllMusic
+ ld a, BANK(Music_MeetEvilTrainer)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ ld a, [wEngagedTrainerClass]
+ ld b, a
+ ld hl, EvilTrainerList
+.evilTrainerListLoop
+ ld a, [hli]
+ cp $ff
+ jr z, .noEvilTrainer
+ cp b
+ jr nz, .evilTrainerListLoop
+ ld a, MUSIC_MEET_EVIL_TRAINER
+ jr .PlaySound
+.noEvilTrainer
+ ld hl, FemaleTrainerList
+.femaleTrainerListLoop
+ ld a, [hli]
+ cp $ff
+ jr z, .maleTrainer
+ cp b
+ jr nz, .femaleTrainerListLoop
+ ld a, MUSIC_MEET_FEMALE_TRAINER
+ jr .PlaySound
+.maleTrainer
+ ld a, MUSIC_MEET_MALE_TRAINER
+.PlaySound
+ ld [wNewSoundID], a
+ jp PlaySound
+
+INCLUDE "data/trainers/encounter_types.asm"
diff --git a/home/trainers2.asm b/home/trainers2.asm
new file mode 100644
index 00000000..78fb6463
--- /dev/null
+++ b/home/trainers2.asm
@@ -0,0 +1,54 @@
+GetTrainerInformation::
+ call GetTrainerName
+ ld a, [wLinkState]
+ and a
+ jr nz, .linkBattle
+ ld a, BANK(TrainerPicAndMoneyPointers)
+ call BankswitchHome
+ ld a, [wTrainerClass]
+ dec a
+ ld hl, TrainerPicAndMoneyPointers
+ ld bc, $5
+ call AddNTimes
+ ld de, wTrainerPicPointer
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld de, wTrainerBaseMoney
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ call IsFightingJessieJames
+ jp BankswitchBack
+.linkBattle
+ ld hl, wTrainerPicPointer
+ ld de, RedPicFront
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ret
+
+IsFightingJessieJames::
+ ld a, [wTrainerClass]
+ cp ROCKET
+ ret nz
+ ld a, [wTrainerNo]
+ cp $2a
+ ret c
+ ld de, JessieJamesPic
+ cp $2e
+ jr c, .dummy
+ ld de, JessieJamesPic ; possibly meant to add another pic
+.dummy
+ ld hl, wTrainerPicPointer
+ ld a, e
+ ld [hli], a
+ ld [hl], d
+ ret
+
+GetTrainerName::
+ farjp GetTrainerName_
diff --git a/home/pic.asm b/home/uncompress.asm
index 236efe9d..182821aa 100644
--- a/home/pic.asm
+++ b/home/uncompress.asm
@@ -2,11 +2,11 @@
; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr
UncompressSpriteData::
ld b, a
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
push af
ld a, b
call BankswitchCommon
- ld a,$0
+ ld a, $0
call SwitchSRAMBankAndLatchClockData
call _UncompressSpriteData
call PrepareRTCDataAndDisableSRAM
@@ -17,8 +17,8 @@ UncompressSpriteData::
; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
_UncompressSpriteData::
ld hl, sSpriteBuffer1
- ld c, (2*SPRITEBUFFERSIZE) % $100
- ld b, (2*SPRITEBUFFERSIZE) / $100
+ ld c, LOW(2 * SPRITEBUFFERSIZE)
+ ld b, HIGH(2 * SPRITEBUFFERSIZE)
xor a
call FillMemory ; clear sprite buffer 1 and 2
ld a, $1
diff --git a/home/update_sprites.asm b/home/update_sprites.asm
new file mode 100644
index 00000000..0c32dad8
--- /dev/null
+++ b/home/update_sprites.asm
@@ -0,0 +1,15 @@
+UpdateSprites::
+ ld a, [wUpdateSpritesEnabled]
+ dec a
+ ret nz
+ ldh a, [hLoadedROMBank]
+ push af
+ switchbank _UpdateSprites
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ call _UpdateSprites
+ ld a, $1
+ ld [wUpdateSpritesEnabled], a
+ pop af
+ call BankswitchCommon
+ ret
diff --git a/home/vblank.asm b/home/vblank.asm
index 764e5277..ed39714f 100644
--- a/home/vblank.asm
+++ b/home/vblank.asm
@@ -5,24 +5,24 @@ VBlank::
push de
push hl
- ld a, [rVBK] ; vram bank
+ ldh a, [rVBK] ; vram bank
push af
xor a
- ld [rVBK], a ; reset vram bank to 0
+ ldh [rVBK], a ; reset vram bank to 0
- ld a, [H_LOADEDROMBANK]
+ ldh a, [hLoadedROMBank]
ld [wVBlankSavedROMBank], a
- ld a, [hSCX]
- ld [rSCX], a
- ld a, [hSCY]
- ld [rSCY], a
+ ldh a, [hSCX]
+ ldh [rSCX], a
+ ldh a, [hSCY]
+ ldh [rSCY], a
ld a, [wDisableVBlankWYUpdate]
and a
jr nz, .ok
- ld a, [hWY]
- ld [rWY], a
+ ldh a, [hWY]
+ ldh [rWY], a
.ok
call AutoBgMapTransfer
@@ -31,9 +31,9 @@ VBlank::
call VBlankCopy
call VBlankCopyDouble
call UpdateMovingBgTiles
- call $ff80 ; hOAMDMA
+ call hDMARoutine
ld a, BANK(PrepareOAMData)
- ld [H_LOADEDROMBANK], a
+ ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call PrepareOAMData
@@ -43,18 +43,18 @@ VBlank::
call Random
call ReadJoypad
- ld a, [H_VBLANKOCCURRED]
+ ldh a, [hVBlankOccurred]
and a
jr z, .skipZeroing
xor a
- ld [H_VBLANKOCCURRED], a
+ ldh [hVBlankOccurred], a
.skipZeroing
- ld a, [H_FRAMECOUNTER]
+ ldh a, [hFrameCounter]
and a
jr z, .skipDec
dec a
- ld [H_FRAMECOUNTER], a
+ ldh [hFrameCounter], a
.skipDec
call FadeOutAudio
@@ -65,11 +65,11 @@ VBlank::
call SerialFunction
ld a, [wVBlankSavedROMBank]
- ld [H_LOADEDROMBANK], a
+ ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
pop af
- ld [rVBK],a
+ ldh [rVBK], a
pop hl
pop de
@@ -85,10 +85,10 @@ DelayFrame::
NOT_VBLANKED EQU 1
ld a, NOT_VBLANKED
- ld [H_VBLANKOCCURRED], a
+ ldh [hVBlankOccurred], a
.halt
halt
- ld a, [H_VBLANKOCCURRED]
+ ldh a, [hVBlankOccurred]
and a
jr nz, .halt
ret
diff --git a/home/vcopy.asm b/home/vcopy.asm
index bec679c4..9b6efb3a 100644
--- a/home/vcopy.asm
+++ b/home/vcopy.asm
@@ -40,19 +40,19 @@ ClearBgMap::
; However, this function is also called repeatedly to redraw the whole screen
; when necessary. It is also used in trade animation and elevator code.
RedrawRowOrColumn::
- ld a, [hRedrawRowOrColumnMode]
+ ldh a, [hRedrawRowOrColumnMode]
and a
ret z
ld b, a
xor a
- ld [hRedrawRowOrColumnMode], a
+ ldh [hRedrawRowOrColumnMode], a
dec b
jr nz, .redrawRow
.redrawColumn
ld hl, wRedrawRowOrColumnSrcTiles
- ld a, [hRedrawRowOrColumnDest]
+ ldh a, [hRedrawRowOrColumnDest]
ld e, a
- ld a, [hRedrawRowOrColumnDest + 1]
+ ldh a, [hRedrawRowOrColumnDest + 1]
ld d, a
ld c, SCREEN_HEIGHT
.loop1
@@ -75,13 +75,13 @@ RedrawRowOrColumn::
dec c
jr nz, .loop1
xor a
- ld [hRedrawRowOrColumnMode], a
+ ldh [hRedrawRowOrColumnMode], a
ret
.redrawRow
ld hl, wRedrawRowOrColumnSrcTiles
- ld a, [hRedrawRowOrColumnDest]
+ ldh a, [hRedrawRowOrColumnDest]
ld e, a
- ld a, [hRedrawRowOrColumnDest + 1]
+ ldh a, [hRedrawRowOrColumnDest + 1]
ld d, a
push de
call .DrawHalf ; draw upper half
@@ -120,59 +120,59 @@ RedrawRowOrColumn::
; the above function, RedrawRowOrColumn, is used when walking to
; improve efficiency.
AutoBgMapTransfer::
- ld a, [H_AUTOBGTRANSFERENABLED]
+ ldh a, [hAutoBGTransferEnabled]
and a
ret z
- ld [H_SPTEMP], sp ; save stack pointer
- ld a, [H_AUTOBGTRANSFERPORTION]
+ ld [hSPTemp], sp ; save stack pointer
+ ldh a, [hAutoBGTransferPortion]
and a
jr z, .transferTopThird
dec a
jr z, .transferMiddleThird
.transferBottomThird
- coord hl, 0, 12
+ hlcoord 0, 12
ld sp, hl
- ld a, [H_AUTOBGTRANSFERDEST + 1]
+ ldh a, [hAutoBGTransferDest + 1]
ld h, a
- ld a, [H_AUTOBGTRANSFERDEST]
+ ldh a, [hAutoBGTransferDest]
ld l, a
ld de, (12 * 32)
add hl, de
xor a ; TRANSFERTOP
jr .doTransfer
.transferTopThird
- coord hl, 0, 0
+ hlcoord 0, 0
ld sp, hl
- ld a, [H_AUTOBGTRANSFERDEST + 1]
+ ldh a, [hAutoBGTransferDest + 1]
ld h, a
- ld a, [H_AUTOBGTRANSFERDEST]
+ ldh a, [hAutoBGTransferDest]
ld l, a
ld a, TRANSFERMIDDLE
jr .doTransfer
.transferMiddleThird
- coord hl, 0, 6
+ hlcoord 0, 6
ld sp, hl
- ld a, [H_AUTOBGTRANSFERDEST + 1]
+ ldh a, [hAutoBGTransferDest + 1]
ld h, a
- ld a, [H_AUTOBGTRANSFERDEST]
+ ldh a, [hAutoBGTransferDest]
ld l, a
ld de, (6 * 32)
add hl, de
ld a, TRANSFERBOTTOM
.doTransfer
- ld [H_AUTOBGTRANSFERPORTION], a ; store next portion
+ ldh [hAutoBGTransferPortion], a ; store next portion
ld b, 6
TransferBgRows::
; unrolled loop and using pop for speed
- rept 20 / 2 - 1
+ REPT 20 / 2 - 1
pop de
ld [hl], e
inc l
ld [hl], d
inc l
- endr
+ ENDR
pop de
ld [hl], e
@@ -188,68 +188,68 @@ TransferBgRows::
dec b
jr nz, TransferBgRows
- ld a, [H_SPTEMP]
+ ldh a, [hSPTemp]
ld l, a
- ld a, [H_SPTEMP + 1]
+ ldh a, [hSPTemp + 1]
ld h, a
ld sp, hl
ret
-; Copies [H_VBCOPYBGNUMROWS] rows from H_VBCOPYBGSRC to H_VBCOPYBGDEST.
-; If H_VBCOPYBGSRC is XX00, the transfer is disabled.
+; Copies [hVBlankCopyBGNumRows] rows from hVBlankCopyBGSource to hVBlankCopyBGDest.
+; If hVBlankCopyBGSource is XX00, the transfer is disabled.
VBlankCopyBgMap::
- ld a, [H_VBCOPYBGSRC] ; doubles as enabling byte
+ ldh a, [hVBlankCopyBGSource] ; doubles as enabling byte
and a
ret z
- ld [H_SPTEMP], sp ; save stack pointer
- ld a, [H_VBCOPYBGSRC]
+ ld [hSPTemp], sp ; save stack pointer
+ ldh a, [hVBlankCopyBGSource]
ld l, a
- ld a, [H_VBCOPYBGSRC + 1]
+ ldh a, [hVBlankCopyBGSource + 1]
ld h, a
ld sp, hl
- ld a, [H_VBCOPYBGDEST]
+ ldh a, [hVBlankCopyBGDest]
ld l, a
- ld a, [H_VBCOPYBGDEST + 1]
+ ldh a, [hVBlankCopyBGDest + 1]
ld h, a
- ld a, [H_VBCOPYBGNUMROWS]
+ ldh a, [hVBlankCopyBGNumRows]
ld b, a
xor a
- ld [H_VBCOPYBGSRC], a ; disable transfer so it doesn't continue next V-blank
+ ldh [hVBlankCopyBGSource], a ; disable transfer so it doesn't continue next V-blank
jr TransferBgRows
VBlankCopyDouble::
-; Copy [H_VBCOPYDOUBLESIZE] 1bpp tiles
-; from H_VBCOPYDOUBLESRC to H_VBCOPYDOUBLEDEST.
+; Copy [hVBlankCopyDoubleSize] 1bpp tiles
+; from hVBlankCopyDoubleSource to hVBlankCopyDoubleDest.
; While we're here, convert to 2bpp.
; The process is straightforward:
; copy each byte twice.
- ld a, [H_VBCOPYDOUBLESIZE]
+ ldh a, [hVBlankCopyDoubleSize]
and a
ret z
- ld [H_SPTEMP], sp ; save stack pointer
+ ld [hSPTemp], sp ; save stack pointer
- ld a, [H_VBCOPYDOUBLESRC]
+ ldh a, [hVBlankCopyDoubleSource]
ld l, a
- ld a, [H_VBCOPYDOUBLESRC + 1]
+ ldh a, [hVBlankCopyDoubleSource + 1]
ld h, a
ld sp, hl
- ld a, [H_VBCOPYDOUBLEDEST]
+ ldh a, [hVBlankCopyDoubleDest]
ld l, a
- ld a, [H_VBCOPYDOUBLEDEST + 1]
+ ldh a, [hVBlankCopyDoubleDest + 1]
ld h, a
- ld a, [H_VBCOPYDOUBLESIZE]
+ ldh a, [hVBlankCopyDoubleSize]
ld b, a
xor a ; transferred
- ld [H_VBCOPYDOUBLESIZE], a
+ ldh [hVBlankCopyDoubleSize], a
.loop
- rept 3
+ REPT 3
pop de
ld [hl], e
inc l
@@ -259,7 +259,7 @@ VBlankCopyDouble::
inc l
ld [hl], d
inc l
- endr
+ ENDR
pop de
ld [hl], e
@@ -273,13 +273,13 @@ VBlankCopyDouble::
dec b
jr nz, .loop
- ld [H_VBCOPYDOUBLESRC], sp
+ ld [hVBlankCopyDoubleSource], sp
ld sp, hl ; load destination into sp to save time with ld [$xxxx], sp
- ld [H_VBCOPYDOUBLEDEST], sp
+ ld [hVBlankCopyDoubleDest], sp
- ld a, [H_SPTEMP]
+ ldh a, [hSPTemp]
ld l, a
- ld a, [H_SPTEMP + 1]
+ ldh a, [hSPTemp + 1]
ld h, a
ld sp, hl
@@ -287,42 +287,42 @@ VBlankCopyDouble::
VBlankCopy::
-; Copy [H_VBCOPYSIZE] 2bpp tiles (or 16 * [H_VBCOPYSIZE] tile map entries)
-; from H_VBCOPYSRC to H_VBCOPYDEST.
+; Copy [hVBlankCopySize] 2bpp tiles (or 16 * [hVBlankCopySize] tile map entries)
+; from hVBlankCopySource to hVBlankCopyDest.
; Source and destination addresses are updated,
; so transfer can continue in subsequent calls.
- ld a, [H_VBCOPYSIZE]
+ ldh a, [hVBlankCopySize]
and a
ret z
- ld [H_SPTEMP], sp
+ ld [hSPTemp], sp
- ld a, [H_VBCOPYSRC]
+ ldh a, [hVBlankCopySource]
ld l, a
- ld a, [H_VBCOPYSRC + 1]
+ ldh a, [hVBlankCopySource + 1]
ld h, a
ld sp, hl
- ld a, [H_VBCOPYDEST]
+ ldh a, [hVBlankCopyDest]
ld l, a
- ld a, [H_VBCOPYDEST + 1]
+ ldh a, [hVBlankCopyDest + 1]
ld h, a
- ld a, [H_VBCOPYSIZE]
+ ldh a, [hVBlankCopySize]
ld b, a
xor a ; transferred
- ld [H_VBCOPYSIZE], a
+ ldh [hVBlankCopySize], a
.loop
- rept 7
+ REPT 7
pop de
ld [hl], e
inc l
ld [hl], d
inc l
- endr
+ ENDR
pop de
ld [hl], e
@@ -332,13 +332,13 @@ VBlankCopy::
dec b
jr nz, .loop
- ld [H_VBCOPYSRC], sp
+ ld [hVBlankCopySource], sp
ld sp, hl
- ld [H_VBCOPYDEST], sp
+ ld [hVBlankCopyDest], sp
- ld a, [H_SPTEMP]
+ ldh a, [hSPTemp]
ld l, a
- ld a, [H_SPTEMP + 1]
+ ldh a, [hSPTemp + 1]
ld h, a
ld sp, hl
@@ -349,17 +349,17 @@ UpdateMovingBgTiles::
; Animate water and flower
; tiles in the overworld.
- ld a, [hTilesetType]
+ ldh a, [hTilesetType]
and a
ret z ; no animations if indoors (or if a menu set this to 0)
- ld a,[rLY]
+ ldh a, [rLY]
cp $90 ; check if not in vblank period??? (maybe if vblank is too long)
ret c
- ld a, [hMovingBGTilesCounter1]
+ ldh a, [hMovingBGTilesCounter1]
inc a
- ld [hMovingBGTilesCounter1], a
+ ldh [hMovingBGTilesCounter1], a
cp 20
ret c
cp 21
@@ -367,7 +367,7 @@ UpdateMovingBgTiles::
; water
- ld hl, vTileset + $14 * $10
+ ld hl, vTileset tile $14
ld c, $10
ld a, [wMovingBGTilesCounter2]
@@ -391,17 +391,17 @@ UpdateMovingBgTiles::
dec c
jr nz, .left
.done
- ld a, [hTilesetType]
+ ldh a, [hTilesetType]
rrca
ret nc
; if in a cave, no flower animations
xor a
- ld [hMovingBGTilesCounter1], a
+ ldh [hMovingBGTilesCounter1], a
ret
.flower
xor a
- ld [hMovingBGTilesCounter1], a
+ ldh [hMovingBGTilesCounter1], a
ld a, [wMovingBGTilesCounter2]
and 3
@@ -412,7 +412,7 @@ UpdateMovingBgTiles::
jr z, .copy
ld hl, FlowerTile3
.copy
- ld de, vTileset + $3 * $10
+ ld de, vTileset tile $03
ld c, $10
.loop
ld a, [hli]
diff --git a/home/window.asm b/home/window.asm
new file mode 100644
index 00000000..8ccb9de9
--- /dev/null
+++ b/home/window.asm
@@ -0,0 +1,292 @@
+HandleMenuInput::
+ xor a
+ ld [wPartyMenuAnimMonEnabled], a
+
+HandleMenuInput_::
+ ldh a, [hDownArrowBlinkCount1]
+ push af
+ ldh a, [hDownArrowBlinkCount2]
+ push af ; save existing values on stack
+ xor a
+ ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1
+ ld a, 6
+ ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2
+.loop1
+ xor a
+ ld [wAnimCounter], a ; counter for pokemon shaking animation
+ call PlaceMenuCursor
+ call Delay3
+.loop2
+ push hl
+ ld a, [wPartyMenuAnimMonEnabled]
+ and a ; is it a pokemon selection menu?
+ jr z, .getJoypadState
+ farcall AnimatePartyMon ; shake mini sprite of selected pokemon
+.getJoypadState
+ pop hl
+ call JoypadLowSensitivity
+ ldh a, [hJoy5]
+ and a ; was a key pressed?
+ jr nz, .keyPressed
+ push hl
+ hlcoord 18, 11 ; coordinates of blinking down arrow in some menus
+ call HandleDownArrowBlinkTiming ; blink down arrow (if any)
+ pop hl
+ ld a, [wMenuJoypadPollCount]
+ dec a
+ jr z, .giveUpWaiting
+ jr .loop2
+.giveUpWaiting
+; if a key wasn't pressed within the specified number of checks
+ pop af
+ ldh [hDownArrowBlinkCount2], a
+ pop af
+ ldh [hDownArrowBlinkCount1], a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled], a ; disable menu wrapping
+ ret
+.keyPressed
+ xor a
+ ld [wCheckFor180DegreeTurn], a
+ ldh a, [hJoy5]
+ ld b, a
+ bit 0, a ; pressed A key?
+ jr nz, .checkOtherKeys
+ bit 6, a ; pressed Up key?
+ jr z, .checkIfDownPressed
+.upPressed
+ ld a, [wCurrentMenuItem] ; selected menu item
+ and a ; already at the top of the menu?
+ jr z, .alreadyAtTop
+.notAtTop
+ dec a
+ ld [wCurrentMenuItem], a ; move selected menu item up one space
+ jr .checkOtherKeys
+.alreadyAtTop
+ ld a, [wMenuWrappingEnabled]
+ and a ; is wrapping around enabled?
+ jr z, .noWrappingAround
+ ld a, [wMaxMenuItem]
+ ld [wCurrentMenuItem], a ; wrap to the bottom of the menu
+ jr .checkOtherKeys
+.checkIfDownPressed
+ bit 7, a
+ jr z, .checkOtherKeys
+.downPressed
+ ld a, [wCurrentMenuItem]
+ inc a
+ ld c, a
+ ld a, [wMaxMenuItem]
+ cp c
+ jr nc, .notAtBottom
+.alreadyAtBottom
+ ld a, [wMenuWrappingEnabled]
+ and a ; is wrapping around enabled?
+ jr z, .noWrappingAround
+ ld c, $00 ; wrap from bottom to top
+.notAtBottom
+ ld a, c
+ ld [wCurrentMenuItem], a
+.checkOtherKeys
+ ld a, [wMenuWatchedKeys]
+ and b ; does the menu care about any of the pressed keys?
+ jp z, .loop1
+.checkIfAButtonOrBButtonPressed
+ ldh a, [hJoy5]
+ and A_BUTTON | B_BUTTON
+ jr z, .skipPlayingSound
+.AButtonOrBButtonPressed
+ push hl
+ ld hl, wFlags_0xcd60
+ bit 5, [hl]
+ pop hl
+ jr nz, .skipPlayingSound
+ ld a, SFX_PRESS_AB
+ call PlaySound
+.skipPlayingSound
+ pop af
+ ldh [hDownArrowBlinkCount2], a
+ pop af
+ ldh [hDownArrowBlinkCount1], a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled], a ; disable menu wrapping
+ ldh a, [hJoy5]
+ ret
+.noWrappingAround
+ ld a, [wMenuWatchMovingOutOfBounds]
+ and a ; should we return if the user tried to go past the top or bottom?
+ jr z, .checkOtherKeys
+ jr .checkIfAButtonOrBButtonPressed
+
+PlaceMenuCursor::
+ ld a, [wTopMenuItemY]
+ and a ; is the y coordinate 0?
+ jr z, .adjustForXCoord
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+.topMenuItemLoop
+ add hl, bc
+ dec a
+ jr nz, .topMenuItemLoop
+.adjustForXCoord
+ ld a, [wTopMenuItemX]
+ ld b, 0
+ ld c, a
+ add hl, bc
+ push hl
+ ld a, [wLastMenuItem]
+ and a ; was the previous menu id 0?
+ jr z, .checkForArrow1
+ ld bc, 40
+ push af
+ ldh a, [hFlagsFFFA]
+ bit 1, a ; is the menu double spaced?
+ jr z, .doubleSpaced1
+ ld bc, 20
+.doubleSpaced1
+ pop af
+.oldMenuItemLoop
+ add hl, bc
+ dec a
+ jr nz, .oldMenuItemLoop
+.checkForArrow1
+ ld a, [hl]
+ cp "▶" ; was an arrow next to the previously selected menu item?
+ jr nz, .skipClearingArrow
+.clearArrow
+ ld a, [wTileBehindCursor]
+ ld [hl], a
+.skipClearingArrow
+ pop hl
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .checkForArrow2
+ ld bc, 40
+ push af
+ ldh a, [hFlagsFFFA]
+ bit 1, a ; is the menu double spaced?
+ jr z, .doubleSpaced2
+ ld bc, 20
+.doubleSpaced2
+ pop af
+.currentMenuItemLoop
+ add hl, bc
+ dec a
+ jr nz, .currentMenuItemLoop
+.checkForArrow2
+ ld a, [hl]
+ cp "▶" ; has the right arrow already been placed?
+ jr z, .skipSavingTile ; if so, don't lose the saved tile
+ ld [wTileBehindCursor], a ; save tile before overwriting with right arrow
+.skipSavingTile
+ ld a, "▶" ; place right arrow
+ ld [hl], a
+ ld a, l
+ ld [wMenuCursorLocation], a
+ ld a, h
+ ld [wMenuCursorLocation + 1], a
+ ld a, [wCurrentMenuItem]
+ ld [wLastMenuItem], a
+ ret
+
+; This is used to mark a menu cursor other than the one currently being
+; manipulated. In the case of submenus, this is used to show the location of
+; the menu cursor in the parent menu. In the case of swapping items in list,
+; this is used to mark the item that was first chosen to be swapped.
+PlaceUnfilledArrowMenuCursor::
+ ld b, a
+ ld a, [wMenuCursorLocation]
+ ld l, a
+ ld a, [wMenuCursorLocation + 1]
+ ld h, a
+ ld [hl], "▷"
+ ld a, b
+ ret
+
+; Replaces the menu cursor with a blank space.
+EraseMenuCursor::
+ ld a, [wMenuCursorLocation]
+ ld l, a
+ ld a, [wMenuCursorLocation + 1]
+ ld h, a
+ ld [hl], " "
+ ret
+
+; This toggles a blinking down arrow at hl on and off after a delay has passed.
+; This is often called even when no blinking is occurring.
+; The reason is that most functions that call this initialize hDownArrowBlinkCount1 to 0.
+; The effect is that if the tile at hl is initialized with a down arrow,
+; this function will toggle that down arrow on and off, but if the tile isn't
+; initialized with a down arrow, this function does nothing.
+; That allows this to be called without worrying about if a down arrow should
+; be blinking.
+HandleDownArrowBlinkTiming::
+ ld a, [hl]
+ ld b, a
+ ld a, "▼"
+ cp b
+ jr nz, .downArrowOff
+.downArrowOn
+ ldh a, [hDownArrowBlinkCount1]
+ dec a
+ ldh [hDownArrowBlinkCount1], a
+ ret nz
+ ldh a, [hDownArrowBlinkCount2]
+ dec a
+ ldh [hDownArrowBlinkCount2], a
+ ret nz
+ ld a, " "
+ ld [hl], a
+ ld a, $ff
+ ldh [hDownArrowBlinkCount1], a
+ ld a, $06
+ ldh [hDownArrowBlinkCount2], a
+ ret
+.downArrowOff
+ ldh a, [hDownArrowBlinkCount1]
+ and a
+ ret z
+ dec a
+ ldh [hDownArrowBlinkCount1], a
+ ret nz
+ dec a
+ ldh [hDownArrowBlinkCount1], a
+ ldh a, [hDownArrowBlinkCount2]
+ dec a
+ ldh [hDownArrowBlinkCount2], a
+ ret nz
+ ld a, $06
+ ldh [hDownArrowBlinkCount2], a
+ ld a, "▼"
+ ld [hl], a
+ ret
+
+; The following code either enables or disables the automatic drawing of
+; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait
+; for a button press after displaying text (unless [wEnteringCableClub] is set).
+
+EnableAutoTextBoxDrawing::
+ xor a
+ jr AutoTextBoxDrawingCommon
+
+DisableAutoTextBoxDrawing::
+ ld a, TRUE
+
+AutoTextBoxDrawingCommon::
+ ld [wAutoTextBoxDrawingControl], a
+ xor a
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a ; make DisplayTextID wait for button press
+ ret
+
+PrintText::
+; Print text hl at (1, 14).
+ push hl
+ ld a, MESSAGE_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ call UpdateSprites
+ call Delay3
+ pop hl
+PrintText_NoCreatingTextBox::
+ bccoord 1, 14
+ jp TextCommandProcessor
diff --git a/home/yes_no.asm b/home/yes_no.asm
new file mode 100644
index 00000000..28d6c7aa
--- /dev/null
+++ b/home/yes_no.asm
@@ -0,0 +1,40 @@
+; displays yes/no choice
+; yes -> set carry
+YesNoChoice::
+ call SaveScreenTilesToBuffer1
+ call InitYesNoTextBoxParameters
+ jr DisplayYesNoChoice
+
+Func_35f7::
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call InitYesNoTextBoxParameters
+ jp DisplayTextBoxID
+
+InitYesNoTextBoxParameters::
+ xor a ; YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ hlcoord 14, 7
+ lb bc, 8, 15
+ ret
+
+YesNoChoicePokeCenter::
+ call SaveScreenTilesToBuffer1
+ ld a, HEAL_CANCEL_MENU
+ ld [wTwoOptionMenuID], a
+ hlcoord 11, 6
+ lb bc, 8, 12
+ jr DisplayYesNoChoice
+
+WideYesNoChoice:: ; unused
+ call SaveScreenTilesToBuffer1
+ ld a, WIDE_YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ hlcoord 12, 7
+ lb bc, 8, 13
+
+DisplayYesNoChoice::
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ jp LoadScreenTilesFromBuffer1