summaryrefslogtreecommitdiff
path: root/home.asm
diff options
context:
space:
mode:
Diffstat (limited to 'home.asm')
-rw-r--r--home.asm9572
1 files changed, 4791 insertions, 4781 deletions
diff --git a/home.asm b/home.asm
index cbbd2250..a54c2685 100644
--- a/home.asm
+++ b/home.asm
@@ -1,4781 +1,4791 @@
-
-; The rst vectors are unused.
-SECTION "rst 00", ROM0 [$00]
- rst $38
-SECTION "rst 08", ROM0 [$08]
- rst $38
-SECTION "rst 10", ROM0 [$10]
- rst $38
-SECTION "rst 18", ROM0 [$18]
- rst $38
-SECTION "rst 20", ROM0 [$20]
- rst $38
-SECTION "rst 28", ROM0 [$28]
- rst $38
-SECTION "rst 30", ROM0 [$30]
- rst $38
-SECTION "rst 38", ROM0 [$38]
- rst $38
-
-; Hardware interrupts
-SECTION "vblank", ROM0 [$40]
- jp VBlank
-SECTION "hblank", ROM0 [$48]
- rst $38
-SECTION "timer", ROM0 [$50]
- jp Timer
-SECTION "serial", ROM0 [$58]
- jp Serial
-SECTION "joypad", ROM0 [$60]
- reti
-
-
-SECTION "Home", ROM0
-
-DisableLCD::
- xor a
- ld [rIF], a
- ld a, [rIE]
- ld b, a
- res 0, a
- ld [rIE], a
-
-.wait
- ld a, [rLY]
- cp LY_VBLANK
- jr nz, .wait
-
- ld a, [rLCDC]
- and $ff ^ rLCDC_ENABLE_MASK
- ld [rLCDC], a
- ld a, b
- ld [rIE], a
- ret
-
-EnableLCD::
- ld a, [rLCDC]
- set rLCDC_ENABLE, a
- ld [rLCDC], a
- ret
-
-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
-
-INCLUDE "home/copy.asm"
-
-
-
-SECTION "Entry", ROM0 [$100]
-
- nop
- jp Start ; 01ab
-
-
-SECTION "Header", ROM0 [$104]
-
- ; The header is generated by rgbfix.
- ; The space here is allocated to prevent code from being overwritten.
-
- ds $150 - $104
-
-
-
-SECTION "Main", ROM0
-
-Func_150:: ; 0150 (0:0150)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,b
- call BankswitchCommon
- ld a,[hli]
- ld c,a
- ld a,[hli]
- ld b,a
-.loop
- ld a,[hli]
- ld d,a
- ld a,$3
-.unknownloop
- dec a
- jr nz,.unknownloop
-
- rept 7
- call Func_199
- call Func_1a5
- endr
-
- call Func_199
- dec bc
- ld a,c
- or b
- jr nz,.loop
- pop af
- call BankswitchCommon
- ret
-
-Func_199:: ; 0199 (0:0199)
- ld a,d
- and $80
- srl a
- srl a
- ld [rNR32],a
- sla d
- ret
-
-Func_1a5:: ; 01a5 (0:01a5)
- ld a,$3
-.unknownloop2
- dec a
- jr nz,.unknownloop2
- ret
-
-Start::
- cp GBC
- jr z, .gbc
- xor a
- jr .ok
-.gbc
- ld a, $1
-.ok
- ld [hGBC], a
- jp Init
-
-Joypad:: ; 01b9
- homecall _Joypad
-
-ReadJoypad: ; 01c8 (0:01c8)
- homecall ReadJoypad_
-
-INCLUDE "data/map_header_pointers.asm"
-INCLUDE "home/overworld.asm"
-
-
-CheckForUserInterruption:: ; 12f8 (0:12f8)
-; 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
-
- ld a, [hJoyHeld]
- cp D_UP + SELECT + B_BUTTON
- jr z, .input
-
- ld 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:: ; 1313 (0:1313)
- ld b,a
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,[wPredefParentBank]
- ld [H_LOADEDROMBANK],a
- ld [$2000],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
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-
-DrawHPBar:: ; 1336 (0:1336)
-; 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 iz 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 W_MONHDEXNUM
-; INPUT:
-; [wWhichPokemon] = index of pokemon within party/box
-; [wcc49] = source
-; 00: player's party
-; 01: enemy's party
-; 02: current box
-; 03: daycare
-; OUTPUT:
-; [wcf91] = pokemon ID
-; wLoadedMon = base address of pokemon data
-; W_MONHDEXNUM = base address of base stats
-LoadMonData:: ; 1372 (0:1372)
- ld hl, LoadMonData_
- ld b, BANK(LoadMonData_)
- jp Bankswitch
-
-
-Func_137a:: ; 137a (0:137a)
-; 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:: ; 1384 (0:1384)
- ld a, 1
- ld [W_SPRITEFLIPPED], a
-
-LoadFrontSpriteByMonIndex:: ; 1389 (0:1389)
- 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
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, Bank(asm_3f0d0)
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- xor a
- ld [$ffe1], a
- call asm_3f0d0
- xor a
- ld [W_SPRITEFLIPPED], a
- pop af
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- ret
-
-
-PlayCry:: ; 13d0 (0:13d0)
-; Play monster a's cry.
- call GetCryData
- call PlaySound
- jp WaitForSoundToFinish
-
-GetCryData:: ; 13d9 (0:13d9)
-; 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 [wc0f1], a
- ld a, [hl]
- ld [wc0f2], a
- call BankswitchBack
-
- ; Cry headers have 3 channels,
- ; and start from index $14,
- ; so add 3 times the cry id.
- ld a, b
- ld c, $14
- rlca ; * 2
- add b
- add c
- ret
-
-
-DisplayPartyMenu:: ; 13fc (0:13fc)
- ld a,[hTilesetType]
- push af
- xor a
- ld [hTilesetType],a
- call GBPalWhiteOutWithDelay3
- call ClearSprites
- call PartyMenuInit
- call DrawPartyMenu
- jp HandlePartyMenuInput
-
-GoBackToPartyMenu:: ; 1411 (0:1411)
- ld a,[hTilesetType]
- push af
- xor a
- ld [hTilesetType],a
- call PartyMenuInit
- call RedrawPartyMenu
- jp HandlePartyMenuInput
-
-PartyMenuInit:: ; 1420 (0:1420)
- ld a, 1 ; hardcoded bank
- call BankswitchHome
- call LoadHpBarAndStatusTilePatterns
- ld hl, wd730
- set 6, [hl] ; turn off letter printing delay
- xor a
- ld [wcc49], a
- ld [wcc37], a
- ld hl, wTopMenuItemY
- inc a
- ld [hli], a ; top menu item Y
- xor a
- ld [hli], a ; top menu item X
- ld a, [wcc2b]
- 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, [wd11f]
- and a
- ld a, A_BUTTON + B_BUTTON
- jr z, .next
- xor a
- ld [wd11f], a
- inc a
-.next
- ld [hli], a ; menu watched keys
- pop af
- ld [hl], a ; old menu item ID
- ret
-
-HandlePartyMenuInput:: ; 145a (0:145a)
- ld a,1
- ld [wMenuWrappingEnabled],a
- ld a,$40
- ld [wd09b],a
- call HandleMenuInputPokemonSelection
- call PlaceUnfilledArrowMenuCursor
- ld b,a
- xor a
- ld [wd09b],a
- ld a,[wCurrentMenuItem]
- ld [wcc2b],a
- ld hl,wd730
- res 6,[hl] ; turn on letter printing delay
- ld a,[wMenuItemToSwap]
- and a
- jp nz,.swappingPokemon
- pop af
- ld [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
-.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
- callba ErasePartyMenuCursors
- xor a
- ld [wMenuItemToSwap],a
- ld [wd07d],a
- call RedrawPartyMenu
- jr HandlePartyMenuInput
-.handleSwap
- ld a,[wCurrentMenuItem]
- ld [wWhichPokemon],a
- callba SwitchPartyMon
- jr HandlePartyMenuInput
-
-DrawPartyMenu:: ; 14d4 (0:14d4)
- ld hl, DrawPartyMenu_
- jr DrawPartyMenuCommon
-
-RedrawPartyMenu:: ; 14d9 (0:14d9)
- ld hl, RedrawPartyMenu_
-
-DrawPartyMenuCommon:: ; 14dc (0:14dc)
- ld b, BANK(RedrawPartyMenu_)
- jp Bankswitch
-
-; prints a pokemon's status condition
-; INPUT:
-; de = address of status condition
-; hl = destination address
-PrintStatusCondition:: ; 14e1 (0:14e1)
- 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 ; 14f6
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,BANK(PrintStatusAilment)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call PrintStatusAilment ; print status condition
- pop bc
- ld a,b
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-; function to print pokemon level, leaving off the ":L" if the level is at least 100
-; INPUT:
-; hl = destination address
-; [wLoadedMonLevel] = level
-PrintLevel:: ; 150b (0:150b)
- ld a,$6e ; ":L" tile ID
- ld [hli],a
- ld c,2 ; number of digits
- ld a,[wLoadedMonLevel] ; level
- cp a,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:: ; 151b (0:151b)
- ld a,$6e ; ":L" tile ID
- ld [hli],a
- ld c,3 ; number of digits
- ld a,[wLoadedMonLevel] ; level
-
-PrintLevelCommon:: ; 1523 (0:1523)
- ld [wd11e],a
- ld de,wd11e
- ld b,$41 ; no leading zeroes, left-aligned, one byte
- jp PrintNumber
-
-Func_152e:: ; 152e (0:152e)
-; Unused.
- 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 W_MONHDEXNUM (W_MONHEADER)
-; INPUT:
-; [wd0b5] = pokemon ID
-GetMonHeader:: ; 1537 (0:1537)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,BANK(BaseStats)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- 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 a,FOSSIL_KABUTOPS ; Kabutops fossil
- jr z,.specialID
- ld de,GhostPic
- cp a,MON_GHOST ; Ghost
- jr z,.specialID
- ld de,FossilAerodactylPic
- ld b,$77 ; size of Aerodactyl fossil sprite
- cp a,FOSSIL_AERODACTYL ; Aerodactyl fossil
- jr z,.specialID
- cp a,MEW
- jr z,.mew
- predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number
- ld a,[wd11e]
- dec a
- ld bc,28
- ld hl,BaseStats
- call AddNTimes
- ld de,W_MONHEADER
- ld bc,28
- call CopyData
- jr .done
-.specialID
- ld hl,W_MONHSPRITEDIM
- ld [hl],b ; write sprite dimensions
- inc hl
- ld [hl],e ; write front sprite pointer
- inc hl
- ld [hl],d
- jr .done
-.mew
- ld hl,MewBaseStats
- ld de,W_MONHEADER
- ld bc,28
- ld a,BANK(MewBaseStats)
- call FarCopyData
-.done
- ld a,[wd0b5]
- ld [W_MONHDEXNUM],a
- pop af
- ld [wd11e],a
- pop hl
- pop de
- pop bc
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-; copy party pokemon's name to wcd6d
-GetPartyMonName2:: ; 15b4 (0:15b4)
- ld a,[wWhichPokemon] ; index within party
- ld hl,wPartyMonNicks
-
-; this is called more often
-GetPartyMonName:: ; 15ba (0:15ba)
- push hl
- push bc
- call SkipFixedLengthTextEntries ; add 11 to hl, a times
- ld de,wcd6d
- push de
- ld bc,11
- call CopyData
- pop de
- pop bc
- pop hl
- ret
-
-; 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:: ; 15cd (0:15cd)
- 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:: ; 1604 (0:1604)
- 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 a,"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
-
-; 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:: ; 1627 (0:1627)
- ld bc,W_MONHEADER
- add hl,bc
- ld a,[hli]
- ld [W_SPRITEINPUTPTR],a ; fetch sprite input pointer
- ld a,[hl]
- ld [W_SPRITEINPUTPTR+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:: ; 1665 (0:1665)
- push de
- ld hl, W_MONHFRONTSPRITE - W_MONHEADER
- call UncompressMonSprite
- ld hl, W_MONHSPRITEDIM
- 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:: ; 1672 (0:1672)
- push de
- and $f
- ld [H_SPRITEWIDTH], 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)
- ld [H_SPRITEOFFSET], a
- ld a, c
- swap a
- and $f
- ld b, a
- add a
- add a
- add a ; 8*tiles is height in bytes
- ld [H_SPRITEHEIGHT], a ; $ff8c
- ld a, $7
- sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
- ld b, a
- ld a, [H_SPRITEOFFSET]
- 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)
- ld [H_SPRITEOFFSET], a
- xor a
- ld [$4000], a
- ld hl, S_SPRITEBUFFER0
- call ZeroSpriteBuffer ; zero buffer 0
- ld de, S_SPRITEBUFFER1
- ld hl, S_SPRITEBUFFER0
- call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
- ld hl, S_SPRITEBUFFER1
- call ZeroSpriteBuffer ; zero buffer 1
- ld de, S_SPRITEBUFFER2
- ld hl, S_SPRITEBUFFER1
- call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
- 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:: ; 16c2 (0:16c2)
- ld a, [H_SPRITEOFFSET]
- ld b, $0
- ld c, a
- add hl, bc
- ld a, [H_SPRITEWIDTH] ; $ff8b
-.columnLoop
- push af
- push hl
- ld a, [H_SPRITEHEIGHT] ; $ff8c
- 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:: ; 16df (0:16df)
- 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:: ; 16ea (0:16ea)
- xor a
- ld [$4000], a
- push de
- ld hl, S_SPRITEBUFFER2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
- ld de, S_SPRITEBUFFER1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
- ld bc, S_SPRITEBUFFER0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
- ld a, SPRITEBUFFERSIZE/2 ; $c4
- ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b
-.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
- ld a, [H_SPRITEINTERLACECOUNTER] ; $ff8b
- dec a
- ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b
- jr nz, .interlaceLoop
- ld a, [W_SPRITEFLIPPED]
- and a
- jr z, .notFlipped
- ld bc, 2*SPRITEBUFFERSIZE
- ld hl, S_SPRITEBUFFER1
-.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, S_SPRITEBUFFER1
- ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
- ld a, [H_LOADEDROMBANK]
- ld b, a
- jp CopyVideoData
-
-
-INCLUDE "data/collision.asm"
-INCLUDE "home/copy2.asm"
-INCLUDE "home/text.asm"
-INCLUDE "home/vcopy.asm"
-INCLUDE "home/init.asm"
-INCLUDE "home/vblank.asm"
-INCLUDE "home/fade.asm"
-INCLUDE "home/serial.asm"
-INCLUDE "home/timer.asm"
-INCLUDE "home/audio.asm"
-
-
-UpdateSprites:: ; 2429 (0:2429)
- ld a, [wUpdateSpritesEnabled]
- dec a
- ret nz
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, Bank(_UpdateSprites)
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- call _UpdateSprites
- pop af
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- ret
-
-INCLUDE "data/mart_inventories.asm"
-
-TextScriptEndingChar:: ; 24d6 (0:24d6)
- db "@"
-TextScriptEnd:: ; 24d7 (0:24d7)
- ld hl,TextScriptEndingChar
- ret
-
-ExclamationText:: ; 24db (0:24db)
- TX_FAR _ExclamationText
- db "@"
-
-GroundRoseText:: ; 24e0 (0:24e0)
- TX_FAR _GroundRoseText
- db "@"
-
-BoulderText:: ; 24e5 (0:24e5)
- TX_FAR _BoulderText
- db "@"
-
-MartSignText:: ; 24ea (0:24ea)
- TX_FAR _MartSignText
- db "@"
-
-PokeCenterSignText:: ; 24ef (0:24ef)
- TX_FAR _PokeCenterSignText
- db "@"
-
-Predef5CText:: ; 24f4 (0:24f4)
-; XXX better label (what does predef $5C do?)
- db $08 ; asm
- predef PickupItem
- jp TextScriptEnd
-
-
-INCLUDE "home/pic.asm"
-
-
-ResetPlayerSpriteData:: ; 28a6 (0:28a6)
- ld hl, wSpriteStateData1
- call ResetPlayerSpriteData_ClearSpriteData
- ld hl, wSpriteStateData2
- call ResetPlayerSpriteData_ClearSpriteData
- ld a, $1
- ld [wSpriteStateData1], a
- ld [wSpriteStateData2 + $0e], a
- ld hl, wSpriteStateData1 + 4
- 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:: ; 28c4 (0:28c4)
- ld bc, $10
- xor a
- jp FillMemory
-
-Func_28cb:: ; 28cb (0:28cb)
- ld a, [wMusicHeaderPointer]
- and a
- jr nz, .asm_28dc
- ld a, [wd72c]
- bit 1, a
- ret nz
- ld a, $77
- ld [$ff24], a
- ret
-.asm_28dc
- ld a, [wcfc9]
- and a
- jr z, .asm_28e7
- dec a
- ld [wcfc9], a
- ret
-.asm_28e7
- ld a, [wcfc8]
- ld [wcfc9], a
- ld a, [$ff24]
- and a
- jr z, .asm_2903
- ld b, a
- and $f
- dec a
- ld c, a
- ld a, b
- and $f0
- swap a
- dec a
- swap a
- or c
- ld [$ff24], a
- ret
-.asm_2903
- ld a, [wMusicHeaderPointer]
- ld b, a
- xor a
- ld [wMusicHeaderPointer], a
- ld a, $ff
- ld [wc0ee], a
- call PlaySound
- ld a, [wc0f0]
- ld [wc0ef], a
- ld a, b
- ld [wc0ee], a
- jp PlaySound
-
-; this function is used to display sign messages, sprite dialog, etc.
-; INPUT: [$ff8c] = sprite ID or text ID
-DisplayTextID:: ; 2920 (0:2920)
- ld a,[H_LOADEDROMBANK]
- push af
- callba DisplayTextIDInit ; initialization
- ld hl,wcf11
- bit 0,[hl]
- res 0,[hl]
- jr nz,.skipSwitchToMapBank
- ld a,[W_CURMAP]
- call SwitchToMapRomBank
-.skipSwitchToMapBank
- ld a,30 ; half a second
- ld [H_FRAMECOUNTER],a ; used as joypad poll timer
- ld hl,W_MAPTEXTPTR
- ld a,[hli]
- ld h,[hl]
- ld l,a ; hl = map text pointer
- ld d,$00
- ld a,[$ff8c] ; text ID
- ld [wSpriteIndex],a
- and a
- jp z,DisplayStartMenu
- cp a,$d3
- jp z,DisplaySafariGameOverText
- cp a,$d0
- jp z,DisplayPokemonFaintedText
- cp a,$d1
- jp z,DisplayPlayerBlackedOutText
- cp a,$d2
- jp z,DisplayRepelWoreOffText
- ld a,[W_NUMSPRITES]
- ld e,a
- ld a,[$ff8c] ; sprite ID
- cp e
- jr z,.spriteHandling
- jr nc,.skipSpriteHandling
-.spriteHandling
-; get the text ID of the sprite
- push hl
- push de
- push bc
- callba UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction)
- pop bc
- pop de
- ld hl,W_MAPSPRITEDATA ; NPC text entries
- ld a,[$ff8c]
- dec a
- add a
- add l
- ld l,a
- jr nc,.noCarry
- inc h
-.noCarry
- 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
- sla e
- 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
- cp a,$fe ; Pokemart NPC
- jp z,DisplayPokemartDialogue
- cp a,$ff ; Pokemon Center NPC
- jp z,DisplayPokemonCenterDialogue
- cp a,$fc ; Item Storage PC
- jp z,FuncTX_ItemStoragePC
- cp a,$fd ; Bill's PC
- jp z,FuncTX_BillsPC
- cp a,$f9 ; Pokemon Center PC
- jp z,FuncTX_PokemonCenterPC
- cp a,$f5 ; Vending Machine
- jr nz,.notVendingMachine
- callba VendingMachineMenu ; jump banks to vending machine routine
- jr AfterDisplayingTextID
-.notVendingMachine
- cp a,$f7 ; slot machine
- jp z,FuncTX_SlotMachine
- cp a,$f6 ; cable connection NPC in Pokemon Center
- jr nz,.notSpecialCase
- callab CableClubNPC
- jr AfterDisplayingTextID
-.notSpecialCase
- call Func_3c59 ; display the text
- ld a,[wDoNotWaitForButtonPressAfterDisplayingText]
- and a
- jr nz,HoldTextDisplayOpen
-
-AfterDisplayingTextID:: ; 29d6 (0:29d6)
- ld a,[wcc47]
- 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:: ; 29df (0:29df)
- call Joypad
- ld a,[hJoyHeld]
- bit 0,a ; is the A button being pressed?
- jr nz,HoldTextDisplayOpen
-
-CloseTextDisplay:: ; 29e8 (0:29e8)
- ld a,[W_CURMAP]
- call SwitchToMapRomBank
- ld a,$90
- ld [hWY],a ; move the window off the screen
- call DelayFrame
- call LoadGBPal
- xor a
- ld [H_AUTOBGTRANSFERENABLED],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,wSpriteStateData2 + $19
- ld c,$0f
- ld de,$0010
-.restoreSpriteFacingDirectionLoop
- ld a,[hl]
- dec h
- ld [hl],a
- inc h
- add hl,de
- dec c
- jr nz,.restoreSpriteFacingDirectionLoop
- ld a,BANK(InitMapSprites)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- 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
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- jp UpdateSprites
-
-DisplayPokemartDialogue:: ; 2a2e (0:2a2e)
- push hl
- ld hl,PokemartGreetingText
- call PrintText
- pop hl
- inc hl
- call LoadItemList
- ld a,$02
- ld [wListMenuID],a ; selects between subtypes of menus
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,Bank(DisplayPokemartDialogue_)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call DisplayPokemartDialogue_
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- jp AfterDisplayingTextID
-
-PokemartGreetingText:: ; 2a55 (0:2a55)
- TX_FAR _PokemartGreetingText
- db "@"
-
-LoadItemList:: ; 2a5a (0:2a5a)
- ld a,$01
- ld [wUpdateSpritesEnabled],a
- ld a,h
- ld [wd128],a
- ld a,l
- ld [wd129],a
- ld de,wStringBuffer2 + 11
-.loop
- ld a,[hli]
- ld [de],a
- inc de
- cp a,$ff
- jr nz,.loop
- ret
-
-DisplayPokemonCenterDialogue:: ; 2a72 (0:2a72)
- xor a
- ld [$ff8b],a
- ld [$ff8c],a
- ld [$ff8d],a
- inc hl
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,Bank(DisplayPokemonCenterDialogue_)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call DisplayPokemonCenterDialogue_
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- jp AfterDisplayingTextID
-
-DisplaySafariGameOverText:: ; 2a90 (0:2a90)
- callab PrintSafariGameOverText
- jp AfterDisplayingTextID
-
-DisplayPokemonFaintedText:: ; 2a9b (0:2a9b)
- ld hl,PokemonFaintedText
- call PrintText
- jp AfterDisplayingTextID
-
-PokemonFaintedText:: ; 2aa4 (0:2aa4)
- TX_FAR _PokemonFaintedText
- db "@"
-
-DisplayPlayerBlackedOutText:: ; 2aa9 (0:2aa9)
- ld hl,PlayerBlackedOutText
- call PrintText
- ld a,[wd732]
- res 5,a ; reset forced to use bike bit
- ld [wd732],a
- jp HoldTextDisplayOpen
-
-PlayerBlackedOutText:: ; 2aba (0:2aba)
- TX_FAR _PlayerBlackedOutText
- db "@"
-
-DisplayRepelWoreOffText:: ; 2abf (0:2abf)
- ld hl,RepelWoreOffText
- call PrintText
- jp AfterDisplayingTextID
-
-RepelWoreOffText:: ; 2ac8 (0:2ac8)
- TX_FAR _RepelWoreOffText
- db "@"
-
-INCLUDE "engine/menu/start_menu.asm"
-
-; 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:
-; [wd11e] = number of set bits
-CountSetBits:: ; 2b7f (0:2b7f)
- 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 [wd11e],a ; store number of set bits
- ret
-
-; subtracts the amount the player paid from their money
-; sets carry flag if there is enough money and unsets carry flag if not
-SubtractAmountPaidFromMoney:: ; 2b96 (0:2b96)
- ld b,BANK(SubtractAmountPaidFromMoney_)
- ld hl,SubtractAmountPaidFromMoney_
- jp Bankswitch
-
-; adds the amount the player sold to their money
-AddAmountSoldToMoney:: ; 2b9e (0:2b9e)
- ld de,wPlayerMoney + 2
- ld hl,$ffa1 ; 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_02_5a - SFX_Headers_02) / 3
- call PlaySoundWaitForCurrent ; play sound
- jp WaitForSoundToFinish ; wait until sound is done playing
-
-; 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
-; [wcf96] = quantity to remove
-RemoveItemFromInventory:: ; 2bbb (0:2bbb)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,BANK(RemoveItemFromInventory_)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call RemoveItemFromInventory_
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- 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
-; [wcf96] = item quantity
-; sets carry flag if successful, unsets carry flag if unsuccessful
-AddItemToInventory:: ; 2bcf (0:2bcf)
- push bc
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,BANK(AddItemToInventory_)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call AddItemToInventory_
- pop bc
- ld a,b
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- pop bc
- ret
-
-; INPUT:
-; [wListMenuID] = list menu ID
-; [wList] = address of the list (2 bytes)
-DisplayListMenuID:: ; 2be6 (0:2be6)
- xor a
- ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer
- ld a,1
- ld [hJoy7],a ; joypad state update flag
- ld a,[W_BATTLETYPE]
- 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 [wd12a],a
- ld a,[wList]
- ld l,a
- ld a,[wList + 1]
- ld h,a ; hl = address of the list
- ld a,[hl]
- ld [wd12a],a ; [wd12a] = number of list entries
- 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
- ld de,$090e ; height and width of menu text box
- ld a,[wListMenuID]
- and a ; is it a PC pokemon list?
- jr nz,.skipMovingSprites
- call UpdateSprites ; move sprites
-.skipMovingSprites
- ld a,1 ; max menu item ID is 1 if the list has less than 2 entries
- ld [wcc37],a
- ld a,[wd12a]
- cp a,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:: ; 2c53 (0:2c53)
- xor a
- ld [H_AUTOBGTRANSFERENABLED],a ; disable transfer
- call PrintListMenuEntries
- ld a,1
- ld [H_AUTOBGTRANSFERENABLED],a ; enable transfer
- call Delay3
- ld a,[W_BATTLETYPE]
- and a ; is it the Old Man battle?
- jr z,.notOldManBattle
-.oldManBattle
- ld a,"▶"
- Coorda 5, 4 ; place menu cursor in front of first menu entry
- ld c,80
- 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
- ld a,$01
- ld [wd12e],a
- ld [wd12d],a
- xor a
- ld [wcc37],a
- ld a,[wCurrentMenuItem]
- ld c,a
- ld a,[wListScrollOffset]
- add c
- ld c,a
- ld a,[wd12a] ; number of list entries
- 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 a,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,[wList]
- ld l,a
- ld a,[wList + 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 ; is it a PC pokemon list?
- jr z,.pokemonList
- push hl
- call GetItemPrice
- pop hl
- ld a,[wListMenuID]
- cp a,ITEMLISTMENU
- jr nz,.skipGettingQuantity
-; if it's an item menu
- inc hl
- ld a,[hl] ; a = item quantity
- ld [wcf97],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,[wList]
- 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,$01
- ld [wd12e],a
- ld a,[wCurrentMenuItem]
- ld [wd12d],a
- xor a
- ld [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 a,3
- ld b,a
- ld a,[wd12a] ; number of list entries
- 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:: ; 2d57 (0:2d57)
-; text box dimensions/coordinates for just quantity
- hlCoord 15, 9
- ld b,1 ; height
- ld c,3 ; width
- ld a,[wListMenuID]
- cp a,PRICEDITEMLISTMENU
- jr nz,.drawTextBox
-; text box dimensions/coordinates for quantity and price
- hlCoord 7, 9
- ld b,1 ; height
- ld c,11 ; width
-.drawTextBox
- call TextBoxBorder
- hlCoord 16, 10
- ld a,[wListMenuID]
- cp a,PRICEDITEMLISTMENU
- jr nz,.printInitialQuantity
- hlCoord 8, 10
-.printInitialQuantity
- ld de,InitialQuantityText
- call PlaceString
- xor a
- ld [wcf96],a ; initialize current quantity to 0
- jp .incrementQuantity
-.waitForKeyPressLoop
- call JoypadLowSensitivity
- ld 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,[wcf97] ; max quantity
- inc a
- ld b,a
- ld hl,wcf96 ; 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,wcf96 ; current quantity
- dec [hl]
- jr nz,.handleNewQuantity
-; wrap to the max quantity if the player goes below 1
- ld a,[wcf97] ; max quantity
- ld [hl],a
-.handleNewQuantity
- hlCoord 17, 10
- ld a,[wListMenuID]
- cp a,PRICEDITEMLISTMENU
- jr nz,.printQuantity
-.printPrice
- ld c,$03
- ld a,[wcf96]
- ld b,a
- ld hl,$ff9f ; 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,$ffa1
- ld hl,$ff8d
- push bc
- predef AddBCDPredef ; add the individual price to the current sum
- pop bc
- dec b
- jr nz,.addLoop
- ld a,[$ff8e]
- and a ; should the price be halved (for selling items)?
- jr z,.skipHalvingPrice
- xor a
- ld [$ffa2],a
- ld [$ffa3],a
- ld a,$02
- ld [$ffa4],a
- predef DivideBCDPredef3 ; halves the price
-; store the halved price
- ld a,[$ffa2]
- ld [$ff9f],a
- ld a,[$ffa3]
- ld [$ffa0],a
- ld a,[$ffa4]
- ld [$ffa1],a
-.skipHalvingPrice
- hlCoord 12, 10
- ld de,SpacesBetweenQuantityAndPriceText
- call PlaceString
- ld de,$ff9f ; total price
- ld c,$a3
- call PrintBCDNumber
- hlCoord 9, 10
-.printQuantity
- ld de,wcf96 ; current quantity
- ld bc,$8102 ; print leading zeroes, 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:: ; 2e30 (0:2e30)
- db "×01@"
-
-SpacesBetweenQuantityAndPriceText:: ; 2e34 (0:2e34)
- db " @"
-
-ExitListMenu:: ; 2e3b (0:2e3b)
- ld a,[wCurrentMenuItem]
- ld [wd12d],a
- ld a,$02
- ld [wd12e],a
- ld [wcc37],a
- xor a
- ld [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:: ; 2e5a (0:2e5a)
- hlCoord 5, 3
- ld b,$09
- ld c,$0e
- call ClearScreenArea
- ld a,[wList]
- ld e,a
- ld a,[wList + 1]
- ld d,a
- inc de ; de = beginning of list entries
- ld a,[wListScrollOffset]
- ld c,a
- ld a,[wListMenuID]
- cp a,ITEMLISTMENU
- ld a,c
- jr nz,.skipMultiplying
-; if it's an item menu
-; item entries are 2 bytes long, so multiply by 2
- sla 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 a,$ff
- jp z,.printCancelMenuItem
- push bc
- push de
- push hl
- push hl
- push de
- ld a,[wListMenuID]
- and a
- jr z,.pokemonPCMenu
- cp a,$01
- jr z,.movesMenu
-.itemMenu
- call GetItemName
- jr .placeNameString
-.pokemonPCMenu
- push hl
- ld hl,wPartyCount
- ld a,[wList]
- 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,[wcf93]
- 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,20 + 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
- jr nz,.skipPrintingPokemonLevel
-.printPokemonLevel
- ld a,[wd11e]
- push af
- push hl
- ld hl,wPartyCount
- ld a,[wList]
- cp l ; is it a list of party pokemon or box pokemon?
- ld a,$00
- jr z,.next
- ld a,$02
-.next
- ld [wcc49],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 ; load pokemon info
- ld a,[wcc49]
- 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,$001c
- add hl,bc
- call PrintLevel ; print level
- pop af
- ld [wd11e],a
-.skipPrintingPokemonLevel
- pop hl
- pop de
- inc de
- ld a,[wListMenuID]
- cp a,ITEMLISTMENU
- jr nz,.nextListEntry
-.printItemQuantity
- ld a,[wd11e]
- ld [wcf91],a
- call IsKeyItem ; check if item is unsellable
- ld a,[wd124]
- and a ; is the item unsellable?
- jr nz,.skipPrintingItemQuantity ; if so, don't print the quantity
- push hl
- ld bc,20 + 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 [wcf97],a
- push de
- ld de,wd11e
- ld [de],a
- ld bc,$0102
- 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
- sla a
- cp c ; is it this item?
- jr nz,.nextListEntry
- dec hl
- ld a,$ec ; unfilled right arrow menu cursor to indicate an item being swapped
- ld [hli],a
-.nextListEntry
- ld bc,2 * 20 ; 2 rows
- add hl,bc
- pop bc
- inc c
- dec b
- jp nz,.loop
- ld bc,-8
- add hl,bc
- ld a,$ee ; down arrow
- ld [hl],a
- ret
-.printCancelMenuItem
- ld de,ListMenuCancelText
- jp PlaceString
-
-ListMenuCancelText:: ; 2f97 (0:2f97)
- db "CANCEL@"
-
-GetMonName:: ; 2f9e (0:2f9e)
- push hl
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,BANK(MonsterNames) ; 07
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ld a,[wd11e]
- dec a
- ld hl,MonsterNames ; 421E
- ld c,10
- ld b,0
- call AddNTimes
- ld de,wcd6d
- push de
- ld bc,10
- call CopyData
- ld hl,wcd77
- ld [hl], "@"
- pop de
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- pop hl
- ret
-
-GetItemName:: ; 2fcf (0:2fcf)
-; 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 HM_01 ; 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:: ; 2ff3 (0:2ff3)
-; copies the name of the TM/HM in [wd11e] to wcd6d
- push hl
- push de
- push bc
- ld a,[wd11e]
- push af
- cp TM_01 ; is this a TM? [not HM]
- jr nc,.WriteTM
-; if HM, then write "HM" and add 5 to the item ID, so we can reuse the
-; TM printing code
- add 5
- ld [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 TM_01 - 1
- ld b,$F6 ; "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,$F6 ; "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:: ; 303c (0:303c)
- db "TM"
-HiddenPrefix:: ; 303e (0:303e)
- db "HM"
-
-; sets carry if item is HM, clears carry if item is not HM
-; Input: a = item ID
-IsItemHM:: ; 3040 (0:3040)
- cp a,HM_01
- jr c,.notHM
- cp a,TM_01
- 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:: ; 3049 (0:3049)
- ld hl,HMMoves
- ld de,1
- jp IsInArray
-
-HMMoves:: ; 3052 (0:3052)
- db CUT,FLY,SURF,STRENGTH,FLASH
- db $ff ; terminator
-
-GetMoveName:: ; 3058 (0:3058)
- 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
-
-; reloads text box tile patterns, current map view, and tileset tile patterns
-ReloadMapData:: ; 3071 (0:3071)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,[W_CURMAP]
- call SwitchToMapRomBank
- call DisableLCD
- call LoadTextBoxTilePatterns
- call LoadCurrentMapView
- call LoadTilesetTilePatternData
- call EnableLCD
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-; reloads tileset tile patterns
-ReloadTilesetTilePatterns:: ; 3090 (0:3090)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,[W_CURMAP]
- call SwitchToMapRomBank
- call DisableLCD
- call LoadTilesetTilePatternData
- call EnableLCD
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-; shows the town map and lets the player choose a destination to fly to
-ChooseFlyDestination:: ; 30a9 (0:30a9)
- ld hl,wd72e
- res 4,[hl]
- ld b, BANK(LoadTownMap_Fly)
- ld hl, LoadTownMap_Fly
- jp Bankswitch
-
-; causes the text box to close without waiting for a button press after displaying text
-DisableWaitingAfterTextDisplay:: ; 30b6 (0:30b6)
- ld a,$01
- ld [wDoNotWaitForButtonPressAfterDisplayingText],a
- ret
-
-; uses an item
-; UseItem is used with dummy items to perform certain other functions as well
-; INPUT:
-; [wcf91] = item ID
-; OUTPUT:
-; [wcd6a] = success
-; 00: unsucessful
-; 01: successful
-; 02: not able to be used right now, no extra menu displayed (only certain items use this)
-UseItem:: ; 30bc (0:30bc)
- ld b,BANK(UseItem_)
- ld hl,UseItem_
- jp Bankswitch
-
-; 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
-; [wcf96] = quantity to toss
-; OUTPUT:
-; clears carry flag if the item is tossed, sets carry flag if not
-TossItem:: ; 30c4 (0:30c4)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,BANK(TossItem_)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call TossItem_
- pop de
- ld a,d
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-; checks if an item is a key item
-; INPUT:
-; [wcf91] = item ID
-; OUTPUT:
-; [wd124] = result
-; 00: item is not key item
-; 01: item is key item
-IsKeyItem:: ; 30d9 (0:30d9)
- push hl
- push de
- push bc
- callba IsKeyItem_
- pop bc
- pop de
- pop hl
- ret
-
-; function to draw various text boxes
-; INPUT:
-; [wTextBoxID] = text box ID
-DisplayTextBoxID:: ; 30e8 (0:30e8)
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,BANK(DisplayTextBoxID_)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call DisplayTextBoxID_
- pop bc
- ld a,b
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-; 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:: ; 30fd (0:30fd)
- 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:: ; 310e (0:310e)
- 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
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, [wNPCMovementScriptBank]
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- ld a, [wNPCMovementScriptFunctionNum]
- call CallFunctionInTable
- pop af
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- ret
-.NPCMovementScriptPointerTables
- dw ProfOakMovementScriptPointerTable
- dw PewterMuseumGuyMovementScriptPointerTable
- dw PewterGymGuyMovementScriptPointerTable
-.playerStepOutFromDoor
- ld b, BANK(PlayerStepOutFromDoor)
- ld hl, PlayerStepOutFromDoor
- jp Bankswitch
-
-EndNPCMovementScript:: ; 314e (0:314e)
- ld b, BANK(_EndNPCMovementScript)
- ld hl, _EndNPCMovementScript
- jp Bankswitch
-
-EmptyFunc2:: ; 3156 (0:3156)
- ret
-
-; stores hl in [W_TRAINERHEADERPTR]
-StoreTrainerHeaderPointer:: ; 3157 (0:3157)
- ld a, h
- ld [W_TRAINERHEADERPTR], a
- ld a, l
- ld [W_TRAINERHEADERPTR+1], a
- ret
-
-; executes the current map script from the function pointer array provided in hl.
-; a: map script index to execute (unless overridden by [wd733] bit 4)
-ExecuteCurMapScriptInTable:: ; 3160 (0:3160)
- push af
- push de
- call StoreTrainerHeaderPointer
- pop hl
- pop af
- push hl
- ld hl, W_FLAGS_D733
- bit 4, [hl]
- res 4, [hl]
- jr z, .useProvidedIndex ; test if map script index was overridden manually
- ld a, [W_CURMAPSCRIPT]
-.useProvidedIndex
- pop hl
- ld [W_CURMAPSCRIPT], a
- call CallFunctionInTable
- ld a, [W_CURMAPSCRIPT]
- ret
-
-LoadGymLeaderAndCityName:: ; 317f (0:317f)
- push de
- ld de, wGymCityName
- ld bc, $11
- call CopyData ; load city name
- pop hl
- ld de, wGymLeaderName
- ld bc, $b
- jp CopyData ; load gym leader name
-
-; reads specific information from trainer header (pointed to at W_TRAINERHEADERPTR)
-; 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:: ; 3193 (0:3193)
- push de
- push af
- ld d, $0
- ld e, a
- ld hl, W_TRAINERHEADERPTR
- 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:: ; 31cc (0:31cc)
- 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, $2
- 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 ; 0x31ed
- 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, W_FLAGS_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, W_CURMAPSCRIPT
- 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:: ; 3219 (0:3219)
- call CheckForEngagingTrainers
- ld a, [wSpriteIndex]
- cp $ff
- jr nz, .trainerEngaging
- xor a
- ld [wSpriteIndex], a
- ld [wTrainerHeaderFlagBit], a
- ret
-.trainerEngaging
- ld hl, W_FLAGS_D733
- set 3, [hl]
- ld [wcd4f], a
- xor a
- ld [wcd50], a
- predef EmotionBubble
- ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
- ld [wJoyIgnore], a
- xor a
- ldh [$b4], a
- call TrainerWalkUpToPlayer_Bank0
- ld hl, W_CURMAPSCRIPT
- 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:: ; 324c (0:324c)
- 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]
- ld [hSpriteIndexOrTextID], a
- call DisplayTextID
- ; fall through
-
-StartTrainerBattle:: ; 325d (0:325d)
- xor a
- ld [wJoyIgnore], a
- call InitBattleEnemyParameters
- ld hl, wd72d
- set 6, [hl]
- set 7, [hl]
- ld hl, wd72e
- set 1, [hl]
- ld hl, W_CURMAPSCRIPT
- inc [hl] ; increment map script index (next script function is usually EndTrainerBattle)
- ret
-
-EndTrainerBattle:: ; 3275 (0:3275)
- ld hl, wd126
- 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, [W_ISINBATTLE] ; W_ISINBATTLE
- cp $ff
- jp z, ResetButtonPressedAndMapScript
- ld a, $2
- call ReadTrainerHeaderInfo
- ld a, [wTrainerHeaderFlagBit]
- ld c, a
- ld b, $1
- call TrainerFlagAction ; flag trainer as fought
- ld a, [W_ENEMYMONORTRAINERCLASS]
- cp $c8
- jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite)
- ld hl, W_MISSABLEOBJECTLIST
- ld de, $2
- ld a, [wSpriteIndex]
- call IsInArray ; search for sprite ID
- inc hl
- ld a, [hl]
- ld [wcc4d], a ; load corresponding missable object index and remove it
- predef HideObject
-.skipRemoveSprite
- ld hl, wd730
- bit 4, [hl]
- res 4, [hl]
- ret nz
-
-ResetButtonPressedAndMapScript:: ; 32c1 (0:32c1)
- xor a
- ld [wJoyIgnore], a
- ld [hJoyHeld], a
- ld [hJoyPressed], a
- ld [hJoyReleased], a
- ld [W_CURMAPSCRIPT], a ; reset battle status
- ret
-
-; calls TrainerWalkUpToPlayer
-TrainerWalkUpToPlayer_Bank0:: ; 32cf (0:32cf)
- ld b, BANK(TrainerWalkUpToPlayer)
- ld hl, TrainerWalkUpToPlayer
- jp Bankswitch
-
-; sets opponent type and mon set/lvl based on the engaging trainer data
-InitBattleEnemyParameters:: ; 32d7 (0:32d7)
- ld a, [wEngagedTrainerClass]
- ld [W_CUROPPONENT], a ; wd059
- ld [W_ENEMYMONORTRAINERCLASS], a
- cp $c8
- ld a, [wEngagedTrainerSet] ; wcd2e
- jr c, .noTrainer
- ld [W_TRAINERNO], a ; wd05d
- ret
-.noTrainer
- ld [W_CURENEMYLVL], a ; W_CURENEMYLVL
- ret
-
-GetSpritePosition1:: ; 32ef (0:32ef)
- ld hl, _GetSpritePosition1
- jr asm_3301
-
-GetSpritePosition2:: ; 32f4 (0:32f4)
- ld hl, _GetSpritePosition2
- jr asm_3301 ; 0x32f7 $8
-
-SetSpritePosition1:: ; 32f9 (0:32f9)
- ld hl, _SetSpritePosition1
- jr asm_3301
-
-SetSpritePosition2:: ; 32fe (0:32fe)
- ld hl, _SetSpritePosition2
-asm_3301:: ; 3301 (0:3301)
- ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2)
- jp Bankswitch ; indirect jump to one of the four functions
-
-CheckForEngagingTrainers:: ; 3306 (0:3306)
- 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 $ff
- ret z
- ld a, $2
- call ReadTrainerHeaderInfo ; read trainer flag's byte ptr
- ld b, $2
- ld a, [wTrainerHeaderFlagBit]
- ld c, a
- call TrainerFlagAction ; read trainer flag
- ld a, c
- and a
- jr nz, .trainerAlreadyFought
- 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 ; wWhichTrade
- predef TrainerEngage
- pop de
- pop hl
- ld a, [wTrainerSpriteOffset] ; wWhichTrade
- and a
- ret nz ; break if the trainer is engaging
-.trainerAlreadyFought
- 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:: ; 3354 (0:3354)
- ld a, [H_LOADEDROMBANK]
- 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:: ; 336a (0:336a)
- ld hl, W_MAPSPRITEEXTRADATA
- 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 [wEnemyMonAttackMod], a ; wcd2e
- jp PlayTrainerMusic
-
-PrintEndBattleText:: ; 3381 (0:3381)
- push hl
- ld hl, wd72d
- bit 7, [hl]
- res 7, [hl]
- pop hl
- ret z
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, [wEndBattleTextRomBank]
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], a
- push hl
- callba SaveTrainerName
- ld hl, TrainerEndBattleText
- call PrintText
- pop hl
- pop af
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], a
- callba FreezeEnemyTrainerSprite
- jp WaitForSoundToFinish
-
-GetSavedEndBattleTextPointer:: ; 33b7 (0:33b7)
- 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:: ; 33cf (0:33cf)
- TX_FAR _TrainerNameText
- db $08
- call GetSavedEndBattleTextPointer
- call TextCommandProcessor
- jp TextScriptEnd
-
-; XXX unused?
-Func_33dd:: ; 33dd (0:33dd)
- ld a, [wFlags_0xcd60]
- bit 0, a
- ret nz
- call EngageMapTrainer
- xor a
- ret
-
-PlayTrainerMusic:: ; 33e8 (0:33e8)
- ld a, [wEngagedTrainerClass]
- cp $c8 + SONY1
- ret z
- cp $c8 + SONY2
- ret z
- cp $c8 + SONY3
- ret z
- ld a, [W_GYMLEADERNO] ; W_GYMLEADERNO
- and a
- ret nz
- xor a
- ld [wMusicHeaderPointer], a
- ld a, $ff
- call PlaySound ; stop music
- ld a, BANK(Music_MeetEvilTrainer)
- ld [wc0ef], a
- ld [wc0f0], 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 [wc0ee], a
- jp PlaySound
-
-INCLUDE "data/trainer_types.asm"
-
-; 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:: ; 3442 (0:3442)
- 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
-
-FuncTX_ItemStoragePC:: ; 3460 (0:3460)
- call SaveScreenTilesToBuffer2
- ld b, BANK(PlayerPC)
- ld hl, PlayerPC
- jr bankswitchAndContinue
-
-FuncTX_BillsPC:: ; 346a (0:346a)
- call SaveScreenTilesToBuffer2
- ld b, BANK(BillsPC_)
- ld hl, BillsPC_
- jr bankswitchAndContinue
-
-FuncTX_SlotMachine:: ; 3474 (0:3474)
-; XXX find a better name for this function
-; special_F7
- ld b,BANK(CeladonPrizeMenu)
- ld hl,CeladonPrizeMenu
-bankswitchAndContinue:: ; 3479 (0:3479)
- call Bankswitch
- jp HoldTextDisplayOpen ; continue to main text-engine function
-
-FuncTX_PokemonCenterPC:: ; 347f (0:347f)
- ld b, BANK(ActivatePC)
- ld hl, ActivatePC
- jr bankswitchAndContinue
-
-StartSimulatingJoypadStates:: ; 3486 (0:3486)
- xor a
- ld [wOverrideSimulatedJoypadStatesMask], a
- ld [wSpriteStateData2 + $06], a ; player's sprite movement byte 1
- ld hl, wd730
- set 7, [hl]
- ret
-
-IsItemInBag:: ; 3493 (0:3493)
-; 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 IsItemInBag_
- ld a,b
- and a
- ret
-
-DisplayPokedex:: ; 349b (0:349b)
- ld [wd11e], a
- ld b, BANK(Func_7c18)
- ld hl, Func_7c18
- jp Bankswitch
-
-SetSpriteFacingDirectionAndDelay:: ; 34a6 (0:34a6)
- call SetSpriteFacingDirection
- ld c, $6
- jp DelayFrames
-
-SetSpriteFacingDirection:: ; 34ae (0:34ae)
- ld a, $9
- ld [H_SPRITEDATAOFFSET], a
- call GetPointerWithinSpriteStateData1
- ld a, [$ff8d]
- ld [hl], a
- ret
-
-SetSpriteImageIndexAfterSettingFacingDirection:: ; 34b9 (0:34b9)
- ld de, -7
- add hl, de
- ld [hl], a
- ret
-
-; tests if the player's coordinates are in a specified array
-; INPUT:
-; hl = address of array
-; OUTPUT:
-; [wWhichTrade] = if there is match, the matching array index
-; sets carry if the coordinates are in the array, clears carry if not
-ArePlayerCoordsInArray:: ; 34bf (0:34bf)
- ld a,[W_YCOORD]
- ld b,a
- ld a,[W_XCOORD]
- ld c,a
- ; fallthrough
-
-CheckCoords:: ; 34c7 (0:34c7)
- xor a
- ld [wWhichTrade],a
-.loop
- ld a,[hli]
- cp a,$ff ; reached terminator?
- jr z,.notInArray
- push hl
- ld hl,wWhichTrade
- 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
-; [H_SPRITEINDEX] = index of boulder sprite
-; OUTPUT:
-; [wWhichTrade] = if there is match, the matching array index
-; sets carry if the coordinates are in the array, clears carry if not
-CheckBoulderCoords:: ; 34e4 (0:34e4)
- push hl
- ld hl, wSpriteStateData2 + $04
- ld a, [H_SPRITEINDEX]
- 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:: ; 34fc (0:34fc)
- ld h, $c1
- jr _GetPointerWithinSpriteStateData
-
-GetPointerWithinSpriteStateData2:: ; 3500 (0:3500)
- ld h, $c2
-
-_GetPointerWithinSpriteStateData:
- ld a, [H_SPRITEDATAOFFSET]
- ld b, a
- ld a, [H_SPRITEINDEX]
- 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:: ; 350c (0:350c)
- xor a
- ld [wRLEByteCount], a ; count written bytes here
-.listLoop
- ld a, [de]
- cp $ff
- jr z, .endOfList
- ld [H_DOWNARROWBLINKCNT1], 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
- ld a, [H_DOWNARROWBLINKCNT1] ; $ff8b
- 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 [$FF8C] to $FE and byte 2 to [$FF8D]
-SetSpriteMovementBytesToFE:: ; 3533 (0:3533)
- push hl
- call GetSpriteMovementByte1Pointer
- ld [hl], $fe
- call GetSpriteMovementByte2Pointer
- ld a, [$ff8d]
- ld [hl], a
- pop hl
- ret
-
-; sets both movement bytes for sprite [$FF8C] to $FF
-SetSpriteMovementBytesToFF:: ; 3541 (0:3541)
- 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 [$FF8C] in hl
-GetSpriteMovementByte1Pointer:: ; 354e (0:354e)
- ld h,$C2
- ld a,[H_SPRITEINDEX] ; the sprite to move
- swap a
- add a,6
- ld l,a
- ret
-
-; returns the sprite movement byte 2 pointer for sprite [$FF8C] in hl
-GetSpriteMovementByte2Pointer:: ; 3558 (0:3558)
- push de
- ld hl,W_MAPSPRITEDATA
- ld a,[$FF8C] ; the sprite to move
- dec a
- add a
- ld d,0
- ld e,a
- add hl,de
- pop de
- ret
-
-GetTrainerInformation:: ; 3566 (0:3566)
- call GetTrainerName
- ld a, [wLinkState]
- and a
- jr nz, .linkBattle
- ld a, Bank(TrainerPicAndMoneyPointers)
- call BankswitchHome
- ld a, [W_TRAINERCLASS] ; wd031
- 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, wd046
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hli]
- ld [de], a
- jp BankswitchBack
-.linkBattle
- ld hl, wTrainerPicPointer
- ld de, RedPicFront
- ld [hl], e
- inc hl
- ld [hl], d
- ret
-
-GetTrainerName:: ; 359e (0:359e)
- ld b, BANK(GetTrainerName_)
- ld hl, GetTrainerName_
- jp Bankswitch
-
-
-HasEnoughMoney::
-; Check if the player has at least as much
-; money as the 3-byte BCD value at $ff9f.
- ld de, wPlayerMoney
- ld hl, $ff9f
- ld c, 3
- jp StringCmp
-
-HasEnoughCoins::
-; Check if the player has at least as many
-; coins as the 2-byte BCD value at $ffa0.
- ld de, wPlayerCoins
- ld hl, $ffa0
- ld c, 2
- jp StringCmp
-
-
-BankswitchHome:: ; 35d9 (0:35d9)
-; switches to bank # in a
-; Only use this when in the home bank!
- ld [wcf09],a
- ld a,[H_LOADEDROMBANK]
- ld [wcf08],a
- ld a,[wcf09]
- call BankswitchCommon
- ret
-
-BankswitchBack:: ; 35e8 (0:35e8)
-; returns from BankswitchHome
- ld a,[wcf08]
- call BankswitchCommon
- ret
-
-BankswitchCommon:: ; 3e7e (0:3e7e)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-Bankswitch:: ; 3e84 (0:3e84)
-; self-contained bankswitch, use this when not in the home bank
-; switches to the bank in b
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,b
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call .jumptoaddress
- pop bc
- ld a,b
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-.jumptoaddress
- jp [hl]
-
-; displays yes/no choice
-; yes -> set carry
-YesNoChoice:: ; 35ec (0:35ec)
- call SaveScreenTilesToBuffer1
- call InitYesNoTextBoxParameters
- jr DisplayYesNoChoice
-
-Func_35f4:: ; 35f4 (0:35f4)
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call InitYesNoTextBoxParameters
- jp DisplayTextBoxID
-
-InitYesNoTextBoxParameters:: ; 35ff (0:35ff)
- xor a ; YES_NO_MENU
- ld [wTwoOptionMenuID], a
- hlCoord 14, 7
- ld bc, $80f
- ret
-
-YesNoChoicePokeCenter:: ; 360a (0:360a)
- call SaveScreenTilesToBuffer1
- ld a, HEAL_CANCEL_MENU
- ld [wTwoOptionMenuID], a
- hlCoord 11, 6
- ld bc, $80c
- jr DisplayYesNoChoice
-
-Func_361a:: ; 361a (0:361a)
- call SaveScreenTilesToBuffer1
- ld a, WIDE_YES_NO_MENU
- ld [wTwoOptionMenuID], a
- hlCoord 12, 7
- ld bc, $080d
-DisplayYesNoChoice:: ; 3628 (0:3628)
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID
- jp LoadScreenTilesFromBuffer1
-
-; calculates the difference |a-b|, setting carry flag if a<b
-CalcDifference:: ; 3633 (0:3633)
- sub b
- ret nc
- cpl
- add $1
- scf
- ret
-
-MoveSprite:: ; 363a (0:363a)
-; move the sprite [$FF8C] with the movement pointed to by de
-; actually only copies the movement data to wcc5b for later
- call SetSpriteMovementBytesToFF
-MoveSprite_:: ; 363d (0:363d)
- push hl
- push bc
- call GetSpriteMovementByte1Pointer
- xor a
- ld [hl],a
- ld hl,wcc5b
- ld c,0
-
-.loop
- ld a,[de]
- ld [hli],a
- inc de
- inc c
- cp a,$FF ; have we reached the end of the movement data?
- jr nz,.loop
-
- ld a,c
- ld [wcf0f],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 [$ffe5] by [$ffe6] and stores the quotient in [$ffe7]
-DivideBytes:: ; 366b (0:366b)
- push hl
- ld hl, $ffe7
- 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
-
-
-LoadFontTilePatterns::
- ld a, [rLCDC]
- bit 7, a ; is the LCD enabled?
- jr nz, .on
-.off
- ld hl, FontGraphics
- ld de, vFont
- ld bc, $400
- ld a, BANK(FontGraphics)
- jp FarCopyDataDouble ; if LCD is off, transfer all at once
-.on
- ld de, FontGraphics
- ld hl, vFont
- ld bc, BANK(FontGraphics) << 8 | $80
- jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
-
-LoadTextBoxTilePatterns::
- ld a, [rLCDC]
- bit 7, a ; is the LCD enabled?
- jr nz, .on
-.off
- ld hl, TextBoxGraphics
- ld de, vChars2 + $600
- ld bc, $200
- ld a, BANK(TextBoxGraphics)
- jp FarCopyData2 ; if LCD is off, transfer all at once
-.on
- ld de, TextBoxGraphics
- ld hl, vChars2 + $600
- ld bc, BANK(TextBoxGraphics) << 8 | $20
- jp CopyVideoData ; if LCD is on, transfer during V-blank
-
-LoadHpBarAndStatusTilePatterns::
- ld a, [rLCDC]
- bit 7, a ; is the LCD enabled?
- jr nz, .on
-.off
- ld hl, HpBarAndStatusGraphics
- ld de, vChars2 + $620
- ld bc, $1e0
- ld a, BANK(HpBarAndStatusGraphics)
- jp FarCopyData2 ; if LCD is off, transfer all at once
-.on
- ld de, HpBarAndStatusGraphics
- ld hl, vChars2 + $620
- ld bc, BANK(HpBarAndStatusGraphics) << 8 | $1e
- jp CopyVideoData ; if LCD is on, transfer during V-blank
-
-
-UncompressSpriteFromDE:: ; 36eb (0:36eb)
-; Decompress pic at a:de.
- ld hl, W_SPRITEINPUTPTR
- ld [hl], e
- inc hl
- ld [hl], d
- jp UncompressSpriteData
-
-
-SaveScreenTilesToBuffer2:: ; 36f4 (0:36f4)
- ld hl, wTileMap
- ld de, wTileMapBackup2
- ld bc, $168
- call CopyData
- ret
-
-LoadScreenTilesFromBuffer2:: ; 3701 (0:3701)
- call LoadScreenTilesFromBuffer2DisableBGTransfer
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
- ret
-
-; loads screen tiles stored in wTileMapBackup2 but leaves H_AUTOBGTRANSFERENABLED disabled
-LoadScreenTilesFromBuffer2DisableBGTransfer:: ; 3709 (0:3709)
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
- ld hl, wTileMapBackup2
- ld de, wTileMap
- ld bc, $168
- call CopyData
- ret
-
-SaveScreenTilesToBuffer1:: ; 3719 (0:3719)
- ld hl, wTileMap
- ld de, wTileMapBackup
- ld bc, $168
- jp CopyData
-
-LoadScreenTilesFromBuffer1:: ; 3725 (0:3725)
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
- ld hl, wTileMapBackup
- ld de, wTileMap
- ld bc, $168
- call CopyData
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
- ret
-
-DelayFrames:: ; 3739 (0:3739)
-; wait n frames, where n is the value in c
- call DelayFrame
- dec c
- jr nz,DelayFrames
- ret
-
-PlaySoundWaitForCurrent:: ; 3740 (0:3740)
- push af
- call WaitForSoundToFinish
- pop af
- jp PlaySound
-
-; Wait for sound to finish playing
-WaitForSoundToFinish:: ; 3748 (0:3748)
- ld a, [wLowHealthAlarm]
- and $80
- ret nz
- push hl
-.asm_374f
- ld hl, wc02a
- xor a
- or [hl]
- inc hl
- or [hl]
- inc hl
- inc hl
- or [hl]
- jr nz, .asm_374f
- pop hl
- ret
-
-NamePointers:: ; 375d (0:375d)
- dw MonsterNames
- dw MoveNames
- dw UnusedNames
- dw ItemNames
- dw wPartyMonOT ; player's OT names list
- dw wEnemyMonOT ; enemy's OT names list
- dw TrainerNames
-
-GetName:: ; 376b (0:376b)
-; 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 HM_01
- jp nc, GetMachineName
-
- ld a,[H_LOADEDROMBANK]
- 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,11
- add hl,de
- ld e,l
- ld d,h
- jr .gotPtr
-.otherEntries ; $378d
- ;2-7 = OTHER ENTRIES
- ld a,[wPredefBank]
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ld a,[wNameListType] ;VariousNames' entryID
- dec a
- add a
- ld d,0
- ld e,a
- jr nc,.skip
- inc d
-.skip ; $37a0
- ld hl,NamePointers
- add hl,de
- ld a,[hli]
- ld [$ff96],a
- ld a,[hl]
- ld [$ff95],a
- ld a,[$ff95]
- ld h,a
- ld a,[$ff96]
- ld l,a
- ld a,[wd0b5]
- ld b,a
- ld c,0
-.nextName
- ld d,h
- ld e,l
-.nextChar
- ld a,[hli]
- cp a, "@"
- 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,$0014
- call CopyData
-.gotPtr ; $37cd
- ld a,e
- ld [wcf8d],a
- ld a,d
- ld [wcf8e],a
- pop de
- pop bc
- pop hl
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- ret
-
-GetItemPrice:: ; 37df (0:37df)
-; Stores item's price as BCD at hItemPrice (3 bytes)
-; Input: [wcf91] = item id
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, [wListMenuID]
- cp MOVESLISTMENU
- ld a, BANK(ItemPrices)
- jr nz, .asm_37ed
- ld a, $f ; hardcoded Bank
-.asm_37ed
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- ld hl, wItemPrices
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [wcf91] ; a contains item id
- cp HM_01
- jr nc, .getTMPrice
- ld bc, $3
-.asm_3802
- add hl, bc
- dec a
- jr nz, .asm_3802
- dec hl
- ld a, [hld]
- ld [hItemPrice + 2], a
- ld a, [hld]
- ld [hItemPrice + 1], a
- ld a, [hl]
- ld [hItemPrice], a
- jr .asm_381c
-.getTMPrice
- ld a, Bank(GetMachinePrice)
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- call GetMachinePrice
-.asm_381c
- ld de, hItemPrice
- pop af
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- ret
-
-; copies a string from [de] to [wcf4b]
-CopyStringToCF4B:: ; 3826 (0:3826)
- ld hl, wcf4b
- ; fall through
-
-; copies a string from [de] to [hl]
-CopyString:: ; 3829 (0:3829)
- ld a, [de]
- inc de
- ld [hli], a
- cp "@"
- jr nz, CopyString
- ret
-
-; 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 esentially 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:: ; 3831 (0:3831)
- call Joypad
- ld a,[hJoy7] ; flag
- and a ; get all currently pressed buttons or only newly pressed buttons?
- ld a,[hJoyPressed] ; newly pressed buttons
- jr z,.storeButtonState
- ld a,[hJoyHeld] ; all currently pressed buttons
-.storeButtonState
- ld [hJoy5],a
- ld 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
- ld [H_FRAMECOUNTER],a
- ret
-.noNewlyPressedButtons
- ld a,[H_FRAMECOUNTER]
- and a ; is the delay over?
- jr z,.delayOver
-.delayNotOver
- xor a
- ld [hJoy5],a ; report no buttons as pressed
- ret
-.delayOver
-; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed
- ld a,[hJoyHeld]
- and A_BUTTON | B_BUTTON
- jr z,.setShortDelay
- ld a,[hJoy6] ; flag
- and a
- jr nz,.setShortDelay
- xor a
- ld [hJoy5],a
-.setShortDelay
- ld a,5 ; 1/12 of a second delay
- ld [H_FRAMECOUNTER],a
- ret
-
-WaitForTextScrollButtonPress:: ; 3865 (0:3865)
- ld a, [H_DOWNARROWBLINKCNT1]
- push af
- ld a, [H_DOWNARROWBLINKCNT2]
- push af
- xor a
- ld [H_DOWNARROWBLINKCNT1], a
- ld a, $6
- ld [H_DOWNARROWBLINKCNT2], a
-.loop
- push hl
- ld a, [wTownMapSpriteBlinkingEnabled]
- and a
- jr z, .skipAnimation
- call TownMapSpriteBlinkingAnimation
-.skipAnimation
- hlCoord 18, 16
- call HandleDownArrowBlinkTiming
- pop hl
- call JoypadLowSensitivity
- predef CableClub_Run
- ld a, [hJoy5]
- and A_BUTTON | B_BUTTON
- jr z, .loop
- pop af
- ld [H_DOWNARROWBLINKCNT2], a
- pop af
- ld [H_DOWNARROWBLINKCNT1], a
- ret
-
-; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect
-ManualTextScroll:: ; 3898 (0:3898)
- ld a, [wLinkState]
- cp LINK_STATE_BATTLING
- jr z, .inLinkBattle
- call WaitForTextScrollButtonPress
- ld a, (SFX_02_40 - SFX_Headers_02) / 3
- jp PlaySound
-.inLinkBattle
- ld c, $41
- jp DelayFrames
-
-; function to do multiplication
-; all values are big endian
-; INPUT
-; FF96-FF98 = multiplicand
-; FF99 = multiplier
-; OUTPUT
-; FF95-FF98 = product
-Multiply:: ; 38ac (0:38ac)
- push hl
- push bc
- callab _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:: ; 38b9 (0:38b9)
- push hl
- push de
- push bc
- ld a,[H_LOADEDROMBANK]
- push af
- ld a,Bank(_Divide)
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- call _Divide
- pop af
- ld [H_LOADEDROMBANK],a
- ld [$2000],a
- pop bc
- pop de
- pop hl
- ret
-
-; 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 [wd358] flags.
-PrintLetterDelay:: ; 38d3 (0:38d3)
- ld a,[wd730]
- bit 6,a
- ret nz
- ld a,[wd358]
- bit 1,a
- ret z
- push hl
- push de
- push bc
- ld a,[wd358]
- bit 0,a
- jr z,.waitOneFrame
- ld a,[W_OPTIONS]
- and $f
- ld [H_FRAMECOUNTER],a
- jr .checkButtons
-.waitOneFrame
- ld a,1
- ld [H_FRAMECOUNTER],a
-.checkButtons
- call Joypad
- ld 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
- ld a,[H_FRAMECOUNTER]
- and a
- jr nz,.checkButtons
-.done
- pop bc
- pop de
- pop hl
- ret
-
-; Copies [hl, bc) to [de, bc - hl).
-; In other words, the source data is from hl up to but not including bc,
-; and the destination is de.
-CopyDataUntil:: ; 3913 (0:3913)
- 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.
-; [wcf95] == 0 specifies the party.
-; [wcf95] != 0 specifies the current box.
-RemovePokemon:: ; 391f (0:391f)
- ld hl, _RemovePokemon
- ld b, BANK(_RemovePokemon)
- jp Bankswitch
-
-AddPartyMon:: ; 3927 (0:3927)
- push hl
- push de
- push bc
- callba _AddPartyMon
- pop bc
- pop de
- pop hl
- ret
-
-; calculates all 5 stats of current mon and writes them to [de]
-CalcStats:: ; 3936 (0:3936)
- ld c, $0
-.statsLoop
- inc c
- call CalcStat
- ld a, [H_MULTIPLICAND+1]
- ld [de], a
- inc de
- ld a, [H_MULTIPLICAND+2]
- ld [de], a
- inc de
- ld a, c
- cp $5
- 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:: ; 394a (0:394a)
- push hl
- push de
- push bc
- ld a, b
- ld d, a
- push hl
- ld hl, W_MONHEADER
- 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
- ld [H_MULTIPLICAND], a
- ld [H_MULTIPLICAND+1], a
- inc b ; increment current stat exp bonus
- ld a, b
- cp $ff
- jr z, .statExpDone
- ld [H_MULTIPLICAND+2], a
- ld [H_MULTIPLIER], a
- call Multiply
- ld a, [hld]
- ld d, a
- ld a, [$ff98]
- sub d
- ld a, [hli]
- ld d, a
- ld a, [$ff97]
- sbc d ; test if (current stat exp bonus)^2 < stat exp
- jr c, .statExpLoop
-.statExpDone
- srl c
- pop hl
- push bc
- ld bc, $b ; skip to stat IV values
- 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 ; da = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4
-.noCarry2
- ld [H_MULTIPLICAND+2], a
- ld a, d
- ld [H_MULTIPLICAND+1], a
- xor a
- ld [H_MULTIPLICAND], a
- ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL
- ld [H_MULTIPLIER], a
- call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level
- ld a, [H_MULTIPLICAND]
- ld [H_DIVIDEND], a
- ld a, [H_MULTIPLICAND+1]
- ld [H_DIVIDEND+1], a
- ld a, [H_MULTIPLICAND+2]
- ld [H_DIVIDEND+2], a
- ld a, $64
- ld [H_DIVISOR], 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
- jr nz, .notHPStat
- ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL
- ld b, a
- ld a, [H_MULTIPLICAND+2]
- add b
- ld [H_MULTIPLICAND+2], a
- jr nc, .noCarry3
- ld a, [H_MULTIPLICAND+1]
- inc a
- ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level
-.noCarry3
- ld a, $a
-.notHPStat
- ld b, a
- ld a, [H_MULTIPLICAND+2]
- add b
- ld [H_MULTIPLICAND+2], a
- jr nc, .noCarry4
- ld a, [H_MULTIPLICAND+1]
- inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5
- ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10
-.noCarry4
- ld a, [H_MULTIPLICAND+1] ; check for overflow (>999)
- cp $4
- jr nc, .overflow
- cp $3
- jr c, .noOverflow
- ld a, [H_MULTIPLICAND+2]
- cp $e8
- jr c, .noOverflow
-.overflow
- ld a, $3 ; overflow: cap at 999
- ld [H_MULTIPLICAND+1], a
- ld a, $e7
- ld [H_MULTIPLICAND+2], a
-.noOverflow
- pop bc
- pop de
- pop hl
- ret
-
-AddEnemyMonToPlayerParty:: ; 3a53 (0:3a53)
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, BANK(_AddEnemyMonToPlayerParty)
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- call _AddEnemyMonToPlayerParty
- pop bc
- ld a, b
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- ret
-
-Func_3a68:: ; 3a68 (0:3a68)
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, BANK(Func_f51e)
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- call Func_f51e
- pop bc
- ld a, b
- ld [H_LOADEDROMBANK], a
- ld [$2000], a
- ret
-
-; skips a text entries, each of size $b (like trainer name, OT name, rival name, ...)
-; hl: base pointer, will be incremented by $b * a
-SkipFixedLengthTextEntries:: ; 3a7d (0:3a7d)
- and a
- ret z
- ld bc, $b
-.skipLoop
- add hl, bc
- dec a
- jr nz, .skipLoop
- ret
-
-AddNTimes:: ; 3a87 (0:3a87)
-; add bc to hl a times
- and a
- ret z
-.loop
- add hl,bc
- dec a
- jr nz,.loop
- ret
-
-; Compare strings, c bytes in length, at de and hl.
-; Often used to compare big endian numbers in battle calculations.
-StringCmp:: ; 3a8e (0:3a8e)
- ld a,[de]
- cp [hl]
- ret nz
- inc de
- inc hl
- dec c
- jr nz,StringCmp
- ret
-
-; 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:: ; 3a97 (0:3a97)
- ld h,wOAMBuffer / $100
- 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
-
-HandleMenuInput:: ; 3abe (0:3abe)
- xor a
- ld [wd09b],a
-
-HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2)
- ld a,[H_DOWNARROWBLINKCNT1]
- push af
- ld a,[H_DOWNARROWBLINKCNT2]
- push af ; save existing values on stack
- xor a
- ld [H_DOWNARROWBLINKCNT1],a ; blinking down arrow timing value 1
- ld a,$06
- ld [H_DOWNARROWBLINKCNT2],a ; blinking down arrow timing value 2
-.loop1
- xor a
- ld [wPartyMonAnimCounter],a ; counter for pokemon shaking animation
- call PlaceMenuCursor
- call Delay3
-.loop2
- push hl
- ld a,[wd09b]
- and a ; is it a pokemon selection menu?
- jr z,.getJoypadState
- callba AnimatePartyMon ; shake mini sprite of selected pokemon
-.getJoypadState
- pop hl
- call JoypadLowSensitivity
- ld 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
- ld [H_DOWNARROWBLINKCNT2],a
- pop af
- ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
- xor a
- ld [wMenuWrappingEnabled],a ; disable menu wrapping
- ret
-.keyPressed
- xor a
- ld [wcc4b],a
- ld a,[hJoy5]
- ld b,a
- 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
- ld 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_02_40 - SFX_Headers_02) / 3
- call PlaySound ; play sound
-.skipPlayingSound
- pop af
- ld [H_DOWNARROWBLINKCNT2],a
- pop af
- ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
- xor a
- ld [wMenuWrappingEnabled],a ; disable menu wrapping
- ld a,[hJoy5]
- ret
-.noWrappingAround
- ld a,[wcc37]
- and a ; should we return if the user tried to go past the top or bottom?
- jr z,.checkOtherKeys
- jr .checkIfAButtonOrBButtonPressed
-
-PlaceMenuCursor:: ; 3b7c (0:3b7c)
- ld a,[wTopMenuItemY]
- and a ; is the y coordinate 0?
- jr z,.adjustForXCoord
- ld hl,wTileMap
- 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
- push af
- ld a,[hFlags_0xFFF6]
- bit 1,a ; is the menu double spaced?
- jr z,.doubleSpaced1
- ld bc,20
- jr .getOldMenuItemScreenPosition
-.doubleSpaced1
- ld bc,40
-.getOldMenuItemScreenPosition
- pop af
-.oldMenuItemLoop
- add hl,bc
- dec a
- jr nz,.oldMenuItemLoop
-.checkForArrow1
- ld a,[hl]
- cp a,"▶" ; 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
- push af
- ld a,[hFlags_0xFFF6]
- bit 1,a ; is the menu double spaced?
- jr z,.doubleSpaced2
- ld bc,20
- jr .getCurrentMenuItemScreenPosition
-.doubleSpaced2
- ld bc,40
-.getCurrentMenuItemScreenPosition
- pop af
-.currentMenuItemLoop
- add hl,bc
- dec a
- jr nz,.currentMenuItemLoop
-.checkForArrow2
- ld a,[hl]
- cp a,"▶" ; 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:: ; 3bec (0:3bec)
- ld b,a
- ld a,[wMenuCursorLocation]
- ld l,a
- ld a,[wMenuCursorLocation + 1]
- ld h,a
- ld [hl],$ec ; outline of right arrow
- ld a,b
- ret
-
-; Replaces the menu cursor with a blank space.
-EraseMenuCursor:: ; 3bf9 (0:3bf9)
- 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 H_DOWNARROWBLINKCNT1 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
-; initliazed 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:: ; 3c04 (0:3c04)
- ld a,[hl]
- ld b,a
- ld a,$ee ; down arrow
- cp b
- jr nz,.downArrowOff
-.downArrowOn
- ld a,[H_DOWNARROWBLINKCNT1]
- dec a
- ld [H_DOWNARROWBLINKCNT1],a
- ret nz
- ld a,[H_DOWNARROWBLINKCNT2]
- dec a
- ld [H_DOWNARROWBLINKCNT2],a
- ret nz
- ld a," "
- ld [hl],a
- ld a,$ff
- ld [H_DOWNARROWBLINKCNT1],a
- ld a,$06
- ld [H_DOWNARROWBLINKCNT2],a
- ret
-.downArrowOff
- ld a,[H_DOWNARROWBLINKCNT1]
- and a
- ret z
- dec a
- ld [H_DOWNARROWBLINKCNT1],a
- ret nz
- dec a
- ld [H_DOWNARROWBLINKCNT1],a
- ld a,[H_DOWNARROWBLINKCNT2]
- dec a
- ld [H_DOWNARROWBLINKCNT2],a
- ret nz
- ld a,$06
- ld [H_DOWNARROWBLINKCNT2],a
- ld a,$ee ; down arrow
- 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 [wcc47] is set).
-
-EnableAutoTextBoxDrawing:: ; 3c3c (0:3c3c)
- xor a
- jr AutoTextBoxDrawingCommon
-
-DisableAutoTextBoxDrawing:: ; 3c3f (0:3c3f)
- ld a,$01
-
-AutoTextBoxDrawingCommon:: ; 3c41 (0:3c41)
- ld [wAutoTextBoxDrawingControl],a
- xor a
- ld [wDoNotWaitForButtonPressAfterDisplayingText],a ; make DisplayTextID wait for button press
- ret
-
-PrintText:: ; 3c49 (0:3c49)
-; Print text hl at (1, 14).
- push hl
- ld a,MESSAGE_BOX
- ld [wTextBoxID],a
- call DisplayTextBoxID
- call UpdateSprites
- call Delay3
- pop hl
-Func_3c59:: ; 3c59 (0:3c59)
- bcCoord 1, 14
- jp TextCommandProcessor
-
-
-PrintNumber:: ; 3c5f
-; 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.
-LEADING_ZEROES EQU 7
-LEFT_ALIGN EQU 6
-
- push bc
- xor a
- ld [H_PASTLEADINGZEROES], a
- ld [H_NUMTOPRINT], a
- ld [H_NUMTOPRINT + 1], a
- ld a, b
- and $f
- cp 1
- jr z, .byte
- cp 2
- jr z, .word
-.long
- ld a, [de]
- ld [H_NUMTOPRINT], a
- inc de
- ld a, [de]
- ld [H_NUMTOPRINT + 1], a
- inc de
- ld a, [de]
- ld [H_NUMTOPRINT + 2], a
- jr .start
-
-.word
- ld a, [de]
- ld [H_NUMTOPRINT + 1], a
- inc de
- ld a, [de]
- ld [H_NUMTOPRINT + 2], a
- jr .start
-
-.byte
- ld a, [de]
- ld [H_NUMTOPRINT + 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
- ld [H_POWEROFTEN + 0], a
-
-if (\1) / $100
- ld a, \1 / $100 % $100
-else xor a
-endc
- ld [H_POWEROFTEN + 1], a
-
- ld a, \1 / $1 % $100
- ld [H_POWEROFTEN + 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
- ld a, [H_NUMTOPRINT + 2]
-.mod
- cp 10
- jr c, .ok
- sub 10
- inc c
- jr .mod
-.ok
-
- ld b, a
- ld a, [H_PASTLEADINGZEROES]
- or c
- ld [H_PASTLEADINGZEROES], 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
- ld a, [H_POWEROFTEN]
- ld b, a
- ld a, [H_NUMTOPRINT]
- ld [H_SAVEDNUMTOPRINT], a
- cp b
- jr c, .underflow0
- sub b
- ld [H_NUMTOPRINT], a
- ld a, [H_POWEROFTEN + 1]
- ld b, a
- ld a, [H_NUMTOPRINT + 1]
- ld [H_SAVEDNUMTOPRINT + 1], a
- cp b
- jr nc, .noborrow1
-
- ld a, [H_NUMTOPRINT]
- or 0
- jr z, .underflow1
- dec a
- ld [H_NUMTOPRINT], a
- ld a, [H_NUMTOPRINT + 1]
-.noborrow1
-
- sub b
- ld [H_NUMTOPRINT + 1], a
- ld a, [H_POWEROFTEN + 2]
- ld b, a
- ld a, [H_NUMTOPRINT + 2]
- ld [H_SAVEDNUMTOPRINT + 2], a
- cp b
- jr nc, .noborrow2
-
- ld a, [H_NUMTOPRINT + 1]
- and a
- jr nz, .borrowed
-
- ld a, [H_NUMTOPRINT]
- and a
- jr z, .underflow2
- dec a
- ld [H_NUMTOPRINT], a
- xor a
-.borrowed
-
- dec a
- ld [H_NUMTOPRINT + 1], a
- ld a, [H_NUMTOPRINT + 2]
-.noborrow2
- sub b
- ld [H_NUMTOPRINT + 2], a
- inc c
- jr .loop
-
-.underflow2
- ld a, [H_SAVEDNUMTOPRINT + 1]
- ld [H_NUMTOPRINT + 1], a
-.underflow1
- ld a, [H_SAVEDNUMTOPRINT]
- ld [H_NUMTOPRINT], a
-.underflow0
- ld a, [H_PASTLEADINGZEROES]
- or c
- jr z, .PrintLeadingZero
-
- ld a, "0"
- add c
- ld [hl], a
- ld [H_PASTLEADINGZEROES], a
- ret
-
-.PrintLeadingZero:
- 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 LEADING_ZEROES, d
- jr nz, .inc
- bit LEFT_ALIGN, d
- jr z, .inc
- ld a, [H_PASTLEADINGZEROES]
- and a
- ret z
-.inc
- inc hl
- ret
-
-
-CallFunctionInTable::
-JumpTable::
-; 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
-
-
-RestoreScreenTilesAndReloadTilePatterns:: ; 3dbe (0:3dbe)
- call ClearSprites
- ld a, $1
- ld [wUpdateSpritesEnabled], a
- call ReloadMapSpriteTilePatterns
- call LoadScreenTilesFromBuffer2
- call LoadTextBoxTilePatterns
- call GoPAL_SET_CF1C
- 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
- ld [rBGP], a
- ld a, %11010000 ; 3100
- ld [rOBP0], a
- ret
-
-GBPalWhiteOut::
-; White out all palettes.
- xor a
- ld [rBGP],a
- ld [rOBP0],a
- ld [rOBP1],a
- ret
-
-
-GoPAL_SET_CF1C:: ; 3ded (0:3ded)
- ld b,$ff
-GoPAL_SET:: ; 3def (0:3def)
- ld a,[wOnSGB]
- and a
- ret z
- predef_jump Func_71ddf
-
-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
-
-; Copy the current map's sprites' tile patterns to VRAM again after they have
-; been overwritten by other tile patterns.
-ReloadMapSpriteTilePatterns:: ; 3e08 (0:3e08)
- ld hl, wFontLoaded
- ld a, [hl]
- push af
- res 0, [hl]
- push hl
- xor a
- ld [W_SPRITESETID], a
- call DisableLCD
- callba InitMapSprites
- call EnableLCD
- pop hl
- pop af
- ld [hl], a
- call LoadPlayerSpriteGraphics
- call LoadFontTilePatterns
- jp UpdateSprites
-
-
-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 [wcf96], 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 [W_CURENEMYLVL], a
- xor a
- ld [wcc49], a
- ld b, BANK(_GivePokemon)
- ld hl, _GivePokemon
- jp Bankswitch
-
-
-Random::
-; Return a random number in a.
-; For battles, use BattleRandom.
- push hl
- push de
- push bc
- callba Random_
- ld a, [hRandomAdd]
- pop bc
- pop de
- pop hl
- ret
-
-
-INCLUDE "home/predef.asm"
-
-
-Func_3ead:: ; 3ead (0:3ead)
- ld b, BANK(CinnabarGymQuiz_1eb0a)
- ld hl, CinnabarGymQuiz_1eb0a
- jp Bankswitch
-
-CheckForHiddenObjectOrBookshelfOrCardKeyDoor:: ; 3eb5 (0:3eb5)
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, [hJoyHeld]
- bit 0, a ; A button
- jr z, .nothingFound
-; A button is pressed
- ld a, Bank(CheckForHiddenObject)
- ld [MBC1RomBank], a
- ld [H_LOADEDROMBANK], a
- call CheckForHiddenObject
- ld a, [$ffee]
- and a
- jr nz, .hiddenObjectNotFound
- ld a, [wHiddenObjectFunctionRomBank]
- ld [MBC1RomBank], a
- ld [H_LOADEDROMBANK], a
- ld de, .returnAddress
- push de
- jp [hl]
-.returnAddress
- xor a
- jr .done
-.hiddenObjectNotFound
- callba PrintBookshelfText
- ld a, [$ffdb]
- and a
- jr z, .done
-.nothingFound
- ld a, $ff
-.done
- ld [$ffeb], a
- pop af
- ld [MBC1RomBank], a
- ld [H_LOADEDROMBANK], a
- ret
-
-PrintPredefTextID:: ; 3ef5 (0:3ef5)
- ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
- ld hl, TextPredefs
- call SetMapTextPointer
- ld hl, wcf11
- set 0, [hl]
- call DisplayTextID
-
-RestoreMapTextPointer:: ; 3f05 (0:3f05)
- ld hl, W_MAPTEXTPTR
- ld a, [$ffec]
- ld [hli], a
- ld a, [$ffec + 1]
- ld [hl], a
- ret
-
-SetMapTextPointer:: ; 3f0f (0:3f0f)
- ld a, [W_MAPTEXTPTR]
- ld [$ffec], a
- ld a, [W_MAPTEXTPTR + 1]
- ld [$ffec + 1], a
- ld a, l
- ld [W_MAPTEXTPTR], a
- ld a, h
- ld [W_MAPTEXTPTR + 1], a
- ret
-
-TextPredefs::
- add_tx_pre CardKeySuccessText ; 01
- add_tx_pre CardKeyFailText ; 02
- add_tx_pre RedBedroomPC ; 03
- add_tx_pre RedBedroomSNESText ; 04
- add_tx_pre PushStartText ; 05
- add_tx_pre SaveOptionText ; 06
- add_tx_pre StrengthsAndWeaknessesText ; 07
- add_tx_pre OakLabEmailText ; 08
- add_tx_pre AerodactylFossilText ; 09
- add_tx_pre Route15UpstairsBinocularsText ; 0A
- add_tx_pre KabutopsFossilText ; 0B
- add_tx_pre GymStatueText1 ; 0C
- add_tx_pre GymStatueText2 ; 0D
- add_tx_pre BookcaseText ; 0E
- add_tx_pre ViridianCityPokecenterBenchGuyText ; 0F
- add_tx_pre PewterCityPokecenterBenchGuyText ; 10
- add_tx_pre CeruleanCityPokecenterBenchGuyText ; 11
- add_tx_pre LavenderCityPokecenterBenchGuyText ; 12
- add_tx_pre VermilionCityPokecenterBenchGuyText ; 13
- add_tx_pre CeladonCityPokecenterBenchGuyText ; 14
- add_tx_pre CeladonCityHotelText ; 15
- add_tx_pre FuchsiaCityPokecenterBenchGuyText ; 16
- add_tx_pre CinnabarIslandPokecenterBenchGuyText ; 17
- add_tx_pre SaffronCityPokecenterBenchGuyText ; 18
- add_tx_pre MtMoonPokecenterBenchGuyText ; 19
- add_tx_pre RockTunnelPokecenterBenchGuyText ; 1A
- add_tx_pre UnusedBenchGuyText1 ; 1B
- add_tx_pre UnusedBenchGuyText2 ; 1C
- add_tx_pre UnusedBenchGuyText3 ; 1D
- add_tx_pre TerminatorText_62508 ; 1E
- add_tx_pre PredefText1f ; 1F
- add_tx_pre ViridianSchoolNotebook ; 20
- add_tx_pre ViridianSchoolBlackboard ; 21
- add_tx_pre JustAMomentText ; 22
- add_tx_pre PredefText23 ; 23
- add_tx_pre FoundHiddenItemText ; 24
- add_tx_pre HiddenItemBagFullText ; 25
- add_tx_pre VermilionGymTrashText ; 26
- add_tx_pre IndigoPlateauHQText ; 27
- add_tx_pre GameCornerOutOfOrderText ; 28
- add_tx_pre GameCornerOutToLunchText ; 29
- add_tx_pre GameCornerSomeonesKeysText ; 2A
- add_tx_pre FoundHiddenCoinsText ; 2B
- add_tx_pre DroppedHiddenCoinsText ; 2C
- add_tx_pre BillsHouseMonitorText ; 2D
- add_tx_pre BillsHouseInitiatedText ; 2E
- add_tx_pre BillsHousePokemonList ; 2F
- add_tx_pre MagazinesText ; 30
- add_tx_pre CinnabarGymQuiz ; 31
- add_tx_pre GameCornerNoCoinsText ; 32
- add_tx_pre GameCornerCoinCaseText ; 33
- add_tx_pre LinkCableHelp ; 34
- add_tx_pre TMNotebook ; 35
- add_tx_pre FightingDojoText ; 36
- add_tx_pre FightingDojoText_52a10 ; 37
- add_tx_pre FightingDojoText_52a1d ; 38
- add_tx_pre NewBicycleText ; 39
- add_tx_pre IndigoPlateauStatues ; 3A
- add_tx_pre VermilionGymTrashSuccesText1 ; 3B
- add_tx_pre VermilionGymTrashSuccesText2 ; 3C
- add_tx_pre VermilionGymTrashSuccesText3 ; 3D
- add_tx_pre VermilionGymTrashFailText ; 3E
- add_tx_pre TownMapText ; 3F
- add_tx_pre BookOrSculptureText ; 40
- add_tx_pre ElevatorText ; 41
- add_tx_pre PokemonStuffText ; 42
+
+; The rst vectors are unused.
+SECTION "rst 00", ROM0 [$00]
+ rst $38
+SECTION "rst 08", ROM0 [$08]
+ rst $38
+SECTION "rst 10", ROM0 [$10]
+ rst $38
+SECTION "rst 18", ROM0 [$18]
+ rst $38
+SECTION "rst 20", ROM0 [$20]
+ rst $38
+SECTION "rst 28", ROM0 [$28]
+ rst $38
+SECTION "rst 30", ROM0 [$30]
+ rst $38
+SECTION "rst 38", ROM0 [$38]
+ rst $38
+
+; Hardware interrupts
+SECTION "vblank", ROM0 [$40]
+ jp VBlank
+SECTION "hblank", ROM0 [$48]
+ rst $38
+SECTION "timer", ROM0 [$50]
+ jp Timer
+SECTION "serial", ROM0 [$58]
+ jp Serial
+SECTION "joypad", ROM0 [$60]
+ reti
+
+
+SECTION "Home", ROM0
+
+DisableLCD::
+ xor a
+ ld [rIF], a
+ ld a, [rIE]
+ ld b, a
+ res 0, a
+ ld [rIE], a
+
+.wait
+ ld a, [rLY]
+ cp LY_VBLANK
+ jr nz, .wait
+
+ ld a, [rLCDC]
+ and $ff ^ rLCDC_ENABLE_MASK
+ ld [rLCDC], a
+ ld a, b
+ ld [rIE], a
+ ret
+
+EnableLCD::
+ ld a, [rLCDC]
+ set rLCDC_ENABLE, a
+ ld [rLCDC], a
+ ret
+
+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
+
+INCLUDE "home/copy.asm"
+
+
+
+SECTION "Entry", ROM0 [$100]
+
+ nop
+ jp Start ; 01ab
+
+
+SECTION "Header", ROM0 [$104]
+
+ ; The header is generated by rgbfix.
+ ; The space here is allocated to prevent code from being overwritten.
+
+ ds $150 - $104
+
+
+
+SECTION "Main", ROM0
+
+Func_150:: ; 0150 (0:0150)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,b
+ call BankswitchCommon
+ ld a,[hli]
+ ld c,a
+ ld a,[hli]
+ ld b,a
+.loop
+ ld a,[hli]
+ ld d,a
+ ld a,$3
+.unknownloop
+ dec a
+ jr nz,.unknownloop
+
+ rept 7
+ call Func_199
+ call Func_1a5
+ endr
+
+ call Func_199
+ dec bc
+ ld a,c
+ or b
+ jr nz,.loop
+ pop af
+ call BankswitchCommon
+ ret
+
+Func_199:: ; 0199 (0:0199)
+ ld a,d
+ and $80
+ srl a
+ srl a
+ ld [rNR32],a
+ sla d
+ ret
+
+Func_1a5:: ; 01a5 (0:01a5)
+ ld a,$3
+.unknownloop2
+ dec a
+ jr nz,.unknownloop2
+ ret
+
+Start::
+ cp GBC
+ jr z, .gbc
+ xor a
+ jr .ok
+.gbc
+ ld a, $1
+.ok
+ ld [hGBC], a
+ jp Init
+
+Joypad:: ; 01b9
+ homecall_jump _Joypad
+
+ReadJoypad:: ; 01c8 (0:01c8)
+ homecall_jump ReadJoypad_
+
+INCLUDE "data/map_header_pointers.asm"
+INCLUDE "home/overworld.asm"
+
+
+CheckForUserInterruption:: ; 12f8 (0:12f8)
+; 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
+
+ ld a, [hJoyHeld]
+ cp D_UP + SELECT + B_BUTTON
+ jr z, .input
+
+ ld 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:: ; 1313 (0:1313)
+ ld b,a
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[wPredefParentBank]
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],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
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+
+DrawHPBar:: ; 1336 (0:1336)
+; 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 iz 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 W_MONHDEXNUM
+; INPUT:
+; [wWhichPokemon] = index of pokemon within party/box
+; [wcc49] = source
+; 00: player's party
+; 01: enemy's party
+; 02: current box
+; 03: daycare
+; OUTPUT:
+; [wcf91] = pokemon ID
+; wLoadedMon = base address of pokemon data
+; W_MONHDEXNUM = base address of base stats
+LoadMonData:: ; 1372 (0:1372)
+ ld hl, LoadMonData_
+ ld b, BANK(LoadMonData_)
+ jp Bankswitch
+
+
+Func_137a:: ; 137a (0:137a)
+; 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:: ; 1384 (0:1384)
+ ld a, 1
+ ld [W_SPRITEFLIPPED], a
+
+LoadFrontSpriteByMonIndex:: ; 1389 (0:1389)
+ 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
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, Bank(asm_3f0d0)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ xor a
+ ld [$ffe1], a
+ call asm_3f0d0
+ xor a
+ ld [W_SPRITEFLIPPED], a
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+
+PlayCry:: ; 13d0 (0:13d0)
+; Play monster a's cry.
+ call GetCryData
+ call PlaySound
+ jp WaitForSoundToFinish
+
+GetCryData:: ; 13d9 (0:13d9)
+; 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 [wc0f1], a
+ ld a, [hl]
+ ld [wc0f2], a
+ call BankswitchBack
+
+ ; Cry headers have 3 channels,
+ ; and start from index $14,
+ ; so add 3 times the cry id.
+ ld a, b
+ ld c, $14
+ rlca ; * 2
+ add b
+ add c
+ ret
+
+
+DisplayPartyMenu:: ; 13fc (0:13fc)
+ ld a,[hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType],a
+ call GBPalWhiteOutWithDelay3
+ call ClearSprites
+ call PartyMenuInit
+ call DrawPartyMenu
+ jp HandlePartyMenuInput
+
+GoBackToPartyMenu:: ; 1411 (0:1411)
+ ld a,[hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType],a
+ call PartyMenuInit
+ call RedrawPartyMenu
+ jp HandlePartyMenuInput
+
+PartyMenuInit:: ; 1420 (0:1420)
+ ld a, 1 ; hardcoded bank
+ call BankswitchHome
+ call LoadHpBarAndStatusTilePatterns
+ ld hl, wd730
+ set 6, [hl] ; turn off letter printing delay
+ xor a
+ ld [wcc49], a
+ ld [wcc37], a
+ ld hl, wTopMenuItemY
+ inc a
+ ld [hli], a ; top menu item Y
+ xor a
+ ld [hli], a ; top menu item X
+ ld a, [wcc2b]
+ 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, [wd11f]
+ and a
+ ld a, A_BUTTON + B_BUTTON
+ jr z, .next
+ xor a
+ ld [wd11f], a
+ inc a
+.next
+ ld [hli], a ; menu watched keys
+ pop af
+ ld [hl], a ; old menu item ID
+ ret
+
+HandlePartyMenuInput:: ; 145a (0:145a)
+ ld a,1
+ ld [wMenuWrappingEnabled],a
+ ld a,$40
+ ld [wd09b],a
+ call HandleMenuInputPokemonSelection
+ call PlaceUnfilledArrowMenuCursor
+ ld b,a
+ xor a
+ ld [wd09b],a
+ ld a,[wCurrentMenuItem]
+ ld [wcc2b],a
+ ld hl,wd730
+ res 6,[hl] ; turn on letter printing delay
+ ld a,[wMenuItemToSwap]
+ and a
+ jp nz,.swappingPokemon
+ pop af
+ ld [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
+.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
+ callba ErasePartyMenuCursors
+ xor a
+ ld [wMenuItemToSwap],a
+ ld [wd07d],a
+ call RedrawPartyMenu
+ jr HandlePartyMenuInput
+.handleSwap
+ ld a,[wCurrentMenuItem]
+ ld [wWhichPokemon],a
+ callba SwitchPartyMon
+ jr HandlePartyMenuInput
+
+DrawPartyMenu:: ; 14d4 (0:14d4)
+ ld hl, DrawPartyMenu_
+ jr DrawPartyMenuCommon
+
+RedrawPartyMenu:: ; 14d9 (0:14d9)
+ ld hl, RedrawPartyMenu_
+
+DrawPartyMenuCommon:: ; 14dc (0:14dc)
+ ld b, BANK(RedrawPartyMenu_)
+ jp Bankswitch
+
+; prints a pokemon's status condition
+; INPUT:
+; de = address of status condition
+; hl = destination address
+PrintStatusCondition:: ; 14e1 (0:14e1)
+ 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 ; 14f6
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(PrintStatusAilment)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call PrintStatusAilment ; print status condition
+ pop bc
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; function to print pokemon level, leaving off the ":L" if the level is at least 100
+; INPUT:
+; hl = destination address
+; [wLoadedMonLevel] = level
+PrintLevel:: ; 150b (0:150b)
+ ld a,$6e ; ":L" tile ID
+ ld [hli],a
+ ld c,2 ; number of digits
+ ld a,[wLoadedMonLevel] ; level
+ cp a,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:: ; 151b (0:151b)
+ ld a,$6e ; ":L" tile ID
+ ld [hli],a
+ ld c,3 ; number of digits
+ ld a,[wLoadedMonLevel] ; level
+
+PrintLevelCommon:: ; 1523 (0:1523)
+ ld [wd11e],a
+ ld de,wd11e
+ ld b,$41 ; no leading zeroes, left-aligned, one byte
+ jp PrintNumber
+
+Func_152e:: ; 152e (0:152e)
+; Unused.
+ 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 W_MONHDEXNUM (W_MONHEADER)
+; INPUT:
+; [wd0b5] = pokemon ID
+GetMonHeader:: ; 1537 (0:1537)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(BaseStats)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ 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 a,FOSSIL_KABUTOPS ; Kabutops fossil
+ jr z,.specialID
+ ld de,GhostPic
+ cp a,MON_GHOST ; Ghost
+ jr z,.specialID
+ ld de,FossilAerodactylPic
+ ld b,$77 ; size of Aerodactyl fossil sprite
+ cp a,FOSSIL_AERODACTYL ; Aerodactyl fossil
+ jr z,.specialID
+ cp a,MEW
+ jr z,.mew
+ predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number
+ ld a,[wd11e]
+ dec a
+ ld bc,28
+ ld hl,BaseStats
+ call AddNTimes
+ ld de,W_MONHEADER
+ ld bc,28
+ call CopyData
+ jr .done
+.specialID
+ ld hl,W_MONHSPRITEDIM
+ ld [hl],b ; write sprite dimensions
+ inc hl
+ ld [hl],e ; write front sprite pointer
+ inc hl
+ ld [hl],d
+ jr .done
+.mew
+ ld hl,MewBaseStats
+ ld de,W_MONHEADER
+ ld bc,28
+ ld a,BANK(MewBaseStats)
+ call FarCopyData
+.done
+ ld a,[wd0b5]
+ ld [W_MONHDEXNUM],a
+ pop af
+ ld [wd11e],a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; copy party pokemon's name to wcd6d
+GetPartyMonName2:: ; 15b4 (0:15b4)
+ ld a,[wWhichPokemon] ; index within party
+ ld hl,wPartyMonNicks
+
+; this is called more often
+GetPartyMonName:: ; 15ba (0:15ba)
+ push hl
+ push bc
+ call SkipFixedLengthTextEntries ; add 11 to hl, a times
+ ld de,wcd6d
+ push de
+ ld bc,11
+ call CopyData
+ pop de
+ pop bc
+ pop hl
+ ret
+
+; 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:: ; 15cd (0:15cd)
+ 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:: ; 1604 (0:1604)
+ 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 a,"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
+
+; 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:: ; 1627 (0:1627)
+ ld bc,W_MONHEADER
+ add hl,bc
+ ld a,[hli]
+ ld [W_SPRITEINPUTPTR],a ; fetch sprite input pointer
+ ld a,[hl]
+ ld [W_SPRITEINPUTPTR+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:: ; 1665 (0:1665)
+ push de
+ ld hl, W_MONHFRONTSPRITE - W_MONHEADER
+ call UncompressMonSprite
+ ld hl, W_MONHSPRITEDIM
+ 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:: ; 1672 (0:1672)
+ push de
+ and $f
+ ld [H_SPRITEWIDTH], 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)
+ ld [H_SPRITEOFFSET], a
+ ld a, c
+ swap a
+ and $f
+ ld b, a
+ add a
+ add a
+ add a ; 8*tiles is height in bytes
+ ld [H_SPRITEHEIGHT], a ; $ff8c
+ ld a, $7
+ sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
+ ld b, a
+ ld a, [H_SPRITEOFFSET]
+ 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)
+ ld [H_SPRITEOFFSET], a
+ xor a
+ ld [$4000], a
+ ld hl, S_SPRITEBUFFER0
+ call ZeroSpriteBuffer ; zero buffer 0
+ ld de, S_SPRITEBUFFER1
+ ld hl, S_SPRITEBUFFER0
+ call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
+ ld hl, S_SPRITEBUFFER1
+ call ZeroSpriteBuffer ; zero buffer 1
+ ld de, S_SPRITEBUFFER2
+ ld hl, S_SPRITEBUFFER1
+ call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
+ 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:: ; 16c2 (0:16c2)
+ ld a, [H_SPRITEOFFSET]
+ ld b, $0
+ ld c, a
+ add hl, bc
+ ld a, [H_SPRITEWIDTH] ; $ff8b
+.columnLoop
+ push af
+ push hl
+ ld a, [H_SPRITEHEIGHT] ; $ff8c
+ 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:: ; 16df (0:16df)
+ 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:: ; 16ea (0:16ea)
+ xor a
+ ld [$4000], a
+ push de
+ ld hl, S_SPRITEBUFFER2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
+ ld de, S_SPRITEBUFFER1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
+ ld bc, S_SPRITEBUFFER0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
+ ld a, SPRITEBUFFERSIZE/2 ; $c4
+ ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b
+.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
+ ld a, [H_SPRITEINTERLACECOUNTER] ; $ff8b
+ dec a
+ ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b
+ jr nz, .interlaceLoop
+ ld a, [W_SPRITEFLIPPED]
+ and a
+ jr z, .notFlipped
+ ld bc, 2*SPRITEBUFFERSIZE
+ ld hl, S_SPRITEBUFFER1
+.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, S_SPRITEBUFFER1
+ ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
+ ld a, [H_LOADEDROMBANK]
+ ld b, a
+ jp CopyVideoData
+
+
+INCLUDE "data/collision.asm"
+
+IsTilePassable:: ; 15c3 (0:15c3)
+; sets carry if tile is passable, resets carry otherwise
+ homecall_sf _IsTilePassable ; 1:4aaa
+ ret
+
+INCLUDE "home/copy2.asm"
+INCLUDE "home/text.asm"
+INCLUDE "home/vcopy.asm"
+INCLUDE "home/init.asm"
+INCLUDE "home/vblank.asm"
+INCLUDE "home/fade.asm"
+INCLUDE "home/serial.asm"
+INCLUDE "home/timer.asm"
+INCLUDE "home/audio.asm"
+
+
+UpdateSprites:: ; 2429 (0:2429)
+ ld a, [wUpdateSpritesEnabled]
+ dec a
+ ret nz
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, Bank(_UpdateSprites)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ call _UpdateSprites
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+INCLUDE "data/mart_inventories.asm"
+
+TextScriptEndingChar:: ; 24d6 (0:24d6)
+ db "@"
+TextScriptEnd:: ; 24d7 (0:24d7)
+ ld hl,TextScriptEndingChar
+ ret
+
+ExclamationText:: ; 24db (0:24db)
+ TX_FAR _ExclamationText
+ db "@"
+
+GroundRoseText:: ; 24e0 (0:24e0)
+ TX_FAR _GroundRoseText
+ db "@"
+
+BoulderText:: ; 24e5 (0:24e5)
+ TX_FAR _BoulderText
+ db "@"
+
+MartSignText:: ; 24ea (0:24ea)
+ TX_FAR _MartSignText
+ db "@"
+
+PokeCenterSignText:: ; 24ef (0:24ef)
+ TX_FAR _PokeCenterSignText
+ db "@"
+
+Predef5CText:: ; 24f4 (0:24f4)
+; XXX better label (what does predef $5C do?)
+ db $08 ; asm
+ predef PickupItem
+ jp TextScriptEnd
+
+
+INCLUDE "home/pic.asm"
+
+
+ResetPlayerSpriteData:: ; 28a6 (0:28a6)
+ ld hl, wSpriteStateData1
+ call ResetPlayerSpriteData_ClearSpriteData
+ ld hl, wSpriteStateData2
+ call ResetPlayerSpriteData_ClearSpriteData
+ ld a, $1
+ ld [wSpriteStateData1], a
+ ld [wSpriteStateData2 + $0e], a
+ ld hl, wSpriteStateData1 + 4
+ 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:: ; 28c4 (0:28c4)
+ ld bc, $10
+ xor a
+ jp FillMemory
+
+Func_28cb:: ; 28cb (0:28cb)
+ ld a, [wMusicHeaderPointer]
+ and a
+ jr nz, .asm_28dc
+ ld a, [wd72c]
+ bit 1, a
+ ret nz
+ ld a, $77
+ ld [$ff24], a
+ ret
+.asm_28dc
+ ld a, [wcfc9]
+ and a
+ jr z, .asm_28e7
+ dec a
+ ld [wcfc9], a
+ ret
+.asm_28e7
+ ld a, [wcfc8]
+ ld [wcfc9], a
+ ld a, [$ff24]
+ and a
+ jr z, .asm_2903
+ ld b, a
+ and $f
+ dec a
+ ld c, a
+ ld a, b
+ and $f0
+ swap a
+ dec a
+ swap a
+ or c
+ ld [$ff24], a
+ ret
+.asm_2903
+ ld a, [wMusicHeaderPointer]
+ ld b, a
+ xor a
+ ld [wMusicHeaderPointer], a
+ ld a, $ff
+ ld [wc0ee], a
+ call PlaySound
+ ld a, [wc0f0]
+ ld [wc0ef], a
+ ld a, b
+ ld [wc0ee], a
+ jp PlaySound
+
+; this function is used to display sign messages, sprite dialog, etc.
+; INPUT: [$ff8c] = sprite ID or text ID
+DisplayTextID:: ; 2920 (0:2920)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ callba DisplayTextIDInit ; initialization
+ ld hl,wcf11
+ bit 0,[hl]
+ res 0,[hl]
+ jr nz,.skipSwitchToMapBank
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+.skipSwitchToMapBank
+ ld a,30 ; half a second
+ ld [H_FRAMECOUNTER],a ; used as joypad poll timer
+ ld hl,W_MAPTEXTPTR
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a ; hl = map text pointer
+ ld d,$00
+ ld a,[$ff8c] ; text ID
+ ld [wSpriteIndex],a
+ and a
+ jp z,DisplayStartMenu
+ cp a,$d3
+ jp z,DisplaySafariGameOverText
+ cp a,$d0
+ jp z,DisplayPokemonFaintedText
+ cp a,$d1
+ jp z,DisplayPlayerBlackedOutText
+ cp a,$d2
+ jp z,DisplayRepelWoreOffText
+ ld a,[W_NUMSPRITES]
+ ld e,a
+ ld a,[$ff8c] ; sprite ID
+ cp e
+ jr z,.spriteHandling
+ jr nc,.skipSpriteHandling
+.spriteHandling
+; get the text ID of the sprite
+ push hl
+ push de
+ push bc
+ callba UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction)
+ pop bc
+ pop de
+ ld hl,W_MAPSPRITEDATA ; NPC text entries
+ ld a,[$ff8c]
+ dec a
+ add a
+ add l
+ ld l,a
+ jr nc,.noCarry
+ inc h
+.noCarry
+ 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
+ sla e
+ 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
+ cp a,$fe ; Pokemart NPC
+ jp z,DisplayPokemartDialogue
+ cp a,$ff ; Pokemon Center NPC
+ jp z,DisplayPokemonCenterDialogue
+ cp a,$fc ; Item Storage PC
+ jp z,FuncTX_ItemStoragePC
+ cp a,$fd ; Bill's PC
+ jp z,FuncTX_BillsPC
+ cp a,$f9 ; Pokemon Center PC
+ jp z,FuncTX_PokemonCenterPC
+ cp a,$f5 ; Vending Machine
+ jr nz,.notVendingMachine
+ callba VendingMachineMenu ; jump banks to vending machine routine
+ jr AfterDisplayingTextID
+.notVendingMachine
+ cp a,$f7 ; slot machine
+ jp z,FuncTX_SlotMachine
+ cp a,$f6 ; cable connection NPC in Pokemon Center
+ jr nz,.notSpecialCase
+ callab CableClubNPC
+ jr AfterDisplayingTextID
+.notSpecialCase
+ call Func_3c59 ; display the text
+ ld a,[wDoNotWaitForButtonPressAfterDisplayingText]
+ and a
+ jr nz,HoldTextDisplayOpen
+
+AfterDisplayingTextID:: ; 29d6 (0:29d6)
+ ld a,[wcc47]
+ 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:: ; 29df (0:29df)
+ call Joypad
+ ld a,[hJoyHeld]
+ bit 0,a ; is the A button being pressed?
+ jr nz,HoldTextDisplayOpen
+
+CloseTextDisplay:: ; 29e8 (0:29e8)
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ ld a,$90
+ ld [hWY],a ; move the window off the screen
+ call DelayFrame
+ call LoadGBPal
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED],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,wSpriteStateData2 + $19
+ ld c,$0f
+ ld de,$0010
+.restoreSpriteFacingDirectionLoop
+ ld a,[hl]
+ dec h
+ ld [hl],a
+ inc h
+ add hl,de
+ dec c
+ jr nz,.restoreSpriteFacingDirectionLoop
+ ld a,BANK(InitMapSprites)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ 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
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ jp UpdateSprites
+
+DisplayPokemartDialogue:: ; 2a2e (0:2a2e)
+ push hl
+ ld hl,PokemartGreetingText
+ call PrintText
+ pop hl
+ inc hl
+ call LoadItemList
+ ld a,$02
+ ld [wListMenuID],a ; selects between subtypes of menus
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,Bank(DisplayPokemartDialogue_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call DisplayPokemartDialogue_
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ jp AfterDisplayingTextID
+
+PokemartGreetingText:: ; 2a55 (0:2a55)
+ TX_FAR _PokemartGreetingText
+ db "@"
+
+LoadItemList:: ; 2a5a (0:2a5a)
+ ld a,$01
+ ld [wUpdateSpritesEnabled],a
+ ld a,h
+ ld [wd128],a
+ ld a,l
+ ld [wd129],a
+ ld de,wStringBuffer2 + 11
+.loop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ cp a,$ff
+ jr nz,.loop
+ ret
+
+DisplayPokemonCenterDialogue:: ; 2a72 (0:2a72)
+ xor a
+ ld [$ff8b],a
+ ld [$ff8c],a
+ ld [$ff8d],a
+ inc hl
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,Bank(DisplayPokemonCenterDialogue_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call DisplayPokemonCenterDialogue_
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ jp AfterDisplayingTextID
+
+DisplaySafariGameOverText:: ; 2a90 (0:2a90)
+ callab PrintSafariGameOverText
+ jp AfterDisplayingTextID
+
+DisplayPokemonFaintedText:: ; 2a9b (0:2a9b)
+ ld hl,PokemonFaintedText
+ call PrintText
+ jp AfterDisplayingTextID
+
+PokemonFaintedText:: ; 2aa4 (0:2aa4)
+ TX_FAR _PokemonFaintedText
+ db "@"
+
+DisplayPlayerBlackedOutText:: ; 2aa9 (0:2aa9)
+ ld hl,PlayerBlackedOutText
+ call PrintText
+ ld a,[wd732]
+ res 5,a ; reset forced to use bike bit
+ ld [wd732],a
+ jp HoldTextDisplayOpen
+
+PlayerBlackedOutText:: ; 2aba (0:2aba)
+ TX_FAR _PlayerBlackedOutText
+ db "@"
+
+DisplayRepelWoreOffText:: ; 2abf (0:2abf)
+ ld hl,RepelWoreOffText
+ call PrintText
+ jp AfterDisplayingTextID
+
+RepelWoreOffText:: ; 2ac8 (0:2ac8)
+ TX_FAR _RepelWoreOffText
+ db "@"
+
+INCLUDE "engine/menu/start_menu.asm"
+
+; 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:
+; [wd11e] = number of set bits
+CountSetBits:: ; 2b7f (0:2b7f)
+ 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 [wd11e],a ; store number of set bits
+ ret
+
+; subtracts the amount the player paid from their money
+; sets carry flag if there is enough money and unsets carry flag if not
+SubtractAmountPaidFromMoney:: ; 2b96 (0:2b96)
+ ld b,BANK(SubtractAmountPaidFromMoney_)
+ ld hl,SubtractAmountPaidFromMoney_
+ jp Bankswitch
+
+; adds the amount the player sold to their money
+AddAmountSoldToMoney:: ; 2b9e (0:2b9e)
+ ld de,wPlayerMoney + 2
+ ld hl,$ffa1 ; 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_02_5a - SFX_Headers_02) / 3
+ call PlaySoundWaitForCurrent ; play sound
+ jp WaitForSoundToFinish ; wait until sound is done playing
+
+; 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
+; [wcf96] = quantity to remove
+RemoveItemFromInventory:: ; 2bbb (0:2bbb)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(RemoveItemFromInventory_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call RemoveItemFromInventory_
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ 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
+; [wcf96] = item quantity
+; sets carry flag if successful, unsets carry flag if unsuccessful
+AddItemToInventory:: ; 2bcf (0:2bcf)
+ push bc
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(AddItemToInventory_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call AddItemToInventory_
+ pop bc
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ pop bc
+ ret
+
+; INPUT:
+; [wListMenuID] = list menu ID
+; [wList] = address of the list (2 bytes)
+DisplayListMenuID:: ; 2be6 (0:2be6)
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer
+ ld a,1
+ ld [hJoy7],a ; joypad state update flag
+ ld a,[W_BATTLETYPE]
+ 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 [wd12a],a
+ ld a,[wList]
+ ld l,a
+ ld a,[wList + 1]
+ ld h,a ; hl = address of the list
+ ld a,[hl]
+ ld [wd12a],a ; [wd12a] = number of list entries
+ 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
+ ld de,$090e ; height and width of menu text box
+ ld a,[wListMenuID]
+ and a ; is it a PC pokemon list?
+ jr nz,.skipMovingSprites
+ call UpdateSprites ; move sprites
+.skipMovingSprites
+ ld a,1 ; max menu item ID is 1 if the list has less than 2 entries
+ ld [wcc37],a
+ ld a,[wd12a]
+ cp a,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:: ; 2c53 (0:2c53)
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED],a ; disable transfer
+ call PrintListMenuEntries
+ ld a,1
+ ld [H_AUTOBGTRANSFERENABLED],a ; enable transfer
+ call Delay3
+ ld a,[W_BATTLETYPE]
+ and a ; is it the Old Man battle?
+ jr z,.notOldManBattle
+.oldManBattle
+ ld a,"▶"
+ Coorda 5, 4 ; place menu cursor in front of first menu entry
+ ld c,80
+ 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
+ ld a,$01
+ ld [wd12e],a
+ ld [wd12d],a
+ xor a
+ ld [wcc37],a
+ ld a,[wCurrentMenuItem]
+ ld c,a
+ ld a,[wListScrollOffset]
+ add c
+ ld c,a
+ ld a,[wd12a] ; number of list entries
+ 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 a,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,[wList]
+ ld l,a
+ ld a,[wList + 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 ; is it a PC pokemon list?
+ jr z,.pokemonList
+ push hl
+ call GetItemPrice
+ pop hl
+ ld a,[wListMenuID]
+ cp a,ITEMLISTMENU
+ jr nz,.skipGettingQuantity
+; if it's an item menu
+ inc hl
+ ld a,[hl] ; a = item quantity
+ ld [wcf97],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,[wList]
+ 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,$01
+ ld [wd12e],a
+ ld a,[wCurrentMenuItem]
+ ld [wd12d],a
+ xor a
+ ld [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 a,3
+ ld b,a
+ ld a,[wd12a] ; number of list entries
+ 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:: ; 2d57 (0:2d57)
+; text box dimensions/coordinates for just quantity
+ hlCoord 15, 9
+ ld b,1 ; height
+ ld c,3 ; width
+ ld a,[wListMenuID]
+ cp a,PRICEDITEMLISTMENU
+ jr nz,.drawTextBox
+; text box dimensions/coordinates for quantity and price
+ hlCoord 7, 9
+ ld b,1 ; height
+ ld c,11 ; width
+.drawTextBox
+ call TextBoxBorder
+ hlCoord 16, 10
+ ld a,[wListMenuID]
+ cp a,PRICEDITEMLISTMENU
+ jr nz,.printInitialQuantity
+ hlCoord 8, 10
+.printInitialQuantity
+ ld de,InitialQuantityText
+ call PlaceString
+ xor a
+ ld [wcf96],a ; initialize current quantity to 0
+ jp .incrementQuantity
+.waitForKeyPressLoop
+ call JoypadLowSensitivity
+ ld 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,[wcf97] ; max quantity
+ inc a
+ ld b,a
+ ld hl,wcf96 ; 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,wcf96 ; current quantity
+ dec [hl]
+ jr nz,.handleNewQuantity
+; wrap to the max quantity if the player goes below 1
+ ld a,[wcf97] ; max quantity
+ ld [hl],a
+.handleNewQuantity
+ hlCoord 17, 10
+ ld a,[wListMenuID]
+ cp a,PRICEDITEMLISTMENU
+ jr nz,.printQuantity
+.printPrice
+ ld c,$03
+ ld a,[wcf96]
+ ld b,a
+ ld hl,$ff9f ; 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,$ffa1
+ ld hl,$ff8d
+ push bc
+ predef AddBCDPredef ; add the individual price to the current sum
+ pop bc
+ dec b
+ jr nz,.addLoop
+ ld a,[$ff8e]
+ and a ; should the price be halved (for selling items)?
+ jr z,.skipHalvingPrice
+ xor a
+ ld [$ffa2],a
+ ld [$ffa3],a
+ ld a,$02
+ ld [$ffa4],a
+ predef DivideBCDPredef3 ; halves the price
+; store the halved price
+ ld a,[$ffa2]
+ ld [$ff9f],a
+ ld a,[$ffa3]
+ ld [$ffa0],a
+ ld a,[$ffa4]
+ ld [$ffa1],a
+.skipHalvingPrice
+ hlCoord 12, 10
+ ld de,SpacesBetweenQuantityAndPriceText
+ call PlaceString
+ ld de,$ff9f ; total price
+ ld c,$a3
+ call PrintBCDNumber
+ hlCoord 9, 10
+.printQuantity
+ ld de,wcf96 ; current quantity
+ ld bc,$8102 ; print leading zeroes, 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:: ; 2e30 (0:2e30)
+ db "×01@"
+
+SpacesBetweenQuantityAndPriceText:: ; 2e34 (0:2e34)
+ db " @"
+
+ExitListMenu:: ; 2e3b (0:2e3b)
+ ld a,[wCurrentMenuItem]
+ ld [wd12d],a
+ ld a,$02
+ ld [wd12e],a
+ ld [wcc37],a
+ xor a
+ ld [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:: ; 2e5a (0:2e5a)
+ hlCoord 5, 3
+ ld b,$09
+ ld c,$0e
+ call ClearScreenArea
+ ld a,[wList]
+ ld e,a
+ ld a,[wList + 1]
+ ld d,a
+ inc de ; de = beginning of list entries
+ ld a,[wListScrollOffset]
+ ld c,a
+ ld a,[wListMenuID]
+ cp a,ITEMLISTMENU
+ ld a,c
+ jr nz,.skipMultiplying
+; if it's an item menu
+; item entries are 2 bytes long, so multiply by 2
+ sla 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 a,$ff
+ jp z,.printCancelMenuItem
+ push bc
+ push de
+ push hl
+ push hl
+ push de
+ ld a,[wListMenuID]
+ and a
+ jr z,.pokemonPCMenu
+ cp a,$01
+ jr z,.movesMenu
+.itemMenu
+ call GetItemName
+ jr .placeNameString
+.pokemonPCMenu
+ push hl
+ ld hl,wPartyCount
+ ld a,[wList]
+ 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,[wcf93]
+ 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,20 + 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
+ jr nz,.skipPrintingPokemonLevel
+.printPokemonLevel
+ ld a,[wd11e]
+ push af
+ push hl
+ ld hl,wPartyCount
+ ld a,[wList]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld a,$00
+ jr z,.next
+ ld a,$02
+.next
+ ld [wcc49],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 ; load pokemon info
+ ld a,[wcc49]
+ 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,$001c
+ add hl,bc
+ call PrintLevel ; print level
+ pop af
+ ld [wd11e],a
+.skipPrintingPokemonLevel
+ pop hl
+ pop de
+ inc de
+ ld a,[wListMenuID]
+ cp a,ITEMLISTMENU
+ jr nz,.nextListEntry
+.printItemQuantity
+ ld a,[wd11e]
+ ld [wcf91],a
+ call IsKeyItem ; check if item is unsellable
+ ld a,[wd124]
+ and a ; is the item unsellable?
+ jr nz,.skipPrintingItemQuantity ; if so, don't print the quantity
+ push hl
+ ld bc,20 + 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 [wcf97],a
+ push de
+ ld de,wd11e
+ ld [de],a
+ ld bc,$0102
+ 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
+ sla a
+ cp c ; is it this item?
+ jr nz,.nextListEntry
+ dec hl
+ ld a,$ec ; unfilled right arrow menu cursor to indicate an item being swapped
+ ld [hli],a
+.nextListEntry
+ ld bc,2 * 20 ; 2 rows
+ add hl,bc
+ pop bc
+ inc c
+ dec b
+ jp nz,.loop
+ ld bc,-8
+ add hl,bc
+ ld a,$ee ; down arrow
+ ld [hl],a
+ ret
+.printCancelMenuItem
+ ld de,ListMenuCancelText
+ jp PlaceString
+
+ListMenuCancelText:: ; 2f97 (0:2f97)
+ db "CANCEL@"
+
+GetMonName:: ; 2f9e (0:2f9e)
+ push hl
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(MonsterNames) ; 07
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ld a,[wd11e]
+ dec a
+ ld hl,MonsterNames ; 421E
+ ld c,10
+ ld b,0
+ call AddNTimes
+ ld de,wcd6d
+ push de
+ ld bc,10
+ call CopyData
+ ld hl,wcd77
+ ld [hl], "@"
+ pop de
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ pop hl
+ ret
+
+GetItemName:: ; 2fcf (0:2fcf)
+; 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 HM_01 ; 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:: ; 2ff3 (0:2ff3)
+; copies the name of the TM/HM in [wd11e] to wcd6d
+ push hl
+ push de
+ push bc
+ ld a,[wd11e]
+ push af
+ cp TM_01 ; is this a TM? [not HM]
+ jr nc,.WriteTM
+; if HM, then write "HM" and add 5 to the item ID, so we can reuse the
+; TM printing code
+ add 5
+ ld [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 TM_01 - 1
+ ld b,$F6 ; "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,$F6 ; "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:: ; 303c (0:303c)
+ db "TM"
+HiddenPrefix:: ; 303e (0:303e)
+ db "HM"
+
+; sets carry if item is HM, clears carry if item is not HM
+; Input: a = item ID
+IsItemHM:: ; 3040 (0:3040)
+ cp a,HM_01
+ jr c,.notHM
+ cp a,TM_01
+ 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:: ; 3049 (0:3049)
+ ld hl,HMMoves
+ ld de,1
+ jp IsInArray
+
+HMMoves:: ; 3052 (0:3052)
+ db CUT,FLY,SURF,STRENGTH,FLASH
+ db $ff ; terminator
+
+GetMoveName:: ; 3058 (0:3058)
+ 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
+
+; reloads text box tile patterns, current map view, and tileset tile patterns
+ReloadMapData:: ; 3071 (0:3071)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ call DisableLCD
+ call LoadTextBoxTilePatterns
+ call LoadCurrentMapView
+ call LoadTilesetTilePatternData
+ call EnableLCD
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; reloads tileset tile patterns
+ReloadTilesetTilePatterns:: ; 3090 (0:3090)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ call DisableLCD
+ call LoadTilesetTilePatternData
+ call EnableLCD
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; shows the town map and lets the player choose a destination to fly to
+ChooseFlyDestination:: ; 30a9 (0:30a9)
+ ld hl,wd72e
+ res 4,[hl]
+ ld b, BANK(LoadTownMap_Fly)
+ ld hl, LoadTownMap_Fly
+ jp Bankswitch
+
+; causes the text box to close without waiting for a button press after displaying text
+DisableWaitingAfterTextDisplay:: ; 30b6 (0:30b6)
+ ld a,$01
+ ld [wDoNotWaitForButtonPressAfterDisplayingText],a
+ ret
+
+; uses an item
+; UseItem is used with dummy items to perform certain other functions as well
+; INPUT:
+; [wcf91] = item ID
+; OUTPUT:
+; [wcd6a] = success
+; 00: unsucessful
+; 01: successful
+; 02: not able to be used right now, no extra menu displayed (only certain items use this)
+UseItem:: ; 30bc (0:30bc)
+ ld b,BANK(UseItem_)
+ ld hl,UseItem_
+ jp Bankswitch
+
+; 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
+; [wcf96] = quantity to toss
+; OUTPUT:
+; clears carry flag if the item is tossed, sets carry flag if not
+TossItem:: ; 30c4 (0:30c4)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(TossItem_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call TossItem_
+ pop de
+ ld a,d
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; checks if an item is a key item
+; INPUT:
+; [wcf91] = item ID
+; OUTPUT:
+; [wd124] = result
+; 00: item is not key item
+; 01: item is key item
+IsKeyItem:: ; 30d9 (0:30d9)
+ push hl
+ push de
+ push bc
+ callba IsKeyItem_
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; function to draw various text boxes
+; INPUT:
+; [wTextBoxID] = text box ID
+DisplayTextBoxID:: ; 30e8 (0:30e8)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(DisplayTextBoxID_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call DisplayTextBoxID_
+ pop bc
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; 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:: ; 30fd (0:30fd)
+ 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:: ; 310e (0:310e)
+ 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
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, [wNPCMovementScriptBank]
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ld a, [wNPCMovementScriptFunctionNum]
+ call CallFunctionInTable
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+.NPCMovementScriptPointerTables
+ dw ProfOakMovementScriptPointerTable
+ dw PewterMuseumGuyMovementScriptPointerTable
+ dw PewterGymGuyMovementScriptPointerTable
+.playerStepOutFromDoor
+ ld b, BANK(PlayerStepOutFromDoor)
+ ld hl, PlayerStepOutFromDoor
+ jp Bankswitch
+
+EndNPCMovementScript:: ; 314e (0:314e)
+ ld b, BANK(_EndNPCMovementScript)
+ ld hl, _EndNPCMovementScript
+ jp Bankswitch
+
+EmptyFunc2:: ; 3156 (0:3156)
+ ret
+
+; stores hl in [W_TRAINERHEADERPTR]
+StoreTrainerHeaderPointer:: ; 3157 (0:3157)
+ ld a, h
+ ld [W_TRAINERHEADERPTR], a
+ ld a, l
+ ld [W_TRAINERHEADERPTR+1], a
+ ret
+
+; executes the current map script from the function pointer array provided in hl.
+; a: map script index to execute (unless overridden by [wd733] bit 4)
+ExecuteCurMapScriptInTable:: ; 3160 (0:3160)
+ push af
+ push de
+ call StoreTrainerHeaderPointer
+ pop hl
+ pop af
+ push hl
+ ld hl, W_FLAGS_D733
+ bit 4, [hl]
+ res 4, [hl]
+ jr z, .useProvidedIndex ; test if map script index was overridden manually
+ ld a, [W_CURMAPSCRIPT]
+.useProvidedIndex
+ pop hl
+ ld [W_CURMAPSCRIPT], a
+ call CallFunctionInTable
+ ld a, [W_CURMAPSCRIPT]
+ ret
+
+LoadGymLeaderAndCityName:: ; 317f (0:317f)
+ push de
+ ld de, wGymCityName
+ ld bc, $11
+ call CopyData ; load city name
+ pop hl
+ ld de, wGymLeaderName
+ ld bc, $b
+ jp CopyData ; load gym leader name
+
+; reads specific information from trainer header (pointed to at W_TRAINERHEADERPTR)
+; 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:: ; 3193 (0:3193)
+ push de
+ push af
+ ld d, $0
+ ld e, a
+ ld hl, W_TRAINERHEADERPTR
+ 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:: ; 31cc (0:31cc)
+ 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, $2
+ 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 ; 0x31ed
+ 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, W_FLAGS_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, W_CURMAPSCRIPT
+ 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:: ; 3219 (0:3219)
+ call CheckForEngagingTrainers
+ ld a, [wSpriteIndex]
+ cp $ff
+ jr nz, .trainerEngaging
+ xor a
+ ld [wSpriteIndex], a
+ ld [wTrainerHeaderFlagBit], a
+ ret
+.trainerEngaging
+ ld hl, W_FLAGS_D733
+ set 3, [hl]
+ ld [wcd4f], a
+ xor a
+ ld [wcd50], a
+ predef EmotionBubble
+ ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
+ ld [wJoyIgnore], a
+ xor a
+ ldh [$b4], a
+ call TrainerWalkUpToPlayer_Bank0
+ ld hl, W_CURMAPSCRIPT
+ 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:: ; 324c (0:324c)
+ 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]
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ ; fall through
+
+StartTrainerBattle:: ; 325d (0:325d)
+ xor a
+ ld [wJoyIgnore], a
+ call InitBattleEnemyParameters
+ ld hl, wd72d
+ set 6, [hl]
+ set 7, [hl]
+ ld hl, wd72e
+ set 1, [hl]
+ ld hl, W_CURMAPSCRIPT
+ inc [hl] ; increment map script index (next script function is usually EndTrainerBattle)
+ ret
+
+EndTrainerBattle:: ; 3275 (0:3275)
+ ld hl, wd126
+ 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, [W_ISINBATTLE] ; W_ISINBATTLE
+ cp $ff
+ jp z, ResetButtonPressedAndMapScript
+ ld a, $2
+ call ReadTrainerHeaderInfo
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ ld b, $1
+ call TrainerFlagAction ; flag trainer as fought
+ ld a, [W_ENEMYMONORTRAINERCLASS]
+ cp $c8
+ jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite)
+ ld hl, W_MISSABLEOBJECTLIST
+ ld de, $2
+ ld a, [wSpriteIndex]
+ call IsInArray ; search for sprite ID
+ inc hl
+ ld a, [hl]
+ ld [wcc4d], a ; load corresponding missable object index and remove it
+ predef HideObject
+.skipRemoveSprite
+ ld hl, wd730
+ bit 4, [hl]
+ res 4, [hl]
+ ret nz
+
+ResetButtonPressedAndMapScript:: ; 32c1 (0:32c1)
+ xor a
+ ld [wJoyIgnore], a
+ ld [hJoyHeld], a
+ ld [hJoyPressed], a
+ ld [hJoyReleased], a
+ ld [W_CURMAPSCRIPT], a ; reset battle status
+ ret
+
+; calls TrainerWalkUpToPlayer
+TrainerWalkUpToPlayer_Bank0:: ; 32cf (0:32cf)
+ ld b, BANK(TrainerWalkUpToPlayer)
+ ld hl, TrainerWalkUpToPlayer
+ jp Bankswitch
+
+; sets opponent type and mon set/lvl based on the engaging trainer data
+InitBattleEnemyParameters:: ; 32d7 (0:32d7)
+ ld a, [wEngagedTrainerClass]
+ ld [W_CUROPPONENT], a ; wd059
+ ld [W_ENEMYMONORTRAINERCLASS], a
+ cp $c8
+ ld a, [wEngagedTrainerSet] ; wcd2e
+ jr c, .noTrainer
+ ld [W_TRAINERNO], a ; wd05d
+ ret
+.noTrainer
+ ld [W_CURENEMYLVL], a ; W_CURENEMYLVL
+ ret
+
+GetSpritePosition1:: ; 32ef (0:32ef)
+ ld hl, _GetSpritePosition1
+ jr asm_3301
+
+GetSpritePosition2:: ; 32f4 (0:32f4)
+ ld hl, _GetSpritePosition2
+ jr asm_3301 ; 0x32f7 $8
+
+SetSpritePosition1:: ; 32f9 (0:32f9)
+ ld hl, _SetSpritePosition1
+ jr asm_3301
+
+SetSpritePosition2:: ; 32fe (0:32fe)
+ ld hl, _SetSpritePosition2
+asm_3301:: ; 3301 (0:3301)
+ ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2)
+ jp Bankswitch ; indirect jump to one of the four functions
+
+CheckForEngagingTrainers:: ; 3306 (0:3306)
+ 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 $ff
+ ret z
+ ld a, $2
+ call ReadTrainerHeaderInfo ; read trainer flag's byte ptr
+ ld b, $2
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ call TrainerFlagAction ; read trainer flag
+ ld a, c
+ and a
+ jr nz, .trainerAlreadyFought
+ 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 ; wWhichTrade
+ predef TrainerEngage
+ pop de
+ pop hl
+ ld a, [wTrainerSpriteOffset] ; wWhichTrade
+ and a
+ ret nz ; break if the trainer is engaging
+.trainerAlreadyFought
+ 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:: ; 3354 (0:3354)
+ ld a, [H_LOADEDROMBANK]
+ 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:: ; 336a (0:336a)
+ ld hl, W_MAPSPRITEEXTRADATA
+ 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 [wEnemyMonAttackMod], a ; wcd2e
+ jp PlayTrainerMusic
+
+PrintEndBattleText:: ; 3381 (0:3381)
+ push hl
+ ld hl, wd72d
+ bit 7, [hl]
+ res 7, [hl]
+ pop hl
+ ret z
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, [wEndBattleTextRomBank]
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ push hl
+ callba SaveTrainerName
+ ld hl, TrainerEndBattleText
+ call PrintText
+ pop hl
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ callba FreezeEnemyTrainerSprite
+ jp WaitForSoundToFinish
+
+GetSavedEndBattleTextPointer:: ; 33b7 (0:33b7)
+ 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:: ; 33cf (0:33cf)
+ TX_FAR _TrainerNameText
+ db $08
+ call GetSavedEndBattleTextPointer
+ call TextCommandProcessor
+ jp TextScriptEnd
+
+; XXX unused?
+Func_33dd:: ; 33dd (0:33dd)
+ ld a, [wFlags_0xcd60]
+ bit 0, a
+ ret nz
+ call EngageMapTrainer
+ xor a
+ ret
+
+PlayTrainerMusic:: ; 33e8 (0:33e8)
+ ld a, [wEngagedTrainerClass]
+ cp $c8 + SONY1
+ ret z
+ cp $c8 + SONY2
+ ret z
+ cp $c8 + SONY3
+ ret z
+ ld a, [W_GYMLEADERNO] ; W_GYMLEADERNO
+ and a
+ ret nz
+ xor a
+ ld [wMusicHeaderPointer], a
+ ld a, $ff
+ call PlaySound ; stop music
+ ld a, BANK(Music_MeetEvilTrainer)
+ ld [wc0ef], a
+ ld [wc0f0], 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 [wc0ee], a
+ jp PlaySound
+
+INCLUDE "data/trainer_types.asm"
+
+; 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:: ; 3442 (0:3442)
+ 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
+
+FuncTX_ItemStoragePC:: ; 3460 (0:3460)
+ call SaveScreenTilesToBuffer2
+ ld b, BANK(PlayerPC)
+ ld hl, PlayerPC
+ jr bankswitchAndContinue
+
+FuncTX_BillsPC:: ; 346a (0:346a)
+ call SaveScreenTilesToBuffer2
+ ld b, BANK(BillsPC_)
+ ld hl, BillsPC_
+ jr bankswitchAndContinue
+
+FuncTX_SlotMachine:: ; 3474 (0:3474)
+; XXX find a better name for this function
+; special_F7
+ ld b,BANK(CeladonPrizeMenu)
+ ld hl,CeladonPrizeMenu
+bankswitchAndContinue:: ; 3479 (0:3479)
+ call Bankswitch
+ jp HoldTextDisplayOpen ; continue to main text-engine function
+
+FuncTX_PokemonCenterPC:: ; 347f (0:347f)
+ ld b, BANK(ActivatePC)
+ ld hl, ActivatePC
+ jr bankswitchAndContinue
+
+StartSimulatingJoypadStates:: ; 3486 (0:3486)
+ xor a
+ ld [wOverrideSimulatedJoypadStatesMask], a
+ ld [wSpriteStateData2 + $06], a ; player's sprite movement byte 1
+ ld hl, wd730
+ set 7, [hl]
+ ret
+
+IsItemInBag:: ; 3493 (0:3493)
+; 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 IsItemInBag_
+ ld a,b
+ and a
+ ret
+
+DisplayPokedex:: ; 349b (0:349b)
+ ld [wd11e], a
+ ld b, BANK(Func_7c18)
+ ld hl, Func_7c18
+ jp Bankswitch
+
+SetSpriteFacingDirectionAndDelay:: ; 34a6 (0:34a6)
+ call SetSpriteFacingDirection
+ ld c, $6
+ jp DelayFrames
+
+SetSpriteFacingDirection:: ; 34ae (0:34ae)
+ ld a, $9
+ ld [H_SPRITEDATAOFFSET], a
+ call GetPointerWithinSpriteStateData1
+ ld a, [$ff8d]
+ ld [hl], a
+ ret
+
+SetSpriteImageIndexAfterSettingFacingDirection:: ; 34b9 (0:34b9)
+ ld de, -7
+ add hl, de
+ ld [hl], a
+ ret
+
+; tests if the player's coordinates are in a specified array
+; INPUT:
+; hl = address of array
+; OUTPUT:
+; [wWhichTrade] = if there is match, the matching array index
+; sets carry if the coordinates are in the array, clears carry if not
+ArePlayerCoordsInArray:: ; 34bf (0:34bf)
+ ld a,[W_YCOORD]
+ ld b,a
+ ld a,[W_XCOORD]
+ ld c,a
+ ; fallthrough
+
+CheckCoords:: ; 34c7 (0:34c7)
+ xor a
+ ld [wWhichTrade],a
+.loop
+ ld a,[hli]
+ cp a,$ff ; reached terminator?
+ jr z,.notInArray
+ push hl
+ ld hl,wWhichTrade
+ 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
+; [H_SPRITEINDEX] = index of boulder sprite
+; OUTPUT:
+; [wWhichTrade] = if there is match, the matching array index
+; sets carry if the coordinates are in the array, clears carry if not
+CheckBoulderCoords:: ; 34e4 (0:34e4)
+ push hl
+ ld hl, wSpriteStateData2 + $04
+ ld a, [H_SPRITEINDEX]
+ 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:: ; 34fc (0:34fc)
+ ld h, $c1
+ jr _GetPointerWithinSpriteStateData
+
+GetPointerWithinSpriteStateData2:: ; 3500 (0:3500)
+ ld h, $c2
+
+_GetPointerWithinSpriteStateData:
+ ld a, [H_SPRITEDATAOFFSET]
+ ld b, a
+ ld a, [H_SPRITEINDEX]
+ 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:: ; 350c (0:350c)
+ xor a
+ ld [wRLEByteCount], a ; count written bytes here
+.listLoop
+ ld a, [de]
+ cp $ff
+ jr z, .endOfList
+ ld [H_DOWNARROWBLINKCNT1], 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
+ ld a, [H_DOWNARROWBLINKCNT1] ; $ff8b
+ 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 [$FF8C] to $FE and byte 2 to [$FF8D]
+SetSpriteMovementBytesToFE:: ; 3533 (0:3533)
+ push hl
+ call GetSpriteMovementByte1Pointer
+ ld [hl], $fe
+ call GetSpriteMovementByte2Pointer
+ ld a, [$ff8d]
+ ld [hl], a
+ pop hl
+ ret
+
+; sets both movement bytes for sprite [$FF8C] to $FF
+SetSpriteMovementBytesToFF:: ; 3541 (0:3541)
+ 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 [$FF8C] in hl
+GetSpriteMovementByte1Pointer:: ; 354e (0:354e)
+ ld h,$C2
+ ld a,[H_SPRITEINDEX] ; the sprite to move
+ swap a
+ add a,6
+ ld l,a
+ ret
+
+; returns the sprite movement byte 2 pointer for sprite [$FF8C] in hl
+GetSpriteMovementByte2Pointer:: ; 3558 (0:3558)
+ push de
+ ld hl,W_MAPSPRITEDATA
+ ld a,[$FF8C] ; the sprite to move
+ dec a
+ add a
+ ld d,0
+ ld e,a
+ add hl,de
+ pop de
+ ret
+
+GetTrainerInformation:: ; 3566 (0:3566)
+ call GetTrainerName
+ ld a, [wLinkState]
+ and a
+ jr nz, .linkBattle
+ ld a, Bank(TrainerPicAndMoneyPointers)
+ call BankswitchHome
+ ld a, [W_TRAINERCLASS] ; wd031
+ 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, wd046
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ jp BankswitchBack
+.linkBattle
+ ld hl, wTrainerPicPointer
+ ld de, RedPicFront
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ret
+
+GetTrainerName:: ; 359e (0:359e)
+ ld b, BANK(GetTrainerName_)
+ ld hl, GetTrainerName_
+ jp Bankswitch
+
+
+HasEnoughMoney::
+; Check if the player has at least as much
+; money as the 3-byte BCD value at $ff9f.
+ ld de, wPlayerMoney
+ ld hl, $ff9f
+ ld c, 3
+ jp StringCmp
+
+HasEnoughCoins::
+; Check if the player has at least as many
+; coins as the 2-byte BCD value at $ffa0.
+ ld de, wPlayerCoins
+ ld hl, $ffa0
+ ld c, 2
+ jp StringCmp
+
+
+BankswitchHome:: ; 35d9 (0:35d9)
+; switches to bank # in a
+; Only use this when in the home bank!
+ ld [wcf09],a
+ ld a,[H_LOADEDROMBANK]
+ ld [wcf08],a
+ ld a,[wcf09]
+ call BankswitchCommon
+ ret
+
+BankswitchBack:: ; 35e8 (0:35e8)
+; returns from BankswitchHome
+ ld a,[wcf08]
+ call BankswitchCommon
+ ret
+
+BankswitchCommon:: ; 3e7e (0:3e7e)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+Bankswitch:: ; 3e84 (0:3e84)
+; self-contained bankswitch, use this when not in the home bank
+; switches to the bank in b
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call .jumptoaddress
+ pop bc
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+.jumptoaddress
+ jp [hl]
+
+; displays yes/no choice
+; yes -> set carry
+YesNoChoice:: ; 35ec (0:35ec)
+ call SaveScreenTilesToBuffer1
+ call InitYesNoTextBoxParameters
+ jr DisplayYesNoChoice
+
+Func_35f4:: ; 35f4 (0:35f4)
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call InitYesNoTextBoxParameters
+ jp DisplayTextBoxID
+
+InitYesNoTextBoxParameters:: ; 35ff (0:35ff)
+ xor a ; YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ hlCoord 14, 7
+ ld bc, $80f
+ ret
+
+YesNoChoicePokeCenter:: ; 360a (0:360a)
+ call SaveScreenTilesToBuffer1
+ ld a, HEAL_CANCEL_MENU
+ ld [wTwoOptionMenuID], a
+ hlCoord 11, 6
+ ld bc, $80c
+ jr DisplayYesNoChoice
+
+Func_361a:: ; 361a (0:361a)
+ call SaveScreenTilesToBuffer1
+ ld a, WIDE_YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ hlCoord 12, 7
+ ld bc, $080d
+DisplayYesNoChoice:: ; 3628 (0:3628)
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ jp LoadScreenTilesFromBuffer1
+
+; calculates the difference |a-b|, setting carry flag if a<b
+CalcDifference:: ; 3633 (0:3633)
+ sub b
+ ret nc
+ cpl
+ add $1
+ scf
+ ret
+
+MoveSprite:: ; 363a (0:363a)
+; move the sprite [$FF8C] with the movement pointed to by de
+; actually only copies the movement data to wcc5b for later
+ call SetSpriteMovementBytesToFF
+MoveSprite_:: ; 363d (0:363d)
+ push hl
+ push bc
+ call GetSpriteMovementByte1Pointer
+ xor a
+ ld [hl],a
+ ld hl,wcc5b
+ ld c,0
+
+.loop
+ ld a,[de]
+ ld [hli],a
+ inc de
+ inc c
+ cp a,$FF ; have we reached the end of the movement data?
+ jr nz,.loop
+
+ ld a,c
+ ld [wcf0f],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 [$ffe5] by [$ffe6] and stores the quotient in [$ffe7]
+DivideBytes:: ; 366b (0:366b)
+ push hl
+ ld hl, $ffe7
+ 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
+
+
+LoadFontTilePatterns::
+ ld a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, FontGraphics
+ ld de, vFont
+ ld bc, $400
+ ld a, BANK(FontGraphics)
+ jp FarCopyDataDouble ; if LCD is off, transfer all at once
+.on
+ ld de, FontGraphics
+ ld hl, vFont
+ ld bc, BANK(FontGraphics) << 8 | $80
+ jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
+
+LoadTextBoxTilePatterns::
+ ld a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, TextBoxGraphics
+ ld de, vChars2 + $600
+ ld bc, $200
+ ld a, BANK(TextBoxGraphics)
+ jp FarCopyData2 ; if LCD is off, transfer all at once
+.on
+ ld de, TextBoxGraphics
+ ld hl, vChars2 + $600
+ ld bc, BANK(TextBoxGraphics) << 8 | $20
+ jp CopyVideoData ; if LCD is on, transfer during V-blank
+
+LoadHpBarAndStatusTilePatterns::
+ ld a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, HpBarAndStatusGraphics
+ ld de, vChars2 + $620
+ ld bc, $1e0
+ ld a, BANK(HpBarAndStatusGraphics)
+ jp FarCopyData2 ; if LCD is off, transfer all at once
+.on
+ ld de, HpBarAndStatusGraphics
+ ld hl, vChars2 + $620
+ ld bc, BANK(HpBarAndStatusGraphics) << 8 | $1e
+ jp CopyVideoData ; if LCD is on, transfer during V-blank
+
+
+UncompressSpriteFromDE:: ; 36eb (0:36eb)
+; Decompress pic at a:de.
+ ld hl, W_SPRITEINPUTPTR
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ jp UncompressSpriteData
+
+
+SaveScreenTilesToBuffer2:: ; 36f4 (0:36f4)
+ ld hl, wTileMap
+ ld de, wTileMapBackup2
+ ld bc, $168
+ call CopyData
+ ret
+
+LoadScreenTilesFromBuffer2:: ; 3701 (0:3701)
+ call LoadScreenTilesFromBuffer2DisableBGTransfer
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
+ ret
+
+; loads screen tiles stored in wTileMapBackup2 but leaves H_AUTOBGTRANSFERENABLED disabled
+LoadScreenTilesFromBuffer2DisableBGTransfer:: ; 3709 (0:3709)
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
+ ld hl, wTileMapBackup2
+ ld de, wTileMap
+ ld bc, $168
+ call CopyData
+ ret
+
+SaveScreenTilesToBuffer1:: ; 3719 (0:3719)
+ ld hl, wTileMap
+ ld de, wTileMapBackup
+ ld bc, $168
+ jp CopyData
+
+LoadScreenTilesFromBuffer1:: ; 3725 (0:3725)
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
+ ld hl, wTileMapBackup
+ ld de, wTileMap
+ ld bc, $168
+ call CopyData
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
+ ret
+
+DelayFrames:: ; 3739 (0:3739)
+; wait n frames, where n is the value in c
+ call DelayFrame
+ dec c
+ jr nz,DelayFrames
+ ret
+
+PlaySoundWaitForCurrent:: ; 3740 (0:3740)
+ push af
+ call WaitForSoundToFinish
+ pop af
+ jp PlaySound
+
+; Wait for sound to finish playing
+WaitForSoundToFinish:: ; 3748 (0:3748)
+ ld a, [wLowHealthAlarm]
+ and $80
+ ret nz
+ push hl
+.asm_374f
+ ld hl, wc02a
+ xor a
+ or [hl]
+ inc hl
+ or [hl]
+ inc hl
+ inc hl
+ or [hl]
+ jr nz, .asm_374f
+ pop hl
+ ret
+
+NamePointers:: ; 375d (0:375d)
+ dw MonsterNames
+ dw MoveNames
+ dw UnusedNames
+ dw ItemNames
+ dw wPartyMonOT ; player's OT names list
+ dw wEnemyMonOT ; enemy's OT names list
+ dw TrainerNames
+
+GetName:: ; 376b (0:376b)
+; 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 HM_01
+ jp nc, GetMachineName
+
+ ld a,[H_LOADEDROMBANK]
+ 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,11
+ add hl,de
+ ld e,l
+ ld d,h
+ jr .gotPtr
+.otherEntries ; $378d
+ ;2-7 = OTHER ENTRIES
+ ld a,[wPredefBank]
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ld a,[wNameListType] ;VariousNames' entryID
+ dec a
+ add a
+ ld d,0
+ ld e,a
+ jr nc,.skip
+ inc d
+.skip ; $37a0
+ ld hl,NamePointers
+ add hl,de
+ ld a,[hli]
+ ld [$ff96],a
+ ld a,[hl]
+ ld [$ff95],a
+ ld a,[$ff95]
+ ld h,a
+ ld a,[$ff96]
+ ld l,a
+ ld a,[wd0b5]
+ ld b,a
+ ld c,0
+.nextName
+ ld d,h
+ ld e,l
+.nextChar
+ ld a,[hli]
+ cp a, "@"
+ 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,$0014
+ call CopyData
+.gotPtr ; $37cd
+ ld a,e
+ ld [wcf8d],a
+ ld a,d
+ ld [wcf8e],a
+ pop de
+ pop bc
+ pop hl
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+GetItemPrice:: ; 37df (0:37df)
+; Stores item's price as BCD at hItemPrice (3 bytes)
+; Input: [wcf91] = item id
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, [wListMenuID]
+ cp MOVESLISTMENU
+ ld a, BANK(ItemPrices)
+ jr nz, .asm_37ed
+ ld a, $f ; hardcoded Bank
+.asm_37ed
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ld hl, wItemPrices
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wcf91] ; a contains item id
+ cp HM_01
+ jr nc, .getTMPrice
+ ld bc, $3
+.asm_3802
+ add hl, bc
+ dec a
+ jr nz, .asm_3802
+ dec hl
+ ld a, [hld]
+ ld [hItemPrice + 2], a
+ ld a, [hld]
+ ld [hItemPrice + 1], a
+ ld a, [hl]
+ ld [hItemPrice], a
+ jr .asm_381c
+.getTMPrice
+ ld a, Bank(GetMachinePrice)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ call GetMachinePrice
+.asm_381c
+ ld de, hItemPrice
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+; copies a string from [de] to [wcf4b]
+CopyStringToCF4B:: ; 3826 (0:3826)
+ ld hl, wcf4b
+ ; fall through
+
+; copies a string from [de] to [hl]
+CopyString:: ; 3829 (0:3829)
+ ld a, [de]
+ inc de
+ ld [hli], a
+ cp "@"
+ jr nz, CopyString
+ ret
+
+; 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 esentially 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:: ; 3831 (0:3831)
+ call Joypad
+ ld a,[hJoy7] ; flag
+ and a ; get all currently pressed buttons or only newly pressed buttons?
+ ld a,[hJoyPressed] ; newly pressed buttons
+ jr z,.storeButtonState
+ ld a,[hJoyHeld] ; all currently pressed buttons
+.storeButtonState
+ ld [hJoy5],a
+ ld 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
+ ld [H_FRAMECOUNTER],a
+ ret
+.noNewlyPressedButtons
+ ld a,[H_FRAMECOUNTER]
+ and a ; is the delay over?
+ jr z,.delayOver
+.delayNotOver
+ xor a
+ ld [hJoy5],a ; report no buttons as pressed
+ ret
+.delayOver
+; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed
+ ld a,[hJoyHeld]
+ and A_BUTTON | B_BUTTON
+ jr z,.setShortDelay
+ ld a,[hJoy6] ; flag
+ and a
+ jr nz,.setShortDelay
+ xor a
+ ld [hJoy5],a
+.setShortDelay
+ ld a,5 ; 1/12 of a second delay
+ ld [H_FRAMECOUNTER],a
+ ret
+
+WaitForTextScrollButtonPress:: ; 3865 (0:3865)
+ ld a, [H_DOWNARROWBLINKCNT1]
+ push af
+ ld a, [H_DOWNARROWBLINKCNT2]
+ push af
+ xor a
+ ld [H_DOWNARROWBLINKCNT1], a
+ ld a, $6
+ ld [H_DOWNARROWBLINKCNT2], a
+.loop
+ push hl
+ ld a, [wTownMapSpriteBlinkingEnabled]
+ and a
+ jr z, .skipAnimation
+ call TownMapSpriteBlinkingAnimation
+.skipAnimation
+ hlCoord 18, 16
+ call HandleDownArrowBlinkTiming
+ pop hl
+ call JoypadLowSensitivity
+ predef CableClub_Run
+ ld a, [hJoy5]
+ and A_BUTTON | B_BUTTON
+ jr z, .loop
+ pop af
+ ld [H_DOWNARROWBLINKCNT2], a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1], a
+ ret
+
+; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect
+ManualTextScroll:: ; 3898 (0:3898)
+ ld a, [wLinkState]
+ cp LINK_STATE_BATTLING
+ jr z, .inLinkBattle
+ call WaitForTextScrollButtonPress
+ ld a, (SFX_02_40 - SFX_Headers_02) / 3
+ jp PlaySound
+.inLinkBattle
+ ld c, $41
+ jp DelayFrames
+
+; function to do multiplication
+; all values are big endian
+; INPUT
+; FF96-FF98 = multiplicand
+; FF99 = multiplier
+; OUTPUT
+; FF95-FF98 = product
+Multiply:: ; 38ac (0:38ac)
+ push hl
+ push bc
+ callab _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:: ; 38b9 (0:38b9)
+ push hl
+ push de
+ push bc
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,Bank(_Divide)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call _Divide
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; 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 [wd358] flags.
+PrintLetterDelay:: ; 38d3 (0:38d3)
+ ld a,[wd730]
+ bit 6,a
+ ret nz
+ ld a,[wd358]
+ bit 1,a
+ ret z
+ push hl
+ push de
+ push bc
+ ld a,[wd358]
+ bit 0,a
+ jr z,.waitOneFrame
+ ld a,[W_OPTIONS]
+ and $f
+ ld [H_FRAMECOUNTER],a
+ jr .checkButtons
+.waitOneFrame
+ ld a,1
+ ld [H_FRAMECOUNTER],a
+.checkButtons
+ call Joypad
+ ld 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
+ ld a,[H_FRAMECOUNTER]
+ and a
+ jr nz,.checkButtons
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; Copies [hl, bc) to [de, bc - hl).
+; In other words, the source data is from hl up to but not including bc,
+; and the destination is de.
+CopyDataUntil:: ; 3913 (0:3913)
+ 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.
+; [wcf95] == 0 specifies the party.
+; [wcf95] != 0 specifies the current box.
+RemovePokemon:: ; 391f (0:391f)
+ ld hl, _RemovePokemon
+ ld b, BANK(_RemovePokemon)
+ jp Bankswitch
+
+AddPartyMon:: ; 3927 (0:3927)
+ push hl
+ push de
+ push bc
+ callba _AddPartyMon
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; calculates all 5 stats of current mon and writes them to [de]
+CalcStats:: ; 3936 (0:3936)
+ ld c, $0
+.statsLoop
+ inc c
+ call CalcStat
+ ld a, [H_MULTIPLICAND+1]
+ ld [de], a
+ inc de
+ ld a, [H_MULTIPLICAND+2]
+ ld [de], a
+ inc de
+ ld a, c
+ cp $5
+ 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:: ; 394a (0:394a)
+ push hl
+ push de
+ push bc
+ ld a, b
+ ld d, a
+ push hl
+ ld hl, W_MONHEADER
+ 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
+ ld [H_MULTIPLICAND], a
+ ld [H_MULTIPLICAND+1], a
+ inc b ; increment current stat exp bonus
+ ld a, b
+ cp $ff
+ jr z, .statExpDone
+ ld [H_MULTIPLICAND+2], a
+ ld [H_MULTIPLIER], a
+ call Multiply
+ ld a, [hld]
+ ld d, a
+ ld a, [$ff98]
+ sub d
+ ld a, [hli]
+ ld d, a
+ ld a, [$ff97]
+ sbc d ; test if (current stat exp bonus)^2 < stat exp
+ jr c, .statExpLoop
+.statExpDone
+ srl c
+ pop hl
+ push bc
+ ld bc, $b ; skip to stat IV values
+ 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 ; da = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4
+.noCarry2
+ ld [H_MULTIPLICAND+2], a
+ ld a, d
+ ld [H_MULTIPLICAND+1], a
+ xor a
+ ld [H_MULTIPLICAND], a
+ ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL
+ ld [H_MULTIPLIER], a
+ call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level
+ ld a, [H_MULTIPLICAND]
+ ld [H_DIVIDEND], a
+ ld a, [H_MULTIPLICAND+1]
+ ld [H_DIVIDEND+1], a
+ ld a, [H_MULTIPLICAND+2]
+ ld [H_DIVIDEND+2], a
+ ld a, $64
+ ld [H_DIVISOR], 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
+ jr nz, .notHPStat
+ ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL
+ ld b, a
+ ld a, [H_MULTIPLICAND+2]
+ add b
+ ld [H_MULTIPLICAND+2], a
+ jr nc, .noCarry3
+ ld a, [H_MULTIPLICAND+1]
+ inc a
+ ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level
+.noCarry3
+ ld a, $a
+.notHPStat
+ ld b, a
+ ld a, [H_MULTIPLICAND+2]
+ add b
+ ld [H_MULTIPLICAND+2], a
+ jr nc, .noCarry4
+ ld a, [H_MULTIPLICAND+1]
+ inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5
+ ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10
+.noCarry4
+ ld a, [H_MULTIPLICAND+1] ; check for overflow (>999)
+ cp $4
+ jr nc, .overflow
+ cp $3
+ jr c, .noOverflow
+ ld a, [H_MULTIPLICAND+2]
+ cp $e8
+ jr c, .noOverflow
+.overflow
+ ld a, $3 ; overflow: cap at 999
+ ld [H_MULTIPLICAND+1], a
+ ld a, $e7
+ ld [H_MULTIPLICAND+2], a
+.noOverflow
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AddEnemyMonToPlayerParty:: ; 3a53 (0:3a53)
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, BANK(_AddEnemyMonToPlayerParty)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ call _AddEnemyMonToPlayerParty
+ pop bc
+ ld a, b
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+Func_3a68:: ; 3a68 (0:3a68)
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, BANK(Func_f51e)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ call Func_f51e
+ pop bc
+ ld a, b
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+; skips a text entries, each of size $b (like trainer name, OT name, rival name, ...)
+; hl: base pointer, will be incremented by $b * a
+SkipFixedLengthTextEntries:: ; 3a7d (0:3a7d)
+ and a
+ ret z
+ ld bc, $b
+.skipLoop
+ add hl, bc
+ dec a
+ jr nz, .skipLoop
+ ret
+
+AddNTimes:: ; 3a87 (0:3a87)
+; add bc to hl a times
+ and a
+ ret z
+.loop
+ add hl,bc
+ dec a
+ jr nz,.loop
+ ret
+
+; Compare strings, c bytes in length, at de and hl.
+; Often used to compare big endian numbers in battle calculations.
+StringCmp:: ; 3a8e (0:3a8e)
+ ld a,[de]
+ cp [hl]
+ ret nz
+ inc de
+ inc hl
+ dec c
+ jr nz,StringCmp
+ ret
+
+; 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:: ; 3a97 (0:3a97)
+ ld h,wOAMBuffer / $100
+ 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
+
+HandleMenuInput:: ; 3abe (0:3abe)
+ xor a
+ ld [wd09b],a
+
+HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2)
+ ld a,[H_DOWNARROWBLINKCNT1]
+ push af
+ ld a,[H_DOWNARROWBLINKCNT2]
+ push af ; save existing values on stack
+ xor a
+ ld [H_DOWNARROWBLINKCNT1],a ; blinking down arrow timing value 1
+ ld a,$06
+ ld [H_DOWNARROWBLINKCNT2],a ; blinking down arrow timing value 2
+.loop1
+ xor a
+ ld [wPartyMonAnimCounter],a ; counter for pokemon shaking animation
+ call PlaceMenuCursor
+ call Delay3
+.loop2
+ push hl
+ ld a,[wd09b]
+ and a ; is it a pokemon selection menu?
+ jr z,.getJoypadState
+ callba AnimatePartyMon ; shake mini sprite of selected pokemon
+.getJoypadState
+ pop hl
+ call JoypadLowSensitivity
+ ld 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
+ ld [H_DOWNARROWBLINKCNT2],a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled],a ; disable menu wrapping
+ ret
+.keyPressed
+ xor a
+ ld [wcc4b],a
+ ld a,[hJoy5]
+ ld b,a
+ 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
+ ld 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_02_40 - SFX_Headers_02) / 3
+ call PlaySound ; play sound
+.skipPlayingSound
+ pop af
+ ld [H_DOWNARROWBLINKCNT2],a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled],a ; disable menu wrapping
+ ld a,[hJoy5]
+ ret
+.noWrappingAround
+ ld a,[wcc37]
+ and a ; should we return if the user tried to go past the top or bottom?
+ jr z,.checkOtherKeys
+ jr .checkIfAButtonOrBButtonPressed
+
+PlaceMenuCursor:: ; 3b7c (0:3b7c)
+ ld a,[wTopMenuItemY]
+ and a ; is the y coordinate 0?
+ jr z,.adjustForXCoord
+ ld hl,wTileMap
+ 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
+ push af
+ ld a,[hFlags_0xFFF6]
+ bit 1,a ; is the menu double spaced?
+ jr z,.doubleSpaced1
+ ld bc,20
+ jr .getOldMenuItemScreenPosition
+.doubleSpaced1
+ ld bc,40
+.getOldMenuItemScreenPosition
+ pop af
+.oldMenuItemLoop
+ add hl,bc
+ dec a
+ jr nz,.oldMenuItemLoop
+.checkForArrow1
+ ld a,[hl]
+ cp a,"▶" ; 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
+ push af
+ ld a,[hFlags_0xFFF6]
+ bit 1,a ; is the menu double spaced?
+ jr z,.doubleSpaced2
+ ld bc,20
+ jr .getCurrentMenuItemScreenPosition
+.doubleSpaced2
+ ld bc,40
+.getCurrentMenuItemScreenPosition
+ pop af
+.currentMenuItemLoop
+ add hl,bc
+ dec a
+ jr nz,.currentMenuItemLoop
+.checkForArrow2
+ ld a,[hl]
+ cp a,"▶" ; 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:: ; 3bec (0:3bec)
+ ld b,a
+ ld a,[wMenuCursorLocation]
+ ld l,a
+ ld a,[wMenuCursorLocation + 1]
+ ld h,a
+ ld [hl],$ec ; outline of right arrow
+ ld a,b
+ ret
+
+; Replaces the menu cursor with a blank space.
+EraseMenuCursor:: ; 3bf9 (0:3bf9)
+ 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 H_DOWNARROWBLINKCNT1 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
+; initliazed 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:: ; 3c04 (0:3c04)
+ ld a,[hl]
+ ld b,a
+ ld a,$ee ; down arrow
+ cp b
+ jr nz,.downArrowOff
+.downArrowOn
+ ld a,[H_DOWNARROWBLINKCNT1]
+ dec a
+ ld [H_DOWNARROWBLINKCNT1],a
+ ret nz
+ ld a,[H_DOWNARROWBLINKCNT2]
+ dec a
+ ld [H_DOWNARROWBLINKCNT2],a
+ ret nz
+ ld a," "
+ ld [hl],a
+ ld a,$ff
+ ld [H_DOWNARROWBLINKCNT1],a
+ ld a,$06
+ ld [H_DOWNARROWBLINKCNT2],a
+ ret
+.downArrowOff
+ ld a,[H_DOWNARROWBLINKCNT1]
+ and a
+ ret z
+ dec a
+ ld [H_DOWNARROWBLINKCNT1],a
+ ret nz
+ dec a
+ ld [H_DOWNARROWBLINKCNT1],a
+ ld a,[H_DOWNARROWBLINKCNT2]
+ dec a
+ ld [H_DOWNARROWBLINKCNT2],a
+ ret nz
+ ld a,$06
+ ld [H_DOWNARROWBLINKCNT2],a
+ ld a,$ee ; down arrow
+ 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 [wcc47] is set).
+
+EnableAutoTextBoxDrawing:: ; 3c3c (0:3c3c)
+ xor a
+ jr AutoTextBoxDrawingCommon
+
+DisableAutoTextBoxDrawing:: ; 3c3f (0:3c3f)
+ ld a,$01
+
+AutoTextBoxDrawingCommon:: ; 3c41 (0:3c41)
+ ld [wAutoTextBoxDrawingControl],a
+ xor a
+ ld [wDoNotWaitForButtonPressAfterDisplayingText],a ; make DisplayTextID wait for button press
+ ret
+
+PrintText:: ; 3c49 (0:3c49)
+; Print text hl at (1, 14).
+ push hl
+ ld a,MESSAGE_BOX
+ ld [wTextBoxID],a
+ call DisplayTextBoxID
+ call UpdateSprites
+ call Delay3
+ pop hl
+Func_3c59:: ; 3c59 (0:3c59)
+ bcCoord 1, 14
+ jp TextCommandProcessor
+
+
+PrintNumber:: ; 3c5f
+; 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.
+LEADING_ZEROES EQU 7
+LEFT_ALIGN EQU 6
+
+ push bc
+ xor a
+ ld [H_PASTLEADINGZEROES], a
+ ld [H_NUMTOPRINT], a
+ ld [H_NUMTOPRINT + 1], a
+ ld a, b
+ and $f
+ cp 1
+ jr z, .byte
+ cp 2
+ jr z, .word
+.long
+ ld a, [de]
+ ld [H_NUMTOPRINT], a
+ inc de
+ ld a, [de]
+ ld [H_NUMTOPRINT + 1], a
+ inc de
+ ld a, [de]
+ ld [H_NUMTOPRINT + 2], a
+ jr .start
+
+.word
+ ld a, [de]
+ ld [H_NUMTOPRINT + 1], a
+ inc de
+ ld a, [de]
+ ld [H_NUMTOPRINT + 2], a
+ jr .start
+
+.byte
+ ld a, [de]
+ ld [H_NUMTOPRINT + 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
+ ld [H_POWEROFTEN + 0], a
+
+if (\1) / $100
+ ld a, \1 / $100 % $100
+else xor a
+endc
+ ld [H_POWEROFTEN + 1], a
+
+ ld a, \1 / $1 % $100
+ ld [H_POWEROFTEN + 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
+ ld a, [H_NUMTOPRINT + 2]
+.mod
+ cp 10
+ jr c, .ok
+ sub 10
+ inc c
+ jr .mod
+.ok
+
+ ld b, a
+ ld a, [H_PASTLEADINGZEROES]
+ or c
+ ld [H_PASTLEADINGZEROES], 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
+ ld a, [H_POWEROFTEN]
+ ld b, a
+ ld a, [H_NUMTOPRINT]
+ ld [H_SAVEDNUMTOPRINT], a
+ cp b
+ jr c, .underflow0
+ sub b
+ ld [H_NUMTOPRINT], a
+ ld a, [H_POWEROFTEN + 1]
+ ld b, a
+ ld a, [H_NUMTOPRINT + 1]
+ ld [H_SAVEDNUMTOPRINT + 1], a
+ cp b
+ jr nc, .noborrow1
+
+ ld a, [H_NUMTOPRINT]
+ or 0
+ jr z, .underflow1
+ dec a
+ ld [H_NUMTOPRINT], a
+ ld a, [H_NUMTOPRINT + 1]
+.noborrow1
+
+ sub b
+ ld [H_NUMTOPRINT + 1], a
+ ld a, [H_POWEROFTEN + 2]
+ ld b, a
+ ld a, [H_NUMTOPRINT + 2]
+ ld [H_SAVEDNUMTOPRINT + 2], a
+ cp b
+ jr nc, .noborrow2
+
+ ld a, [H_NUMTOPRINT + 1]
+ and a
+ jr nz, .borrowed
+
+ ld a, [H_NUMTOPRINT]
+ and a
+ jr z, .underflow2
+ dec a
+ ld [H_NUMTOPRINT], a
+ xor a
+.borrowed
+
+ dec a
+ ld [H_NUMTOPRINT + 1], a
+ ld a, [H_NUMTOPRINT + 2]
+.noborrow2
+ sub b
+ ld [H_NUMTOPRINT + 2], a
+ inc c
+ jr .loop
+
+.underflow2
+ ld a, [H_SAVEDNUMTOPRINT + 1]
+ ld [H_NUMTOPRINT + 1], a
+.underflow1
+ ld a, [H_SAVEDNUMTOPRINT]
+ ld [H_NUMTOPRINT], a
+.underflow0
+ ld a, [H_PASTLEADINGZEROES]
+ or c
+ jr z, .PrintLeadingZero
+
+ ld a, "0"
+ add c
+ ld [hl], a
+ ld [H_PASTLEADINGZEROES], a
+ ret
+
+.PrintLeadingZero:
+ 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 LEADING_ZEROES, d
+ jr nz, .inc
+ bit LEFT_ALIGN, d
+ jr z, .inc
+ ld a, [H_PASTLEADINGZEROES]
+ and a
+ ret z
+.inc
+ inc hl
+ ret
+
+
+CallFunctionInTable::
+JumpTable::
+; 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
+
+InitMapSprites:: ; 3dba (0:3dba)
+ ld hl, _InitMapSprites ; 1401b (5:401b)
+ ld b,BANK(_InitMapSprites)
+ jp Bankswitch
+
+RestoreScreenTilesAndReloadTilePatterns:: ; 3dbe (0:3dbe)
+ call ClearSprites
+ ld a, $1
+ ld [wUpdateSpritesEnabled], a
+ call ReloadMapSpriteTilePatterns
+ call LoadScreenTilesFromBuffer2
+ call LoadTextBoxTilePatterns
+ call GoPAL_SET_CF1C
+ 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
+ ld [rBGP], a
+ ld a, %11010000 ; 3100
+ ld [rOBP0], a
+ ret
+
+GBPalWhiteOut::
+; White out all palettes.
+ xor a
+ ld [rBGP],a
+ ld [rOBP0],a
+ ld [rOBP1],a
+ ret
+
+
+GoPAL_SET_CF1C:: ; 3ded (0:3ded)
+ ld b,$ff
+GoPAL_SET:: ; 3def (0:3def)
+ ld a,[wOnSGB]
+ and a
+ ret z
+ predef_jump Func_71ddf
+
+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
+
+; Copy the current map's sprites' tile patterns to VRAM again after they have
+; been overwritten by other tile patterns.
+ReloadMapSpriteTilePatterns:: ; 3e08 (0:3e08)
+ ld hl, wFontLoaded
+ ld a, [hl]
+ push af
+ res 0, [hl]
+ push hl
+ xor a
+ ld [W_SPRITESETID], a
+ call DisableLCD
+ callba InitMapSprites
+ call EnableLCD
+ pop hl
+ pop af
+ ld [hl], a
+ call LoadPlayerSpriteGraphics
+ call LoadFontTilePatterns
+ jp UpdateSprites
+
+
+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 [wcf96], 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 [W_CURENEMYLVL], a
+ xor a
+ ld [wcc49], a
+ ld b, BANK(_GivePokemon)
+ ld hl, _GivePokemon
+ jp Bankswitch
+
+
+Random::
+; Return a random number in a.
+; For battles, use BattleRandom.
+ push hl
+ push de
+ push bc
+ callba Random_
+ ld a, [hRandomAdd]
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+INCLUDE "home/predef.asm"
+
+
+Func_3ead:: ; 3ead (0:3ead)
+ ld b, BANK(CinnabarGymQuiz_1eb0a)
+ ld hl, CinnabarGymQuiz_1eb0a
+ jp Bankswitch
+
+CheckForHiddenObjectOrBookshelfOrCardKeyDoor:: ; 3eb5 (0:3eb5)
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, [hJoyHeld]
+ bit 0, a ; A button
+ jr z, .nothingFound
+; A button is pressed
+ ld a, Bank(CheckForHiddenObject)
+ ld [MBC1RomBank], a
+ ld [H_LOADEDROMBANK], a
+ call CheckForHiddenObject
+ ld a, [$ffee]
+ and a
+ jr nz, .hiddenObjectNotFound
+ ld a, [wHiddenObjectFunctionRomBank]
+ ld [MBC1RomBank], a
+ ld [H_LOADEDROMBANK], a
+ ld de, .returnAddress
+ push de
+ jp [hl]
+.returnAddress
+ xor a
+ jr .done
+.hiddenObjectNotFound
+ callba PrintBookshelfText
+ ld a, [$ffdb]
+ and a
+ jr z, .done
+.nothingFound
+ ld a, $ff
+.done
+ ld [$ffeb], a
+ pop af
+ ld [MBC1RomBank], a
+ ld [H_LOADEDROMBANK], a
+ ret
+
+PrintPredefTextID:: ; 3ef5 (0:3ef5)
+ ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
+ ld hl, TextPredefs
+ call SetMapTextPointer
+ ld hl, wcf11
+ set 0, [hl]
+ call DisplayTextID
+
+RestoreMapTextPointer:: ; 3f05 (0:3f05)
+ ld hl, W_MAPTEXTPTR
+ ld a, [$ffec]
+ ld [hli], a
+ ld a, [$ffec + 1]
+ ld [hl], a
+ ret
+
+SetMapTextPointer:: ; 3f0f (0:3f0f)
+ ld a, [W_MAPTEXTPTR]
+ ld [$ffec], a
+ ld a, [W_MAPTEXTPTR + 1]
+ ld [$ffec + 1], a
+ ld a, l
+ ld [W_MAPTEXTPTR], a
+ ld a, h
+ ld [W_MAPTEXTPTR + 1], a
+ ret
+
+TextPredefs::
+ add_tx_pre CardKeySuccessText ; 01
+ add_tx_pre CardKeyFailText ; 02
+ add_tx_pre RedBedroomPC ; 03
+ add_tx_pre RedBedroomSNESText ; 04
+ add_tx_pre PushStartText ; 05
+ add_tx_pre SaveOptionText ; 06
+ add_tx_pre StrengthsAndWeaknessesText ; 07
+ add_tx_pre OakLabEmailText ; 08
+ add_tx_pre AerodactylFossilText ; 09
+ add_tx_pre Route15UpstairsBinocularsText ; 0A
+ add_tx_pre KabutopsFossilText ; 0B
+ add_tx_pre GymStatueText1 ; 0C
+ add_tx_pre GymStatueText2 ; 0D
+ add_tx_pre BookcaseText ; 0E
+ add_tx_pre ViridianCityPokecenterBenchGuyText ; 0F
+ add_tx_pre PewterCityPokecenterBenchGuyText ; 10
+ add_tx_pre CeruleanCityPokecenterBenchGuyText ; 11
+ add_tx_pre LavenderCityPokecenterBenchGuyText ; 12
+ add_tx_pre VermilionCityPokecenterBenchGuyText ; 13
+ add_tx_pre CeladonCityPokecenterBenchGuyText ; 14
+ add_tx_pre CeladonCityHotelText ; 15
+ add_tx_pre FuchsiaCityPokecenterBenchGuyText ; 16
+ add_tx_pre CinnabarIslandPokecenterBenchGuyText ; 17
+ add_tx_pre SaffronCityPokecenterBenchGuyText ; 18
+ add_tx_pre MtMoonPokecenterBenchGuyText ; 19
+ add_tx_pre RockTunnelPokecenterBenchGuyText ; 1A
+ add_tx_pre UnusedBenchGuyText1 ; 1B
+ add_tx_pre UnusedBenchGuyText2 ; 1C
+ add_tx_pre UnusedBenchGuyText3 ; 1D
+ add_tx_pre TerminatorText_62508 ; 1E
+ add_tx_pre PredefText1f ; 1F
+ add_tx_pre ViridianSchoolNotebook ; 20
+ add_tx_pre ViridianSchoolBlackboard ; 21
+ add_tx_pre JustAMomentText ; 22
+ add_tx_pre PredefText23 ; 23
+ add_tx_pre FoundHiddenItemText ; 24
+ add_tx_pre HiddenItemBagFullText ; 25
+ add_tx_pre VermilionGymTrashText ; 26
+ add_tx_pre IndigoPlateauHQText ; 27
+ add_tx_pre GameCornerOutOfOrderText ; 28
+ add_tx_pre GameCornerOutToLunchText ; 29
+ add_tx_pre GameCornerSomeonesKeysText ; 2A
+ add_tx_pre FoundHiddenCoinsText ; 2B
+ add_tx_pre DroppedHiddenCoinsText ; 2C
+ add_tx_pre BillsHouseMonitorText ; 2D
+ add_tx_pre BillsHouseInitiatedText ; 2E
+ add_tx_pre BillsHousePokemonList ; 2F
+ add_tx_pre MagazinesText ; 30
+ add_tx_pre CinnabarGymQuiz ; 31
+ add_tx_pre GameCornerNoCoinsText ; 32
+ add_tx_pre GameCornerCoinCaseText ; 33
+ add_tx_pre LinkCableHelp ; 34
+ add_tx_pre TMNotebook ; 35
+ add_tx_pre FightingDojoText ; 36
+ add_tx_pre FightingDojoText_52a10 ; 37
+ add_tx_pre FightingDojoText_52a1d ; 38
+ add_tx_pre NewBicycleText ; 39
+ add_tx_pre IndigoPlateauStatues ; 3A
+ add_tx_pre VermilionGymTrashSuccesText1 ; 3B
+ add_tx_pre VermilionGymTrashSuccesText2 ; 3C
+ add_tx_pre VermilionGymTrashSuccesText3 ; 3D
+ add_tx_pre VermilionGymTrashFailText ; 3E
+ add_tx_pre TownMapText ; 3F
+ add_tx_pre BookOrSculptureText ; 40
+ add_tx_pre ElevatorText ; 41
+ add_tx_pre PokemonStuffText ; 42