From 139e117d0717c69ae4c47a8d1a040267ee28d91d Mon Sep 17 00:00:00 2001 From: luckytyphlosion Date: Fri, 5 Jun 2015 17:23:06 -0400 Subject: Fix EOL to LF to make push requests more doable. --- home.asm | 9844 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 4922 insertions(+), 4922 deletions(-) (limited to 'home.asm') diff --git a/home.asm b/home.asm index e07bdadd..f66a098a 100644 --- a/home.asm +++ b/home.asm @@ -1,4922 +1,4922 @@ - -; 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:: ; 10ba (0:10ba) -; 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:: ; 10d5 (0:10d5) - 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:: ; 10f8 (0:10f8) -; 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:: ; 1132 (0:1132) - ld hl, LoadMonData_ - ld b, BANK(LoadMonData_) ; 1:442b - jp Bankswitch - - -Func_137a:: ; 113a (0:113a) -; 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:: ; 1144 (0:1144) - ld a, 1 - ld [W_SPRITEFLIPPED], a - -LoadFrontSpriteByMonIndex:: ; 1149 (0:1149) - 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(Func_f6203) - call BankswitchCommon - xor a - ld [$ffe1], a - call Func_f6203 - xor a - ld [W_SPRITEFLIPPED], a - pop af - jp BankswitchCommon - -PlayCry:: ; 118b (0:118b) -; Play monster a's cry. - push bc - ld b,a - ld a,[wLowHealthAlarm] - push af - xor a - ld [wLowHealthAlarm],a - ld a,b - call Func_11a5 - call PlaySound - call WaitForSoundToFinish - pop af - ld [wLowHealthAlarm],a - pop bc - ret - -GetCryData:: ; 11a5 (0:11a5) -; 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:: ; 11c8 (0:11c8) - ld a,[hTilesetType] - push af - xor a - ld [hTilesetType],a - call GBPalWhiteOutWithDelay3 - call ClearSprites - call PartyMenuInit - call DrawPartyMenu - jp HandlePartyMenuInput - -GoBackToPartyMenu:: ; 11dd (0:11dd) - ld a,[hTilesetType] - push af - xor a - ld [hTilesetType],a - call PartyMenuInit - call RedrawPartyMenu - jp HandlePartyMenuInput - -PartyMenuInit:: ; 11ec (0:11ec) - 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:: ; 1226 (0:1226) - ld a,1 - ld [wMenuWrappingEnabled],a - ld a,$40 - ld [wd09b],a - call HandleMenuInputPokemonSelection - push af ; save hJoy5 OR wMenuWrapping enabled, if no inputs were selected within a certain period of time - bit 1,a ; was B button pressed? - ld a,$0 - ld [wd09b],a - ld a,[wCurrentMenuItem] - ld [wcc2b],a - jr nz,.asm_1258 - ld a,[wCurrentMenuItem] - ld [wWhichPokemon],a - callab Func_fce18 ; 3f:4e18 - jr nc,.asm_1258 - call Func_154a - jr nz,.asm_128f -.asm_1258 - pop af - call PlaceUnfilledArrowMenuCursor - ld b,a - ld hl,wd730 - res 6,[hl] ; turn on letter printing delay - ld a,[wMenuItemToSwap] - and a - jp nz,.swappingPokemon - pop af ; double 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 -.asm_128f - pop af - ld hl,PartyMenuText_12cc - call PrintText - xor a - ld [wMenuItemToSwap],a - pop af - ld [hTilesetType],a -.noPokemonChosen - call BankswitchBack - scf - ret -.swappingPokemon - bit 1,b ; was the B button pressed? - jr z,.handleSwap ; if not, handle swapping the pokemon -.cancelSwap ; if the B button was pressed - callba ErasePartyMenuCursors ; 4:5e98 - xor a - ld [wMenuItemToSwap],a - ld [wd07d],a - call RedrawPartyMenu - jp HandlePartyMenuInput -.handleSwap - ld a,[wCurrentMenuItem] - ld [wWhichPokemon],a - callba SwitchPartyMon ; 4:61c5 - jp HandlePartyMenuInput - -PartyMenuText_12cc:: ; 12cc (0:12cc) - TX_FAR _PartyMenuText_12cc ; 28:411b - db "@" - -DrawPartyMenu:: ; 12d1 (0:12d1) - ld hl, DrawPartyMenu_ ; 4:5875 - jr DrawPartyMenuCommon - -RedrawPartyMenu:: ; 12d6 (0:12d6) - ld hl, RedrawPartyMenu_ ; 4:5886 - -DrawPartyMenuCommon:: ; 12d9 (0:12d9) - ld b, BANK(RedrawPartyMenu_) - jp Bankswitch - -; prints a pokemon's status condition -; INPUT: -; de = address of status condition -; hl = destination address -PrintStatusCondition:: ; 12de (0:12de) - 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: ; 12f3 (0:12f3) - homecall_jump_sf PrintStatusAilment - -; function to print pokemon level, leaving off the ":L" if the level is at least 100 -; INPUT: -; hl = destination address -; [wLoadedMonLevel] = level -PrintLevel:: ; 1303 (0:1303) - 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:: ; 1313 (0:1313) - ld a,$6e ; ":L" tile ID - ld [hli],a - ld c,3 ; number of digits - ld a,[wLoadedMonLevel] ; level - -PrintLevelCommon:: ; 131b (0:131b) - ld [wd11e],a - ld de,wd11e - ld b,$41 ; no leading zeroes, left-aligned, one byte - jp PrintNumber - -Func_1326:: ; 1326 (0:132) -; 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:: ; 132f (0:132f) - ld a,[H_LOADEDROMBANK] - push af - switchbank BaseStats - push bc - push de - push hl - ld a,[wd11e] - push af - ld a,[wd0b5] - ld [wd11e],a - ld de,FossilKabutopsPic - ld b,$66 ; size of Kabutops fossil and Ghost sprites - cp 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 -.done - ld a,[wd0b5] - ld [W_MONHDEXNUM],a - pop af - ld [wd11e],a - pop hl - pop de - pop bc - pop af - call BankswitchCommon - ret - -; copy party pokemon's name to wcd6d -GetPartyMonName2:: ; 1394 (0:1394) - ld a,[wWhichPokemon] ; index within party - ld hl,wPartyMonNicks - -; this is called more often -GetPartyMonName:: ; 139a (0:139a) - 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:: ; 13ad (0:13ad) - 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:: ; 13e4 (0:13e4) - 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:: ; 1407 (0:1407) - 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 ; 23f8 - -; de: destination location -LoadMonFrontSprite:: ; 143e (0:143e) - 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 - ld a,$0 - call SwitchSRAMBankAndLatchClockData - 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) - call PrepareRTCDataAndDisableSRAM - pop de - jp InterlaceMergeSpriteBuffers ; 14c7 - -; 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:: ; 149f (0:149f) - 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:: ; 14bc (0:14bc) - 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:: ; 14c7 (0:14c7) - ld a,$0 - 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 - call CopyVideoDataLCDEnabled - jp PrepareRTCDataAndDisableSRAM - -Func_1510:: ; 1510 (0:1510) - push hl - ld hl,wd430 - set 7,[hl] - ld hl,wSpriteStateData1 + $f2 ; pikachu data? - ld [hl],$ff - pop hl - ret - -Func_151d:: ; 151d (0:151d) - push hl - ld hl,wd430 - res 7,[hl] - pop hl - ret - -Func_1525:: ; 1525 (0:1525) - push hl - ld hl,wd430 - res 3,[hl] - pop hl - ret - -Func_152d:: ; 152d (0:152d) - push hl - ld hl,wd430 - set 3,[hl] - ld hl,wSpriteStateData1 + $f2 ; pikachu data? - ld [hl],$ff - pop hl - ret - -Func_153a:: ; 153a (0:153a) - push hl - ld hl,wd430 - set 1,[hl] - pop hl - ret - -Func_1542:: ; 1542 (0:1542) - push hl - ld hl,wd430 - res 1,[hl] - pop hl - ret - -Func_154a:: ; 154a (0:154a) - push hl - ld hl,wd430 - bit 1,[hl] - pop hl - ret - -Func_1552:: ; 1552 (0:1552) - ld a,[hl] - dec a - swap a - ld [$ff93],a - homecall Func_fc6d5 ; 3f:46d5 - ret - -Func_1568:: ; 1568 (0:1568) - ld b,$0 - ld c,a -.asm_156b - inc b - ld a,[hli] - cp $ff - jr z,.asm_1578 - cp c - jr nz,.asm_156b - dec b - dec hl - scf - ret -.asm_1578 - dec b - dec hl - and a - ret - -Func_157c:: ; 157c (0:157c) - push hl - push bc - ld a,[H_LOADEDROMBANK] - push af - ld a,[wd44a] - call BankswitchCommon - ld hl,wd44b - ld c,[hl] - inc hl - ld b,[hl] - ld a,[bc] - inc bc - ld [hl],b - dec hl - ld [hl],c - ld c,a - pop af - call BankswitchCommon - ld a,c - pop bc - pop hl - ret - -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 -; 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:: ; 35c3 (0:35c3) -; 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] - -SwitchSRAMBankAndLatchClockData:: ; 3e99 (0:3e99) - push af - ld a,$1 - ld [$6000],a - ld a,SRAM_ENABLE - ld [$0],a - pop af - ld [$4000],a - ret - -PrepareRTCDataAndDisableSRAM:: ; 3eac (0:3eac) - push af - ld a,$0 - ld [$6000],a - ld [$0],a - pop af - ret - -; 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 a999) - 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 0,a ; pressed A key? - jr z,.checkOtherKeys - bit 6,a ; pressed Up key? - jr z,.checkIfDownPressed -.upPressed - ld a,[wCurrentMenuItem] ; selected menu item - and a ; already at the top of the menu? - jr z,.alreadyAtTop -.notAtTop - dec a - ld [wCurrentMenuItem],a ; move selected menu item up one space - jr .checkOtherKeys -.alreadyAtTop - ld a,[wMenuWrappingEnabled] - and a ; is wrapping around enabled? - jr z,.noWrappingAround - ld a,[wMaxMenuItem] - ld [wCurrentMenuItem],a ; wrap to the bottom of the menu - jr .checkOtherKeys -.checkIfDownPressed - bit 7,a - jr z,.checkOtherKeys -.downPressed - ld a,[wCurrentMenuItem] - inc a - ld c,a - ld a,[wMaxMenuItem] - cp c - jr nc,.notAtBottom -.alreadyAtBottom - ld a,[wMenuWrappingEnabled] - and a ; is wrapping around enabled? - jr z,.noWrappingAround - ld c,$00 ; wrap from bottom to top -.notAtBottom - ld a,c - ld [wCurrentMenuItem],a -.checkOtherKeys - ld a,[wMenuWatchedKeys] - and b ; does the menu care about any of the pressed keys? - jp z,.loop1 -.checkIfAButtonOrBButtonPressed - 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:: ; 3b6d (0:3b6d) - 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 - ld bc,40 - push af - ld a,[hFlags_0xFFFA] - bit 1,a ; is the menu double spaced? - jr z,.doubleSpaced1 - ld bc,20 -.doubleSpaced1 - pop af -.oldMenuItemLoop - add hl,bc - dec a - jr nz,.oldMenuItemLoop -.checkForArrow1 - ld a,[hl] - cp 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 - ld bc,40 - push af - ld a,[hFlags_0xFFFA] - bit 1,a ; is the menu double spaced? - jr z,.doubleSpaced2 - ld bc,20 -.doubleSpaced2 - pop af -.currentMenuItemLoop - add hl,bc - dec a - jr nz,.currentMenuItemLoop -.checkForArrow2 - ld a,[hl] - cp 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:: ; 3bd9 (0:3bd9) - 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:: ; 3be6 (0:3be6) - 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 + +; 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:: ; 10ba (0:10ba) +; 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:: ; 10d5 (0:10d5) + 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:: ; 10f8 (0:10f8) +; 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:: ; 1132 (0:1132) + ld hl, LoadMonData_ + ld b, BANK(LoadMonData_) ; 1:442b + jp Bankswitch + + +Func_137a:: ; 113a (0:113a) +; 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:: ; 1144 (0:1144) + ld a, 1 + ld [W_SPRITEFLIPPED], a + +LoadFrontSpriteByMonIndex:: ; 1149 (0:1149) + 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(Func_f6203) + call BankswitchCommon + xor a + ld [$ffe1], a + call Func_f6203 + xor a + ld [W_SPRITEFLIPPED], a + pop af + jp BankswitchCommon + +PlayCry:: ; 118b (0:118b) +; Play monster a's cry. + push bc + ld b,a + ld a,[wLowHealthAlarm] + push af + xor a + ld [wLowHealthAlarm],a + ld a,b + call Func_11a5 + call PlaySound + call WaitForSoundToFinish + pop af + ld [wLowHealthAlarm],a + pop bc + ret + +GetCryData:: ; 11a5 (0:11a5) +; 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:: ; 11c8 (0:11c8) + ld a,[hTilesetType] + push af + xor a + ld [hTilesetType],a + call GBPalWhiteOutWithDelay3 + call ClearSprites + call PartyMenuInit + call DrawPartyMenu + jp HandlePartyMenuInput + +GoBackToPartyMenu:: ; 11dd (0:11dd) + ld a,[hTilesetType] + push af + xor a + ld [hTilesetType],a + call PartyMenuInit + call RedrawPartyMenu + jp HandlePartyMenuInput + +PartyMenuInit:: ; 11ec (0:11ec) + 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:: ; 1226 (0:1226) + ld a,1 + ld [wMenuWrappingEnabled],a + ld a,$40 + ld [wd09b],a + call HandleMenuInputPokemonSelection + push af ; save hJoy5 OR wMenuWrapping enabled, if no inputs were selected within a certain period of time + bit 1,a ; was B button pressed? + ld a,$0 + ld [wd09b],a + ld a,[wCurrentMenuItem] + ld [wcc2b],a + jr nz,.asm_1258 + ld a,[wCurrentMenuItem] + ld [wWhichPokemon],a + callab Func_fce18 ; 3f:4e18 + jr nc,.asm_1258 + call Func_154a + jr nz,.asm_128f +.asm_1258 + pop af + call PlaceUnfilledArrowMenuCursor + ld b,a + ld hl,wd730 + res 6,[hl] ; turn on letter printing delay + ld a,[wMenuItemToSwap] + and a + jp nz,.swappingPokemon + pop af ; double 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 +.asm_128f + pop af + ld hl,PartyMenuText_12cc + call PrintText + xor a + ld [wMenuItemToSwap],a + pop af + ld [hTilesetType],a +.noPokemonChosen + call BankswitchBack + scf + ret +.swappingPokemon + bit 1,b ; was the B button pressed? + jr z,.handleSwap ; if not, handle swapping the pokemon +.cancelSwap ; if the B button was pressed + callba ErasePartyMenuCursors ; 4:5e98 + xor a + ld [wMenuItemToSwap],a + ld [wd07d],a + call RedrawPartyMenu + jp HandlePartyMenuInput +.handleSwap + ld a,[wCurrentMenuItem] + ld [wWhichPokemon],a + callba SwitchPartyMon ; 4:61c5 + jp HandlePartyMenuInput + +PartyMenuText_12cc:: ; 12cc (0:12cc) + TX_FAR _PartyMenuText_12cc ; 28:411b + db "@" + +DrawPartyMenu:: ; 12d1 (0:12d1) + ld hl, DrawPartyMenu_ ; 4:5875 + jr DrawPartyMenuCommon + +RedrawPartyMenu:: ; 12d6 (0:12d6) + ld hl, RedrawPartyMenu_ ; 4:5886 + +DrawPartyMenuCommon:: ; 12d9 (0:12d9) + ld b, BANK(RedrawPartyMenu_) + jp Bankswitch + +; prints a pokemon's status condition +; INPUT: +; de = address of status condition +; hl = destination address +PrintStatusCondition:: ; 12de (0:12de) + 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: ; 12f3 (0:12f3) + homecall_jump_sf PrintStatusAilment + +; function to print pokemon level, leaving off the ":L" if the level is at least 100 +; INPUT: +; hl = destination address +; [wLoadedMonLevel] = level +PrintLevel:: ; 1303 (0:1303) + 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:: ; 1313 (0:1313) + ld a,$6e ; ":L" tile ID + ld [hli],a + ld c,3 ; number of digits + ld a,[wLoadedMonLevel] ; level + +PrintLevelCommon:: ; 131b (0:131b) + ld [wd11e],a + ld de,wd11e + ld b,$41 ; no leading zeroes, left-aligned, one byte + jp PrintNumber + +Func_1326:: ; 1326 (0:132) +; 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:: ; 132f (0:132f) + ld a,[H_LOADEDROMBANK] + push af + switchbank BaseStats + push bc + push de + push hl + ld a,[wd11e] + push af + ld a,[wd0b5] + ld [wd11e],a + ld de,FossilKabutopsPic + ld b,$66 ; size of Kabutops fossil and Ghost sprites + cp 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 +.done + ld a,[wd0b5] + ld [W_MONHDEXNUM],a + pop af + ld [wd11e],a + pop hl + pop de + pop bc + pop af + call BankswitchCommon + ret + +; copy party pokemon's name to wcd6d +GetPartyMonName2:: ; 1394 (0:1394) + ld a,[wWhichPokemon] ; index within party + ld hl,wPartyMonNicks + +; this is called more often +GetPartyMonName:: ; 139a (0:139a) + 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:: ; 13ad (0:13ad) + 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:: ; 13e4 (0:13e4) + 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:: ; 1407 (0:1407) + 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 ; 23f8 + +; de: destination location +LoadMonFrontSprite:: ; 143e (0:143e) + 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 + ld a,$0 + call SwitchSRAMBankAndLatchClockData + 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) + call PrepareRTCDataAndDisableSRAM + pop de + jp InterlaceMergeSpriteBuffers ; 14c7 + +; 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:: ; 149f (0:149f) + 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:: ; 14bc (0:14bc) + 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:: ; 14c7 (0:14c7) + ld a,$0 + 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 + call CopyVideoDataLCDEnabled + jp PrepareRTCDataAndDisableSRAM + +Func_1510:: ; 1510 (0:1510) + push hl + ld hl,wd430 + set 7,[hl] + ld hl,wSpriteStateData1 + $f2 ; pikachu data? + ld [hl],$ff + pop hl + ret + +Func_151d:: ; 151d (0:151d) + push hl + ld hl,wd430 + res 7,[hl] + pop hl + ret + +Func_1525:: ; 1525 (0:1525) + push hl + ld hl,wd430 + res 3,[hl] + pop hl + ret + +Func_152d:: ; 152d (0:152d) + push hl + ld hl,wd430 + set 3,[hl] + ld hl,wSpriteStateData1 + $f2 ; pikachu data? + ld [hl],$ff + pop hl + ret + +Func_153a:: ; 153a (0:153a) + push hl + ld hl,wd430 + set 1,[hl] + pop hl + ret + +Func_1542:: ; 1542 (0:1542) + push hl + ld hl,wd430 + res 1,[hl] + pop hl + ret + +Func_154a:: ; 154a (0:154a) + push hl + ld hl,wd430 + bit 1,[hl] + pop hl + ret + +Func_1552:: ; 1552 (0:1552) + ld a,[hl] + dec a + swap a + ld [$ff93],a + homecall Func_fc6d5 ; 3f:46d5 + ret + +Func_1568:: ; 1568 (0:1568) + ld b,$0 + ld c,a +.asm_156b + inc b + ld a,[hli] + cp $ff + jr z,.asm_1578 + cp c + jr nz,.asm_156b + dec b + dec hl + scf + ret +.asm_1578 + dec b + dec hl + and a + ret + +Func_157c:: ; 157c (0:157c) + push hl + push bc + ld a,[H_LOADEDROMBANK] + push af + ld a,[wd44a] + call BankswitchCommon + ld hl,wd44b + ld c,[hl] + inc hl + ld b,[hl] + ld a,[bc] + inc bc + ld [hl],b + dec hl + ld [hl],c + ld c,a + pop af + call BankswitchCommon + ld a,c + pop bc + pop hl + ret + +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 +; 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:: ; 35c3 (0:35c3) +; 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] + +SwitchSRAMBankAndLatchClockData:: ; 3e99 (0:3e99) + push af + ld a,$1 + ld [$6000],a + ld a,SRAM_ENABLE + ld [$0],a + pop af + ld [$4000],a + ret + +PrepareRTCDataAndDisableSRAM:: ; 3eac (0:3eac) + push af + ld a,$0 + ld [$6000],a + ld [$0],a + pop af + ret + +; 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 a999) + 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 0,a ; pressed A key? + jr z,.checkOtherKeys + bit 6,a ; pressed Up key? + jr z,.checkIfDownPressed +.upPressed + ld a,[wCurrentMenuItem] ; selected menu item + and a ; already at the top of the menu? + jr z,.alreadyAtTop +.notAtTop + dec a + ld [wCurrentMenuItem],a ; move selected menu item up one space + jr .checkOtherKeys +.alreadyAtTop + ld a,[wMenuWrappingEnabled] + and a ; is wrapping around enabled? + jr z,.noWrappingAround + ld a,[wMaxMenuItem] + ld [wCurrentMenuItem],a ; wrap to the bottom of the menu + jr .checkOtherKeys +.checkIfDownPressed + bit 7,a + jr z,.checkOtherKeys +.downPressed + ld a,[wCurrentMenuItem] + inc a + ld c,a + ld a,[wMaxMenuItem] + cp c + jr nc,.notAtBottom +.alreadyAtBottom + ld a,[wMenuWrappingEnabled] + and a ; is wrapping around enabled? + jr z,.noWrappingAround + ld c,$00 ; wrap from bottom to top +.notAtBottom + ld a,c + ld [wCurrentMenuItem],a +.checkOtherKeys + ld a,[wMenuWatchedKeys] + and b ; does the menu care about any of the pressed keys? + jp z,.loop1 +.checkIfAButtonOrBButtonPressed + 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:: ; 3b6d (0:3b6d) + 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 + ld bc,40 + push af + ld a,[hFlags_0xFFFA] + bit 1,a ; is the menu double spaced? + jr z,.doubleSpaced1 + ld bc,20 +.doubleSpaced1 + pop af +.oldMenuItemLoop + add hl,bc + dec a + jr nz,.oldMenuItemLoop +.checkForArrow1 + ld a,[hl] + cp 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 + ld bc,40 + push af + ld a,[hFlags_0xFFFA] + bit 1,a ; is the menu double spaced? + jr z,.doubleSpaced2 + ld bc,20 +.doubleSpaced2 + pop af +.currentMenuItemLoop + add hl,bc + dec a + jr nz,.currentMenuItemLoop +.checkForArrow2 + ld a,[hl] + cp 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:: ; 3bd9 (0:3bd9) + 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:: ; 3be6 (0:3be6) + 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 -- cgit v1.2.3