diff options
| author | luckytyphlosion <alan.rj.huang@gmail.com> | 2015-05-17 18:21:24 -0400 |
|---|---|---|
| committer | luckytyphlosion <alan.rj.huang@gmail.com> | 2015-05-17 18:21:24 -0400 |
| commit | b5f5a16f43ef62680f09666073f07911306e1561 (patch) | |
| tree | b62055647e8b02b8d0341639b398f1ed1a1913a2 /home | |
| parent | Create main.asm (diff) | |
| download | pokeyellow-b5f5a16f43ef62680f09666073f07911306e1561.tar.gz pokeyellow-b5f5a16f43ef62680f09666073f07911306e1561.tar.xz pokeyellow-b5f5a16f43ef62680f09666073f07911306e1561.zip | |
Completed home/overworld.asm with other related functions
Diffstat (limited to '')
| -rw-r--r-- | home.asm | 9572 | ||||
| -rw-r--r-- | home/audio.asm | 369 | ||||
| -rw-r--r-- | home/init.asm | 273 | ||||
| -rw-r--r-- | home/overworld.asm | 4518 |
4 files changed, 7406 insertions, 7326 deletions
@@ -1,4781 +1,4791 @@ - -; The rst vectors are unused. -SECTION "rst 00", ROM0 [$00] - rst $38 -SECTION "rst 08", ROM0 [$08] - rst $38 -SECTION "rst 10", ROM0 [$10] - rst $38 -SECTION "rst 18", ROM0 [$18] - rst $38 -SECTION "rst 20", ROM0 [$20] - rst $38 -SECTION "rst 28", ROM0 [$28] - rst $38 -SECTION "rst 30", ROM0 [$30] - rst $38 -SECTION "rst 38", ROM0 [$38] - rst $38 - -; Hardware interrupts -SECTION "vblank", ROM0 [$40] - jp VBlank -SECTION "hblank", ROM0 [$48] - rst $38 -SECTION "timer", ROM0 [$50] - jp Timer -SECTION "serial", ROM0 [$58] - jp Serial -SECTION "joypad", ROM0 [$60] - reti - - -SECTION "Home", ROM0 - -DisableLCD:: - xor a - ld [rIF], a - ld a, [rIE] - ld b, a - res 0, a - ld [rIE], a - -.wait - ld a, [rLY] - cp LY_VBLANK - jr nz, .wait - - ld a, [rLCDC] - and $ff ^ rLCDC_ENABLE_MASK - ld [rLCDC], a - ld a, b - ld [rIE], a - ret - -EnableLCD:: - ld a, [rLCDC] - set rLCDC_ENABLE, a - ld [rLCDC], a - ret - -ClearSprites:: - xor a - ld hl, wOAMBuffer - ld b, 40 * 4 -.loop - ld [hli], a - dec b - jr nz, .loop - ret - -HideSprites:: - ld a, 160 - ld hl, wOAMBuffer - ld de, 4 - ld b, 40 -.loop - ld [hl], a - add hl, de - dec b - jr nz, .loop - ret - -INCLUDE "home/copy.asm" - - - -SECTION "Entry", ROM0 [$100] - - nop - jp Start ; 01ab - - -SECTION "Header", ROM0 [$104] - - ; The header is generated by rgbfix. - ; The space here is allocated to prevent code from being overwritten. - - ds $150 - $104 - - - -SECTION "Main", ROM0 - -Func_150:: ; 0150 (0:0150) - ld a,[H_LOADEDROMBANK] - push af - ld a,b - call BankswitchCommon - ld a,[hli] - ld c,a - ld a,[hli] - ld b,a -.loop - ld a,[hli] - ld d,a - ld a,$3 -.unknownloop - dec a - jr nz,.unknownloop - - rept 7 - call Func_199 - call Func_1a5 - endr - - call Func_199 - dec bc - ld a,c - or b - jr nz,.loop - pop af - call BankswitchCommon - ret - -Func_199:: ; 0199 (0:0199) - ld a,d - and $80 - srl a - srl a - ld [rNR32],a - sla d - ret - -Func_1a5:: ; 01a5 (0:01a5) - ld a,$3 -.unknownloop2 - dec a - jr nz,.unknownloop2 - ret - -Start:: - cp GBC - jr z, .gbc - xor a - jr .ok -.gbc - ld a, $1 -.ok - ld [hGBC], a - jp Init - -Joypad:: ; 01b9 - homecall _Joypad - -ReadJoypad: ; 01c8 (0:01c8) - homecall ReadJoypad_ - -INCLUDE "data/map_header_pointers.asm" -INCLUDE "home/overworld.asm" - - -CheckForUserInterruption:: ; 12f8 (0:12f8) -; Return carry if Up+Select+B, Start or A are pressed in c frames. -; Used only in the intro and title screen. - call DelayFrame - - push bc - call JoypadLowSensitivity - pop bc - - ld a, [hJoyHeld] - cp D_UP + SELECT + B_BUTTON - jr z, .input - - ld a, [hJoy5] - and START | A_BUTTON - jr nz, .input - - dec c - jr nz, CheckForUserInterruption - - and a - ret - -.input - scf - ret - -; function to load position data for destination warp when switching maps -; INPUT: -; a = ID of destination warp within destination map -LoadDestinationWarpPosition:: ; 1313 (0:1313) - ld b,a - ld a,[H_LOADEDROMBANK] - push af - ld a,[wPredefParentBank] - ld [H_LOADEDROMBANK],a - ld [$2000],a - ld a,b - add a - add a - ld c,a - ld b,0 - add hl,bc - ld bc,4 - ld de,wCurrentTileBlockMapViewPointer - call CopyData - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - - -DrawHPBar:: ; 1336 (0:1336) -; Draw an HP bar d tiles long, and fill it to e pixels. -; If c is nonzero, show at least a sliver regardless. -; The right end of the bar changes with [wHPBarType]. - - push hl - push de - push bc - - ; Left - ld a, $71 ; "HP:" - ld [hli], a - ld a, $62 - ld [hli], a - - push hl - - ; Middle - ld a, $63 ; empty -.draw - ld [hli],a - dec d - jr nz, .draw - - ; Right - ld a,[wHPBarType] - dec a - ld a, $6d ; status screen and battle - jr z, .ok - dec a ; pokemon menu -.ok - ld [hl],a - - pop hl - - ld a, e - and a - jr nz, .fill - - ; If c iz nonzero, draw a pixel anyway. - ld a, c - and a - jr z, .done - ld e, 1 - -.fill - ld a, e - sub 8 - jr c, .partial - ld e, a - ld a, $6b ; full - ld [hli], a - ld a, e - and a - jr z, .done - jr .fill - -.partial - ; Fill remaining pixels at the end if necessary. - ld a, $63 ; empty - add e - ld [hl], a -.done - pop bc - pop de - pop hl - ret - - -; loads pokemon data from one of multiple sources to wLoadedMon -; loads base stats to W_MONHDEXNUM -; INPUT: -; [wWhichPokemon] = index of pokemon within party/box -; [wcc49] = source -; 00: player's party -; 01: enemy's party -; 02: current box -; 03: daycare -; OUTPUT: -; [wcf91] = pokemon ID -; wLoadedMon = base address of pokemon data -; W_MONHDEXNUM = base address of base stats -LoadMonData:: ; 1372 (0:1372) - ld hl, LoadMonData_ - ld b, BANK(LoadMonData_) - jp Bankswitch - - -Func_137a:: ; 137a (0:137a) -; Write c to [wMoves + b]. Unused. - ld hl, wMoves - ld e, b - ld d, 0 - add hl, de - ld a, c - ld [hl], a - ret - -LoadFlippedFrontSpriteByMonIndex:: ; 1384 (0:1384) - ld a, 1 - ld [W_SPRITEFLIPPED], a - -LoadFrontSpriteByMonIndex:: ; 1389 (0:1389) - push hl - ld a, [wd11e] - push af - ld a, [wcf91] - ld [wd11e], a - predef IndexToPokedex - ld hl, wd11e - ld a, [hl] - pop bc - ld [hl], b - and a - pop hl - jr z, .invalidDexNumber ; dex #0 invalid - cp NUM_POKEMON + 1 - jr c, .validDexNumber ; dex >#151 invalid -.invalidDexNumber - ld a, RHYDON ; $1 - ld [wcf91], a - ret -.validDexNumber - push hl - ld de, vFrontPic - call LoadMonFrontSprite - pop hl - ld a, [H_LOADEDROMBANK] - push af - ld a, Bank(asm_3f0d0) - ld [H_LOADEDROMBANK], a - ld [$2000], a - xor a - ld [$ffe1], a - call asm_3f0d0 - xor a - ld [W_SPRITEFLIPPED], a - pop af - ld [H_LOADEDROMBANK], a - ld [$2000], a - ret - - -PlayCry:: ; 13d0 (0:13d0) -; Play monster a's cry. - call GetCryData - call PlaySound - jp WaitForSoundToFinish - -GetCryData:: ; 13d9 (0:13d9) -; Load cry data for monster a. - dec a - ld c, a - ld b, 0 - ld hl, CryData - add hl, bc - add hl, bc - add hl, bc - - ld a, Bank(CryData) - call BankswitchHome - ld a, [hli] - ld b, a ; cry id - ld a, [hli] - ld [wc0f1], a - ld a, [hl] - ld [wc0f2], a - call BankswitchBack - - ; Cry headers have 3 channels, - ; and start from index $14, - ; so add 3 times the cry id. - ld a, b - ld c, $14 - rlca ; * 2 - add b - add c - ret - - -DisplayPartyMenu:: ; 13fc (0:13fc) - ld a,[hTilesetType] - push af - xor a - ld [hTilesetType],a - call GBPalWhiteOutWithDelay3 - call ClearSprites - call PartyMenuInit - call DrawPartyMenu - jp HandlePartyMenuInput - -GoBackToPartyMenu:: ; 1411 (0:1411) - ld a,[hTilesetType] - push af - xor a - ld [hTilesetType],a - call PartyMenuInit - call RedrawPartyMenu - jp HandlePartyMenuInput - -PartyMenuInit:: ; 1420 (0:1420) - ld a, 1 ; hardcoded bank - call BankswitchHome - call LoadHpBarAndStatusTilePatterns - ld hl, wd730 - set 6, [hl] ; turn off letter printing delay - xor a - ld [wcc49], a - ld [wcc37], a - ld hl, wTopMenuItemY - inc a - ld [hli], a ; top menu item Y - xor a - ld [hli], a ; top menu item X - ld a, [wcc2b] - push af - ld [hli], a ; current menu item ID - inc hl - ld a, [wPartyCount] - and a ; are there more than 0 pokemon in the party? - jr z, .storeMaxMenuItemID - dec a -; if party is not empty, the max menu item ID is ([wPartyCount] - 1) -; otherwise, it is 0 -.storeMaxMenuItemID - ld [hli], a ; max menu item ID - ld a, [wd11f] - and a - ld a, A_BUTTON + B_BUTTON - jr z, .next - xor a - ld [wd11f], a - inc a -.next - ld [hli], a ; menu watched keys - pop af - ld [hl], a ; old menu item ID - ret - -HandlePartyMenuInput:: ; 145a (0:145a) - ld a,1 - ld [wMenuWrappingEnabled],a - ld a,$40 - ld [wd09b],a - call HandleMenuInputPokemonSelection - call PlaceUnfilledArrowMenuCursor - ld b,a - xor a - ld [wd09b],a - ld a,[wCurrentMenuItem] - ld [wcc2b],a - ld hl,wd730 - res 6,[hl] ; turn on letter printing delay - ld a,[wMenuItemToSwap] - and a - jp nz,.swappingPokemon - pop af - ld [hTilesetType],a - bit 1,b - jr nz,.noPokemonChosen - ld a,[wPartyCount] - and a - jr z,.noPokemonChosen - ld a,[wCurrentMenuItem] - ld [wWhichPokemon],a - ld hl,wPartySpecies - ld b,0 - ld c,a - add hl,bc - ld a,[hl] - ld [wcf91],a - ld [wBattleMonSpecies2],a - call BankswitchBack - and a - ret -.noPokemonChosen - call BankswitchBack - scf - ret -.swappingPokemon - bit 1,b ; was the B button pressed? - jr z,.handleSwap ; if not, handle swapping the pokemon -.cancelSwap ; if the B button was pressed - callba ErasePartyMenuCursors - xor a - ld [wMenuItemToSwap],a - ld [wd07d],a - call RedrawPartyMenu - jr HandlePartyMenuInput -.handleSwap - ld a,[wCurrentMenuItem] - ld [wWhichPokemon],a - callba SwitchPartyMon - jr HandlePartyMenuInput - -DrawPartyMenu:: ; 14d4 (0:14d4) - ld hl, DrawPartyMenu_ - jr DrawPartyMenuCommon - -RedrawPartyMenu:: ; 14d9 (0:14d9) - ld hl, RedrawPartyMenu_ - -DrawPartyMenuCommon:: ; 14dc (0:14dc) - ld b, BANK(RedrawPartyMenu_) - jp Bankswitch - -; prints a pokemon's status condition -; INPUT: -; de = address of status condition -; hl = destination address -PrintStatusCondition:: ; 14e1 (0:14e1) - push de - dec de - dec de ; de = address of current HP - ld a,[de] - ld b,a - dec de - ld a,[de] - or b ; is the pokemon's HP zero? - pop de - jr nz,PrintStatusConditionNotFainted -; if the pokemon's HP is 0, print "FNT" - ld a,"F" - ld [hli],a - ld a,"N" - ld [hli],a - ld [hl],"T" - and a - ret -PrintStatusConditionNotFainted ; 14f6 - ld a,[H_LOADEDROMBANK] - push af - ld a,BANK(PrintStatusAilment) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call PrintStatusAilment ; print status condition - pop bc - ld a,b - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; function to print pokemon level, leaving off the ":L" if the level is at least 100 -; INPUT: -; hl = destination address -; [wLoadedMonLevel] = level -PrintLevel:: ; 150b (0:150b) - ld a,$6e ; ":L" tile ID - ld [hli],a - ld c,2 ; number of digits - ld a,[wLoadedMonLevel] ; level - cp a,100 - jr c,PrintLevelCommon -; if level at least 100, write over the ":L" tile - dec hl - inc c ; increment number of digits to 3 - jr PrintLevelCommon - -; prints the level without leaving off ":L" regardless of level -; INPUT: -; hl = destination address -; [wLoadedMonLevel] = level -PrintLevelFull:: ; 151b (0:151b) - ld a,$6e ; ":L" tile ID - ld [hli],a - ld c,3 ; number of digits - ld a,[wLoadedMonLevel] ; level - -PrintLevelCommon:: ; 1523 (0:1523) - ld [wd11e],a - ld de,wd11e - ld b,$41 ; no leading zeroes, left-aligned, one byte - jp PrintNumber - -Func_152e:: ; 152e (0:152e) -; Unused. - ld hl,wMoves - ld c,a - ld b,0 - add hl,bc - ld a,[hl] - ret - -; copies the base stat data of a pokemon to W_MONHDEXNUM (W_MONHEADER) -; INPUT: -; [wd0b5] = pokemon ID -GetMonHeader:: ; 1537 (0:1537) - ld a,[H_LOADEDROMBANK] - push af - ld a,BANK(BaseStats) - ld [H_LOADEDROMBANK],a - ld [$2000],a - push bc - push de - push hl - ld a,[wd11e] - push af - ld a,[wd0b5] - ld [wd11e],a - ld de,FossilKabutopsPic - ld b,$66 ; size of Kabutops fossil and Ghost sprites - cp a,FOSSIL_KABUTOPS ; Kabutops fossil - jr z,.specialID - ld de,GhostPic - cp a,MON_GHOST ; Ghost - jr z,.specialID - ld de,FossilAerodactylPic - ld b,$77 ; size of Aerodactyl fossil sprite - cp a,FOSSIL_AERODACTYL ; Aerodactyl fossil - jr z,.specialID - cp a,MEW - jr z,.mew - predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number - ld a,[wd11e] - dec a - ld bc,28 - ld hl,BaseStats - call AddNTimes - ld de,W_MONHEADER - ld bc,28 - call CopyData - jr .done -.specialID - ld hl,W_MONHSPRITEDIM - ld [hl],b ; write sprite dimensions - inc hl - ld [hl],e ; write front sprite pointer - inc hl - ld [hl],d - jr .done -.mew - ld hl,MewBaseStats - ld de,W_MONHEADER - ld bc,28 - ld a,BANK(MewBaseStats) - call FarCopyData -.done - ld a,[wd0b5] - ld [W_MONHDEXNUM],a - pop af - ld [wd11e],a - pop hl - pop de - pop bc - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; copy party pokemon's name to wcd6d -GetPartyMonName2:: ; 15b4 (0:15b4) - ld a,[wWhichPokemon] ; index within party - ld hl,wPartyMonNicks - -; this is called more often -GetPartyMonName:: ; 15ba (0:15ba) - push hl - push bc - call SkipFixedLengthTextEntries ; add 11 to hl, a times - ld de,wcd6d - push de - ld bc,11 - call CopyData - pop de - pop bc - pop hl - ret - -; function to print a BCD (Binary-coded decimal) number -; de = address of BCD number -; hl = destination address -; c = flags and length -; bit 7: if set, do not print leading zeroes -; if unset, print leading zeroes -; bit 6: if set, left-align the string (do not pad empty digits with spaces) -; if unset, right-align the string -; bit 5: if set, print currency symbol at the beginning of the string -; if unset, do not print the currency symbol -; bits 0-4: length of BCD number in bytes -; Note that bits 5 and 7 are modified during execution. The above reflects -; their meaning at the beginning of the functions's execution. -PrintBCDNumber:: ; 15cd (0:15cd) - ld b,c ; save flags in b - res 7,c - res 6,c - res 5,c ; c now holds the length - bit 5,b - jr z,.loop - bit 7,b - jr nz,.loop - ld [hl],"¥" - inc hl -.loop - ld a,[de] - swap a - call PrintBCDDigit ; print upper digit - ld a,[de] - call PrintBCDDigit ; print lower digit - inc de - dec c - jr nz,.loop - bit 7,b ; were any non-zero digits printed? - jr z,.done ; if so, we are done -.numberEqualsZero ; if every digit of the BCD number is zero - bit 6,b ; left or right alignment? - jr nz,.skipRightAlignmentAdjustment - dec hl ; if the string is right-aligned, it needs to be moved back one space -.skipRightAlignmentAdjustment - bit 5,b - jr z,.skipCurrencySymbol - ld [hl],"¥" - inc hl -.skipCurrencySymbol - ld [hl],"0" - call PrintLetterDelay - inc hl -.done - ret - -PrintBCDDigit:: ; 1604 (0:1604) - and $f - and a - jr z,.zeroDigit -.nonzeroDigit - bit 7,b ; have any non-space characters been printed? - jr z,.outputDigit -; if bit 7 is set, then no numbers have been printed yet - bit 5,b ; print the currency symbol? - jr z,.skipCurrencySymbol - ld [hl],"¥" - inc hl - res 5,b -.skipCurrencySymbol - res 7,b ; unset 7 to indicate that a nonzero digit has been reached -.outputDigit - add a,"0" - ld [hli],a - jp PrintLetterDelay -.zeroDigit - bit 7,b ; either printing leading zeroes or already reached a nonzero digit? - jr z,.outputDigit ; if so, print a zero digit - bit 6,b ; left or right alignment? - ret nz - inc hl ; if right-aligned, "print" a space by advancing the pointer - ret - -; uncompresses the front or back sprite of the specified mon -; assumes the corresponding mon header is already loaded -; hl contains offset to sprite pointer ($b for front or $d for back) -UncompressMonSprite:: ; 1627 (0:1627) - ld bc,W_MONHEADER - add hl,bc - ld a,[hli] - ld [W_SPRITEINPUTPTR],a ; fetch sprite input pointer - ld a,[hl] - ld [W_SPRITEINPUTPTR+1],a -; define (by index number) the bank that a pokemon's image is in -; index = Mew, bank 1 -; index = Kabutops fossil, bank $B -; index < $1F, bank 9 -; $1F ≤ index < $4A, bank $A -; $4A ≤ index < $74, bank $B -; $74 ≤ index < $99, bank $C -; $99 ≤ index, bank $D - ld a,[wcf91] ; XXX name for this ram location - ld b,a - cp MEW - ld a,BANK(MewPicFront) - jr z,.GotBank - ld a,b - cp FOSSIL_KABUTOPS - ld a,BANK(FossilKabutopsPic) - jr z,.GotBank - ld a,b - cp TANGELA + 1 - ld a,BANK(TangelaPicFront) - jr c,.GotBank - ld a,b - cp MOLTRES + 1 - ld a,BANK(MoltresPicFront) - jr c,.GotBank - ld a,b - cp BEEDRILL + 2 - ld a,BANK(BeedrillPicFront) - jr c,.GotBank - ld a,b - cp STARMIE + 1 - ld a,BANK(StarmiePicFront) - jr c,.GotBank - ld a,BANK(VictreebelPicFront) -.GotBank - jp UncompressSpriteData - -; de: destination location -LoadMonFrontSprite:: ; 1665 (0:1665) - push de - ld hl, W_MONHFRONTSPRITE - W_MONHEADER - call UncompressMonSprite - ld hl, W_MONHSPRITEDIM - ld a, [hli] - ld c, a - pop de - ; fall through - -; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram -; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers -; de: destination location -; a,c: sprite dimensions (in tiles of 8x8 each) -LoadUncompressedSpriteData:: ; 1672 (0:1672) - push de - and $f - ld [H_SPRITEWIDTH], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width - ld b, a - ld a, $7 - sub b ; 7-w - inc a ; 8-w - srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up) - ld b, a - add a - add a - add a - sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles) - ld [H_SPRITEOFFSET], a - ld a, c - swap a - and $f - ld b, a - add a - add a - add a ; 8*tiles is height in bytes - ld [H_SPRITEHEIGHT], a ; $ff8c - ld a, $7 - sub b ; 7-h ; skip for vertical center (in tiles, relative to current column) - ld b, a - ld a, [H_SPRITEOFFSET] - add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles) - add a - add a - add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes) - ld [H_SPRITEOFFSET], a - xor a - ld [$4000], a - ld hl, S_SPRITEBUFFER0 - call ZeroSpriteBuffer ; zero buffer 0 - ld de, S_SPRITEBUFFER1 - ld hl, S_SPRITEBUFFER0 - call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite) - ld hl, S_SPRITEBUFFER1 - call ZeroSpriteBuffer ; zero buffer 1 - ld de, S_SPRITEBUFFER2 - ld hl, S_SPRITEBUFFER1 - call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite) - pop de - jp InterlaceMergeSpriteBuffers - -; copies and aligns the sprite data properly inside the sprite buffer -; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area -AlignSpriteDataCentered:: ; 16c2 (0:16c2) - ld a, [H_SPRITEOFFSET] - ld b, $0 - ld c, a - add hl, bc - ld a, [H_SPRITEWIDTH] ; $ff8b -.columnLoop - push af - push hl - ld a, [H_SPRITEHEIGHT] ; $ff8c - ld c, a -.columnInnerLoop - ld a, [de] - inc de - ld [hli], a - dec c - jr nz, .columnInnerLoop - pop hl - ld bc, 7*8 ; 7 tiles - add hl, bc ; advance one full column - pop af - dec a - jr nz, .columnLoop - ret - -; fills the sprite buffer (pointed to in hl) with zeros -ZeroSpriteBuffer:: ; 16df (0:16df) - ld bc, SPRITEBUFFERSIZE -.nextByteLoop - xor a - ld [hli], a - dec bc - ld a, b - or c - jr nz, .nextByteLoop - ret - -; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2 -; in the resulting sprite, the rows of the two source sprites are interlaced -; de: output address -InterlaceMergeSpriteBuffers:: ; 16ea (0:16ea) - xor a - ld [$4000], a - push de - ld hl, S_SPRITEBUFFER2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2 - ld de, S_SPRITEBUFFER1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1 - ld bc, S_SPRITEBUFFER0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0 - ld a, SPRITEBUFFERSIZE/2 ; $c4 - ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b -.interlaceLoop - ld a, [de] - dec de - ld [hld], a ; write byte of source 2 - ld a, [bc] - dec bc - ld [hld], a ; write byte of source 1 - ld a, [de] - dec de - ld [hld], a ; write byte of source 2 - ld a, [bc] - dec bc - ld [hld], a ; write byte of source 1 - ld a, [H_SPRITEINTERLACECOUNTER] ; $ff8b - dec a - ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b - jr nz, .interlaceLoop - ld a, [W_SPRITEFLIPPED] - and a - jr z, .notFlipped - ld bc, 2*SPRITEBUFFERSIZE - ld hl, S_SPRITEBUFFER1 -.swapLoop - swap [hl] ; if flipped swap nybbles in all bytes - inc hl - dec bc - ld a, b - or c - jr nz, .swapLoop -.notFlipped - pop hl - ld de, S_SPRITEBUFFER1 - ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied - ld a, [H_LOADEDROMBANK] - ld b, a - jp CopyVideoData - - -INCLUDE "data/collision.asm" -INCLUDE "home/copy2.asm" -INCLUDE "home/text.asm" -INCLUDE "home/vcopy.asm" -INCLUDE "home/init.asm" -INCLUDE "home/vblank.asm" -INCLUDE "home/fade.asm" -INCLUDE "home/serial.asm" -INCLUDE "home/timer.asm" -INCLUDE "home/audio.asm" - - -UpdateSprites:: ; 2429 (0:2429) - ld a, [wUpdateSpritesEnabled] - dec a - ret nz - ld a, [H_LOADEDROMBANK] - push af - ld a, Bank(_UpdateSprites) - ld [H_LOADEDROMBANK], a - ld [$2000], a - call _UpdateSprites - pop af - ld [H_LOADEDROMBANK], a - ld [$2000], a - ret - -INCLUDE "data/mart_inventories.asm" - -TextScriptEndingChar:: ; 24d6 (0:24d6) - db "@" -TextScriptEnd:: ; 24d7 (0:24d7) - ld hl,TextScriptEndingChar - ret - -ExclamationText:: ; 24db (0:24db) - TX_FAR _ExclamationText - db "@" - -GroundRoseText:: ; 24e0 (0:24e0) - TX_FAR _GroundRoseText - db "@" - -BoulderText:: ; 24e5 (0:24e5) - TX_FAR _BoulderText - db "@" - -MartSignText:: ; 24ea (0:24ea) - TX_FAR _MartSignText - db "@" - -PokeCenterSignText:: ; 24ef (0:24ef) - TX_FAR _PokeCenterSignText - db "@" - -Predef5CText:: ; 24f4 (0:24f4) -; XXX better label (what does predef $5C do?) - db $08 ; asm - predef PickupItem - jp TextScriptEnd - - -INCLUDE "home/pic.asm" - - -ResetPlayerSpriteData:: ; 28a6 (0:28a6) - ld hl, wSpriteStateData1 - call ResetPlayerSpriteData_ClearSpriteData - ld hl, wSpriteStateData2 - call ResetPlayerSpriteData_ClearSpriteData - ld a, $1 - ld [wSpriteStateData1], a - ld [wSpriteStateData2 + $0e], a - ld hl, wSpriteStateData1 + 4 - ld [hl], $3c ; set Y screen pos - inc hl - inc hl - ld [hl], $40 ; set X screen pos - ret - -; overwrites sprite data with zeroes -ResetPlayerSpriteData_ClearSpriteData:: ; 28c4 (0:28c4) - ld bc, $10 - xor a - jp FillMemory - -Func_28cb:: ; 28cb (0:28cb) - ld a, [wMusicHeaderPointer] - and a - jr nz, .asm_28dc - ld a, [wd72c] - bit 1, a - ret nz - ld a, $77 - ld [$ff24], a - ret -.asm_28dc - ld a, [wcfc9] - and a - jr z, .asm_28e7 - dec a - ld [wcfc9], a - ret -.asm_28e7 - ld a, [wcfc8] - ld [wcfc9], a - ld a, [$ff24] - and a - jr z, .asm_2903 - ld b, a - and $f - dec a - ld c, a - ld a, b - and $f0 - swap a - dec a - swap a - or c - ld [$ff24], a - ret -.asm_2903 - ld a, [wMusicHeaderPointer] - ld b, a - xor a - ld [wMusicHeaderPointer], a - ld a, $ff - ld [wc0ee], a - call PlaySound - ld a, [wc0f0] - ld [wc0ef], a - ld a, b - ld [wc0ee], a - jp PlaySound - -; this function is used to display sign messages, sprite dialog, etc. -; INPUT: [$ff8c] = sprite ID or text ID -DisplayTextID:: ; 2920 (0:2920) - ld a,[H_LOADEDROMBANK] - push af - callba DisplayTextIDInit ; initialization - ld hl,wcf11 - bit 0,[hl] - res 0,[hl] - jr nz,.skipSwitchToMapBank - ld a,[W_CURMAP] - call SwitchToMapRomBank -.skipSwitchToMapBank - ld a,30 ; half a second - ld [H_FRAMECOUNTER],a ; used as joypad poll timer - ld hl,W_MAPTEXTPTR - ld a,[hli] - ld h,[hl] - ld l,a ; hl = map text pointer - ld d,$00 - ld a,[$ff8c] ; text ID - ld [wSpriteIndex],a - and a - jp z,DisplayStartMenu - cp a,$d3 - jp z,DisplaySafariGameOverText - cp a,$d0 - jp z,DisplayPokemonFaintedText - cp a,$d1 - jp z,DisplayPlayerBlackedOutText - cp a,$d2 - jp z,DisplayRepelWoreOffText - ld a,[W_NUMSPRITES] - ld e,a - ld a,[$ff8c] ; sprite ID - cp e - jr z,.spriteHandling - jr nc,.skipSpriteHandling -.spriteHandling -; get the text ID of the sprite - push hl - push de - push bc - callba UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction) - pop bc - pop de - ld hl,W_MAPSPRITEDATA ; NPC text entries - ld a,[$ff8c] - dec a - add a - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - inc hl - ld a,[hl] ; a = text ID of the sprite - pop hl -.skipSpriteHandling -; look up the address of the text in the map's text entries - dec a - ld e,a - sla e - add hl,de - ld a,[hli] - ld h,[hl] - ld l,a ; hl = address of the text - ld a,[hl] ; a = first byte of text -; check first byte of text for special cases - cp a,$fe ; Pokemart NPC - jp z,DisplayPokemartDialogue - cp a,$ff ; Pokemon Center NPC - jp z,DisplayPokemonCenterDialogue - cp a,$fc ; Item Storage PC - jp z,FuncTX_ItemStoragePC - cp a,$fd ; Bill's PC - jp z,FuncTX_BillsPC - cp a,$f9 ; Pokemon Center PC - jp z,FuncTX_PokemonCenterPC - cp a,$f5 ; Vending Machine - jr nz,.notVendingMachine - callba VendingMachineMenu ; jump banks to vending machine routine - jr AfterDisplayingTextID -.notVendingMachine - cp a,$f7 ; slot machine - jp z,FuncTX_SlotMachine - cp a,$f6 ; cable connection NPC in Pokemon Center - jr nz,.notSpecialCase - callab CableClubNPC - jr AfterDisplayingTextID -.notSpecialCase - call Func_3c59 ; display the text - ld a,[wDoNotWaitForButtonPressAfterDisplayingText] - and a - jr nz,HoldTextDisplayOpen - -AfterDisplayingTextID:: ; 29d6 (0:29d6) - ld a,[wcc47] - and a - jr nz,HoldTextDisplayOpen - call WaitForTextScrollButtonPress ; wait for a button press after displaying all the text - -; loop to hold the dialogue box open as long as the player keeps holding down the A button -HoldTextDisplayOpen:: ; 29df (0:29df) - call Joypad - ld a,[hJoyHeld] - bit 0,a ; is the A button being pressed? - jr nz,HoldTextDisplayOpen - -CloseTextDisplay:: ; 29e8 (0:29e8) - ld a,[W_CURMAP] - call SwitchToMapRomBank - ld a,$90 - ld [hWY],a ; move the window off the screen - call DelayFrame - call LoadGBPal - xor a - ld [H_AUTOBGTRANSFERENABLED],a ; disable continuous WRAM to VRAM transfer each V-blank -; loop to make sprites face the directions they originally faced before the dialogue - ld hl,wSpriteStateData2 + $19 - ld c,$0f - ld de,$0010 -.restoreSpriteFacingDirectionLoop - ld a,[hl] - dec h - ld [hl],a - inc h - add hl,de - dec c - jr nz,.restoreSpriteFacingDirectionLoop - ld a,BANK(InitMapSprites) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call InitMapSprites ; reload sprite tile pattern data (since it was partially overwritten by text tile patterns) - ld hl,wFontLoaded - res 0,[hl] - ld a,[wd732] - bit 3,a ; used fly warp - call z,LoadPlayerSpriteGraphics - call LoadCurrentMapView - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - jp UpdateSprites - -DisplayPokemartDialogue:: ; 2a2e (0:2a2e) - push hl - ld hl,PokemartGreetingText - call PrintText - pop hl - inc hl - call LoadItemList - ld a,$02 - ld [wListMenuID],a ; selects between subtypes of menus - ld a,[H_LOADEDROMBANK] - push af - ld a,Bank(DisplayPokemartDialogue_) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call DisplayPokemartDialogue_ - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - jp AfterDisplayingTextID - -PokemartGreetingText:: ; 2a55 (0:2a55) - TX_FAR _PokemartGreetingText - db "@" - -LoadItemList:: ; 2a5a (0:2a5a) - ld a,$01 - ld [wUpdateSpritesEnabled],a - ld a,h - ld [wd128],a - ld a,l - ld [wd129],a - ld de,wStringBuffer2 + 11 -.loop - ld a,[hli] - ld [de],a - inc de - cp a,$ff - jr nz,.loop - ret - -DisplayPokemonCenterDialogue:: ; 2a72 (0:2a72) - xor a - ld [$ff8b],a - ld [$ff8c],a - ld [$ff8d],a - inc hl - ld a,[H_LOADEDROMBANK] - push af - ld a,Bank(DisplayPokemonCenterDialogue_) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call DisplayPokemonCenterDialogue_ - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - jp AfterDisplayingTextID - -DisplaySafariGameOverText:: ; 2a90 (0:2a90) - callab PrintSafariGameOverText - jp AfterDisplayingTextID - -DisplayPokemonFaintedText:: ; 2a9b (0:2a9b) - ld hl,PokemonFaintedText - call PrintText - jp AfterDisplayingTextID - -PokemonFaintedText:: ; 2aa4 (0:2aa4) - TX_FAR _PokemonFaintedText - db "@" - -DisplayPlayerBlackedOutText:: ; 2aa9 (0:2aa9) - ld hl,PlayerBlackedOutText - call PrintText - ld a,[wd732] - res 5,a ; reset forced to use bike bit - ld [wd732],a - jp HoldTextDisplayOpen - -PlayerBlackedOutText:: ; 2aba (0:2aba) - TX_FAR _PlayerBlackedOutText - db "@" - -DisplayRepelWoreOffText:: ; 2abf (0:2abf) - ld hl,RepelWoreOffText - call PrintText - jp AfterDisplayingTextID - -RepelWoreOffText:: ; 2ac8 (0:2ac8) - TX_FAR _RepelWoreOffText - db "@" - -INCLUDE "engine/menu/start_menu.asm" - -; function to count how many bits are set in a string of bytes -; INPUT: -; hl = address of string of bytes -; b = length of string of bytes -; OUTPUT: -; [wd11e] = number of set bits -CountSetBits:: ; 2b7f (0:2b7f) - ld c,0 -.loop - ld a,[hli] - ld e,a - ld d,8 -.innerLoop ; count how many bits are set in the current byte - srl e - ld a,0 - adc c - ld c,a - dec d - jr nz,.innerLoop - dec b - jr nz,.loop - ld a,c - ld [wd11e],a ; store number of set bits - ret - -; subtracts the amount the player paid from their money -; sets carry flag if there is enough money and unsets carry flag if not -SubtractAmountPaidFromMoney:: ; 2b96 (0:2b96) - ld b,BANK(SubtractAmountPaidFromMoney_) - ld hl,SubtractAmountPaidFromMoney_ - jp Bankswitch - -; adds the amount the player sold to their money -AddAmountSoldToMoney:: ; 2b9e (0:2b9e) - ld de,wPlayerMoney + 2 - ld hl,$ffa1 ; total price of items - ld c,3 ; length of money in bytes - predef AddBCDPredef ; add total price to money - ld a,MONEY_BOX - ld [wTextBoxID],a - call DisplayTextBoxID ; redraw money text box - ld a, (SFX_02_5a - SFX_Headers_02) / 3 - call PlaySoundWaitForCurrent ; play sound - jp WaitForSoundToFinish ; wait until sound is done playing - -; function to remove an item (in varying quantities) from the player's bag or PC box -; INPUT: -; HL = address of inventory (either wNumBagItems or wNumBoxItems) -; [wWhichPokemon] = index (within the inventory) of the item to remove -; [wcf96] = quantity to remove -RemoveItemFromInventory:: ; 2bbb (0:2bbb) - ld a,[H_LOADEDROMBANK] - push af - ld a,BANK(RemoveItemFromInventory_) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call RemoveItemFromInventory_ - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; function to add an item (in varying quantities) to the player's bag or PC box -; INPUT: -; HL = address of inventory (either wNumBagItems or wNumBoxItems) -; [wcf91] = item ID -; [wcf96] = item quantity -; sets carry flag if successful, unsets carry flag if unsuccessful -AddItemToInventory:: ; 2bcf (0:2bcf) - push bc - ld a,[H_LOADEDROMBANK] - push af - ld a,BANK(AddItemToInventory_) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call AddItemToInventory_ - pop bc - ld a,b - ld [H_LOADEDROMBANK],a - ld [$2000],a - pop bc - ret - -; INPUT: -; [wListMenuID] = list menu ID -; [wList] = address of the list (2 bytes) -DisplayListMenuID:: ; 2be6 (0:2be6) - xor a - ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer - ld a,1 - ld [hJoy7],a ; joypad state update flag - ld a,[W_BATTLETYPE] - and a ; is it the Old Man battle? - jr nz,.specialBattleType - ld a,$01 ; hardcoded bank - jr .bankswitch -.specialBattleType ; Old Man battle - ld a, Bank(DisplayBattleMenu) -.bankswitch - call BankswitchHome - ld hl,wd730 - set 6,[hl] ; turn off letter printing delay - xor a - ld [wMenuItemToSwap],a ; 0 means no item is currently being swapped - ld [wd12a],a - ld a,[wList] - ld l,a - ld a,[wList + 1] - ld h,a ; hl = address of the list - ld a,[hl] - ld [wd12a],a ; [wd12a] = number of list entries - ld a,LIST_MENU_BOX - ld [wTextBoxID],a - call DisplayTextBoxID ; draw the menu text box - call UpdateSprites ; disable sprites behind the text box -; the code up to .skipMovingSprites appears to be useless - hlCoord 4, 2 ; coordinates of upper left corner of menu text box - ld de,$090e ; height and width of menu text box - ld a,[wListMenuID] - and a ; is it a PC pokemon list? - jr nz,.skipMovingSprites - call UpdateSprites ; move sprites -.skipMovingSprites - ld a,1 ; max menu item ID is 1 if the list has less than 2 entries - ld [wcc37],a - ld a,[wd12a] - cp a,2 ; does the list have less than 2 entries? - jr c,.setMenuVariables - ld a,2 ; max menu item ID is 2 if the list has at least 2 entries -.setMenuVariables - ld [wMaxMenuItem],a - ld a,4 - ld [wTopMenuItemY],a - ld a,5 - ld [wTopMenuItemX],a - ld a,A_BUTTON | B_BUTTON | SELECT - ld [wMenuWatchedKeys],a - ld c,10 - call DelayFrames - -DisplayListMenuIDLoop:: ; 2c53 (0:2c53) - xor a - ld [H_AUTOBGTRANSFERENABLED],a ; disable transfer - call PrintListMenuEntries - ld a,1 - ld [H_AUTOBGTRANSFERENABLED],a ; enable transfer - call Delay3 - ld a,[W_BATTLETYPE] - and a ; is it the Old Man battle? - jr z,.notOldManBattle -.oldManBattle - ld a,"▶" - Coorda 5, 4 ; place menu cursor in front of first menu entry - ld c,80 - call DelayFrames - xor a - ld [wCurrentMenuItem],a - hlCoord 5, 4 - ld a,l - ld [wMenuCursorLocation],a - ld a,h - ld [wMenuCursorLocation + 1],a - jr .buttonAPressed -.notOldManBattle - call LoadGBPal - call HandleMenuInput - push af - call PlaceMenuCursor - pop af - bit 0,a ; was the A button pressed? - jp z,.checkOtherKeys -.buttonAPressed - ld a,[wCurrentMenuItem] - call PlaceUnfilledArrowMenuCursor - ld a,$01 - ld [wd12e],a - ld [wd12d],a - xor a - ld [wcc37],a - ld a,[wCurrentMenuItem] - ld c,a - ld a,[wListScrollOffset] - add c - ld c,a - ld a,[wd12a] ; number of list entries - and a ; is the list empty? - jp z,ExitListMenu ; if so, exit the menu - dec a - cp c ; did the player select Cancel? - jp c,ExitListMenu ; if so, exit the menu - ld a,c - ld [wWhichPokemon],a - ld a,[wListMenuID] - cp a,ITEMLISTMENU - jr nz,.skipMultiplying -; if it's an item menu - sla c ; item entries are 2 bytes long, so multiply by 2 -.skipMultiplying - ld a,[wList] - ld l,a - ld a,[wList + 1] - ld h,a - inc hl ; hl = beginning of list entries - ld b,0 - add hl,bc - ld a,[hl] - ld [wcf91],a - ld a,[wListMenuID] - and a ; is it a PC pokemon list? - jr z,.pokemonList - push hl - call GetItemPrice - pop hl - ld a,[wListMenuID] - cp a,ITEMLISTMENU - jr nz,.skipGettingQuantity -; if it's an item menu - inc hl - ld a,[hl] ; a = item quantity - ld [wcf97],a -.skipGettingQuantity - ld a,[wcf91] - ld [wd0b5],a - ld a,BANK(ItemNames) - ld [wPredefBank],a - call GetName - jr .storeChosenEntry -.pokemonList - ld hl,wPartyCount - ld a,[wList] - cp l ; is it a list of party pokemon or box pokemon? - ld hl,wPartyMonNicks - jr z,.getPokemonName - ld hl, wBoxMonNicks ; box pokemon names -.getPokemonName - ld a,[wWhichPokemon] - call GetPartyMonName -.storeChosenEntry ; store the menu entry that the player chose and return - ld de,wcd6d - call CopyStringToCF4B ; copy name to wcf4b - ld a,$01 - ld [wd12e],a - ld a,[wCurrentMenuItem] - ld [wd12d],a - xor a - ld [hJoy7],a ; joypad state update flag - ld hl,wd730 - res 6,[hl] ; turn on letter printing delay - jp BankswitchBack -.checkOtherKeys ; check B, SELECT, Up, and Down keys - bit 1,a ; was the B button pressed? - jp nz,ExitListMenu ; if so, exit the menu - bit 2,a ; was the select button pressed? - jp nz,HandleItemListSwapping ; if so, allow the player to swap menu entries - ld b,a - bit 7,b ; was Down pressed? - ld hl,wListScrollOffset - jr z,.upPressed -.downPressed - ld a,[hl] - add a,3 - ld b,a - ld a,[wd12a] ; number of list entries - cp b ; will going down scroll past the Cancel button? - jp c,DisplayListMenuIDLoop - inc [hl] ; if not, go down - jp DisplayListMenuIDLoop -.upPressed - ld a,[hl] - and a - jp z,DisplayListMenuIDLoop - dec [hl] - jp DisplayListMenuIDLoop - -DisplayChooseQuantityMenu:: ; 2d57 (0:2d57) -; text box dimensions/coordinates for just quantity - hlCoord 15, 9 - ld b,1 ; height - ld c,3 ; width - ld a,[wListMenuID] - cp a,PRICEDITEMLISTMENU - jr nz,.drawTextBox -; text box dimensions/coordinates for quantity and price - hlCoord 7, 9 - ld b,1 ; height - ld c,11 ; width -.drawTextBox - call TextBoxBorder - hlCoord 16, 10 - ld a,[wListMenuID] - cp a,PRICEDITEMLISTMENU - jr nz,.printInitialQuantity - hlCoord 8, 10 -.printInitialQuantity - ld de,InitialQuantityText - call PlaceString - xor a - ld [wcf96],a ; initialize current quantity to 0 - jp .incrementQuantity -.waitForKeyPressLoop - call JoypadLowSensitivity - ld a,[hJoyPressed] ; newly pressed buttons - bit 0,a ; was the A button pressed? - jp nz,.buttonAPressed - bit 1,a ; was the B button pressed? - jp nz,.buttonBPressed - bit 6,a ; was Up pressed? - jr nz,.incrementQuantity - bit 7,a ; was Down pressed? - jr nz,.decrementQuantity - jr .waitForKeyPressLoop -.incrementQuantity - ld a,[wcf97] ; max quantity - inc a - ld b,a - ld hl,wcf96 ; current quantity - inc [hl] - ld a,[hl] - cp b - jr nz,.handleNewQuantity -; wrap to 1 if the player goes above the max quantity - ld a,1 - ld [hl],a - jr .handleNewQuantity -.decrementQuantity - ld hl,wcf96 ; current quantity - dec [hl] - jr nz,.handleNewQuantity -; wrap to the max quantity if the player goes below 1 - ld a,[wcf97] ; max quantity - ld [hl],a -.handleNewQuantity - hlCoord 17, 10 - ld a,[wListMenuID] - cp a,PRICEDITEMLISTMENU - jr nz,.printQuantity -.printPrice - ld c,$03 - ld a,[wcf96] - ld b,a - ld hl,$ff9f ; total price -; initialize total price to 0 - xor a - ld [hli],a - ld [hli],a - ld [hl],a -.addLoop ; loop to multiply the individual price by the quantity to get the total price - ld de,$ffa1 - ld hl,$ff8d - push bc - predef AddBCDPredef ; add the individual price to the current sum - pop bc - dec b - jr nz,.addLoop - ld a,[$ff8e] - and a ; should the price be halved (for selling items)? - jr z,.skipHalvingPrice - xor a - ld [$ffa2],a - ld [$ffa3],a - ld a,$02 - ld [$ffa4],a - predef DivideBCDPredef3 ; halves the price -; store the halved price - ld a,[$ffa2] - ld [$ff9f],a - ld a,[$ffa3] - ld [$ffa0],a - ld a,[$ffa4] - ld [$ffa1],a -.skipHalvingPrice - hlCoord 12, 10 - ld de,SpacesBetweenQuantityAndPriceText - call PlaceString - ld de,$ff9f ; total price - ld c,$a3 - call PrintBCDNumber - hlCoord 9, 10 -.printQuantity - ld de,wcf96 ; current quantity - ld bc,$8102 ; print leading zeroes, 1 byte, 2 digits - call PrintNumber - jp .waitForKeyPressLoop -.buttonAPressed ; the player chose to make the transaction - xor a - ld [wMenuItemToSwap],a ; 0 means no item is currently being swapped - ret -.buttonBPressed ; the player chose to cancel the transaction - xor a - ld [wMenuItemToSwap],a ; 0 means no item is currently being swapped - ld a,$ff - ret - -InitialQuantityText:: ; 2e30 (0:2e30) - db "×01@" - -SpacesBetweenQuantityAndPriceText:: ; 2e34 (0:2e34) - db " @" - -ExitListMenu:: ; 2e3b (0:2e3b) - ld a,[wCurrentMenuItem] - ld [wd12d],a - ld a,$02 - ld [wd12e],a - ld [wcc37],a - xor a - ld [hJoy7],a - ld hl,wd730 - res 6,[hl] - call BankswitchBack - xor a - ld [wMenuItemToSwap],a ; 0 means no item is currently being swapped - scf - ret - -PrintListMenuEntries:: ; 2e5a (0:2e5a) - hlCoord 5, 3 - ld b,$09 - ld c,$0e - call ClearScreenArea - ld a,[wList] - ld e,a - ld a,[wList + 1] - ld d,a - inc de ; de = beginning of list entries - ld a,[wListScrollOffset] - ld c,a - ld a,[wListMenuID] - cp a,ITEMLISTMENU - ld a,c - jr nz,.skipMultiplying -; if it's an item menu -; item entries are 2 bytes long, so multiply by 2 - sla a - sla c -.skipMultiplying - add e - ld e,a - jr nc,.noCarry - inc d -.noCarry - hlCoord 6, 4 ; coordinates of first list entry name - ld b,4 ; print 4 names -.loop - ld a,b - ld [wWhichPokemon],a - ld a,[de] - ld [wd11e],a - cp a,$ff - jp z,.printCancelMenuItem - push bc - push de - push hl - push hl - push de - ld a,[wListMenuID] - and a - jr z,.pokemonPCMenu - cp a,$01 - jr z,.movesMenu -.itemMenu - call GetItemName - jr .placeNameString -.pokemonPCMenu - push hl - ld hl,wPartyCount - ld a,[wList] - cp l ; is it a list of party pokemon or box pokemon? - ld hl,wPartyMonNicks - jr z,.getPokemonName - ld hl, wBoxMonNicks ; box pokemon names -.getPokemonName - ld a,[wWhichPokemon] - ld b,a - ld a,4 - sub b - ld b,a - ld a,[wListScrollOffset] - add b - call GetPartyMonName - pop hl - jr .placeNameString -.movesMenu - call GetMoveName -.placeNameString - call PlaceString - pop de - pop hl - ld a,[wcf93] - and a ; should prices be printed? - jr z,.skipPrintingItemPrice -.printItemPrice - push hl - ld a,[de] - ld de,ItemPrices - ld [wcf91],a - call GetItemPrice ; get price - pop hl - ld bc,20 + 5 ; 1 row down and 5 columns right - add hl,bc - ld c,$a3 ; no leading zeroes, right-aligned, print currency symbol, 3 bytes - call PrintBCDNumber -.skipPrintingItemPrice - ld a,[wListMenuID] - and a - jr nz,.skipPrintingPokemonLevel -.printPokemonLevel - ld a,[wd11e] - push af - push hl - ld hl,wPartyCount - ld a,[wList] - cp l ; is it a list of party pokemon or box pokemon? - ld a,$00 - jr z,.next - ld a,$02 -.next - ld [wcc49],a - ld hl,wWhichPokemon - ld a,[hl] - ld b,a - ld a,$04 - sub b - ld b,a - ld a,[wListScrollOffset] - add b - ld [hl],a - call LoadMonData ; load pokemon info - ld a,[wcc49] - and a ; is it a list of party pokemon or box pokemon? - jr z,.skipCopyingLevel -.copyLevel - ld a,[wLoadedMonBoxLevel] - ld [wLoadedMonLevel],a -.skipCopyingLevel - pop hl - ld bc,$001c - add hl,bc - call PrintLevel ; print level - pop af - ld [wd11e],a -.skipPrintingPokemonLevel - pop hl - pop de - inc de - ld a,[wListMenuID] - cp a,ITEMLISTMENU - jr nz,.nextListEntry -.printItemQuantity - ld a,[wd11e] - ld [wcf91],a - call IsKeyItem ; check if item is unsellable - ld a,[wd124] - and a ; is the item unsellable? - jr nz,.skipPrintingItemQuantity ; if so, don't print the quantity - push hl - ld bc,20 + 8 ; 1 row down and 8 columns right - add hl,bc - ld a,"×" - ld [hli],a - ld a,[wd11e] - push af - ld a,[de] - ld [wcf97],a - push de - ld de,wd11e - ld [de],a - ld bc,$0102 - call PrintNumber - pop de - pop af - ld [wd11e],a - pop hl -.skipPrintingItemQuantity - inc de - pop bc - inc c - push bc - inc c - ld a,[wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1) - and a ; is an item being swapped? - jr z,.nextListEntry - sla a - cp c ; is it this item? - jr nz,.nextListEntry - dec hl - ld a,$ec ; unfilled right arrow menu cursor to indicate an item being swapped - ld [hli],a -.nextListEntry - ld bc,2 * 20 ; 2 rows - add hl,bc - pop bc - inc c - dec b - jp nz,.loop - ld bc,-8 - add hl,bc - ld a,$ee ; down arrow - ld [hl],a - ret -.printCancelMenuItem - ld de,ListMenuCancelText - jp PlaceString - -ListMenuCancelText:: ; 2f97 (0:2f97) - db "CANCEL@" - -GetMonName:: ; 2f9e (0:2f9e) - push hl - ld a,[H_LOADEDROMBANK] - push af - ld a,BANK(MonsterNames) ; 07 - ld [H_LOADEDROMBANK],a - ld [$2000],a - ld a,[wd11e] - dec a - ld hl,MonsterNames ; 421E - ld c,10 - ld b,0 - call AddNTimes - ld de,wcd6d - push de - ld bc,10 - call CopyData - ld hl,wcd77 - ld [hl], "@" - pop de - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - pop hl - ret - -GetItemName:: ; 2fcf (0:2fcf) -; given an item ID at [wd11e], store the name of the item into a string -; starting at wcd6d - push hl - push bc - ld a,[wd11e] - cp HM_01 ; is this a TM/HM? - jr nc,.Machine - - ld [wd0b5],a - ld a,ITEM_NAME - ld [wNameListType],a - ld a,BANK(ItemNames) - ld [wPredefBank],a - call GetName - jr .Finish - -.Machine - call GetMachineName -.Finish - ld de,wcd6d ; pointer to where item name is stored in RAM - pop bc - pop hl - ret - -GetMachineName:: ; 2ff3 (0:2ff3) -; copies the name of the TM/HM in [wd11e] to wcd6d - push hl - push de - push bc - ld a,[wd11e] - push af - cp TM_01 ; is this a TM? [not HM] - jr nc,.WriteTM -; if HM, then write "HM" and add 5 to the item ID, so we can reuse the -; TM printing code - add 5 - ld [wd11e],a - ld hl,HiddenPrefix ; points to "HM" - ld bc,2 - jr .WriteMachinePrefix -.WriteTM - ld hl,TechnicalPrefix ; points to "TM" - ld bc,2 -.WriteMachinePrefix - ld de,wcd6d - call CopyData - -; now get the machine number and convert it to text - ld a,[wd11e] - sub TM_01 - 1 - ld b,$F6 ; "0" -.FirstDigit - sub 10 - jr c,.SecondDigit - inc b - jr .FirstDigit -.SecondDigit - add 10 - push af - ld a,b - ld [de],a - inc de - pop af - ld b,$F6 ; "0" - add b - ld [de],a - inc de - ld a,"@" - ld [de],a - - pop af - ld [wd11e],a - pop bc - pop de - pop hl - ret - -TechnicalPrefix:: ; 303c (0:303c) - db "TM" -HiddenPrefix:: ; 303e (0:303e) - db "HM" - -; sets carry if item is HM, clears carry if item is not HM -; Input: a = item ID -IsItemHM:: ; 3040 (0:3040) - cp a,HM_01 - jr c,.notHM - cp a,TM_01 - ret -.notHM - and a - ret - -; sets carry if move is an HM, clears carry if move is not an HM -; Input: a = move ID -IsMoveHM:: ; 3049 (0:3049) - ld hl,HMMoves - ld de,1 - jp IsInArray - -HMMoves:: ; 3052 (0:3052) - db CUT,FLY,SURF,STRENGTH,FLASH - db $ff ; terminator - -GetMoveName:: ; 3058 (0:3058) - push hl - ld a,MOVE_NAME - ld [wNameListType],a - ld a,[wd11e] - ld [wd0b5],a - ld a,BANK(MoveNames) - ld [wPredefBank],a - call GetName - ld de,wcd6d ; pointer to where move name is stored in RAM - pop hl - ret - -; reloads text box tile patterns, current map view, and tileset tile patterns -ReloadMapData:: ; 3071 (0:3071) - ld a,[H_LOADEDROMBANK] - push af - ld a,[W_CURMAP] - call SwitchToMapRomBank - call DisableLCD - call LoadTextBoxTilePatterns - call LoadCurrentMapView - call LoadTilesetTilePatternData - call EnableLCD - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; reloads tileset tile patterns -ReloadTilesetTilePatterns:: ; 3090 (0:3090) - ld a,[H_LOADEDROMBANK] - push af - ld a,[W_CURMAP] - call SwitchToMapRomBank - call DisableLCD - call LoadTilesetTilePatternData - call EnableLCD - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; shows the town map and lets the player choose a destination to fly to -ChooseFlyDestination:: ; 30a9 (0:30a9) - ld hl,wd72e - res 4,[hl] - ld b, BANK(LoadTownMap_Fly) - ld hl, LoadTownMap_Fly - jp Bankswitch - -; causes the text box to close without waiting for a button press after displaying text -DisableWaitingAfterTextDisplay:: ; 30b6 (0:30b6) - ld a,$01 - ld [wDoNotWaitForButtonPressAfterDisplayingText],a - ret - -; uses an item -; UseItem is used with dummy items to perform certain other functions as well -; INPUT: -; [wcf91] = item ID -; OUTPUT: -; [wcd6a] = success -; 00: unsucessful -; 01: successful -; 02: not able to be used right now, no extra menu displayed (only certain items use this) -UseItem:: ; 30bc (0:30bc) - ld b,BANK(UseItem_) - ld hl,UseItem_ - jp Bankswitch - -; confirms the item toss and then tosses the item -; INPUT: -; hl = address of inventory (either wNumBagItems or wNumBoxItems) -; [wcf91] = item ID -; [wWhichPokemon] = index of item within inventory -; [wcf96] = quantity to toss -; OUTPUT: -; clears carry flag if the item is tossed, sets carry flag if not -TossItem:: ; 30c4 (0:30c4) - ld a,[H_LOADEDROMBANK] - push af - ld a,BANK(TossItem_) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call TossItem_ - pop de - ld a,d - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; checks if an item is a key item -; INPUT: -; [wcf91] = item ID -; OUTPUT: -; [wd124] = result -; 00: item is not key item -; 01: item is key item -IsKeyItem:: ; 30d9 (0:30d9) - push hl - push de - push bc - callba IsKeyItem_ - pop bc - pop de - pop hl - ret - -; function to draw various text boxes -; INPUT: -; [wTextBoxID] = text box ID -DisplayTextBoxID:: ; 30e8 (0:30e8) - ld a,[H_LOADEDROMBANK] - push af - ld a,BANK(DisplayTextBoxID_) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call DisplayTextBoxID_ - pop bc - ld a,b - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; not zero if an NPC movement script is running, the player character is -; automatically stepping down from a door, or joypad states are being simulated -IsPlayerCharacterBeingControlledByGame:: ; 30fd (0:30fd) - ld a, [wNPCMovementScriptPointerTableNum] - and a - ret nz - ld a, [wd736] - bit 1, a ; currently stepping down from door bit - ret nz - ld a, [wd730] - and $80 - ret - -RunNPCMovementScript:: ; 310e (0:310e) - ld hl, wd736 - bit 0, [hl] - res 0, [hl] - jr nz, .playerStepOutFromDoor - ld a, [wNPCMovementScriptPointerTableNum] - and a - ret z - dec a - add a - ld d, 0 - ld e, a - ld hl, .NPCMovementScriptPointerTables - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [H_LOADEDROMBANK] - push af - ld a, [wNPCMovementScriptBank] - ld [H_LOADEDROMBANK], a - ld [$2000], a - ld a, [wNPCMovementScriptFunctionNum] - call CallFunctionInTable - pop af - ld [H_LOADEDROMBANK], a - ld [$2000], a - ret -.NPCMovementScriptPointerTables - dw ProfOakMovementScriptPointerTable - dw PewterMuseumGuyMovementScriptPointerTable - dw PewterGymGuyMovementScriptPointerTable -.playerStepOutFromDoor - ld b, BANK(PlayerStepOutFromDoor) - ld hl, PlayerStepOutFromDoor - jp Bankswitch - -EndNPCMovementScript:: ; 314e (0:314e) - ld b, BANK(_EndNPCMovementScript) - ld hl, _EndNPCMovementScript - jp Bankswitch - -EmptyFunc2:: ; 3156 (0:3156) - ret - -; stores hl in [W_TRAINERHEADERPTR] -StoreTrainerHeaderPointer:: ; 3157 (0:3157) - ld a, h - ld [W_TRAINERHEADERPTR], a - ld a, l - ld [W_TRAINERHEADERPTR+1], a - ret - -; executes the current map script from the function pointer array provided in hl. -; a: map script index to execute (unless overridden by [wd733] bit 4) -ExecuteCurMapScriptInTable:: ; 3160 (0:3160) - push af - push de - call StoreTrainerHeaderPointer - pop hl - pop af - push hl - ld hl, W_FLAGS_D733 - bit 4, [hl] - res 4, [hl] - jr z, .useProvidedIndex ; test if map script index was overridden manually - ld a, [W_CURMAPSCRIPT] -.useProvidedIndex - pop hl - ld [W_CURMAPSCRIPT], a - call CallFunctionInTable - ld a, [W_CURMAPSCRIPT] - ret - -LoadGymLeaderAndCityName:: ; 317f (0:317f) - push de - ld de, wGymCityName - ld bc, $11 - call CopyData ; load city name - pop hl - ld de, wGymLeaderName - ld bc, $b - jp CopyData ; load gym leader name - -; reads specific information from trainer header (pointed to at W_TRAINERHEADERPTR) -; a: offset in header data -; 0 -> flag's bit (into wTrainerHeaderFlagBit) -; 2 -> flag's byte ptr (into hl) -; 4 -> before battle text (into hl) -; 6 -> after battle text (into hl) -; 8 -> end battle text (into hl) -ReadTrainerHeaderInfo:: ; 3193 (0:3193) - push de - push af - ld d, $0 - ld e, a - ld hl, W_TRAINERHEADERPTR - ld a, [hli] - ld l, [hl] - ld h, a - add hl, de - pop af - and a - jr nz, .nonZeroOffset - ld a, [hl] - ld [wTrainerHeaderFlagBit], a ; store flag's bit - jr .done -.nonZeroOffset - cp $2 - jr z, .readPointer ; read flag's byte ptr - cp $4 - jr z, .readPointer ; read before battle text - cp $6 - jr z, .readPointer ; read after battle text - cp $8 - jr z, .readPointer ; read end battle text - cp $a - jr nz, .done - ld a, [hli] ; read end battle text (2) but override the result afterwards (XXX why, bug?) - ld d, [hl] - ld e, a - jr .done -.readPointer - ld a, [hli] - ld h, [hl] - ld l, a -.done - pop de - ret - -TrainerFlagAction:: - predef_jump FlagActionPredef - -TalkToTrainer:: ; 31cc (0:31cc) - call StoreTrainerHeaderPointer - xor a - call ReadTrainerHeaderInfo ; read flag's bit - ld a, $2 - call ReadTrainerHeaderInfo ; read flag's byte ptr - ld a, [wTrainerHeaderFlagBit] - ld c, a - ld b, $2 - call TrainerFlagAction ; read trainer's flag - ld a, c - and a - jr z, .trainerNotYetFought ; test trainer's flag - ld a, $6 - call ReadTrainerHeaderInfo ; print after battle text - jp PrintText -.trainerNotYetFought ; 0x31ed - ld a, $4 - call ReadTrainerHeaderInfo ; print before battle text - call PrintText - ld a, $a - call ReadTrainerHeaderInfo ; (?) does nothing apparently (maybe bug in ReadTrainerHeaderInfo) - push de - ld a, $8 - call ReadTrainerHeaderInfo ; read end battle text - pop de - call SaveEndBattleTextPointers - ld hl, W_FLAGS_D733 - set 4, [hl] ; activate map script index override (index is set below) - ld hl, wFlags_0xcd60 - bit 0, [hl] ; test if player is already engaging the trainer (because the trainer saw the player) - ret nz -; if the player talked to the trainer of his own volition - call EngageMapTrainer - ld hl, W_CURMAPSCRIPT - inc [hl] ; increment map script index before StartTrainerBattle increments it again (next script function is usually EndTrainerBattle) - jp StartTrainerBattle - -; checks if any trainers are seeing the player and wanting to fight -CheckFightingMapTrainers:: ; 3219 (0:3219) - call CheckForEngagingTrainers - ld a, [wSpriteIndex] - cp $ff - jr nz, .trainerEngaging - xor a - ld [wSpriteIndex], a - ld [wTrainerHeaderFlagBit], a - ret -.trainerEngaging - ld hl, W_FLAGS_D733 - set 3, [hl] - ld [wcd4f], a - xor a - ld [wcd50], a - predef EmotionBubble - ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN - ld [wJoyIgnore], a - xor a - ldh [$b4], a - call TrainerWalkUpToPlayer_Bank0 - ld hl, W_CURMAPSCRIPT - inc [hl] ; increment map script index (next script function is usually DisplayEnemyTrainerTextAndStartBattle) - ret - -; display the before battle text after the enemy trainer has walked up to the player's sprite -DisplayEnemyTrainerTextAndStartBattle:: ; 324c (0:324c) - ld a, [wd730] - and $1 - ret nz ; return if the enemy trainer hasn't finished walking to the player's sprite - ld [wJoyIgnore], a - ld a, [wSpriteIndex] - ld [hSpriteIndexOrTextID], a - call DisplayTextID - ; fall through - -StartTrainerBattle:: ; 325d (0:325d) - xor a - ld [wJoyIgnore], a - call InitBattleEnemyParameters - ld hl, wd72d - set 6, [hl] - set 7, [hl] - ld hl, wd72e - set 1, [hl] - ld hl, W_CURMAPSCRIPT - inc [hl] ; increment map script index (next script function is usually EndTrainerBattle) - ret - -EndTrainerBattle:: ; 3275 (0:3275) - ld hl, wd126 - set 5, [hl] - set 6, [hl] - ld hl, wd72d - res 7, [hl] - ld hl, wFlags_0xcd60 - res 0, [hl] ; player is no longer engaged by any trainer - ld a, [W_ISINBATTLE] ; W_ISINBATTLE - cp $ff - jp z, ResetButtonPressedAndMapScript - ld a, $2 - call ReadTrainerHeaderInfo - ld a, [wTrainerHeaderFlagBit] - ld c, a - ld b, $1 - call TrainerFlagAction ; flag trainer as fought - ld a, [W_ENEMYMONORTRAINERCLASS] - cp $c8 - jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite) - ld hl, W_MISSABLEOBJECTLIST - ld de, $2 - ld a, [wSpriteIndex] - call IsInArray ; search for sprite ID - inc hl - ld a, [hl] - ld [wcc4d], a ; load corresponding missable object index and remove it - predef HideObject -.skipRemoveSprite - ld hl, wd730 - bit 4, [hl] - res 4, [hl] - ret nz - -ResetButtonPressedAndMapScript:: ; 32c1 (0:32c1) - xor a - ld [wJoyIgnore], a - ld [hJoyHeld], a - ld [hJoyPressed], a - ld [hJoyReleased], a - ld [W_CURMAPSCRIPT], a ; reset battle status - ret - -; calls TrainerWalkUpToPlayer -TrainerWalkUpToPlayer_Bank0:: ; 32cf (0:32cf) - ld b, BANK(TrainerWalkUpToPlayer) - ld hl, TrainerWalkUpToPlayer - jp Bankswitch - -; sets opponent type and mon set/lvl based on the engaging trainer data -InitBattleEnemyParameters:: ; 32d7 (0:32d7) - ld a, [wEngagedTrainerClass] - ld [W_CUROPPONENT], a ; wd059 - ld [W_ENEMYMONORTRAINERCLASS], a - cp $c8 - ld a, [wEngagedTrainerSet] ; wcd2e - jr c, .noTrainer - ld [W_TRAINERNO], a ; wd05d - ret -.noTrainer - ld [W_CURENEMYLVL], a ; W_CURENEMYLVL - ret - -GetSpritePosition1:: ; 32ef (0:32ef) - ld hl, _GetSpritePosition1 - jr asm_3301 - -GetSpritePosition2:: ; 32f4 (0:32f4) - ld hl, _GetSpritePosition2 - jr asm_3301 ; 0x32f7 $8 - -SetSpritePosition1:: ; 32f9 (0:32f9) - ld hl, _SetSpritePosition1 - jr asm_3301 - -SetSpritePosition2:: ; 32fe (0:32fe) - ld hl, _SetSpritePosition2 -asm_3301:: ; 3301 (0:3301) - ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2) - jp Bankswitch ; indirect jump to one of the four functions - -CheckForEngagingTrainers:: ; 3306 (0:3306) - xor a - call ReadTrainerHeaderInfo ; read trainer flag's bit (unused) - ld d, h ; store trainer header address in de - ld e, l -.trainerLoop - call StoreTrainerHeaderPointer ; set trainer header pointer to current trainer - ld a, [de] - ld [wSpriteIndex], a ; store trainer flag's bit - ld [wTrainerHeaderFlagBit], a - cp $ff - ret z - ld a, $2 - call ReadTrainerHeaderInfo ; read trainer flag's byte ptr - ld b, $2 - ld a, [wTrainerHeaderFlagBit] - ld c, a - call TrainerFlagAction ; read trainer flag - ld a, c - and a - jr nz, .trainerAlreadyFought - push hl - push de - push hl - xor a - call ReadTrainerHeaderInfo ; get trainer header pointer - inc hl - ld a, [hl] ; read trainer engage distance - pop hl - ld [wTrainerEngageDistance], a - ld a, [wSpriteIndex] - swap a - ld [wTrainerSpriteOffset], a ; wWhichTrade - predef TrainerEngage - pop de - pop hl - ld a, [wTrainerSpriteOffset] ; wWhichTrade - and a - ret nz ; break if the trainer is engaging -.trainerAlreadyFought - ld hl, $c - add hl, de - ld d, h - ld e, l - jr .trainerLoop - -; hl = text if the player wins -; de = text if the player loses -SaveEndBattleTextPointers:: ; 3354 (0:3354) - ld a, [H_LOADEDROMBANK] - ld [wEndBattleTextRomBank], a - ld a, h - ld [wEndBattleWinTextPointer], a - ld a, l - ld [wEndBattleWinTextPointer + 1], a - ld a, d - ld [wEndBattleLoseTextPointer], a - ld a, e - ld [wEndBattleLoseTextPointer + 1], a - ret - -; loads data of some trainer on the current map and plays pre-battle music -; [wSpriteIndex]: sprite ID of trainer who is engaged -EngageMapTrainer:: ; 336a (0:336a) - ld hl, W_MAPSPRITEEXTRADATA - ld d, $0 - ld a, [wSpriteIndex] - dec a - add a - ld e, a - add hl, de ; seek to engaged trainer data - ld a, [hli] ; load trainer class - ld [wEngagedTrainerClass], a - ld a, [hl] ; load trainer mon set - ld [wEnemyMonAttackMod], a ; wcd2e - jp PlayTrainerMusic - -PrintEndBattleText:: ; 3381 (0:3381) - push hl - ld hl, wd72d - bit 7, [hl] - res 7, [hl] - pop hl - ret z - ld a, [H_LOADEDROMBANK] - push af - ld a, [wEndBattleTextRomBank] - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - push hl - callba SaveTrainerName - ld hl, TrainerEndBattleText - call PrintText - pop hl - pop af - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - callba FreezeEnemyTrainerSprite - jp WaitForSoundToFinish - -GetSavedEndBattleTextPointer:: ; 33b7 (0:33b7) - ld a, [wBattleResult] - and a -; won battle - jr nz, .lostBattle - ld a, [wEndBattleWinTextPointer] - ld h, a - ld a, [wEndBattleWinTextPointer + 1] - ld l, a - ret -.lostBattle - ld a, [wEndBattleLoseTextPointer] - ld h, a - ld a, [wEndBattleLoseTextPointer + 1] - ld l, a - ret - -TrainerEndBattleText:: ; 33cf (0:33cf) - TX_FAR _TrainerNameText - db $08 - call GetSavedEndBattleTextPointer - call TextCommandProcessor - jp TextScriptEnd - -; XXX unused? -Func_33dd:: ; 33dd (0:33dd) - ld a, [wFlags_0xcd60] - bit 0, a - ret nz - call EngageMapTrainer - xor a - ret - -PlayTrainerMusic:: ; 33e8 (0:33e8) - ld a, [wEngagedTrainerClass] - cp $c8 + SONY1 - ret z - cp $c8 + SONY2 - ret z - cp $c8 + SONY3 - ret z - ld a, [W_GYMLEADERNO] ; W_GYMLEADERNO - and a - ret nz - xor a - ld [wMusicHeaderPointer], a - ld a, $ff - call PlaySound ; stop music - ld a, BANK(Music_MeetEvilTrainer) - ld [wc0ef], a - ld [wc0f0], a - ld a, [wEngagedTrainerClass] - ld b, a - ld hl, EvilTrainerList -.evilTrainerListLoop - ld a, [hli] - cp $ff - jr z, .noEvilTrainer - cp b - jr nz, .evilTrainerListLoop - ld a, MUSIC_MEET_EVIL_TRAINER - jr .PlaySound -.noEvilTrainer - ld hl, FemaleTrainerList -.femaleTrainerListLoop - ld a, [hli] - cp $ff - jr z, .maleTrainer - cp b - jr nz, .femaleTrainerListLoop - ld a, MUSIC_MEET_FEMALE_TRAINER - jr .PlaySound -.maleTrainer - ld a, MUSIC_MEET_MALE_TRAINER -.PlaySound - ld [wc0ee], a - jp PlaySound - -INCLUDE "data/trainer_types.asm" - -; checks if the player's coordinates match an arrow movement tile's coordinates -; and if so, decodes the RLE movement data -; b = player Y -; c = player X -DecodeArrowMovementRLE:: ; 3442 (0:3442) - ld a, [hli] - cp $ff - ret z ; no match in the list - cp b - jr nz, .nextArrowMovementTileEntry1 - ld a, [hli] - cp c - jr nz, .nextArrowMovementTileEntry2 - ld a, [hli] - ld d, [hl] - ld e, a - ld hl, wSimulatedJoypadStatesEnd - call DecodeRLEList - dec a - ld [wSimulatedJoypadStatesIndex], a - ret -.nextArrowMovementTileEntry1 - inc hl -.nextArrowMovementTileEntry2 - inc hl - inc hl - jr DecodeArrowMovementRLE - -FuncTX_ItemStoragePC:: ; 3460 (0:3460) - call SaveScreenTilesToBuffer2 - ld b, BANK(PlayerPC) - ld hl, PlayerPC - jr bankswitchAndContinue - -FuncTX_BillsPC:: ; 346a (0:346a) - call SaveScreenTilesToBuffer2 - ld b, BANK(BillsPC_) - ld hl, BillsPC_ - jr bankswitchAndContinue - -FuncTX_SlotMachine:: ; 3474 (0:3474) -; XXX find a better name for this function -; special_F7 - ld b,BANK(CeladonPrizeMenu) - ld hl,CeladonPrizeMenu -bankswitchAndContinue:: ; 3479 (0:3479) - call Bankswitch - jp HoldTextDisplayOpen ; continue to main text-engine function - -FuncTX_PokemonCenterPC:: ; 347f (0:347f) - ld b, BANK(ActivatePC) - ld hl, ActivatePC - jr bankswitchAndContinue - -StartSimulatingJoypadStates:: ; 3486 (0:3486) - xor a - ld [wOverrideSimulatedJoypadStatesMask], a - ld [wSpriteStateData2 + $06], a ; player's sprite movement byte 1 - ld hl, wd730 - set 7, [hl] - ret - -IsItemInBag:: ; 3493 (0:3493) -; given an item_id in b -; set zero flag if item isn't in player's bag -; else reset zero flag -; related to Pokémon Tower and ghosts - predef IsItemInBag_ - ld a,b - and a - ret - -DisplayPokedex:: ; 349b (0:349b) - ld [wd11e], a - ld b, BANK(Func_7c18) - ld hl, Func_7c18 - jp Bankswitch - -SetSpriteFacingDirectionAndDelay:: ; 34a6 (0:34a6) - call SetSpriteFacingDirection - ld c, $6 - jp DelayFrames - -SetSpriteFacingDirection:: ; 34ae (0:34ae) - ld a, $9 - ld [H_SPRITEDATAOFFSET], a - call GetPointerWithinSpriteStateData1 - ld a, [$ff8d] - ld [hl], a - ret - -SetSpriteImageIndexAfterSettingFacingDirection:: ; 34b9 (0:34b9) - ld de, -7 - add hl, de - ld [hl], a - ret - -; tests if the player's coordinates are in a specified array -; INPUT: -; hl = address of array -; OUTPUT: -; [wWhichTrade] = if there is match, the matching array index -; sets carry if the coordinates are in the array, clears carry if not -ArePlayerCoordsInArray:: ; 34bf (0:34bf) - ld a,[W_YCOORD] - ld b,a - ld a,[W_XCOORD] - ld c,a - ; fallthrough - -CheckCoords:: ; 34c7 (0:34c7) - xor a - ld [wWhichTrade],a -.loop - ld a,[hli] - cp a,$ff ; reached terminator? - jr z,.notInArray - push hl - ld hl,wWhichTrade - inc [hl] - pop hl -.compareYCoord - cp b - jr z,.compareXCoord - inc hl - jr .loop -.compareXCoord - ld a,[hli] - cp c - jr nz,.loop -.inArray - scf - ret -.notInArray - and a - ret - -; tests if a boulder's coordinates are in a specified array -; INPUT: -; hl = address of array -; [H_SPRITEINDEX] = index of boulder sprite -; OUTPUT: -; [wWhichTrade] = if there is match, the matching array index -; sets carry if the coordinates are in the array, clears carry if not -CheckBoulderCoords:: ; 34e4 (0:34e4) - push hl - ld hl, wSpriteStateData2 + $04 - ld a, [H_SPRITEINDEX] - swap a - ld d, $0 - ld e, a - add hl, de - ld a, [hli] - sub $4 ; because sprite coordinates are offset by 4 - ld b, a - ld a, [hl] - sub $4 ; because sprite coordinates are offset by 4 - ld c, a - pop hl - jp CheckCoords - -GetPointerWithinSpriteStateData1:: ; 34fc (0:34fc) - ld h, $c1 - jr _GetPointerWithinSpriteStateData - -GetPointerWithinSpriteStateData2:: ; 3500 (0:3500) - ld h, $c2 - -_GetPointerWithinSpriteStateData: - ld a, [H_SPRITEDATAOFFSET] - ld b, a - ld a, [H_SPRITEINDEX] - swap a - add b - ld l, a - ret - -; decodes a $ff-terminated RLEncoded list -; each entry is a pair of bytes <byte value> <repetitions> -; the final $ff will be replicated in the output list and a contains the number of bytes written -; de: input list -; hl: output list -DecodeRLEList:: ; 350c (0:350c) - xor a - ld [wRLEByteCount], a ; count written bytes here -.listLoop - ld a, [de] - cp $ff - jr z, .endOfList - ld [H_DOWNARROWBLINKCNT1], a ; store byte value to be written - inc de - ld a, [de] - ld b, $0 - ld c, a ; number of bytes to be written - ld a, [wRLEByteCount] - add c - ld [wRLEByteCount], a ; update total number of written bytes - ld a, [H_DOWNARROWBLINKCNT1] ; $ff8b - call FillMemory ; write a c-times to output - inc de - jr .listLoop -.endOfList - ld a, $ff - ld [hl], a ; write final $ff - ld a, [wRLEByteCount] - inc a ; include sentinel in counting - ret - -; sets movement byte 1 for sprite [$FF8C] to $FE and byte 2 to [$FF8D] -SetSpriteMovementBytesToFE:: ; 3533 (0:3533) - push hl - call GetSpriteMovementByte1Pointer - ld [hl], $fe - call GetSpriteMovementByte2Pointer - ld a, [$ff8d] - ld [hl], a - pop hl - ret - -; sets both movement bytes for sprite [$FF8C] to $FF -SetSpriteMovementBytesToFF:: ; 3541 (0:3541) - push hl - call GetSpriteMovementByte1Pointer - ld [hl],$FF - call GetSpriteMovementByte2Pointer - ld [hl],$FF ; prevent person from walking? - pop hl - ret - -; returns the sprite movement byte 1 pointer for sprite [$FF8C] in hl -GetSpriteMovementByte1Pointer:: ; 354e (0:354e) - ld h,$C2 - ld a,[H_SPRITEINDEX] ; the sprite to move - swap a - add a,6 - ld l,a - ret - -; returns the sprite movement byte 2 pointer for sprite [$FF8C] in hl -GetSpriteMovementByte2Pointer:: ; 3558 (0:3558) - push de - ld hl,W_MAPSPRITEDATA - ld a,[$FF8C] ; the sprite to move - dec a - add a - ld d,0 - ld e,a - add hl,de - pop de - ret - -GetTrainerInformation:: ; 3566 (0:3566) - call GetTrainerName - ld a, [wLinkState] - and a - jr nz, .linkBattle - ld a, Bank(TrainerPicAndMoneyPointers) - call BankswitchHome - ld a, [W_TRAINERCLASS] ; wd031 - dec a - ld hl, TrainerPicAndMoneyPointers - ld bc, $5 - call AddNTimes - ld de, wTrainerPicPointer - ld a, [hli] - ld [de], a - inc de - ld a, [hli] - ld [de], a - ld de, wd046 - ld a, [hli] - ld [de], a - inc de - ld a, [hli] - ld [de], a - jp BankswitchBack -.linkBattle - ld hl, wTrainerPicPointer - ld de, RedPicFront - ld [hl], e - inc hl - ld [hl], d - ret - -GetTrainerName:: ; 359e (0:359e) - ld b, BANK(GetTrainerName_) - ld hl, GetTrainerName_ - jp Bankswitch - - -HasEnoughMoney:: -; Check if the player has at least as much -; money as the 3-byte BCD value at $ff9f. - ld de, wPlayerMoney - ld hl, $ff9f - ld c, 3 - jp StringCmp - -HasEnoughCoins:: -; Check if the player has at least as many -; coins as the 2-byte BCD value at $ffa0. - ld de, wPlayerCoins - ld hl, $ffa0 - ld c, 2 - jp StringCmp - - -BankswitchHome:: ; 35d9 (0:35d9) -; switches to bank # in a -; Only use this when in the home bank! - ld [wcf09],a - ld a,[H_LOADEDROMBANK] - ld [wcf08],a - ld a,[wcf09] - call BankswitchCommon - ret - -BankswitchBack:: ; 35e8 (0:35e8) -; returns from BankswitchHome - ld a,[wcf08] - call BankswitchCommon - ret - -BankswitchCommon:: ; 3e7e (0:3e7e) - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -Bankswitch:: ; 3e84 (0:3e84) -; self-contained bankswitch, use this when not in the home bank -; switches to the bank in b - ld a,[H_LOADEDROMBANK] - push af - ld a,b - ld [H_LOADEDROMBANK],a - ld [$2000],a - call .jumptoaddress - pop bc - ld a,b - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret -.jumptoaddress - jp [hl] - -; displays yes/no choice -; yes -> set carry -YesNoChoice:: ; 35ec (0:35ec) - call SaveScreenTilesToBuffer1 - call InitYesNoTextBoxParameters - jr DisplayYesNoChoice - -Func_35f4:: ; 35f4 (0:35f4) - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call InitYesNoTextBoxParameters - jp DisplayTextBoxID - -InitYesNoTextBoxParameters:: ; 35ff (0:35ff) - xor a ; YES_NO_MENU - ld [wTwoOptionMenuID], a - hlCoord 14, 7 - ld bc, $80f - ret - -YesNoChoicePokeCenter:: ; 360a (0:360a) - call SaveScreenTilesToBuffer1 - ld a, HEAL_CANCEL_MENU - ld [wTwoOptionMenuID], a - hlCoord 11, 6 - ld bc, $80c - jr DisplayYesNoChoice - -Func_361a:: ; 361a (0:361a) - call SaveScreenTilesToBuffer1 - ld a, WIDE_YES_NO_MENU - ld [wTwoOptionMenuID], a - hlCoord 12, 7 - ld bc, $080d -DisplayYesNoChoice:: ; 3628 (0:3628) - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID - jp LoadScreenTilesFromBuffer1 - -; calculates the difference |a-b|, setting carry flag if a<b -CalcDifference:: ; 3633 (0:3633) - sub b - ret nc - cpl - add $1 - scf - ret - -MoveSprite:: ; 363a (0:363a) -; move the sprite [$FF8C] with the movement pointed to by de -; actually only copies the movement data to wcc5b for later - call SetSpriteMovementBytesToFF -MoveSprite_:: ; 363d (0:363d) - push hl - push bc - call GetSpriteMovementByte1Pointer - xor a - ld [hl],a - ld hl,wcc5b - ld c,0 - -.loop - ld a,[de] - ld [hli],a - inc de - inc c - cp a,$FF ; have we reached the end of the movement data? - jr nz,.loop - - ld a,c - ld [wcf0f],a ; number of steps taken - - pop bc - ld hl,wd730 - set 0,[hl] - pop hl - xor a - ld [wOverrideSimulatedJoypadStatesMask],a - ld [wSimulatedJoypadStatesEnd],a - dec a - ld [wJoyIgnore],a - ld [wWastedByteCD3A],a - ret - -; divides [$ffe5] by [$ffe6] and stores the quotient in [$ffe7] -DivideBytes:: ; 366b (0:366b) - push hl - ld hl, $ffe7 - xor a - ld [hld], a - ld a, [hld] - and a - jr z, .done - ld a, [hli] -.loop - sub [hl] - jr c, .done - inc hl - inc [hl] - dec hl - jr .loop -.done - pop hl - ret - - -LoadFontTilePatterns:: - ld a, [rLCDC] - bit 7, a ; is the LCD enabled? - jr nz, .on -.off - ld hl, FontGraphics - ld de, vFont - ld bc, $400 - ld a, BANK(FontGraphics) - jp FarCopyDataDouble ; if LCD is off, transfer all at once -.on - ld de, FontGraphics - ld hl, vFont - ld bc, BANK(FontGraphics) << 8 | $80 - jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank - -LoadTextBoxTilePatterns:: - ld a, [rLCDC] - bit 7, a ; is the LCD enabled? - jr nz, .on -.off - ld hl, TextBoxGraphics - ld de, vChars2 + $600 - ld bc, $200 - ld a, BANK(TextBoxGraphics) - jp FarCopyData2 ; if LCD is off, transfer all at once -.on - ld de, TextBoxGraphics - ld hl, vChars2 + $600 - ld bc, BANK(TextBoxGraphics) << 8 | $20 - jp CopyVideoData ; if LCD is on, transfer during V-blank - -LoadHpBarAndStatusTilePatterns:: - ld a, [rLCDC] - bit 7, a ; is the LCD enabled? - jr nz, .on -.off - ld hl, HpBarAndStatusGraphics - ld de, vChars2 + $620 - ld bc, $1e0 - ld a, BANK(HpBarAndStatusGraphics) - jp FarCopyData2 ; if LCD is off, transfer all at once -.on - ld de, HpBarAndStatusGraphics - ld hl, vChars2 + $620 - ld bc, BANK(HpBarAndStatusGraphics) << 8 | $1e - jp CopyVideoData ; if LCD is on, transfer during V-blank - - -UncompressSpriteFromDE:: ; 36eb (0:36eb) -; Decompress pic at a:de. - ld hl, W_SPRITEINPUTPTR - ld [hl], e - inc hl - ld [hl], d - jp UncompressSpriteData - - -SaveScreenTilesToBuffer2:: ; 36f4 (0:36f4) - ld hl, wTileMap - ld de, wTileMapBackup2 - ld bc, $168 - call CopyData - ret - -LoadScreenTilesFromBuffer2:: ; 3701 (0:3701) - call LoadScreenTilesFromBuffer2DisableBGTransfer - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a ; $ffba - ret - -; loads screen tiles stored in wTileMapBackup2 but leaves H_AUTOBGTRANSFERENABLED disabled -LoadScreenTilesFromBuffer2DisableBGTransfer:: ; 3709 (0:3709) - xor a - ld [H_AUTOBGTRANSFERENABLED], a ; $ffba - ld hl, wTileMapBackup2 - ld de, wTileMap - ld bc, $168 - call CopyData - ret - -SaveScreenTilesToBuffer1:: ; 3719 (0:3719) - ld hl, wTileMap - ld de, wTileMapBackup - ld bc, $168 - jp CopyData - -LoadScreenTilesFromBuffer1:: ; 3725 (0:3725) - xor a - ld [H_AUTOBGTRANSFERENABLED], a ; $ffba - ld hl, wTileMapBackup - ld de, wTileMap - ld bc, $168 - call CopyData - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a ; $ffba - ret - -DelayFrames:: ; 3739 (0:3739) -; wait n frames, where n is the value in c - call DelayFrame - dec c - jr nz,DelayFrames - ret - -PlaySoundWaitForCurrent:: ; 3740 (0:3740) - push af - call WaitForSoundToFinish - pop af - jp PlaySound - -; Wait for sound to finish playing -WaitForSoundToFinish:: ; 3748 (0:3748) - ld a, [wLowHealthAlarm] - and $80 - ret nz - push hl -.asm_374f - ld hl, wc02a - xor a - or [hl] - inc hl - or [hl] - inc hl - inc hl - or [hl] - jr nz, .asm_374f - pop hl - ret - -NamePointers:: ; 375d (0:375d) - dw MonsterNames - dw MoveNames - dw UnusedNames - dw ItemNames - dw wPartyMonOT ; player's OT names list - dw wEnemyMonOT ; enemy's OT names list - dw TrainerNames - -GetName:: ; 376b (0:376b) -; arguments: -; [wd0b5] = which name -; [wNameListType] = which list -; [wPredefBank] = bank of list -; -; returns pointer to name in de - ld a,[wd0b5] - ld [wd11e],a - - ; TM names are separate from item names. - ; BUG: This applies to all names instead of just items. - cp HM_01 - jp nc, GetMachineName - - ld a,[H_LOADEDROMBANK] - push af - push hl - push bc - push de - ld a,[wNameListType] ;List3759_entrySelector - dec a - jr nz,.otherEntries - ;1 = MON_NAMES - call GetMonName - ld hl,11 - add hl,de - ld e,l - ld d,h - jr .gotPtr -.otherEntries ; $378d - ;2-7 = OTHER ENTRIES - ld a,[wPredefBank] - ld [H_LOADEDROMBANK],a - ld [$2000],a - ld a,[wNameListType] ;VariousNames' entryID - dec a - add a - ld d,0 - ld e,a - jr nc,.skip - inc d -.skip ; $37a0 - ld hl,NamePointers - add hl,de - ld a,[hli] - ld [$ff96],a - ld a,[hl] - ld [$ff95],a - ld a,[$ff95] - ld h,a - ld a,[$ff96] - ld l,a - ld a,[wd0b5] - ld b,a - ld c,0 -.nextName - ld d,h - ld e,l -.nextChar - ld a,[hli] - cp a, "@" - jr nz,.nextChar - inc c ;entry counter - ld a,b ;wanted entry - cp c - jr nz,.nextName - ld h,d - ld l,e - ld de,wcd6d - ld bc,$0014 - call CopyData -.gotPtr ; $37cd - ld a,e - ld [wcf8d],a - ld a,d - ld [wcf8e],a - pop de - pop bc - pop hl - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -GetItemPrice:: ; 37df (0:37df) -; Stores item's price as BCD at hItemPrice (3 bytes) -; Input: [wcf91] = item id - ld a, [H_LOADEDROMBANK] - push af - ld a, [wListMenuID] - cp MOVESLISTMENU - ld a, BANK(ItemPrices) - jr nz, .asm_37ed - ld a, $f ; hardcoded Bank -.asm_37ed - ld [H_LOADEDROMBANK], a - ld [$2000], a - ld hl, wItemPrices - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wcf91] ; a contains item id - cp HM_01 - jr nc, .getTMPrice - ld bc, $3 -.asm_3802 - add hl, bc - dec a - jr nz, .asm_3802 - dec hl - ld a, [hld] - ld [hItemPrice + 2], a - ld a, [hld] - ld [hItemPrice + 1], a - ld a, [hl] - ld [hItemPrice], a - jr .asm_381c -.getTMPrice - ld a, Bank(GetMachinePrice) - ld [H_LOADEDROMBANK], a - ld [$2000], a - call GetMachinePrice -.asm_381c - ld de, hItemPrice - pop af - ld [H_LOADEDROMBANK], a - ld [$2000], a - ret - -; copies a string from [de] to [wcf4b] -CopyStringToCF4B:: ; 3826 (0:3826) - ld hl, wcf4b - ; fall through - -; copies a string from [de] to [hl] -CopyString:: ; 3829 (0:3829) - ld a, [de] - inc de - ld [hli], a - cp "@" - jr nz, CopyString - ret - -; this function is used when lower button sensitivity is wanted (e.g. menus) -; OUTPUT: [hJoy5] = pressed buttons in usual format -; there are two flags that control its functionality, [hJoy6] and [hJoy7] -; there are esentially three modes of operation -; 1. Get newly pressed buttons only -; ([hJoy7] == 0, [hJoy6] == any) -; Just copies [hJoyPressed] to [hJoy5]. -; 2. Get currently pressed buttons at low sample rate with delay -; ([hJoy7] == 1, [hJoy6] != 0) -; If the user holds down buttons for more than half a second, -; report buttons as being pressed up to 12 times per second thereafter. -; If the user holds down buttons for less than half a second, -; report only one button press. -; 3. Same as 2, but report no buttons as pressed if A or B is held down. -; ([hJoy7] == 1, [hJoy6] == 0) -JoypadLowSensitivity:: ; 3831 (0:3831) - call Joypad - ld a,[hJoy7] ; flag - and a ; get all currently pressed buttons or only newly pressed buttons? - ld a,[hJoyPressed] ; newly pressed buttons - jr z,.storeButtonState - ld a,[hJoyHeld] ; all currently pressed buttons -.storeButtonState - ld [hJoy5],a - ld a,[hJoyPressed] ; newly pressed buttons - and a ; have any buttons been newly pressed since last check? - jr z,.noNewlyPressedButtons -.newlyPressedButtons - ld a,30 ; half a second delay - ld [H_FRAMECOUNTER],a - ret -.noNewlyPressedButtons - ld a,[H_FRAMECOUNTER] - and a ; is the delay over? - jr z,.delayOver -.delayNotOver - xor a - ld [hJoy5],a ; report no buttons as pressed - ret -.delayOver -; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed - ld a,[hJoyHeld] - and A_BUTTON | B_BUTTON - jr z,.setShortDelay - ld a,[hJoy6] ; flag - and a - jr nz,.setShortDelay - xor a - ld [hJoy5],a -.setShortDelay - ld a,5 ; 1/12 of a second delay - ld [H_FRAMECOUNTER],a - ret - -WaitForTextScrollButtonPress:: ; 3865 (0:3865) - ld a, [H_DOWNARROWBLINKCNT1] - push af - ld a, [H_DOWNARROWBLINKCNT2] - push af - xor a - ld [H_DOWNARROWBLINKCNT1], a - ld a, $6 - ld [H_DOWNARROWBLINKCNT2], a -.loop - push hl - ld a, [wTownMapSpriteBlinkingEnabled] - and a - jr z, .skipAnimation - call TownMapSpriteBlinkingAnimation -.skipAnimation - hlCoord 18, 16 - call HandleDownArrowBlinkTiming - pop hl - call JoypadLowSensitivity - predef CableClub_Run - ld a, [hJoy5] - and A_BUTTON | B_BUTTON - jr z, .loop - pop af - ld [H_DOWNARROWBLINKCNT2], a - pop af - ld [H_DOWNARROWBLINKCNT1], a - ret - -; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect -ManualTextScroll:: ; 3898 (0:3898) - ld a, [wLinkState] - cp LINK_STATE_BATTLING - jr z, .inLinkBattle - call WaitForTextScrollButtonPress - ld a, (SFX_02_40 - SFX_Headers_02) / 3 - jp PlaySound -.inLinkBattle - ld c, $41 - jp DelayFrames - -; function to do multiplication -; all values are big endian -; INPUT -; FF96-FF98 = multiplicand -; FF99 = multiplier -; OUTPUT -; FF95-FF98 = product -Multiply:: ; 38ac (0:38ac) - push hl - push bc - callab _Multiply - pop bc - pop hl - ret - -; function to do division -; all values are big endian -; INPUT -; FF95-FF98 = dividend -; FF99 = divisor -; b = number of bytes in the dividend (starting from FF95) -; OUTPUT -; FF95-FF98 = quotient -; FF99 = remainder -Divide:: ; 38b9 (0:38b9) - push hl - push de - push bc - ld a,[H_LOADEDROMBANK] - push af - ld a,Bank(_Divide) - ld [H_LOADEDROMBANK],a - ld [$2000],a - call _Divide - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - pop bc - pop de - pop hl - ret - -; This function is used to wait a short period after printing a letter to the -; screen unless the player presses the A/B button or the delay is turned off -; through the [wd730] or [wd358] flags. -PrintLetterDelay:: ; 38d3 (0:38d3) - ld a,[wd730] - bit 6,a - ret nz - ld a,[wd358] - bit 1,a - ret z - push hl - push de - push bc - ld a,[wd358] - bit 0,a - jr z,.waitOneFrame - ld a,[W_OPTIONS] - and $f - ld [H_FRAMECOUNTER],a - jr .checkButtons -.waitOneFrame - ld a,1 - ld [H_FRAMECOUNTER],a -.checkButtons - call Joypad - ld a,[hJoyHeld] -.checkAButton - bit 0,a ; is the A button pressed? - jr z,.checkBButton - jr .endWait -.checkBButton - bit 1,a ; is the B button pressed? - jr z,.buttonsNotPressed -.endWait - call DelayFrame - jr .done -.buttonsNotPressed ; if neither A nor B is pressed - ld a,[H_FRAMECOUNTER] - and a - jr nz,.checkButtons -.done - pop bc - pop de - pop hl - ret - -; Copies [hl, bc) to [de, bc - hl). -; In other words, the source data is from hl up to but not including bc, -; and the destination is de. -CopyDataUntil:: ; 3913 (0:3913) - ld a,[hli] - ld [de],a - inc de - ld a,h - cp b - jr nz,CopyDataUntil - ld a,l - cp c - jr nz,CopyDataUntil - ret - -; Function to remove a pokemon from the party or the current box. -; wWhichPokemon determines the pokemon. -; [wcf95] == 0 specifies the party. -; [wcf95] != 0 specifies the current box. -RemovePokemon:: ; 391f (0:391f) - ld hl, _RemovePokemon - ld b, BANK(_RemovePokemon) - jp Bankswitch - -AddPartyMon:: ; 3927 (0:3927) - push hl - push de - push bc - callba _AddPartyMon - pop bc - pop de - pop hl - ret - -; calculates all 5 stats of current mon and writes them to [de] -CalcStats:: ; 3936 (0:3936) - ld c, $0 -.statsLoop - inc c - call CalcStat - ld a, [H_MULTIPLICAND+1] - ld [de], a - inc de - ld a, [H_MULTIPLICAND+2] - ld [de], a - inc de - ld a, c - cp $5 - jr nz, .statsLoop - ret - -; calculates stat c of current mon -; c: stat to calc (HP=1,Atk=2,Def=3,Spd=4,Spc=5) -; b: consider stat exp? -; hl: base ptr to stat exp values ([hl + 2*c - 1] and [hl + 2*c]) -CalcStat:: ; 394a (0:394a) - push hl - push de - push bc - ld a, b - ld d, a - push hl - ld hl, W_MONHEADER - ld b, $0 - add hl, bc - ld a, [hl] ; read base value of stat - ld e, a - pop hl - push hl - sla c - ld a, d - and a - jr z, .statExpDone ; consider stat exp? - add hl, bc ; skip to corresponding stat exp value -.statExpLoop ; calculates ceil(Sqrt(stat exp)) in b - xor a - ld [H_MULTIPLICAND], a - ld [H_MULTIPLICAND+1], a - inc b ; increment current stat exp bonus - ld a, b - cp $ff - jr z, .statExpDone - ld [H_MULTIPLICAND+2], a - ld [H_MULTIPLIER], a - call Multiply - ld a, [hld] - ld d, a - ld a, [$ff98] - sub d - ld a, [hli] - ld d, a - ld a, [$ff97] - sbc d ; test if (current stat exp bonus)^2 < stat exp - jr c, .statExpLoop -.statExpDone - srl c - pop hl - push bc - ld bc, $b ; skip to stat IV values - add hl, bc - pop bc - ld a, c - cp $2 - jr z, .getAttackIV - cp $3 - jr z, .getDefenseIV - cp $4 - jr z, .getSpeedIV - cp $5 - jr z, .getSpecialIV -.getHpIV - push bc - ld a, [hl] ; Atk IV - swap a - and $1 - sla a - sla a - sla a - ld b, a - ld a, [hli] ; Def IV - and $1 - sla a - sla a - add b - ld b, a - ld a, [hl] ; Spd IV - swap a - and $1 - sla a - add b - ld b, a - ld a, [hl] ; Spc IV - and $1 - add b ; HP IV: LSB of the other 4 IVs - pop bc - jr .calcStatFromIV -.getAttackIV - ld a, [hl] - swap a - and $f - jr .calcStatFromIV -.getDefenseIV - ld a, [hl] - and $f - jr .calcStatFromIV -.getSpeedIV - inc hl - ld a, [hl] - swap a - and $f - jr .calcStatFromIV -.getSpecialIV - inc hl - ld a, [hl] - and $f -.calcStatFromIV - ld d, $0 - add e - ld e, a - jr nc, .noCarry - inc d ; de = Base + IV -.noCarry - sla e - rl d ; de = (Base + IV) * 2 - srl b - srl b ; b = ceil(Sqrt(stat exp)) / 4 - ld a, b - add e - jr nc, .noCarry2 - inc d ; da = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4 -.noCarry2 - ld [H_MULTIPLICAND+2], a - ld a, d - ld [H_MULTIPLICAND+1], a - xor a - ld [H_MULTIPLICAND], a - ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL - ld [H_MULTIPLIER], a - call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level - ld a, [H_MULTIPLICAND] - ld [H_DIVIDEND], a - ld a, [H_MULTIPLICAND+1] - ld [H_DIVIDEND+1], a - ld a, [H_MULTIPLICAND+2] - ld [H_DIVIDEND+2], a - ld a, $64 - ld [H_DIVISOR], a - ld a, $3 - ld b, a - call Divide ; (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 - ld a, c - cp $1 - ld a, $5 - jr nz, .notHPStat - ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL - ld b, a - ld a, [H_MULTIPLICAND+2] - add b - ld [H_MULTIPLICAND+2], a - jr nc, .noCarry3 - ld a, [H_MULTIPLICAND+1] - inc a - ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level -.noCarry3 - ld a, $a -.notHPStat - ld b, a - ld a, [H_MULTIPLICAND+2] - add b - ld [H_MULTIPLICAND+2], a - jr nc, .noCarry4 - ld a, [H_MULTIPLICAND+1] - inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5 - ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10 -.noCarry4 - ld a, [H_MULTIPLICAND+1] ; check for overflow (>999) - cp $4 - jr nc, .overflow - cp $3 - jr c, .noOverflow - ld a, [H_MULTIPLICAND+2] - cp $e8 - jr c, .noOverflow -.overflow - ld a, $3 ; overflow: cap at 999 - ld [H_MULTIPLICAND+1], a - ld a, $e7 - ld [H_MULTIPLICAND+2], a -.noOverflow - pop bc - pop de - pop hl - ret - -AddEnemyMonToPlayerParty:: ; 3a53 (0:3a53) - ld a, [H_LOADEDROMBANK] - push af - ld a, BANK(_AddEnemyMonToPlayerParty) - ld [H_LOADEDROMBANK], a - ld [$2000], a - call _AddEnemyMonToPlayerParty - pop bc - ld a, b - ld [H_LOADEDROMBANK], a - ld [$2000], a - ret - -Func_3a68:: ; 3a68 (0:3a68) - ld a, [H_LOADEDROMBANK] - push af - ld a, BANK(Func_f51e) - ld [H_LOADEDROMBANK], a - ld [$2000], a - call Func_f51e - pop bc - ld a, b - ld [H_LOADEDROMBANK], a - ld [$2000], a - ret - -; skips a text entries, each of size $b (like trainer name, OT name, rival name, ...) -; hl: base pointer, will be incremented by $b * a -SkipFixedLengthTextEntries:: ; 3a7d (0:3a7d) - and a - ret z - ld bc, $b -.skipLoop - add hl, bc - dec a - jr nz, .skipLoop - ret - -AddNTimes:: ; 3a87 (0:3a87) -; add bc to hl a times - and a - ret z -.loop - add hl,bc - dec a - jr nz,.loop - ret - -; Compare strings, c bytes in length, at de and hl. -; Often used to compare big endian numbers in battle calculations. -StringCmp:: ; 3a8e (0:3a8e) - ld a,[de] - cp [hl] - ret nz - inc de - inc hl - dec c - jr nz,StringCmp - ret - -; INPUT: -; a = oam block index (each block is 4 oam entries) -; b = Y coordinate of upper left corner of sprite -; c = X coordinate of upper left corner of sprite -; de = base address of 4 tile number and attribute pairs -WriteOAMBlock:: ; 3a97 (0:3a97) - ld h,wOAMBuffer / $100 - swap a ; multiply by 16 - ld l,a - call .writeOneEntry ; upper left - push bc - ld a,8 - add c - ld c,a - call .writeOneEntry ; upper right - pop bc - ld a,8 - add b - ld b,a - call .writeOneEntry ; lower left - ld a,8 - add c - ld c,a - ; lower right -.writeOneEntry - ld [hl],b ; Y coordinate - inc hl - ld [hl],c ; X coordinate - inc hl - ld a,[de] ; tile number - inc de - ld [hli],a - ld a,[de] ; attribute - inc de - ld [hli],a - ret - -HandleMenuInput:: ; 3abe (0:3abe) - xor a - ld [wd09b],a - -HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2) - ld a,[H_DOWNARROWBLINKCNT1] - push af - ld a,[H_DOWNARROWBLINKCNT2] - push af ; save existing values on stack - xor a - ld [H_DOWNARROWBLINKCNT1],a ; blinking down arrow timing value 1 - ld a,$06 - ld [H_DOWNARROWBLINKCNT2],a ; blinking down arrow timing value 2 -.loop1 - xor a - ld [wPartyMonAnimCounter],a ; counter for pokemon shaking animation - call PlaceMenuCursor - call Delay3 -.loop2 - push hl - ld a,[wd09b] - and a ; is it a pokemon selection menu? - jr z,.getJoypadState - callba AnimatePartyMon ; shake mini sprite of selected pokemon -.getJoypadState - pop hl - call JoypadLowSensitivity - ld a,[hJoy5] - and a ; was a key pressed? - jr nz,.keyPressed - push hl - hlCoord 18, 11 ; coordinates of blinking down arrow in some menus - call HandleDownArrowBlinkTiming ; blink down arrow (if any) - pop hl - ld a,[wMenuJoypadPollCount] - dec a - jr z,.giveUpWaiting - jr .loop2 -.giveUpWaiting -; if a key wasn't pressed within the specified number of checks - pop af - ld [H_DOWNARROWBLINKCNT2],a - pop af - ld [H_DOWNARROWBLINKCNT1],a ; restore previous values - xor a - ld [wMenuWrappingEnabled],a ; disable menu wrapping - ret -.keyPressed - xor a - ld [wcc4b],a - ld a,[hJoy5] - ld b,a - bit 6,a ; pressed Up key? - jr z,.checkIfDownPressed -.upPressed - ld a,[wCurrentMenuItem] ; selected menu item - and a ; already at the top of the menu? - jr z,.alreadyAtTop -.notAtTop - dec a - ld [wCurrentMenuItem],a ; move selected menu item up one space - jr .checkOtherKeys -.alreadyAtTop - ld a,[wMenuWrappingEnabled] - and a ; is wrapping around enabled? - jr z,.noWrappingAround - ld a,[wMaxMenuItem] - ld [wCurrentMenuItem],a ; wrap to the bottom of the menu - jr .checkOtherKeys -.checkIfDownPressed - bit 7,a - jr z,.checkOtherKeys -.downPressed - ld a,[wCurrentMenuItem] - inc a - ld c,a - ld a,[wMaxMenuItem] - cp c - jr nc,.notAtBottom -.alreadyAtBottom - ld a,[wMenuWrappingEnabled] - and a ; is wrapping around enabled? - jr z,.noWrappingAround - ld c,$00 ; wrap from bottom to top -.notAtBottom - ld a,c - ld [wCurrentMenuItem],a -.checkOtherKeys - ld a,[wMenuWatchedKeys] - and b ; does the menu care about any of the pressed keys? - jp z,.loop1 -.checkIfAButtonOrBButtonPressed - ld a,[hJoy5] - and A_BUTTON | B_BUTTON - jr z,.skipPlayingSound -.AButtonOrBButtonPressed - push hl - ld hl,wFlags_0xcd60 - bit 5,[hl] - pop hl - jr nz,.skipPlayingSound - ld a,(SFX_02_40 - SFX_Headers_02) / 3 - call PlaySound ; play sound -.skipPlayingSound - pop af - ld [H_DOWNARROWBLINKCNT2],a - pop af - ld [H_DOWNARROWBLINKCNT1],a ; restore previous values - xor a - ld [wMenuWrappingEnabled],a ; disable menu wrapping - ld a,[hJoy5] - ret -.noWrappingAround - ld a,[wcc37] - and a ; should we return if the user tried to go past the top or bottom? - jr z,.checkOtherKeys - jr .checkIfAButtonOrBButtonPressed - -PlaceMenuCursor:: ; 3b7c (0:3b7c) - ld a,[wTopMenuItemY] - and a ; is the y coordinate 0? - jr z,.adjustForXCoord - ld hl,wTileMap - ld bc,SCREEN_WIDTH -.topMenuItemLoop - add hl,bc - dec a - jr nz,.topMenuItemLoop -.adjustForXCoord - ld a,[wTopMenuItemX] - ld b,0 - ld c,a - add hl,bc - push hl - ld a,[wLastMenuItem] - and a ; was the previous menu id 0? - jr z,.checkForArrow1 - push af - ld a,[hFlags_0xFFF6] - bit 1,a ; is the menu double spaced? - jr z,.doubleSpaced1 - ld bc,20 - jr .getOldMenuItemScreenPosition -.doubleSpaced1 - ld bc,40 -.getOldMenuItemScreenPosition - pop af -.oldMenuItemLoop - add hl,bc - dec a - jr nz,.oldMenuItemLoop -.checkForArrow1 - ld a,[hl] - cp a,"▶" ; was an arrow next to the previously selected menu item? - jr nz,.skipClearingArrow -.clearArrow - ld a,[wTileBehindCursor] - ld [hl],a -.skipClearingArrow - pop hl - ld a,[wCurrentMenuItem] - and a - jr z,.checkForArrow2 - push af - ld a,[hFlags_0xFFF6] - bit 1,a ; is the menu double spaced? - jr z,.doubleSpaced2 - ld bc,20 - jr .getCurrentMenuItemScreenPosition -.doubleSpaced2 - ld bc,40 -.getCurrentMenuItemScreenPosition - pop af -.currentMenuItemLoop - add hl,bc - dec a - jr nz,.currentMenuItemLoop -.checkForArrow2 - ld a,[hl] - cp a,"▶" ; has the right arrow already been placed? - jr z,.skipSavingTile ; if so, don't lose the saved tile - ld [wTileBehindCursor],a ; save tile before overwriting with right arrow -.skipSavingTile - ld a,"▶" ; place right arrow - ld [hl],a - ld a,l - ld [wMenuCursorLocation],a - ld a,h - ld [wMenuCursorLocation + 1],a - ld a,[wCurrentMenuItem] - ld [wLastMenuItem],a - ret - -; This is used to mark a menu cursor other than the one currently being -; manipulated. In the case of submenus, this is used to show the location of -; the menu cursor in the parent menu. In the case of swapping items in list, -; this is used to mark the item that was first chosen to be swapped. -PlaceUnfilledArrowMenuCursor:: ; 3bec (0:3bec) - ld b,a - ld a,[wMenuCursorLocation] - ld l,a - ld a,[wMenuCursorLocation + 1] - ld h,a - ld [hl],$ec ; outline of right arrow - ld a,b - ret - -; Replaces the menu cursor with a blank space. -EraseMenuCursor:: ; 3bf9 (0:3bf9) - ld a,[wMenuCursorLocation] - ld l,a - ld a,[wMenuCursorLocation + 1] - ld h,a - ld [hl]," " - ret - -; This toggles a blinking down arrow at hl on and off after a delay has passed. -; This is often called even when no blinking is occurring. -; The reason is that most functions that call this initialize H_DOWNARROWBLINKCNT1 to 0. -; The effect is that if the tile at hl is initialized with a down arrow, -; this function will toggle that down arrow on and off, but if the tile isn't -; initliazed with a down arrow, this function does nothing. -; That allows this to be called without worrying about if a down arrow should -; be blinking. -HandleDownArrowBlinkTiming:: ; 3c04 (0:3c04) - ld a,[hl] - ld b,a - ld a,$ee ; down arrow - cp b - jr nz,.downArrowOff -.downArrowOn - ld a,[H_DOWNARROWBLINKCNT1] - dec a - ld [H_DOWNARROWBLINKCNT1],a - ret nz - ld a,[H_DOWNARROWBLINKCNT2] - dec a - ld [H_DOWNARROWBLINKCNT2],a - ret nz - ld a," " - ld [hl],a - ld a,$ff - ld [H_DOWNARROWBLINKCNT1],a - ld a,$06 - ld [H_DOWNARROWBLINKCNT2],a - ret -.downArrowOff - ld a,[H_DOWNARROWBLINKCNT1] - and a - ret z - dec a - ld [H_DOWNARROWBLINKCNT1],a - ret nz - dec a - ld [H_DOWNARROWBLINKCNT1],a - ld a,[H_DOWNARROWBLINKCNT2] - dec a - ld [H_DOWNARROWBLINKCNT2],a - ret nz - ld a,$06 - ld [H_DOWNARROWBLINKCNT2],a - ld a,$ee ; down arrow - ld [hl],a - ret - -; The following code either enables or disables the automatic drawing of -; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait -; for a button press after displaying text (unless [wcc47] is set). - -EnableAutoTextBoxDrawing:: ; 3c3c (0:3c3c) - xor a - jr AutoTextBoxDrawingCommon - -DisableAutoTextBoxDrawing:: ; 3c3f (0:3c3f) - ld a,$01 - -AutoTextBoxDrawingCommon:: ; 3c41 (0:3c41) - ld [wAutoTextBoxDrawingControl],a - xor a - ld [wDoNotWaitForButtonPressAfterDisplayingText],a ; make DisplayTextID wait for button press - ret - -PrintText:: ; 3c49 (0:3c49) -; Print text hl at (1, 14). - push hl - ld a,MESSAGE_BOX - ld [wTextBoxID],a - call DisplayTextBoxID - call UpdateSprites - call Delay3 - pop hl -Func_3c59:: ; 3c59 (0:3c59) - bcCoord 1, 14 - jp TextCommandProcessor - - -PrintNumber:: ; 3c5f -; Print the c-digit, b-byte value at de. -; Allows 2 to 7 digits. For 1-digit numbers, add -; the value to char "0" instead of calling PrintNumber. -; Flags LEADING_ZEROES and LEFT_ALIGN can be given -; in bits 7 and 6 of b respectively. -LEADING_ZEROES EQU 7 -LEFT_ALIGN EQU 6 - - push bc - xor a - ld [H_PASTLEADINGZEROES], a - ld [H_NUMTOPRINT], a - ld [H_NUMTOPRINT + 1], a - ld a, b - and $f - cp 1 - jr z, .byte - cp 2 - jr z, .word -.long - ld a, [de] - ld [H_NUMTOPRINT], a - inc de - ld a, [de] - ld [H_NUMTOPRINT + 1], a - inc de - ld a, [de] - ld [H_NUMTOPRINT + 2], a - jr .start - -.word - ld a, [de] - ld [H_NUMTOPRINT + 1], a - inc de - ld a, [de] - ld [H_NUMTOPRINT + 2], a - jr .start - -.byte - ld a, [de] - ld [H_NUMTOPRINT + 2], a - -.start - push de - - ld d, b - ld a, c - ld b, a - xor a - ld c, a - ld a, b - - cp 2 - jr z, .tens - cp 3 - jr z, .hundreds - cp 4 - jr z, .thousands - cp 5 - jr z, .ten_thousands - cp 6 - jr z, .hundred_thousands - -print_digit: macro - -if (\1) / $10000 - ld a, \1 / $10000 % $100 -else xor a -endc - ld [H_POWEROFTEN + 0], a - -if (\1) / $100 - ld a, \1 / $100 % $100 -else xor a -endc - ld [H_POWEROFTEN + 1], a - - ld a, \1 / $1 % $100 - ld [H_POWEROFTEN + 2], a - - call .PrintDigit - call .NextDigit -endm - -.millions print_digit 1000000 -.hundred_thousands print_digit 100000 -.ten_thousands print_digit 10000 -.thousands print_digit 1000 -.hundreds print_digit 100 - -.tens - ld c, 0 - ld a, [H_NUMTOPRINT + 2] -.mod - cp 10 - jr c, .ok - sub 10 - inc c - jr .mod -.ok - - ld b, a - ld a, [H_PASTLEADINGZEROES] - or c - ld [H_PASTLEADINGZEROES], a - jr nz, .past - call .PrintLeadingZero - jr .next -.past - ld a, "0" - add c - ld [hl], a -.next - - call .NextDigit -.ones - ld a, "0" - add b - ld [hli], a - pop de - dec de - pop bc - ret - -.PrintDigit: -; Divide by the current decimal place. -; Print the quotient, and keep the modulus. - ld c, 0 -.loop - ld a, [H_POWEROFTEN] - ld b, a - ld a, [H_NUMTOPRINT] - ld [H_SAVEDNUMTOPRINT], a - cp b - jr c, .underflow0 - sub b - ld [H_NUMTOPRINT], a - ld a, [H_POWEROFTEN + 1] - ld b, a - ld a, [H_NUMTOPRINT + 1] - ld [H_SAVEDNUMTOPRINT + 1], a - cp b - jr nc, .noborrow1 - - ld a, [H_NUMTOPRINT] - or 0 - jr z, .underflow1 - dec a - ld [H_NUMTOPRINT], a - ld a, [H_NUMTOPRINT + 1] -.noborrow1 - - sub b - ld [H_NUMTOPRINT + 1], a - ld a, [H_POWEROFTEN + 2] - ld b, a - ld a, [H_NUMTOPRINT + 2] - ld [H_SAVEDNUMTOPRINT + 2], a - cp b - jr nc, .noborrow2 - - ld a, [H_NUMTOPRINT + 1] - and a - jr nz, .borrowed - - ld a, [H_NUMTOPRINT] - and a - jr z, .underflow2 - dec a - ld [H_NUMTOPRINT], a - xor a -.borrowed - - dec a - ld [H_NUMTOPRINT + 1], a - ld a, [H_NUMTOPRINT + 2] -.noborrow2 - sub b - ld [H_NUMTOPRINT + 2], a - inc c - jr .loop - -.underflow2 - ld a, [H_SAVEDNUMTOPRINT + 1] - ld [H_NUMTOPRINT + 1], a -.underflow1 - ld a, [H_SAVEDNUMTOPRINT] - ld [H_NUMTOPRINT], a -.underflow0 - ld a, [H_PASTLEADINGZEROES] - or c - jr z, .PrintLeadingZero - - ld a, "0" - add c - ld [hl], a - ld [H_PASTLEADINGZEROES], a - ret - -.PrintLeadingZero: - bit LEADING_ZEROES, d - ret z - ld [hl], "0" - ret - -.NextDigit: -; Increment unless the number is left-aligned, -; leading zeroes are not printed, and no digits -; have been printed yet. - bit LEADING_ZEROES, d - jr nz, .inc - bit LEFT_ALIGN, d - jr z, .inc - ld a, [H_PASTLEADINGZEROES] - and a - ret z -.inc - inc hl - ret - - -CallFunctionInTable:: -JumpTable:: -; Call function a in jumptable hl. -; de is not preserved. - push hl - push de - push bc - add a - ld d, 0 - ld e, a - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - ld de, .returnAddress - push de - jp [hl] -.returnAddress - pop bc - pop de - pop hl - ret - - -IsInArray:: -; Search an array at hl for the value in a. -; Entry size is de bytes. -; Return count b and carry if found. - ld b, 0 - -IsInRestOfArray:: - ld c, a -.loop - ld a, [hl] - cp -1 - jr z, .notfound - cp c - jr z, .found - inc b - add hl, de - jr .loop - -.notfound - and a - ret - -.found - scf - ret - - -RestoreScreenTilesAndReloadTilePatterns:: ; 3dbe (0:3dbe) - call ClearSprites - ld a, $1 - ld [wUpdateSpritesEnabled], a - call ReloadMapSpriteTilePatterns - call LoadScreenTilesFromBuffer2 - call LoadTextBoxTilePatterns - call GoPAL_SET_CF1C - jr Delay3 - - -GBPalWhiteOutWithDelay3:: - call GBPalWhiteOut - -Delay3:: -; The bg map is updated each frame in thirds. -; Wait three frames to let the bg map fully update. - ld c, 3 - jp DelayFrames - -GBPalNormal:: -; Reset BGP and OBP0. - ld a, %11100100 ; 3210 - ld [rBGP], a - ld a, %11010000 ; 3100 - ld [rOBP0], a - ret - -GBPalWhiteOut:: -; White out all palettes. - xor a - ld [rBGP],a - ld [rOBP0],a - ld [rOBP1],a - ret - - -GoPAL_SET_CF1C:: ; 3ded (0:3ded) - ld b,$ff -GoPAL_SET:: ; 3def (0:3def) - ld a,[wOnSGB] - and a - ret z - predef_jump Func_71ddf - -GetHealthBarColor:: -; Return at hl the palette of -; an HP bar e pixels long. - ld a, e - cp 27 - ld d, 0 ; green - jr nc, .gotColor - cp 10 - inc d ; yellow - jr nc, .gotColor - inc d ; red -.gotColor - ld [hl], d - ret - -; Copy the current map's sprites' tile patterns to VRAM again after they have -; been overwritten by other tile patterns. -ReloadMapSpriteTilePatterns:: ; 3e08 (0:3e08) - ld hl, wFontLoaded - ld a, [hl] - push af - res 0, [hl] - push hl - xor a - ld [W_SPRITESETID], a - call DisableLCD - callba InitMapSprites - call EnableLCD - pop hl - pop af - ld [hl], a - call LoadPlayerSpriteGraphics - call LoadFontTilePatterns - jp UpdateSprites - - -GiveItem:: -; Give player quantity c of item b, -; and copy the item's name to wcf4b. -; Return carry on success. - ld a, b - ld [wd11e], a - ld [wcf91], a - ld a, c - ld [wcf96], a - ld hl,wNumBagItems - call AddItemToInventory - ret nc - call GetItemName - call CopyStringToCF4B - scf - ret - -GivePokemon:: -; Give the player monster b at level c. - ld a, b - ld [wcf91], a - ld a, c - ld [W_CURENEMYLVL], a - xor a - ld [wcc49], a - ld b, BANK(_GivePokemon) - ld hl, _GivePokemon - jp Bankswitch - - -Random:: -; Return a random number in a. -; For battles, use BattleRandom. - push hl - push de - push bc - callba Random_ - ld a, [hRandomAdd] - pop bc - pop de - pop hl - ret - - -INCLUDE "home/predef.asm" - - -Func_3ead:: ; 3ead (0:3ead) - ld b, BANK(CinnabarGymQuiz_1eb0a) - ld hl, CinnabarGymQuiz_1eb0a - jp Bankswitch - -CheckForHiddenObjectOrBookshelfOrCardKeyDoor:: ; 3eb5 (0:3eb5) - ld a, [H_LOADEDROMBANK] - push af - ld a, [hJoyHeld] - bit 0, a ; A button - jr z, .nothingFound -; A button is pressed - ld a, Bank(CheckForHiddenObject) - ld [MBC1RomBank], a - ld [H_LOADEDROMBANK], a - call CheckForHiddenObject - ld a, [$ffee] - and a - jr nz, .hiddenObjectNotFound - ld a, [wHiddenObjectFunctionRomBank] - ld [MBC1RomBank], a - ld [H_LOADEDROMBANK], a - ld de, .returnAddress - push de - jp [hl] -.returnAddress - xor a - jr .done -.hiddenObjectNotFound - callba PrintBookshelfText - ld a, [$ffdb] - and a - jr z, .done -.nothingFound - ld a, $ff -.done - ld [$ffeb], a - pop af - ld [MBC1RomBank], a - ld [H_LOADEDROMBANK], a - ret - -PrintPredefTextID:: ; 3ef5 (0:3ef5) - ld [H_DOWNARROWBLINKCNT2], a ; $ff8c - ld hl, TextPredefs - call SetMapTextPointer - ld hl, wcf11 - set 0, [hl] - call DisplayTextID - -RestoreMapTextPointer:: ; 3f05 (0:3f05) - ld hl, W_MAPTEXTPTR - ld a, [$ffec] - ld [hli], a - ld a, [$ffec + 1] - ld [hl], a - ret - -SetMapTextPointer:: ; 3f0f (0:3f0f) - ld a, [W_MAPTEXTPTR] - ld [$ffec], a - ld a, [W_MAPTEXTPTR + 1] - ld [$ffec + 1], a - ld a, l - ld [W_MAPTEXTPTR], a - ld a, h - ld [W_MAPTEXTPTR + 1], a - ret - -TextPredefs:: - add_tx_pre CardKeySuccessText ; 01 - add_tx_pre CardKeyFailText ; 02 - add_tx_pre RedBedroomPC ; 03 - add_tx_pre RedBedroomSNESText ; 04 - add_tx_pre PushStartText ; 05 - add_tx_pre SaveOptionText ; 06 - add_tx_pre StrengthsAndWeaknessesText ; 07 - add_tx_pre OakLabEmailText ; 08 - add_tx_pre AerodactylFossilText ; 09 - add_tx_pre Route15UpstairsBinocularsText ; 0A - add_tx_pre KabutopsFossilText ; 0B - add_tx_pre GymStatueText1 ; 0C - add_tx_pre GymStatueText2 ; 0D - add_tx_pre BookcaseText ; 0E - add_tx_pre ViridianCityPokecenterBenchGuyText ; 0F - add_tx_pre PewterCityPokecenterBenchGuyText ; 10 - add_tx_pre CeruleanCityPokecenterBenchGuyText ; 11 - add_tx_pre LavenderCityPokecenterBenchGuyText ; 12 - add_tx_pre VermilionCityPokecenterBenchGuyText ; 13 - add_tx_pre CeladonCityPokecenterBenchGuyText ; 14 - add_tx_pre CeladonCityHotelText ; 15 - add_tx_pre FuchsiaCityPokecenterBenchGuyText ; 16 - add_tx_pre CinnabarIslandPokecenterBenchGuyText ; 17 - add_tx_pre SaffronCityPokecenterBenchGuyText ; 18 - add_tx_pre MtMoonPokecenterBenchGuyText ; 19 - add_tx_pre RockTunnelPokecenterBenchGuyText ; 1A - add_tx_pre UnusedBenchGuyText1 ; 1B - add_tx_pre UnusedBenchGuyText2 ; 1C - add_tx_pre UnusedBenchGuyText3 ; 1D - add_tx_pre TerminatorText_62508 ; 1E - add_tx_pre PredefText1f ; 1F - add_tx_pre ViridianSchoolNotebook ; 20 - add_tx_pre ViridianSchoolBlackboard ; 21 - add_tx_pre JustAMomentText ; 22 - add_tx_pre PredefText23 ; 23 - add_tx_pre FoundHiddenItemText ; 24 - add_tx_pre HiddenItemBagFullText ; 25 - add_tx_pre VermilionGymTrashText ; 26 - add_tx_pre IndigoPlateauHQText ; 27 - add_tx_pre GameCornerOutOfOrderText ; 28 - add_tx_pre GameCornerOutToLunchText ; 29 - add_tx_pre GameCornerSomeonesKeysText ; 2A - add_tx_pre FoundHiddenCoinsText ; 2B - add_tx_pre DroppedHiddenCoinsText ; 2C - add_tx_pre BillsHouseMonitorText ; 2D - add_tx_pre BillsHouseInitiatedText ; 2E - add_tx_pre BillsHousePokemonList ; 2F - add_tx_pre MagazinesText ; 30 - add_tx_pre CinnabarGymQuiz ; 31 - add_tx_pre GameCornerNoCoinsText ; 32 - add_tx_pre GameCornerCoinCaseText ; 33 - add_tx_pre LinkCableHelp ; 34 - add_tx_pre TMNotebook ; 35 - add_tx_pre FightingDojoText ; 36 - add_tx_pre FightingDojoText_52a10 ; 37 - add_tx_pre FightingDojoText_52a1d ; 38 - add_tx_pre NewBicycleText ; 39 - add_tx_pre IndigoPlateauStatues ; 3A - add_tx_pre VermilionGymTrashSuccesText1 ; 3B - add_tx_pre VermilionGymTrashSuccesText2 ; 3C - add_tx_pre VermilionGymTrashSuccesText3 ; 3D - add_tx_pre VermilionGymTrashFailText ; 3E - add_tx_pre TownMapText ; 3F - add_tx_pre BookOrSculptureText ; 40 - add_tx_pre ElevatorText ; 41 - add_tx_pre PokemonStuffText ; 42 +
+; The rst vectors are unused.
+SECTION "rst 00", ROM0 [$00]
+ rst $38
+SECTION "rst 08", ROM0 [$08]
+ rst $38
+SECTION "rst 10", ROM0 [$10]
+ rst $38
+SECTION "rst 18", ROM0 [$18]
+ rst $38
+SECTION "rst 20", ROM0 [$20]
+ rst $38
+SECTION "rst 28", ROM0 [$28]
+ rst $38
+SECTION "rst 30", ROM0 [$30]
+ rst $38
+SECTION "rst 38", ROM0 [$38]
+ rst $38
+
+; Hardware interrupts
+SECTION "vblank", ROM0 [$40]
+ jp VBlank
+SECTION "hblank", ROM0 [$48]
+ rst $38
+SECTION "timer", ROM0 [$50]
+ jp Timer
+SECTION "serial", ROM0 [$58]
+ jp Serial
+SECTION "joypad", ROM0 [$60]
+ reti
+
+
+SECTION "Home", ROM0
+
+DisableLCD::
+ xor a
+ ld [rIF], a
+ ld a, [rIE]
+ ld b, a
+ res 0, a
+ ld [rIE], a
+
+.wait
+ ld a, [rLY]
+ cp LY_VBLANK
+ jr nz, .wait
+
+ ld a, [rLCDC]
+ and $ff ^ rLCDC_ENABLE_MASK
+ ld [rLCDC], a
+ ld a, b
+ ld [rIE], a
+ ret
+
+EnableLCD::
+ ld a, [rLCDC]
+ set rLCDC_ENABLE, a
+ ld [rLCDC], a
+ ret
+
+ClearSprites::
+ xor a
+ ld hl, wOAMBuffer
+ ld b, 40 * 4
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+HideSprites::
+ ld a, 160
+ ld hl, wOAMBuffer
+ ld de, 4
+ ld b, 40
+.loop
+ ld [hl], a
+ add hl, de
+ dec b
+ jr nz, .loop
+ ret
+
+INCLUDE "home/copy.asm"
+
+
+
+SECTION "Entry", ROM0 [$100]
+
+ nop
+ jp Start ; 01ab
+
+
+SECTION "Header", ROM0 [$104]
+
+ ; The header is generated by rgbfix.
+ ; The space here is allocated to prevent code from being overwritten.
+
+ ds $150 - $104
+
+
+
+SECTION "Main", ROM0
+
+Func_150:: ; 0150 (0:0150)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,b
+ call BankswitchCommon
+ ld a,[hli]
+ ld c,a
+ ld a,[hli]
+ ld b,a
+.loop
+ ld a,[hli]
+ ld d,a
+ ld a,$3
+.unknownloop
+ dec a
+ jr nz,.unknownloop
+
+ rept 7
+ call Func_199
+ call Func_1a5
+ endr
+
+ call Func_199
+ dec bc
+ ld a,c
+ or b
+ jr nz,.loop
+ pop af
+ call BankswitchCommon
+ ret
+
+Func_199:: ; 0199 (0:0199)
+ ld a,d
+ and $80
+ srl a
+ srl a
+ ld [rNR32],a
+ sla d
+ ret
+
+Func_1a5:: ; 01a5 (0:01a5)
+ ld a,$3
+.unknownloop2
+ dec a
+ jr nz,.unknownloop2
+ ret
+
+Start::
+ cp GBC
+ jr z, .gbc
+ xor a
+ jr .ok
+.gbc
+ ld a, $1
+.ok
+ ld [hGBC], a
+ jp Init
+
+Joypad:: ; 01b9
+ homecall_jump _Joypad
+
+ReadJoypad:: ; 01c8 (0:01c8)
+ homecall_jump ReadJoypad_
+
+INCLUDE "data/map_header_pointers.asm"
+INCLUDE "home/overworld.asm"
+
+
+CheckForUserInterruption:: ; 12f8 (0:12f8)
+; Return carry if Up+Select+B, Start or A are pressed in c frames.
+; Used only in the intro and title screen.
+ call DelayFrame
+
+ push bc
+ call JoypadLowSensitivity
+ pop bc
+
+ ld a, [hJoyHeld]
+ cp D_UP + SELECT + B_BUTTON
+ jr z, .input
+
+ ld a, [hJoy5]
+ and START | A_BUTTON
+ jr nz, .input
+
+ dec c
+ jr nz, CheckForUserInterruption
+
+ and a
+ ret
+
+.input
+ scf
+ ret
+
+; function to load position data for destination warp when switching maps
+; INPUT:
+; a = ID of destination warp within destination map
+LoadDestinationWarpPosition:: ; 1313 (0:1313)
+ ld b,a
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[wPredefParentBank]
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ld a,b
+ add a
+ add a
+ ld c,a
+ ld b,0
+ add hl,bc
+ ld bc,4
+ ld de,wCurrentTileBlockMapViewPointer
+ call CopyData
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+
+DrawHPBar:: ; 1336 (0:1336)
+; Draw an HP bar d tiles long, and fill it to e pixels.
+; If c is nonzero, show at least a sliver regardless.
+; The right end of the bar changes with [wHPBarType].
+
+ push hl
+ push de
+ push bc
+
+ ; Left
+ ld a, $71 ; "HP:"
+ ld [hli], a
+ ld a, $62
+ ld [hli], a
+
+ push hl
+
+ ; Middle
+ ld a, $63 ; empty
+.draw
+ ld [hli],a
+ dec d
+ jr nz, .draw
+
+ ; Right
+ ld a,[wHPBarType]
+ dec a
+ ld a, $6d ; status screen and battle
+ jr z, .ok
+ dec a ; pokemon menu
+.ok
+ ld [hl],a
+
+ pop hl
+
+ ld a, e
+ and a
+ jr nz, .fill
+
+ ; If c iz nonzero, draw a pixel anyway.
+ ld a, c
+ and a
+ jr z, .done
+ ld e, 1
+
+.fill
+ ld a, e
+ sub 8
+ jr c, .partial
+ ld e, a
+ ld a, $6b ; full
+ ld [hli], a
+ ld a, e
+ and a
+ jr z, .done
+ jr .fill
+
+.partial
+ ; Fill remaining pixels at the end if necessary.
+ ld a, $63 ; empty
+ add e
+ ld [hl], a
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+; loads pokemon data from one of multiple sources to wLoadedMon
+; loads base stats to W_MONHDEXNUM
+; INPUT:
+; [wWhichPokemon] = index of pokemon within party/box
+; [wcc49] = source
+; 00: player's party
+; 01: enemy's party
+; 02: current box
+; 03: daycare
+; OUTPUT:
+; [wcf91] = pokemon ID
+; wLoadedMon = base address of pokemon data
+; W_MONHDEXNUM = base address of base stats
+LoadMonData:: ; 1372 (0:1372)
+ ld hl, LoadMonData_
+ ld b, BANK(LoadMonData_)
+ jp Bankswitch
+
+
+Func_137a:: ; 137a (0:137a)
+; Write c to [wMoves + b]. Unused.
+ ld hl, wMoves
+ ld e, b
+ ld d, 0
+ add hl, de
+ ld a, c
+ ld [hl], a
+ ret
+
+LoadFlippedFrontSpriteByMonIndex:: ; 1384 (0:1384)
+ ld a, 1
+ ld [W_SPRITEFLIPPED], a
+
+LoadFrontSpriteByMonIndex:: ; 1389 (0:1389)
+ push hl
+ ld a, [wd11e]
+ push af
+ ld a, [wcf91]
+ ld [wd11e], a
+ predef IndexToPokedex
+ ld hl, wd11e
+ ld a, [hl]
+ pop bc
+ ld [hl], b
+ and a
+ pop hl
+ jr z, .invalidDexNumber ; dex #0 invalid
+ cp NUM_POKEMON + 1
+ jr c, .validDexNumber ; dex >#151 invalid
+.invalidDexNumber
+ ld a, RHYDON ; $1
+ ld [wcf91], a
+ ret
+.validDexNumber
+ push hl
+ ld de, vFrontPic
+ call LoadMonFrontSprite
+ pop hl
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, Bank(asm_3f0d0)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ xor a
+ ld [$ffe1], a
+ call asm_3f0d0
+ xor a
+ ld [W_SPRITEFLIPPED], a
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+
+PlayCry:: ; 13d0 (0:13d0)
+; Play monster a's cry.
+ call GetCryData
+ call PlaySound
+ jp WaitForSoundToFinish
+
+GetCryData:: ; 13d9 (0:13d9)
+; Load cry data for monster a.
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, CryData
+ add hl, bc
+ add hl, bc
+ add hl, bc
+
+ ld a, Bank(CryData)
+ call BankswitchHome
+ ld a, [hli]
+ ld b, a ; cry id
+ ld a, [hli]
+ ld [wc0f1], a
+ ld a, [hl]
+ ld [wc0f2], a
+ call BankswitchBack
+
+ ; Cry headers have 3 channels,
+ ; and start from index $14,
+ ; so add 3 times the cry id.
+ ld a, b
+ ld c, $14
+ rlca ; * 2
+ add b
+ add c
+ ret
+
+
+DisplayPartyMenu:: ; 13fc (0:13fc)
+ ld a,[hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType],a
+ call GBPalWhiteOutWithDelay3
+ call ClearSprites
+ call PartyMenuInit
+ call DrawPartyMenu
+ jp HandlePartyMenuInput
+
+GoBackToPartyMenu:: ; 1411 (0:1411)
+ ld a,[hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType],a
+ call PartyMenuInit
+ call RedrawPartyMenu
+ jp HandlePartyMenuInput
+
+PartyMenuInit:: ; 1420 (0:1420)
+ ld a, 1 ; hardcoded bank
+ call BankswitchHome
+ call LoadHpBarAndStatusTilePatterns
+ ld hl, wd730
+ set 6, [hl] ; turn off letter printing delay
+ xor a
+ ld [wcc49], a
+ ld [wcc37], a
+ ld hl, wTopMenuItemY
+ inc a
+ ld [hli], a ; top menu item Y
+ xor a
+ ld [hli], a ; top menu item X
+ ld a, [wcc2b]
+ push af
+ ld [hli], a ; current menu item ID
+ inc hl
+ ld a, [wPartyCount]
+ and a ; are there more than 0 pokemon in the party?
+ jr z, .storeMaxMenuItemID
+ dec a
+; if party is not empty, the max menu item ID is ([wPartyCount] - 1)
+; otherwise, it is 0
+.storeMaxMenuItemID
+ ld [hli], a ; max menu item ID
+ ld a, [wd11f]
+ and a
+ ld a, A_BUTTON + B_BUTTON
+ jr z, .next
+ xor a
+ ld [wd11f], a
+ inc a
+.next
+ ld [hli], a ; menu watched keys
+ pop af
+ ld [hl], a ; old menu item ID
+ ret
+
+HandlePartyMenuInput:: ; 145a (0:145a)
+ ld a,1
+ ld [wMenuWrappingEnabled],a
+ ld a,$40
+ ld [wd09b],a
+ call HandleMenuInputPokemonSelection
+ call PlaceUnfilledArrowMenuCursor
+ ld b,a
+ xor a
+ ld [wd09b],a
+ ld a,[wCurrentMenuItem]
+ ld [wcc2b],a
+ ld hl,wd730
+ res 6,[hl] ; turn on letter printing delay
+ ld a,[wMenuItemToSwap]
+ and a
+ jp nz,.swappingPokemon
+ pop af
+ ld [hTilesetType],a
+ bit 1,b
+ jr nz,.noPokemonChosen
+ ld a,[wPartyCount]
+ and a
+ jr z,.noPokemonChosen
+ ld a,[wCurrentMenuItem]
+ ld [wWhichPokemon],a
+ ld hl,wPartySpecies
+ ld b,0
+ ld c,a
+ add hl,bc
+ ld a,[hl]
+ ld [wcf91],a
+ ld [wBattleMonSpecies2],a
+ call BankswitchBack
+ and a
+ ret
+.noPokemonChosen
+ call BankswitchBack
+ scf
+ ret
+.swappingPokemon
+ bit 1,b ; was the B button pressed?
+ jr z,.handleSwap ; if not, handle swapping the pokemon
+.cancelSwap ; if the B button was pressed
+ callba ErasePartyMenuCursors
+ xor a
+ ld [wMenuItemToSwap],a
+ ld [wd07d],a
+ call RedrawPartyMenu
+ jr HandlePartyMenuInput
+.handleSwap
+ ld a,[wCurrentMenuItem]
+ ld [wWhichPokemon],a
+ callba SwitchPartyMon
+ jr HandlePartyMenuInput
+
+DrawPartyMenu:: ; 14d4 (0:14d4)
+ ld hl, DrawPartyMenu_
+ jr DrawPartyMenuCommon
+
+RedrawPartyMenu:: ; 14d9 (0:14d9)
+ ld hl, RedrawPartyMenu_
+
+DrawPartyMenuCommon:: ; 14dc (0:14dc)
+ ld b, BANK(RedrawPartyMenu_)
+ jp Bankswitch
+
+; prints a pokemon's status condition
+; INPUT:
+; de = address of status condition
+; hl = destination address
+PrintStatusCondition:: ; 14e1 (0:14e1)
+ push de
+ dec de
+ dec de ; de = address of current HP
+ ld a,[de]
+ ld b,a
+ dec de
+ ld a,[de]
+ or b ; is the pokemon's HP zero?
+ pop de
+ jr nz,PrintStatusConditionNotFainted
+; if the pokemon's HP is 0, print "FNT"
+ ld a,"F"
+ ld [hli],a
+ ld a,"N"
+ ld [hli],a
+ ld [hl],"T"
+ and a
+ ret
+PrintStatusConditionNotFainted ; 14f6
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(PrintStatusAilment)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call PrintStatusAilment ; print status condition
+ pop bc
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; function to print pokemon level, leaving off the ":L" if the level is at least 100
+; INPUT:
+; hl = destination address
+; [wLoadedMonLevel] = level
+PrintLevel:: ; 150b (0:150b)
+ ld a,$6e ; ":L" tile ID
+ ld [hli],a
+ ld c,2 ; number of digits
+ ld a,[wLoadedMonLevel] ; level
+ cp a,100
+ jr c,PrintLevelCommon
+; if level at least 100, write over the ":L" tile
+ dec hl
+ inc c ; increment number of digits to 3
+ jr PrintLevelCommon
+
+; prints the level without leaving off ":L" regardless of level
+; INPUT:
+; hl = destination address
+; [wLoadedMonLevel] = level
+PrintLevelFull:: ; 151b (0:151b)
+ ld a,$6e ; ":L" tile ID
+ ld [hli],a
+ ld c,3 ; number of digits
+ ld a,[wLoadedMonLevel] ; level
+
+PrintLevelCommon:: ; 1523 (0:1523)
+ ld [wd11e],a
+ ld de,wd11e
+ ld b,$41 ; no leading zeroes, left-aligned, one byte
+ jp PrintNumber
+
+Func_152e:: ; 152e (0:152e)
+; Unused.
+ ld hl,wMoves
+ ld c,a
+ ld b,0
+ add hl,bc
+ ld a,[hl]
+ ret
+
+; copies the base stat data of a pokemon to W_MONHDEXNUM (W_MONHEADER)
+; INPUT:
+; [wd0b5] = pokemon ID
+GetMonHeader:: ; 1537 (0:1537)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(BaseStats)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ push bc
+ push de
+ push hl
+ ld a,[wd11e]
+ push af
+ ld a,[wd0b5]
+ ld [wd11e],a
+ ld de,FossilKabutopsPic
+ ld b,$66 ; size of Kabutops fossil and Ghost sprites
+ cp a,FOSSIL_KABUTOPS ; Kabutops fossil
+ jr z,.specialID
+ ld de,GhostPic
+ cp a,MON_GHOST ; Ghost
+ jr z,.specialID
+ ld de,FossilAerodactylPic
+ ld b,$77 ; size of Aerodactyl fossil sprite
+ cp a,FOSSIL_AERODACTYL ; Aerodactyl fossil
+ jr z,.specialID
+ cp a,MEW
+ jr z,.mew
+ predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number
+ ld a,[wd11e]
+ dec a
+ ld bc,28
+ ld hl,BaseStats
+ call AddNTimes
+ ld de,W_MONHEADER
+ ld bc,28
+ call CopyData
+ jr .done
+.specialID
+ ld hl,W_MONHSPRITEDIM
+ ld [hl],b ; write sprite dimensions
+ inc hl
+ ld [hl],e ; write front sprite pointer
+ inc hl
+ ld [hl],d
+ jr .done
+.mew
+ ld hl,MewBaseStats
+ ld de,W_MONHEADER
+ ld bc,28
+ ld a,BANK(MewBaseStats)
+ call FarCopyData
+.done
+ ld a,[wd0b5]
+ ld [W_MONHDEXNUM],a
+ pop af
+ ld [wd11e],a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; copy party pokemon's name to wcd6d
+GetPartyMonName2:: ; 15b4 (0:15b4)
+ ld a,[wWhichPokemon] ; index within party
+ ld hl,wPartyMonNicks
+
+; this is called more often
+GetPartyMonName:: ; 15ba (0:15ba)
+ push hl
+ push bc
+ call SkipFixedLengthTextEntries ; add 11 to hl, a times
+ ld de,wcd6d
+ push de
+ ld bc,11
+ call CopyData
+ pop de
+ pop bc
+ pop hl
+ ret
+
+; function to print a BCD (Binary-coded decimal) number
+; de = address of BCD number
+; hl = destination address
+; c = flags and length
+; bit 7: if set, do not print leading zeroes
+; if unset, print leading zeroes
+; bit 6: if set, left-align the string (do not pad empty digits with spaces)
+; if unset, right-align the string
+; bit 5: if set, print currency symbol at the beginning of the string
+; if unset, do not print the currency symbol
+; bits 0-4: length of BCD number in bytes
+; Note that bits 5 and 7 are modified during execution. The above reflects
+; their meaning at the beginning of the functions's execution.
+PrintBCDNumber:: ; 15cd (0:15cd)
+ ld b,c ; save flags in b
+ res 7,c
+ res 6,c
+ res 5,c ; c now holds the length
+ bit 5,b
+ jr z,.loop
+ bit 7,b
+ jr nz,.loop
+ ld [hl],"¥"
+ inc hl
+.loop
+ ld a,[de]
+ swap a
+ call PrintBCDDigit ; print upper digit
+ ld a,[de]
+ call PrintBCDDigit ; print lower digit
+ inc de
+ dec c
+ jr nz,.loop
+ bit 7,b ; were any non-zero digits printed?
+ jr z,.done ; if so, we are done
+.numberEqualsZero ; if every digit of the BCD number is zero
+ bit 6,b ; left or right alignment?
+ jr nz,.skipRightAlignmentAdjustment
+ dec hl ; if the string is right-aligned, it needs to be moved back one space
+.skipRightAlignmentAdjustment
+ bit 5,b
+ jr z,.skipCurrencySymbol
+ ld [hl],"¥"
+ inc hl
+.skipCurrencySymbol
+ ld [hl],"0"
+ call PrintLetterDelay
+ inc hl
+.done
+ ret
+
+PrintBCDDigit:: ; 1604 (0:1604)
+ and $f
+ and a
+ jr z,.zeroDigit
+.nonzeroDigit
+ bit 7,b ; have any non-space characters been printed?
+ jr z,.outputDigit
+; if bit 7 is set, then no numbers have been printed yet
+ bit 5,b ; print the currency symbol?
+ jr z,.skipCurrencySymbol
+ ld [hl],"¥"
+ inc hl
+ res 5,b
+.skipCurrencySymbol
+ res 7,b ; unset 7 to indicate that a nonzero digit has been reached
+.outputDigit
+ add a,"0"
+ ld [hli],a
+ jp PrintLetterDelay
+.zeroDigit
+ bit 7,b ; either printing leading zeroes or already reached a nonzero digit?
+ jr z,.outputDigit ; if so, print a zero digit
+ bit 6,b ; left or right alignment?
+ ret nz
+ inc hl ; if right-aligned, "print" a space by advancing the pointer
+ ret
+
+; uncompresses the front or back sprite of the specified mon
+; assumes the corresponding mon header is already loaded
+; hl contains offset to sprite pointer ($b for front or $d for back)
+UncompressMonSprite:: ; 1627 (0:1627)
+ ld bc,W_MONHEADER
+ add hl,bc
+ ld a,[hli]
+ ld [W_SPRITEINPUTPTR],a ; fetch sprite input pointer
+ ld a,[hl]
+ ld [W_SPRITEINPUTPTR+1],a
+; define (by index number) the bank that a pokemon's image is in
+; index = Mew, bank 1
+; index = Kabutops fossil, bank $B
+; index < $1F, bank 9
+; $1F ≤ index < $4A, bank $A
+; $4A ≤ index < $74, bank $B
+; $74 ≤ index < $99, bank $C
+; $99 ≤ index, bank $D
+ ld a,[wcf91] ; XXX name for this ram location
+ ld b,a
+ cp MEW
+ ld a,BANK(MewPicFront)
+ jr z,.GotBank
+ ld a,b
+ cp FOSSIL_KABUTOPS
+ ld a,BANK(FossilKabutopsPic)
+ jr z,.GotBank
+ ld a,b
+ cp TANGELA + 1
+ ld a,BANK(TangelaPicFront)
+ jr c,.GotBank
+ ld a,b
+ cp MOLTRES + 1
+ ld a,BANK(MoltresPicFront)
+ jr c,.GotBank
+ ld a,b
+ cp BEEDRILL + 2
+ ld a,BANK(BeedrillPicFront)
+ jr c,.GotBank
+ ld a,b
+ cp STARMIE + 1
+ ld a,BANK(StarmiePicFront)
+ jr c,.GotBank
+ ld a,BANK(VictreebelPicFront)
+.GotBank
+ jp UncompressSpriteData
+
+; de: destination location
+LoadMonFrontSprite:: ; 1665 (0:1665)
+ push de
+ ld hl, W_MONHFRONTSPRITE - W_MONHEADER
+ call UncompressMonSprite
+ ld hl, W_MONHSPRITEDIM
+ ld a, [hli]
+ ld c, a
+ pop de
+ ; fall through
+
+; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram
+; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers
+; de: destination location
+; a,c: sprite dimensions (in tiles of 8x8 each)
+LoadUncompressedSpriteData:: ; 1672 (0:1672)
+ push de
+ and $f
+ ld [H_SPRITEWIDTH], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
+ ld b, a
+ ld a, $7
+ sub b ; 7-w
+ inc a ; 8-w
+ srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up)
+ ld b, a
+ add a
+ add a
+ add a
+ sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles)
+ ld [H_SPRITEOFFSET], a
+ ld a, c
+ swap a
+ and $f
+ ld b, a
+ add a
+ add a
+ add a ; 8*tiles is height in bytes
+ ld [H_SPRITEHEIGHT], a ; $ff8c
+ ld a, $7
+ sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
+ ld b, a
+ ld a, [H_SPRITEOFFSET]
+ add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles)
+ add a
+ add a
+ add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes)
+ ld [H_SPRITEOFFSET], a
+ xor a
+ ld [$4000], a
+ ld hl, S_SPRITEBUFFER0
+ call ZeroSpriteBuffer ; zero buffer 0
+ ld de, S_SPRITEBUFFER1
+ ld hl, S_SPRITEBUFFER0
+ call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
+ ld hl, S_SPRITEBUFFER1
+ call ZeroSpriteBuffer ; zero buffer 1
+ ld de, S_SPRITEBUFFER2
+ ld hl, S_SPRITEBUFFER1
+ call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
+ pop de
+ jp InterlaceMergeSpriteBuffers
+
+; copies and aligns the sprite data properly inside the sprite buffer
+; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area
+AlignSpriteDataCentered:: ; 16c2 (0:16c2)
+ ld a, [H_SPRITEOFFSET]
+ ld b, $0
+ ld c, a
+ add hl, bc
+ ld a, [H_SPRITEWIDTH] ; $ff8b
+.columnLoop
+ push af
+ push hl
+ ld a, [H_SPRITEHEIGHT] ; $ff8c
+ ld c, a
+.columnInnerLoop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .columnInnerLoop
+ pop hl
+ ld bc, 7*8 ; 7 tiles
+ add hl, bc ; advance one full column
+ pop af
+ dec a
+ jr nz, .columnLoop
+ ret
+
+; fills the sprite buffer (pointed to in hl) with zeros
+ZeroSpriteBuffer:: ; 16df (0:16df)
+ ld bc, SPRITEBUFFERSIZE
+.nextByteLoop
+ xor a
+ ld [hli], a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .nextByteLoop
+ ret
+
+; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2
+; in the resulting sprite, the rows of the two source sprites are interlaced
+; de: output address
+InterlaceMergeSpriteBuffers:: ; 16ea (0:16ea)
+ xor a
+ ld [$4000], a
+ push de
+ ld hl, S_SPRITEBUFFER2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
+ ld de, S_SPRITEBUFFER1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
+ ld bc, S_SPRITEBUFFER0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
+ ld a, SPRITEBUFFERSIZE/2 ; $c4
+ ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b
+.interlaceLoop
+ ld a, [de]
+ dec de
+ ld [hld], a ; write byte of source 2
+ ld a, [bc]
+ dec bc
+ ld [hld], a ; write byte of source 1
+ ld a, [de]
+ dec de
+ ld [hld], a ; write byte of source 2
+ ld a, [bc]
+ dec bc
+ ld [hld], a ; write byte of source 1
+ ld a, [H_SPRITEINTERLACECOUNTER] ; $ff8b
+ dec a
+ ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b
+ jr nz, .interlaceLoop
+ ld a, [W_SPRITEFLIPPED]
+ and a
+ jr z, .notFlipped
+ ld bc, 2*SPRITEBUFFERSIZE
+ ld hl, S_SPRITEBUFFER1
+.swapLoop
+ swap [hl] ; if flipped swap nybbles in all bytes
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .swapLoop
+.notFlipped
+ pop hl
+ ld de, S_SPRITEBUFFER1
+ ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
+ ld a, [H_LOADEDROMBANK]
+ ld b, a
+ jp CopyVideoData
+
+
+INCLUDE "data/collision.asm"
+
+IsTilePassable:: ; 15c3 (0:15c3)
+; sets carry if tile is passable, resets carry otherwise
+ homecall_sf _IsTilePassable ; 1:4aaa
+ ret
+
+INCLUDE "home/copy2.asm"
+INCLUDE "home/text.asm"
+INCLUDE "home/vcopy.asm"
+INCLUDE "home/init.asm"
+INCLUDE "home/vblank.asm"
+INCLUDE "home/fade.asm"
+INCLUDE "home/serial.asm"
+INCLUDE "home/timer.asm"
+INCLUDE "home/audio.asm"
+
+
+UpdateSprites:: ; 2429 (0:2429)
+ ld a, [wUpdateSpritesEnabled]
+ dec a
+ ret nz
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, Bank(_UpdateSprites)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ call _UpdateSprites
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+INCLUDE "data/mart_inventories.asm"
+
+TextScriptEndingChar:: ; 24d6 (0:24d6)
+ db "@"
+TextScriptEnd:: ; 24d7 (0:24d7)
+ ld hl,TextScriptEndingChar
+ ret
+
+ExclamationText:: ; 24db (0:24db)
+ TX_FAR _ExclamationText
+ db "@"
+
+GroundRoseText:: ; 24e0 (0:24e0)
+ TX_FAR _GroundRoseText
+ db "@"
+
+BoulderText:: ; 24e5 (0:24e5)
+ TX_FAR _BoulderText
+ db "@"
+
+MartSignText:: ; 24ea (0:24ea)
+ TX_FAR _MartSignText
+ db "@"
+
+PokeCenterSignText:: ; 24ef (0:24ef)
+ TX_FAR _PokeCenterSignText
+ db "@"
+
+Predef5CText:: ; 24f4 (0:24f4)
+; XXX better label (what does predef $5C do?)
+ db $08 ; asm
+ predef PickupItem
+ jp TextScriptEnd
+
+
+INCLUDE "home/pic.asm"
+
+
+ResetPlayerSpriteData:: ; 28a6 (0:28a6)
+ ld hl, wSpriteStateData1
+ call ResetPlayerSpriteData_ClearSpriteData
+ ld hl, wSpriteStateData2
+ call ResetPlayerSpriteData_ClearSpriteData
+ ld a, $1
+ ld [wSpriteStateData1], a
+ ld [wSpriteStateData2 + $0e], a
+ ld hl, wSpriteStateData1 + 4
+ ld [hl], $3c ; set Y screen pos
+ inc hl
+ inc hl
+ ld [hl], $40 ; set X screen pos
+ ret
+
+; overwrites sprite data with zeroes
+ResetPlayerSpriteData_ClearSpriteData:: ; 28c4 (0:28c4)
+ ld bc, $10
+ xor a
+ jp FillMemory
+
+Func_28cb:: ; 28cb (0:28cb)
+ ld a, [wMusicHeaderPointer]
+ and a
+ jr nz, .asm_28dc
+ ld a, [wd72c]
+ bit 1, a
+ ret nz
+ ld a, $77
+ ld [$ff24], a
+ ret
+.asm_28dc
+ ld a, [wcfc9]
+ and a
+ jr z, .asm_28e7
+ dec a
+ ld [wcfc9], a
+ ret
+.asm_28e7
+ ld a, [wcfc8]
+ ld [wcfc9], a
+ ld a, [$ff24]
+ and a
+ jr z, .asm_2903
+ ld b, a
+ and $f
+ dec a
+ ld c, a
+ ld a, b
+ and $f0
+ swap a
+ dec a
+ swap a
+ or c
+ ld [$ff24], a
+ ret
+.asm_2903
+ ld a, [wMusicHeaderPointer]
+ ld b, a
+ xor a
+ ld [wMusicHeaderPointer], a
+ ld a, $ff
+ ld [wc0ee], a
+ call PlaySound
+ ld a, [wc0f0]
+ ld [wc0ef], a
+ ld a, b
+ ld [wc0ee], a
+ jp PlaySound
+
+; this function is used to display sign messages, sprite dialog, etc.
+; INPUT: [$ff8c] = sprite ID or text ID
+DisplayTextID:: ; 2920 (0:2920)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ callba DisplayTextIDInit ; initialization
+ ld hl,wcf11
+ bit 0,[hl]
+ res 0,[hl]
+ jr nz,.skipSwitchToMapBank
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+.skipSwitchToMapBank
+ ld a,30 ; half a second
+ ld [H_FRAMECOUNTER],a ; used as joypad poll timer
+ ld hl,W_MAPTEXTPTR
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a ; hl = map text pointer
+ ld d,$00
+ ld a,[$ff8c] ; text ID
+ ld [wSpriteIndex],a
+ and a
+ jp z,DisplayStartMenu
+ cp a,$d3
+ jp z,DisplaySafariGameOverText
+ cp a,$d0
+ jp z,DisplayPokemonFaintedText
+ cp a,$d1
+ jp z,DisplayPlayerBlackedOutText
+ cp a,$d2
+ jp z,DisplayRepelWoreOffText
+ ld a,[W_NUMSPRITES]
+ ld e,a
+ ld a,[$ff8c] ; sprite ID
+ cp e
+ jr z,.spriteHandling
+ jr nc,.skipSpriteHandling
+.spriteHandling
+; get the text ID of the sprite
+ push hl
+ push de
+ push bc
+ callba UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction)
+ pop bc
+ pop de
+ ld hl,W_MAPSPRITEDATA ; NPC text entries
+ ld a,[$ff8c]
+ dec a
+ add a
+ add l
+ ld l,a
+ jr nc,.noCarry
+ inc h
+.noCarry
+ inc hl
+ ld a,[hl] ; a = text ID of the sprite
+ pop hl
+.skipSpriteHandling
+; look up the address of the text in the map's text entries
+ dec a
+ ld e,a
+ sla e
+ add hl,de
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a ; hl = address of the text
+ ld a,[hl] ; a = first byte of text
+; check first byte of text for special cases
+ cp a,$fe ; Pokemart NPC
+ jp z,DisplayPokemartDialogue
+ cp a,$ff ; Pokemon Center NPC
+ jp z,DisplayPokemonCenterDialogue
+ cp a,$fc ; Item Storage PC
+ jp z,FuncTX_ItemStoragePC
+ cp a,$fd ; Bill's PC
+ jp z,FuncTX_BillsPC
+ cp a,$f9 ; Pokemon Center PC
+ jp z,FuncTX_PokemonCenterPC
+ cp a,$f5 ; Vending Machine
+ jr nz,.notVendingMachine
+ callba VendingMachineMenu ; jump banks to vending machine routine
+ jr AfterDisplayingTextID
+.notVendingMachine
+ cp a,$f7 ; slot machine
+ jp z,FuncTX_SlotMachine
+ cp a,$f6 ; cable connection NPC in Pokemon Center
+ jr nz,.notSpecialCase
+ callab CableClubNPC
+ jr AfterDisplayingTextID
+.notSpecialCase
+ call Func_3c59 ; display the text
+ ld a,[wDoNotWaitForButtonPressAfterDisplayingText]
+ and a
+ jr nz,HoldTextDisplayOpen
+
+AfterDisplayingTextID:: ; 29d6 (0:29d6)
+ ld a,[wcc47]
+ and a
+ jr nz,HoldTextDisplayOpen
+ call WaitForTextScrollButtonPress ; wait for a button press after displaying all the text
+
+; loop to hold the dialogue box open as long as the player keeps holding down the A button
+HoldTextDisplayOpen:: ; 29df (0:29df)
+ call Joypad
+ ld a,[hJoyHeld]
+ bit 0,a ; is the A button being pressed?
+ jr nz,HoldTextDisplayOpen
+
+CloseTextDisplay:: ; 29e8 (0:29e8)
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ ld a,$90
+ ld [hWY],a ; move the window off the screen
+ call DelayFrame
+ call LoadGBPal
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED],a ; disable continuous WRAM to VRAM transfer each V-blank
+; loop to make sprites face the directions they originally faced before the dialogue
+ ld hl,wSpriteStateData2 + $19
+ ld c,$0f
+ ld de,$0010
+.restoreSpriteFacingDirectionLoop
+ ld a,[hl]
+ dec h
+ ld [hl],a
+ inc h
+ add hl,de
+ dec c
+ jr nz,.restoreSpriteFacingDirectionLoop
+ ld a,BANK(InitMapSprites)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call InitMapSprites ; reload sprite tile pattern data (since it was partially overwritten by text tile patterns)
+ ld hl,wFontLoaded
+ res 0,[hl]
+ ld a,[wd732]
+ bit 3,a ; used fly warp
+ call z,LoadPlayerSpriteGraphics
+ call LoadCurrentMapView
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ jp UpdateSprites
+
+DisplayPokemartDialogue:: ; 2a2e (0:2a2e)
+ push hl
+ ld hl,PokemartGreetingText
+ call PrintText
+ pop hl
+ inc hl
+ call LoadItemList
+ ld a,$02
+ ld [wListMenuID],a ; selects between subtypes of menus
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,Bank(DisplayPokemartDialogue_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call DisplayPokemartDialogue_
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ jp AfterDisplayingTextID
+
+PokemartGreetingText:: ; 2a55 (0:2a55)
+ TX_FAR _PokemartGreetingText
+ db "@"
+
+LoadItemList:: ; 2a5a (0:2a5a)
+ ld a,$01
+ ld [wUpdateSpritesEnabled],a
+ ld a,h
+ ld [wd128],a
+ ld a,l
+ ld [wd129],a
+ ld de,wStringBuffer2 + 11
+.loop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ cp a,$ff
+ jr nz,.loop
+ ret
+
+DisplayPokemonCenterDialogue:: ; 2a72 (0:2a72)
+ xor a
+ ld [$ff8b],a
+ ld [$ff8c],a
+ ld [$ff8d],a
+ inc hl
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,Bank(DisplayPokemonCenterDialogue_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call DisplayPokemonCenterDialogue_
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ jp AfterDisplayingTextID
+
+DisplaySafariGameOverText:: ; 2a90 (0:2a90)
+ callab PrintSafariGameOverText
+ jp AfterDisplayingTextID
+
+DisplayPokemonFaintedText:: ; 2a9b (0:2a9b)
+ ld hl,PokemonFaintedText
+ call PrintText
+ jp AfterDisplayingTextID
+
+PokemonFaintedText:: ; 2aa4 (0:2aa4)
+ TX_FAR _PokemonFaintedText
+ db "@"
+
+DisplayPlayerBlackedOutText:: ; 2aa9 (0:2aa9)
+ ld hl,PlayerBlackedOutText
+ call PrintText
+ ld a,[wd732]
+ res 5,a ; reset forced to use bike bit
+ ld [wd732],a
+ jp HoldTextDisplayOpen
+
+PlayerBlackedOutText:: ; 2aba (0:2aba)
+ TX_FAR _PlayerBlackedOutText
+ db "@"
+
+DisplayRepelWoreOffText:: ; 2abf (0:2abf)
+ ld hl,RepelWoreOffText
+ call PrintText
+ jp AfterDisplayingTextID
+
+RepelWoreOffText:: ; 2ac8 (0:2ac8)
+ TX_FAR _RepelWoreOffText
+ db "@"
+
+INCLUDE "engine/menu/start_menu.asm"
+
+; function to count how many bits are set in a string of bytes
+; INPUT:
+; hl = address of string of bytes
+; b = length of string of bytes
+; OUTPUT:
+; [wd11e] = number of set bits
+CountSetBits:: ; 2b7f (0:2b7f)
+ ld c,0
+.loop
+ ld a,[hli]
+ ld e,a
+ ld d,8
+.innerLoop ; count how many bits are set in the current byte
+ srl e
+ ld a,0
+ adc c
+ ld c,a
+ dec d
+ jr nz,.innerLoop
+ dec b
+ jr nz,.loop
+ ld a,c
+ ld [wd11e],a ; store number of set bits
+ ret
+
+; subtracts the amount the player paid from their money
+; sets carry flag if there is enough money and unsets carry flag if not
+SubtractAmountPaidFromMoney:: ; 2b96 (0:2b96)
+ ld b,BANK(SubtractAmountPaidFromMoney_)
+ ld hl,SubtractAmountPaidFromMoney_
+ jp Bankswitch
+
+; adds the amount the player sold to their money
+AddAmountSoldToMoney:: ; 2b9e (0:2b9e)
+ ld de,wPlayerMoney + 2
+ ld hl,$ffa1 ; total price of items
+ ld c,3 ; length of money in bytes
+ predef AddBCDPredef ; add total price to money
+ ld a,MONEY_BOX
+ ld [wTextBoxID],a
+ call DisplayTextBoxID ; redraw money text box
+ ld a, (SFX_02_5a - SFX_Headers_02) / 3
+ call PlaySoundWaitForCurrent ; play sound
+ jp WaitForSoundToFinish ; wait until sound is done playing
+
+; function to remove an item (in varying quantities) from the player's bag or PC box
+; INPUT:
+; HL = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wWhichPokemon] = index (within the inventory) of the item to remove
+; [wcf96] = quantity to remove
+RemoveItemFromInventory:: ; 2bbb (0:2bbb)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(RemoveItemFromInventory_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call RemoveItemFromInventory_
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; function to add an item (in varying quantities) to the player's bag or PC box
+; INPUT:
+; HL = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wcf91] = item ID
+; [wcf96] = item quantity
+; sets carry flag if successful, unsets carry flag if unsuccessful
+AddItemToInventory:: ; 2bcf (0:2bcf)
+ push bc
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(AddItemToInventory_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call AddItemToInventory_
+ pop bc
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ pop bc
+ ret
+
+; INPUT:
+; [wListMenuID] = list menu ID
+; [wList] = address of the list (2 bytes)
+DisplayListMenuID:: ; 2be6 (0:2be6)
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer
+ ld a,1
+ ld [hJoy7],a ; joypad state update flag
+ ld a,[W_BATTLETYPE]
+ and a ; is it the Old Man battle?
+ jr nz,.specialBattleType
+ ld a,$01 ; hardcoded bank
+ jr .bankswitch
+.specialBattleType ; Old Man battle
+ ld a, Bank(DisplayBattleMenu)
+.bankswitch
+ call BankswitchHome
+ ld hl,wd730
+ set 6,[hl] ; turn off letter printing delay
+ xor a
+ ld [wMenuItemToSwap],a ; 0 means no item is currently being swapped
+ ld [wd12a],a
+ ld a,[wList]
+ ld l,a
+ ld a,[wList + 1]
+ ld h,a ; hl = address of the list
+ ld a,[hl]
+ ld [wd12a],a ; [wd12a] = number of list entries
+ ld a,LIST_MENU_BOX
+ ld [wTextBoxID],a
+ call DisplayTextBoxID ; draw the menu text box
+ call UpdateSprites ; disable sprites behind the text box
+; the code up to .skipMovingSprites appears to be useless
+ hlCoord 4, 2 ; coordinates of upper left corner of menu text box
+ ld de,$090e ; height and width of menu text box
+ ld a,[wListMenuID]
+ and a ; is it a PC pokemon list?
+ jr nz,.skipMovingSprites
+ call UpdateSprites ; move sprites
+.skipMovingSprites
+ ld a,1 ; max menu item ID is 1 if the list has less than 2 entries
+ ld [wcc37],a
+ ld a,[wd12a]
+ cp a,2 ; does the list have less than 2 entries?
+ jr c,.setMenuVariables
+ ld a,2 ; max menu item ID is 2 if the list has at least 2 entries
+.setMenuVariables
+ ld [wMaxMenuItem],a
+ ld a,4
+ ld [wTopMenuItemY],a
+ ld a,5
+ ld [wTopMenuItemX],a
+ ld a,A_BUTTON | B_BUTTON | SELECT
+ ld [wMenuWatchedKeys],a
+ ld c,10
+ call DelayFrames
+
+DisplayListMenuIDLoop:: ; 2c53 (0:2c53)
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED],a ; disable transfer
+ call PrintListMenuEntries
+ ld a,1
+ ld [H_AUTOBGTRANSFERENABLED],a ; enable transfer
+ call Delay3
+ ld a,[W_BATTLETYPE]
+ and a ; is it the Old Man battle?
+ jr z,.notOldManBattle
+.oldManBattle
+ ld a,"▶"
+ Coorda 5, 4 ; place menu cursor in front of first menu entry
+ ld c,80
+ call DelayFrames
+ xor a
+ ld [wCurrentMenuItem],a
+ hlCoord 5, 4
+ ld a,l
+ ld [wMenuCursorLocation],a
+ ld a,h
+ ld [wMenuCursorLocation + 1],a
+ jr .buttonAPressed
+.notOldManBattle
+ call LoadGBPal
+ call HandleMenuInput
+ push af
+ call PlaceMenuCursor
+ pop af
+ bit 0,a ; was the A button pressed?
+ jp z,.checkOtherKeys
+.buttonAPressed
+ ld a,[wCurrentMenuItem]
+ call PlaceUnfilledArrowMenuCursor
+ ld a,$01
+ ld [wd12e],a
+ ld [wd12d],a
+ xor a
+ ld [wcc37],a
+ ld a,[wCurrentMenuItem]
+ ld c,a
+ ld a,[wListScrollOffset]
+ add c
+ ld c,a
+ ld a,[wd12a] ; number of list entries
+ and a ; is the list empty?
+ jp z,ExitListMenu ; if so, exit the menu
+ dec a
+ cp c ; did the player select Cancel?
+ jp c,ExitListMenu ; if so, exit the menu
+ ld a,c
+ ld [wWhichPokemon],a
+ ld a,[wListMenuID]
+ cp a,ITEMLISTMENU
+ jr nz,.skipMultiplying
+; if it's an item menu
+ sla c ; item entries are 2 bytes long, so multiply by 2
+.skipMultiplying
+ ld a,[wList]
+ ld l,a
+ ld a,[wList + 1]
+ ld h,a
+ inc hl ; hl = beginning of list entries
+ ld b,0
+ add hl,bc
+ ld a,[hl]
+ ld [wcf91],a
+ ld a,[wListMenuID]
+ and a ; is it a PC pokemon list?
+ jr z,.pokemonList
+ push hl
+ call GetItemPrice
+ pop hl
+ ld a,[wListMenuID]
+ cp a,ITEMLISTMENU
+ jr nz,.skipGettingQuantity
+; if it's an item menu
+ inc hl
+ ld a,[hl] ; a = item quantity
+ ld [wcf97],a
+.skipGettingQuantity
+ ld a,[wcf91]
+ ld [wd0b5],a
+ ld a,BANK(ItemNames)
+ ld [wPredefBank],a
+ call GetName
+ jr .storeChosenEntry
+.pokemonList
+ ld hl,wPartyCount
+ ld a,[wList]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld hl,wPartyMonNicks
+ jr z,.getPokemonName
+ ld hl, wBoxMonNicks ; box pokemon names
+.getPokemonName
+ ld a,[wWhichPokemon]
+ call GetPartyMonName
+.storeChosenEntry ; store the menu entry that the player chose and return
+ ld de,wcd6d
+ call CopyStringToCF4B ; copy name to wcf4b
+ ld a,$01
+ ld [wd12e],a
+ ld a,[wCurrentMenuItem]
+ ld [wd12d],a
+ xor a
+ ld [hJoy7],a ; joypad state update flag
+ ld hl,wd730
+ res 6,[hl] ; turn on letter printing delay
+ jp BankswitchBack
+.checkOtherKeys ; check B, SELECT, Up, and Down keys
+ bit 1,a ; was the B button pressed?
+ jp nz,ExitListMenu ; if so, exit the menu
+ bit 2,a ; was the select button pressed?
+ jp nz,HandleItemListSwapping ; if so, allow the player to swap menu entries
+ ld b,a
+ bit 7,b ; was Down pressed?
+ ld hl,wListScrollOffset
+ jr z,.upPressed
+.downPressed
+ ld a,[hl]
+ add a,3
+ ld b,a
+ ld a,[wd12a] ; number of list entries
+ cp b ; will going down scroll past the Cancel button?
+ jp c,DisplayListMenuIDLoop
+ inc [hl] ; if not, go down
+ jp DisplayListMenuIDLoop
+.upPressed
+ ld a,[hl]
+ and a
+ jp z,DisplayListMenuIDLoop
+ dec [hl]
+ jp DisplayListMenuIDLoop
+
+DisplayChooseQuantityMenu:: ; 2d57 (0:2d57)
+; text box dimensions/coordinates for just quantity
+ hlCoord 15, 9
+ ld b,1 ; height
+ ld c,3 ; width
+ ld a,[wListMenuID]
+ cp a,PRICEDITEMLISTMENU
+ jr nz,.drawTextBox
+; text box dimensions/coordinates for quantity and price
+ hlCoord 7, 9
+ ld b,1 ; height
+ ld c,11 ; width
+.drawTextBox
+ call TextBoxBorder
+ hlCoord 16, 10
+ ld a,[wListMenuID]
+ cp a,PRICEDITEMLISTMENU
+ jr nz,.printInitialQuantity
+ hlCoord 8, 10
+.printInitialQuantity
+ ld de,InitialQuantityText
+ call PlaceString
+ xor a
+ ld [wcf96],a ; initialize current quantity to 0
+ jp .incrementQuantity
+.waitForKeyPressLoop
+ call JoypadLowSensitivity
+ ld a,[hJoyPressed] ; newly pressed buttons
+ bit 0,a ; was the A button pressed?
+ jp nz,.buttonAPressed
+ bit 1,a ; was the B button pressed?
+ jp nz,.buttonBPressed
+ bit 6,a ; was Up pressed?
+ jr nz,.incrementQuantity
+ bit 7,a ; was Down pressed?
+ jr nz,.decrementQuantity
+ jr .waitForKeyPressLoop
+.incrementQuantity
+ ld a,[wcf97] ; max quantity
+ inc a
+ ld b,a
+ ld hl,wcf96 ; current quantity
+ inc [hl]
+ ld a,[hl]
+ cp b
+ jr nz,.handleNewQuantity
+; wrap to 1 if the player goes above the max quantity
+ ld a,1
+ ld [hl],a
+ jr .handleNewQuantity
+.decrementQuantity
+ ld hl,wcf96 ; current quantity
+ dec [hl]
+ jr nz,.handleNewQuantity
+; wrap to the max quantity if the player goes below 1
+ ld a,[wcf97] ; max quantity
+ ld [hl],a
+.handleNewQuantity
+ hlCoord 17, 10
+ ld a,[wListMenuID]
+ cp a,PRICEDITEMLISTMENU
+ jr nz,.printQuantity
+.printPrice
+ ld c,$03
+ ld a,[wcf96]
+ ld b,a
+ ld hl,$ff9f ; total price
+; initialize total price to 0
+ xor a
+ ld [hli],a
+ ld [hli],a
+ ld [hl],a
+.addLoop ; loop to multiply the individual price by the quantity to get the total price
+ ld de,$ffa1
+ ld hl,$ff8d
+ push bc
+ predef AddBCDPredef ; add the individual price to the current sum
+ pop bc
+ dec b
+ jr nz,.addLoop
+ ld a,[$ff8e]
+ and a ; should the price be halved (for selling items)?
+ jr z,.skipHalvingPrice
+ xor a
+ ld [$ffa2],a
+ ld [$ffa3],a
+ ld a,$02
+ ld [$ffa4],a
+ predef DivideBCDPredef3 ; halves the price
+; store the halved price
+ ld a,[$ffa2]
+ ld [$ff9f],a
+ ld a,[$ffa3]
+ ld [$ffa0],a
+ ld a,[$ffa4]
+ ld [$ffa1],a
+.skipHalvingPrice
+ hlCoord 12, 10
+ ld de,SpacesBetweenQuantityAndPriceText
+ call PlaceString
+ ld de,$ff9f ; total price
+ ld c,$a3
+ call PrintBCDNumber
+ hlCoord 9, 10
+.printQuantity
+ ld de,wcf96 ; current quantity
+ ld bc,$8102 ; print leading zeroes, 1 byte, 2 digits
+ call PrintNumber
+ jp .waitForKeyPressLoop
+.buttonAPressed ; the player chose to make the transaction
+ xor a
+ ld [wMenuItemToSwap],a ; 0 means no item is currently being swapped
+ ret
+.buttonBPressed ; the player chose to cancel the transaction
+ xor a
+ ld [wMenuItemToSwap],a ; 0 means no item is currently being swapped
+ ld a,$ff
+ ret
+
+InitialQuantityText:: ; 2e30 (0:2e30)
+ db "×01@"
+
+SpacesBetweenQuantityAndPriceText:: ; 2e34 (0:2e34)
+ db " @"
+
+ExitListMenu:: ; 2e3b (0:2e3b)
+ ld a,[wCurrentMenuItem]
+ ld [wd12d],a
+ ld a,$02
+ ld [wd12e],a
+ ld [wcc37],a
+ xor a
+ ld [hJoy7],a
+ ld hl,wd730
+ res 6,[hl]
+ call BankswitchBack
+ xor a
+ ld [wMenuItemToSwap],a ; 0 means no item is currently being swapped
+ scf
+ ret
+
+PrintListMenuEntries:: ; 2e5a (0:2e5a)
+ hlCoord 5, 3
+ ld b,$09
+ ld c,$0e
+ call ClearScreenArea
+ ld a,[wList]
+ ld e,a
+ ld a,[wList + 1]
+ ld d,a
+ inc de ; de = beginning of list entries
+ ld a,[wListScrollOffset]
+ ld c,a
+ ld a,[wListMenuID]
+ cp a,ITEMLISTMENU
+ ld a,c
+ jr nz,.skipMultiplying
+; if it's an item menu
+; item entries are 2 bytes long, so multiply by 2
+ sla a
+ sla c
+.skipMultiplying
+ add e
+ ld e,a
+ jr nc,.noCarry
+ inc d
+.noCarry
+ hlCoord 6, 4 ; coordinates of first list entry name
+ ld b,4 ; print 4 names
+.loop
+ ld a,b
+ ld [wWhichPokemon],a
+ ld a,[de]
+ ld [wd11e],a
+ cp a,$ff
+ jp z,.printCancelMenuItem
+ push bc
+ push de
+ push hl
+ push hl
+ push de
+ ld a,[wListMenuID]
+ and a
+ jr z,.pokemonPCMenu
+ cp a,$01
+ jr z,.movesMenu
+.itemMenu
+ call GetItemName
+ jr .placeNameString
+.pokemonPCMenu
+ push hl
+ ld hl,wPartyCount
+ ld a,[wList]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld hl,wPartyMonNicks
+ jr z,.getPokemonName
+ ld hl, wBoxMonNicks ; box pokemon names
+.getPokemonName
+ ld a,[wWhichPokemon]
+ ld b,a
+ ld a,4
+ sub b
+ ld b,a
+ ld a,[wListScrollOffset]
+ add b
+ call GetPartyMonName
+ pop hl
+ jr .placeNameString
+.movesMenu
+ call GetMoveName
+.placeNameString
+ call PlaceString
+ pop de
+ pop hl
+ ld a,[wcf93]
+ and a ; should prices be printed?
+ jr z,.skipPrintingItemPrice
+.printItemPrice
+ push hl
+ ld a,[de]
+ ld de,ItemPrices
+ ld [wcf91],a
+ call GetItemPrice ; get price
+ pop hl
+ ld bc,20 + 5 ; 1 row down and 5 columns right
+ add hl,bc
+ ld c,$a3 ; no leading zeroes, right-aligned, print currency symbol, 3 bytes
+ call PrintBCDNumber
+.skipPrintingItemPrice
+ ld a,[wListMenuID]
+ and a
+ jr nz,.skipPrintingPokemonLevel
+.printPokemonLevel
+ ld a,[wd11e]
+ push af
+ push hl
+ ld hl,wPartyCount
+ ld a,[wList]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld a,$00
+ jr z,.next
+ ld a,$02
+.next
+ ld [wcc49],a
+ ld hl,wWhichPokemon
+ ld a,[hl]
+ ld b,a
+ ld a,$04
+ sub b
+ ld b,a
+ ld a,[wListScrollOffset]
+ add b
+ ld [hl],a
+ call LoadMonData ; load pokemon info
+ ld a,[wcc49]
+ and a ; is it a list of party pokemon or box pokemon?
+ jr z,.skipCopyingLevel
+.copyLevel
+ ld a,[wLoadedMonBoxLevel]
+ ld [wLoadedMonLevel],a
+.skipCopyingLevel
+ pop hl
+ ld bc,$001c
+ add hl,bc
+ call PrintLevel ; print level
+ pop af
+ ld [wd11e],a
+.skipPrintingPokemonLevel
+ pop hl
+ pop de
+ inc de
+ ld a,[wListMenuID]
+ cp a,ITEMLISTMENU
+ jr nz,.nextListEntry
+.printItemQuantity
+ ld a,[wd11e]
+ ld [wcf91],a
+ call IsKeyItem ; check if item is unsellable
+ ld a,[wd124]
+ and a ; is the item unsellable?
+ jr nz,.skipPrintingItemQuantity ; if so, don't print the quantity
+ push hl
+ ld bc,20 + 8 ; 1 row down and 8 columns right
+ add hl,bc
+ ld a,"×"
+ ld [hli],a
+ ld a,[wd11e]
+ push af
+ ld a,[de]
+ ld [wcf97],a
+ push de
+ ld de,wd11e
+ ld [de],a
+ ld bc,$0102
+ call PrintNumber
+ pop de
+ pop af
+ ld [wd11e],a
+ pop hl
+.skipPrintingItemQuantity
+ inc de
+ pop bc
+ inc c
+ push bc
+ inc c
+ ld a,[wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
+ and a ; is an item being swapped?
+ jr z,.nextListEntry
+ sla a
+ cp c ; is it this item?
+ jr nz,.nextListEntry
+ dec hl
+ ld a,$ec ; unfilled right arrow menu cursor to indicate an item being swapped
+ ld [hli],a
+.nextListEntry
+ ld bc,2 * 20 ; 2 rows
+ add hl,bc
+ pop bc
+ inc c
+ dec b
+ jp nz,.loop
+ ld bc,-8
+ add hl,bc
+ ld a,$ee ; down arrow
+ ld [hl],a
+ ret
+.printCancelMenuItem
+ ld de,ListMenuCancelText
+ jp PlaceString
+
+ListMenuCancelText:: ; 2f97 (0:2f97)
+ db "CANCEL@"
+
+GetMonName:: ; 2f9e (0:2f9e)
+ push hl
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(MonsterNames) ; 07
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ld a,[wd11e]
+ dec a
+ ld hl,MonsterNames ; 421E
+ ld c,10
+ ld b,0
+ call AddNTimes
+ ld de,wcd6d
+ push de
+ ld bc,10
+ call CopyData
+ ld hl,wcd77
+ ld [hl], "@"
+ pop de
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ pop hl
+ ret
+
+GetItemName:: ; 2fcf (0:2fcf)
+; given an item ID at [wd11e], store the name of the item into a string
+; starting at wcd6d
+ push hl
+ push bc
+ ld a,[wd11e]
+ cp HM_01 ; is this a TM/HM?
+ jr nc,.Machine
+
+ ld [wd0b5],a
+ ld a,ITEM_NAME
+ ld [wNameListType],a
+ ld a,BANK(ItemNames)
+ ld [wPredefBank],a
+ call GetName
+ jr .Finish
+
+.Machine
+ call GetMachineName
+.Finish
+ ld de,wcd6d ; pointer to where item name is stored in RAM
+ pop bc
+ pop hl
+ ret
+
+GetMachineName:: ; 2ff3 (0:2ff3)
+; copies the name of the TM/HM in [wd11e] to wcd6d
+ push hl
+ push de
+ push bc
+ ld a,[wd11e]
+ push af
+ cp TM_01 ; is this a TM? [not HM]
+ jr nc,.WriteTM
+; if HM, then write "HM" and add 5 to the item ID, so we can reuse the
+; TM printing code
+ add 5
+ ld [wd11e],a
+ ld hl,HiddenPrefix ; points to "HM"
+ ld bc,2
+ jr .WriteMachinePrefix
+.WriteTM
+ ld hl,TechnicalPrefix ; points to "TM"
+ ld bc,2
+.WriteMachinePrefix
+ ld de,wcd6d
+ call CopyData
+
+; now get the machine number and convert it to text
+ ld a,[wd11e]
+ sub TM_01 - 1
+ ld b,$F6 ; "0"
+.FirstDigit
+ sub 10
+ jr c,.SecondDigit
+ inc b
+ jr .FirstDigit
+.SecondDigit
+ add 10
+ push af
+ ld a,b
+ ld [de],a
+ inc de
+ pop af
+ ld b,$F6 ; "0"
+ add b
+ ld [de],a
+ inc de
+ ld a,"@"
+ ld [de],a
+
+ pop af
+ ld [wd11e],a
+ pop bc
+ pop de
+ pop hl
+ ret
+
+TechnicalPrefix:: ; 303c (0:303c)
+ db "TM"
+HiddenPrefix:: ; 303e (0:303e)
+ db "HM"
+
+; sets carry if item is HM, clears carry if item is not HM
+; Input: a = item ID
+IsItemHM:: ; 3040 (0:3040)
+ cp a,HM_01
+ jr c,.notHM
+ cp a,TM_01
+ ret
+.notHM
+ and a
+ ret
+
+; sets carry if move is an HM, clears carry if move is not an HM
+; Input: a = move ID
+IsMoveHM:: ; 3049 (0:3049)
+ ld hl,HMMoves
+ ld de,1
+ jp IsInArray
+
+HMMoves:: ; 3052 (0:3052)
+ db CUT,FLY,SURF,STRENGTH,FLASH
+ db $ff ; terminator
+
+GetMoveName:: ; 3058 (0:3058)
+ push hl
+ ld a,MOVE_NAME
+ ld [wNameListType],a
+ ld a,[wd11e]
+ ld [wd0b5],a
+ ld a,BANK(MoveNames)
+ ld [wPredefBank],a
+ call GetName
+ ld de,wcd6d ; pointer to where move name is stored in RAM
+ pop hl
+ ret
+
+; reloads text box tile patterns, current map view, and tileset tile patterns
+ReloadMapData:: ; 3071 (0:3071)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ call DisableLCD
+ call LoadTextBoxTilePatterns
+ call LoadCurrentMapView
+ call LoadTilesetTilePatternData
+ call EnableLCD
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; reloads tileset tile patterns
+ReloadTilesetTilePatterns:: ; 3090 (0:3090)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ call DisableLCD
+ call LoadTilesetTilePatternData
+ call EnableLCD
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; shows the town map and lets the player choose a destination to fly to
+ChooseFlyDestination:: ; 30a9 (0:30a9)
+ ld hl,wd72e
+ res 4,[hl]
+ ld b, BANK(LoadTownMap_Fly)
+ ld hl, LoadTownMap_Fly
+ jp Bankswitch
+
+; causes the text box to close without waiting for a button press after displaying text
+DisableWaitingAfterTextDisplay:: ; 30b6 (0:30b6)
+ ld a,$01
+ ld [wDoNotWaitForButtonPressAfterDisplayingText],a
+ ret
+
+; uses an item
+; UseItem is used with dummy items to perform certain other functions as well
+; INPUT:
+; [wcf91] = item ID
+; OUTPUT:
+; [wcd6a] = success
+; 00: unsucessful
+; 01: successful
+; 02: not able to be used right now, no extra menu displayed (only certain items use this)
+UseItem:: ; 30bc (0:30bc)
+ ld b,BANK(UseItem_)
+ ld hl,UseItem_
+ jp Bankswitch
+
+; confirms the item toss and then tosses the item
+; INPUT:
+; hl = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wcf91] = item ID
+; [wWhichPokemon] = index of item within inventory
+; [wcf96] = quantity to toss
+; OUTPUT:
+; clears carry flag if the item is tossed, sets carry flag if not
+TossItem:: ; 30c4 (0:30c4)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(TossItem_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call TossItem_
+ pop de
+ ld a,d
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; checks if an item is a key item
+; INPUT:
+; [wcf91] = item ID
+; OUTPUT:
+; [wd124] = result
+; 00: item is not key item
+; 01: item is key item
+IsKeyItem:: ; 30d9 (0:30d9)
+ push hl
+ push de
+ push bc
+ callba IsKeyItem_
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; function to draw various text boxes
+; INPUT:
+; [wTextBoxID] = text box ID
+DisplayTextBoxID:: ; 30e8 (0:30e8)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,BANK(DisplayTextBoxID_)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call DisplayTextBoxID_
+ pop bc
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+; not zero if an NPC movement script is running, the player character is
+; automatically stepping down from a door, or joypad states are being simulated
+IsPlayerCharacterBeingControlledByGame:: ; 30fd (0:30fd)
+ ld a, [wNPCMovementScriptPointerTableNum]
+ and a
+ ret nz
+ ld a, [wd736]
+ bit 1, a ; currently stepping down from door bit
+ ret nz
+ ld a, [wd730]
+ and $80
+ ret
+
+RunNPCMovementScript:: ; 310e (0:310e)
+ ld hl, wd736
+ bit 0, [hl]
+ res 0, [hl]
+ jr nz, .playerStepOutFromDoor
+ ld a, [wNPCMovementScriptPointerTableNum]
+ and a
+ ret z
+ dec a
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, .NPCMovementScriptPointerTables
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, [wNPCMovementScriptBank]
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ld a, [wNPCMovementScriptFunctionNum]
+ call CallFunctionInTable
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+.NPCMovementScriptPointerTables
+ dw ProfOakMovementScriptPointerTable
+ dw PewterMuseumGuyMovementScriptPointerTable
+ dw PewterGymGuyMovementScriptPointerTable
+.playerStepOutFromDoor
+ ld b, BANK(PlayerStepOutFromDoor)
+ ld hl, PlayerStepOutFromDoor
+ jp Bankswitch
+
+EndNPCMovementScript:: ; 314e (0:314e)
+ ld b, BANK(_EndNPCMovementScript)
+ ld hl, _EndNPCMovementScript
+ jp Bankswitch
+
+EmptyFunc2:: ; 3156 (0:3156)
+ ret
+
+; stores hl in [W_TRAINERHEADERPTR]
+StoreTrainerHeaderPointer:: ; 3157 (0:3157)
+ ld a, h
+ ld [W_TRAINERHEADERPTR], a
+ ld a, l
+ ld [W_TRAINERHEADERPTR+1], a
+ ret
+
+; executes the current map script from the function pointer array provided in hl.
+; a: map script index to execute (unless overridden by [wd733] bit 4)
+ExecuteCurMapScriptInTable:: ; 3160 (0:3160)
+ push af
+ push de
+ call StoreTrainerHeaderPointer
+ pop hl
+ pop af
+ push hl
+ ld hl, W_FLAGS_D733
+ bit 4, [hl]
+ res 4, [hl]
+ jr z, .useProvidedIndex ; test if map script index was overridden manually
+ ld a, [W_CURMAPSCRIPT]
+.useProvidedIndex
+ pop hl
+ ld [W_CURMAPSCRIPT], a
+ call CallFunctionInTable
+ ld a, [W_CURMAPSCRIPT]
+ ret
+
+LoadGymLeaderAndCityName:: ; 317f (0:317f)
+ push de
+ ld de, wGymCityName
+ ld bc, $11
+ call CopyData ; load city name
+ pop hl
+ ld de, wGymLeaderName
+ ld bc, $b
+ jp CopyData ; load gym leader name
+
+; reads specific information from trainer header (pointed to at W_TRAINERHEADERPTR)
+; a: offset in header data
+; 0 -> flag's bit (into wTrainerHeaderFlagBit)
+; 2 -> flag's byte ptr (into hl)
+; 4 -> before battle text (into hl)
+; 6 -> after battle text (into hl)
+; 8 -> end battle text (into hl)
+ReadTrainerHeaderInfo:: ; 3193 (0:3193)
+ push de
+ push af
+ ld d, $0
+ ld e, a
+ ld hl, W_TRAINERHEADERPTR
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+ add hl, de
+ pop af
+ and a
+ jr nz, .nonZeroOffset
+ ld a, [hl]
+ ld [wTrainerHeaderFlagBit], a ; store flag's bit
+ jr .done
+.nonZeroOffset
+ cp $2
+ jr z, .readPointer ; read flag's byte ptr
+ cp $4
+ jr z, .readPointer ; read before battle text
+ cp $6
+ jr z, .readPointer ; read after battle text
+ cp $8
+ jr z, .readPointer ; read end battle text
+ cp $a
+ jr nz, .done
+ ld a, [hli] ; read end battle text (2) but override the result afterwards (XXX why, bug?)
+ ld d, [hl]
+ ld e, a
+ jr .done
+.readPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.done
+ pop de
+ ret
+
+TrainerFlagAction::
+ predef_jump FlagActionPredef
+
+TalkToTrainer:: ; 31cc (0:31cc)
+ call StoreTrainerHeaderPointer
+ xor a
+ call ReadTrainerHeaderInfo ; read flag's bit
+ ld a, $2
+ call ReadTrainerHeaderInfo ; read flag's byte ptr
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ ld b, $2
+ call TrainerFlagAction ; read trainer's flag
+ ld a, c
+ and a
+ jr z, .trainerNotYetFought ; test trainer's flag
+ ld a, $6
+ call ReadTrainerHeaderInfo ; print after battle text
+ jp PrintText
+.trainerNotYetFought ; 0x31ed
+ ld a, $4
+ call ReadTrainerHeaderInfo ; print before battle text
+ call PrintText
+ ld a, $a
+ call ReadTrainerHeaderInfo ; (?) does nothing apparently (maybe bug in ReadTrainerHeaderInfo)
+ push de
+ ld a, $8
+ call ReadTrainerHeaderInfo ; read end battle text
+ pop de
+ call SaveEndBattleTextPointers
+ ld hl, W_FLAGS_D733
+ set 4, [hl] ; activate map script index override (index is set below)
+ ld hl, wFlags_0xcd60
+ bit 0, [hl] ; test if player is already engaging the trainer (because the trainer saw the player)
+ ret nz
+; if the player talked to the trainer of his own volition
+ call EngageMapTrainer
+ ld hl, W_CURMAPSCRIPT
+ inc [hl] ; increment map script index before StartTrainerBattle increments it again (next script function is usually EndTrainerBattle)
+ jp StartTrainerBattle
+
+; checks if any trainers are seeing the player and wanting to fight
+CheckFightingMapTrainers:: ; 3219 (0:3219)
+ call CheckForEngagingTrainers
+ ld a, [wSpriteIndex]
+ cp $ff
+ jr nz, .trainerEngaging
+ xor a
+ ld [wSpriteIndex], a
+ ld [wTrainerHeaderFlagBit], a
+ ret
+.trainerEngaging
+ ld hl, W_FLAGS_D733
+ set 3, [hl]
+ ld [wcd4f], a
+ xor a
+ ld [wcd50], a
+ predef EmotionBubble
+ ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
+ ld [wJoyIgnore], a
+ xor a
+ ldh [$b4], a
+ call TrainerWalkUpToPlayer_Bank0
+ ld hl, W_CURMAPSCRIPT
+ inc [hl] ; increment map script index (next script function is usually DisplayEnemyTrainerTextAndStartBattle)
+ ret
+
+; display the before battle text after the enemy trainer has walked up to the player's sprite
+DisplayEnemyTrainerTextAndStartBattle:: ; 324c (0:324c)
+ ld a, [wd730]
+ and $1
+ ret nz ; return if the enemy trainer hasn't finished walking to the player's sprite
+ ld [wJoyIgnore], a
+ ld a, [wSpriteIndex]
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ ; fall through
+
+StartTrainerBattle:: ; 325d (0:325d)
+ xor a
+ ld [wJoyIgnore], a
+ call InitBattleEnemyParameters
+ ld hl, wd72d
+ set 6, [hl]
+ set 7, [hl]
+ ld hl, wd72e
+ set 1, [hl]
+ ld hl, W_CURMAPSCRIPT
+ inc [hl] ; increment map script index (next script function is usually EndTrainerBattle)
+ ret
+
+EndTrainerBattle:: ; 3275 (0:3275)
+ ld hl, wd126
+ set 5, [hl]
+ set 6, [hl]
+ ld hl, wd72d
+ res 7, [hl]
+ ld hl, wFlags_0xcd60
+ res 0, [hl] ; player is no longer engaged by any trainer
+ ld a, [W_ISINBATTLE] ; W_ISINBATTLE
+ cp $ff
+ jp z, ResetButtonPressedAndMapScript
+ ld a, $2
+ call ReadTrainerHeaderInfo
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ ld b, $1
+ call TrainerFlagAction ; flag trainer as fought
+ ld a, [W_ENEMYMONORTRAINERCLASS]
+ cp $c8
+ jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite)
+ ld hl, W_MISSABLEOBJECTLIST
+ ld de, $2
+ ld a, [wSpriteIndex]
+ call IsInArray ; search for sprite ID
+ inc hl
+ ld a, [hl]
+ ld [wcc4d], a ; load corresponding missable object index and remove it
+ predef HideObject
+.skipRemoveSprite
+ ld hl, wd730
+ bit 4, [hl]
+ res 4, [hl]
+ ret nz
+
+ResetButtonPressedAndMapScript:: ; 32c1 (0:32c1)
+ xor a
+ ld [wJoyIgnore], a
+ ld [hJoyHeld], a
+ ld [hJoyPressed], a
+ ld [hJoyReleased], a
+ ld [W_CURMAPSCRIPT], a ; reset battle status
+ ret
+
+; calls TrainerWalkUpToPlayer
+TrainerWalkUpToPlayer_Bank0:: ; 32cf (0:32cf)
+ ld b, BANK(TrainerWalkUpToPlayer)
+ ld hl, TrainerWalkUpToPlayer
+ jp Bankswitch
+
+; sets opponent type and mon set/lvl based on the engaging trainer data
+InitBattleEnemyParameters:: ; 32d7 (0:32d7)
+ ld a, [wEngagedTrainerClass]
+ ld [W_CUROPPONENT], a ; wd059
+ ld [W_ENEMYMONORTRAINERCLASS], a
+ cp $c8
+ ld a, [wEngagedTrainerSet] ; wcd2e
+ jr c, .noTrainer
+ ld [W_TRAINERNO], a ; wd05d
+ ret
+.noTrainer
+ ld [W_CURENEMYLVL], a ; W_CURENEMYLVL
+ ret
+
+GetSpritePosition1:: ; 32ef (0:32ef)
+ ld hl, _GetSpritePosition1
+ jr asm_3301
+
+GetSpritePosition2:: ; 32f4 (0:32f4)
+ ld hl, _GetSpritePosition2
+ jr asm_3301 ; 0x32f7 $8
+
+SetSpritePosition1:: ; 32f9 (0:32f9)
+ ld hl, _SetSpritePosition1
+ jr asm_3301
+
+SetSpritePosition2:: ; 32fe (0:32fe)
+ ld hl, _SetSpritePosition2
+asm_3301:: ; 3301 (0:3301)
+ ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2)
+ jp Bankswitch ; indirect jump to one of the four functions
+
+CheckForEngagingTrainers:: ; 3306 (0:3306)
+ xor a
+ call ReadTrainerHeaderInfo ; read trainer flag's bit (unused)
+ ld d, h ; store trainer header address in de
+ ld e, l
+.trainerLoop
+ call StoreTrainerHeaderPointer ; set trainer header pointer to current trainer
+ ld a, [de]
+ ld [wSpriteIndex], a ; store trainer flag's bit
+ ld [wTrainerHeaderFlagBit], a
+ cp $ff
+ ret z
+ ld a, $2
+ call ReadTrainerHeaderInfo ; read trainer flag's byte ptr
+ ld b, $2
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ call TrainerFlagAction ; read trainer flag
+ ld a, c
+ and a
+ jr nz, .trainerAlreadyFought
+ push hl
+ push de
+ push hl
+ xor a
+ call ReadTrainerHeaderInfo ; get trainer header pointer
+ inc hl
+ ld a, [hl] ; read trainer engage distance
+ pop hl
+ ld [wTrainerEngageDistance], a
+ ld a, [wSpriteIndex]
+ swap a
+ ld [wTrainerSpriteOffset], a ; wWhichTrade
+ predef TrainerEngage
+ pop de
+ pop hl
+ ld a, [wTrainerSpriteOffset] ; wWhichTrade
+ and a
+ ret nz ; break if the trainer is engaging
+.trainerAlreadyFought
+ ld hl, $c
+ add hl, de
+ ld d, h
+ ld e, l
+ jr .trainerLoop
+
+; hl = text if the player wins
+; de = text if the player loses
+SaveEndBattleTextPointers:: ; 3354 (0:3354)
+ ld a, [H_LOADEDROMBANK]
+ ld [wEndBattleTextRomBank], a
+ ld a, h
+ ld [wEndBattleWinTextPointer], a
+ ld a, l
+ ld [wEndBattleWinTextPointer + 1], a
+ ld a, d
+ ld [wEndBattleLoseTextPointer], a
+ ld a, e
+ ld [wEndBattleLoseTextPointer + 1], a
+ ret
+
+; loads data of some trainer on the current map and plays pre-battle music
+; [wSpriteIndex]: sprite ID of trainer who is engaged
+EngageMapTrainer:: ; 336a (0:336a)
+ ld hl, W_MAPSPRITEEXTRADATA
+ ld d, $0
+ ld a, [wSpriteIndex]
+ dec a
+ add a
+ ld e, a
+ add hl, de ; seek to engaged trainer data
+ ld a, [hli] ; load trainer class
+ ld [wEngagedTrainerClass], a
+ ld a, [hl] ; load trainer mon set
+ ld [wEnemyMonAttackMod], a ; wcd2e
+ jp PlayTrainerMusic
+
+PrintEndBattleText:: ; 3381 (0:3381)
+ push hl
+ ld hl, wd72d
+ bit 7, [hl]
+ res 7, [hl]
+ pop hl
+ ret z
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, [wEndBattleTextRomBank]
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ push hl
+ callba SaveTrainerName
+ ld hl, TrainerEndBattleText
+ call PrintText
+ pop hl
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ callba FreezeEnemyTrainerSprite
+ jp WaitForSoundToFinish
+
+GetSavedEndBattleTextPointer:: ; 33b7 (0:33b7)
+ ld a, [wBattleResult]
+ and a
+; won battle
+ jr nz, .lostBattle
+ ld a, [wEndBattleWinTextPointer]
+ ld h, a
+ ld a, [wEndBattleWinTextPointer + 1]
+ ld l, a
+ ret
+.lostBattle
+ ld a, [wEndBattleLoseTextPointer]
+ ld h, a
+ ld a, [wEndBattleLoseTextPointer + 1]
+ ld l, a
+ ret
+
+TrainerEndBattleText:: ; 33cf (0:33cf)
+ TX_FAR _TrainerNameText
+ db $08
+ call GetSavedEndBattleTextPointer
+ call TextCommandProcessor
+ jp TextScriptEnd
+
+; XXX unused?
+Func_33dd:: ; 33dd (0:33dd)
+ ld a, [wFlags_0xcd60]
+ bit 0, a
+ ret nz
+ call EngageMapTrainer
+ xor a
+ ret
+
+PlayTrainerMusic:: ; 33e8 (0:33e8)
+ ld a, [wEngagedTrainerClass]
+ cp $c8 + SONY1
+ ret z
+ cp $c8 + SONY2
+ ret z
+ cp $c8 + SONY3
+ ret z
+ ld a, [W_GYMLEADERNO] ; W_GYMLEADERNO
+ and a
+ ret nz
+ xor a
+ ld [wMusicHeaderPointer], a
+ ld a, $ff
+ call PlaySound ; stop music
+ ld a, BANK(Music_MeetEvilTrainer)
+ ld [wc0ef], a
+ ld [wc0f0], a
+ ld a, [wEngagedTrainerClass]
+ ld b, a
+ ld hl, EvilTrainerList
+.evilTrainerListLoop
+ ld a, [hli]
+ cp $ff
+ jr z, .noEvilTrainer
+ cp b
+ jr nz, .evilTrainerListLoop
+ ld a, MUSIC_MEET_EVIL_TRAINER
+ jr .PlaySound
+.noEvilTrainer
+ ld hl, FemaleTrainerList
+.femaleTrainerListLoop
+ ld a, [hli]
+ cp $ff
+ jr z, .maleTrainer
+ cp b
+ jr nz, .femaleTrainerListLoop
+ ld a, MUSIC_MEET_FEMALE_TRAINER
+ jr .PlaySound
+.maleTrainer
+ ld a, MUSIC_MEET_MALE_TRAINER
+.PlaySound
+ ld [wc0ee], a
+ jp PlaySound
+
+INCLUDE "data/trainer_types.asm"
+
+; checks if the player's coordinates match an arrow movement tile's coordinates
+; and if so, decodes the RLE movement data
+; b = player Y
+; c = player X
+DecodeArrowMovementRLE:: ; 3442 (0:3442)
+ ld a, [hli]
+ cp $ff
+ ret z ; no match in the list
+ cp b
+ jr nz, .nextArrowMovementTileEntry1
+ ld a, [hli]
+ cp c
+ jr nz, .nextArrowMovementTileEntry2
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ ld hl, wSimulatedJoypadStatesEnd
+ call DecodeRLEList
+ dec a
+ ld [wSimulatedJoypadStatesIndex], a
+ ret
+.nextArrowMovementTileEntry1
+ inc hl
+.nextArrowMovementTileEntry2
+ inc hl
+ inc hl
+ jr DecodeArrowMovementRLE
+
+FuncTX_ItemStoragePC:: ; 3460 (0:3460)
+ call SaveScreenTilesToBuffer2
+ ld b, BANK(PlayerPC)
+ ld hl, PlayerPC
+ jr bankswitchAndContinue
+
+FuncTX_BillsPC:: ; 346a (0:346a)
+ call SaveScreenTilesToBuffer2
+ ld b, BANK(BillsPC_)
+ ld hl, BillsPC_
+ jr bankswitchAndContinue
+
+FuncTX_SlotMachine:: ; 3474 (0:3474)
+; XXX find a better name for this function
+; special_F7
+ ld b,BANK(CeladonPrizeMenu)
+ ld hl,CeladonPrizeMenu
+bankswitchAndContinue:: ; 3479 (0:3479)
+ call Bankswitch
+ jp HoldTextDisplayOpen ; continue to main text-engine function
+
+FuncTX_PokemonCenterPC:: ; 347f (0:347f)
+ ld b, BANK(ActivatePC)
+ ld hl, ActivatePC
+ jr bankswitchAndContinue
+
+StartSimulatingJoypadStates:: ; 3486 (0:3486)
+ xor a
+ ld [wOverrideSimulatedJoypadStatesMask], a
+ ld [wSpriteStateData2 + $06], a ; player's sprite movement byte 1
+ ld hl, wd730
+ set 7, [hl]
+ ret
+
+IsItemInBag:: ; 3493 (0:3493)
+; given an item_id in b
+; set zero flag if item isn't in player's bag
+; else reset zero flag
+; related to Pokémon Tower and ghosts
+ predef IsItemInBag_
+ ld a,b
+ and a
+ ret
+
+DisplayPokedex:: ; 349b (0:349b)
+ ld [wd11e], a
+ ld b, BANK(Func_7c18)
+ ld hl, Func_7c18
+ jp Bankswitch
+
+SetSpriteFacingDirectionAndDelay:: ; 34a6 (0:34a6)
+ call SetSpriteFacingDirection
+ ld c, $6
+ jp DelayFrames
+
+SetSpriteFacingDirection:: ; 34ae (0:34ae)
+ ld a, $9
+ ld [H_SPRITEDATAOFFSET], a
+ call GetPointerWithinSpriteStateData1
+ ld a, [$ff8d]
+ ld [hl], a
+ ret
+
+SetSpriteImageIndexAfterSettingFacingDirection:: ; 34b9 (0:34b9)
+ ld de, -7
+ add hl, de
+ ld [hl], a
+ ret
+
+; tests if the player's coordinates are in a specified array
+; INPUT:
+; hl = address of array
+; OUTPUT:
+; [wWhichTrade] = if there is match, the matching array index
+; sets carry if the coordinates are in the array, clears carry if not
+ArePlayerCoordsInArray:: ; 34bf (0:34bf)
+ ld a,[W_YCOORD]
+ ld b,a
+ ld a,[W_XCOORD]
+ ld c,a
+ ; fallthrough
+
+CheckCoords:: ; 34c7 (0:34c7)
+ xor a
+ ld [wWhichTrade],a
+.loop
+ ld a,[hli]
+ cp a,$ff ; reached terminator?
+ jr z,.notInArray
+ push hl
+ ld hl,wWhichTrade
+ inc [hl]
+ pop hl
+.compareYCoord
+ cp b
+ jr z,.compareXCoord
+ inc hl
+ jr .loop
+.compareXCoord
+ ld a,[hli]
+ cp c
+ jr nz,.loop
+.inArray
+ scf
+ ret
+.notInArray
+ and a
+ ret
+
+; tests if a boulder's coordinates are in a specified array
+; INPUT:
+; hl = address of array
+; [H_SPRITEINDEX] = index of boulder sprite
+; OUTPUT:
+; [wWhichTrade] = if there is match, the matching array index
+; sets carry if the coordinates are in the array, clears carry if not
+CheckBoulderCoords:: ; 34e4 (0:34e4)
+ push hl
+ ld hl, wSpriteStateData2 + $04
+ ld a, [H_SPRITEINDEX]
+ swap a
+ ld d, $0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ sub $4 ; because sprite coordinates are offset by 4
+ ld b, a
+ ld a, [hl]
+ sub $4 ; because sprite coordinates are offset by 4
+ ld c, a
+ pop hl
+ jp CheckCoords
+
+GetPointerWithinSpriteStateData1:: ; 34fc (0:34fc)
+ ld h, $c1
+ jr _GetPointerWithinSpriteStateData
+
+GetPointerWithinSpriteStateData2:: ; 3500 (0:3500)
+ ld h, $c2
+
+_GetPointerWithinSpriteStateData:
+ ld a, [H_SPRITEDATAOFFSET]
+ ld b, a
+ ld a, [H_SPRITEINDEX]
+ swap a
+ add b
+ ld l, a
+ ret
+
+; decodes a $ff-terminated RLEncoded list
+; each entry is a pair of bytes <byte value> <repetitions>
+; the final $ff will be replicated in the output list and a contains the number of bytes written
+; de: input list
+; hl: output list
+DecodeRLEList:: ; 350c (0:350c)
+ xor a
+ ld [wRLEByteCount], a ; count written bytes here
+.listLoop
+ ld a, [de]
+ cp $ff
+ jr z, .endOfList
+ ld [H_DOWNARROWBLINKCNT1], a ; store byte value to be written
+ inc de
+ ld a, [de]
+ ld b, $0
+ ld c, a ; number of bytes to be written
+ ld a, [wRLEByteCount]
+ add c
+ ld [wRLEByteCount], a ; update total number of written bytes
+ ld a, [H_DOWNARROWBLINKCNT1] ; $ff8b
+ call FillMemory ; write a c-times to output
+ inc de
+ jr .listLoop
+.endOfList
+ ld a, $ff
+ ld [hl], a ; write final $ff
+ ld a, [wRLEByteCount]
+ inc a ; include sentinel in counting
+ ret
+
+; sets movement byte 1 for sprite [$FF8C] to $FE and byte 2 to [$FF8D]
+SetSpriteMovementBytesToFE:: ; 3533 (0:3533)
+ push hl
+ call GetSpriteMovementByte1Pointer
+ ld [hl], $fe
+ call GetSpriteMovementByte2Pointer
+ ld a, [$ff8d]
+ ld [hl], a
+ pop hl
+ ret
+
+; sets both movement bytes for sprite [$FF8C] to $FF
+SetSpriteMovementBytesToFF:: ; 3541 (0:3541)
+ push hl
+ call GetSpriteMovementByte1Pointer
+ ld [hl],$FF
+ call GetSpriteMovementByte2Pointer
+ ld [hl],$FF ; prevent person from walking?
+ pop hl
+ ret
+
+; returns the sprite movement byte 1 pointer for sprite [$FF8C] in hl
+GetSpriteMovementByte1Pointer:: ; 354e (0:354e)
+ ld h,$C2
+ ld a,[H_SPRITEINDEX] ; the sprite to move
+ swap a
+ add a,6
+ ld l,a
+ ret
+
+; returns the sprite movement byte 2 pointer for sprite [$FF8C] in hl
+GetSpriteMovementByte2Pointer:: ; 3558 (0:3558)
+ push de
+ ld hl,W_MAPSPRITEDATA
+ ld a,[$FF8C] ; the sprite to move
+ dec a
+ add a
+ ld d,0
+ ld e,a
+ add hl,de
+ pop de
+ ret
+
+GetTrainerInformation:: ; 3566 (0:3566)
+ call GetTrainerName
+ ld a, [wLinkState]
+ and a
+ jr nz, .linkBattle
+ ld a, Bank(TrainerPicAndMoneyPointers)
+ call BankswitchHome
+ ld a, [W_TRAINERCLASS] ; wd031
+ dec a
+ ld hl, TrainerPicAndMoneyPointers
+ ld bc, $5
+ call AddNTimes
+ ld de, wTrainerPicPointer
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld de, wd046
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ jp BankswitchBack
+.linkBattle
+ ld hl, wTrainerPicPointer
+ ld de, RedPicFront
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ret
+
+GetTrainerName:: ; 359e (0:359e)
+ ld b, BANK(GetTrainerName_)
+ ld hl, GetTrainerName_
+ jp Bankswitch
+
+
+HasEnoughMoney::
+; Check if the player has at least as much
+; money as the 3-byte BCD value at $ff9f.
+ ld de, wPlayerMoney
+ ld hl, $ff9f
+ ld c, 3
+ jp StringCmp
+
+HasEnoughCoins::
+; Check if the player has at least as many
+; coins as the 2-byte BCD value at $ffa0.
+ ld de, wPlayerCoins
+ ld hl, $ffa0
+ ld c, 2
+ jp StringCmp
+
+
+BankswitchHome:: ; 35d9 (0:35d9)
+; switches to bank # in a
+; Only use this when in the home bank!
+ ld [wcf09],a
+ ld a,[H_LOADEDROMBANK]
+ ld [wcf08],a
+ ld a,[wcf09]
+ call BankswitchCommon
+ ret
+
+BankswitchBack:: ; 35e8 (0:35e8)
+; returns from BankswitchHome
+ ld a,[wcf08]
+ call BankswitchCommon
+ ret
+
+BankswitchCommon:: ; 3e7e (0:3e7e)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+Bankswitch:: ; 3e84 (0:3e84)
+; self-contained bankswitch, use this when not in the home bank
+; switches to the bank in b
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call .jumptoaddress
+ pop bc
+ ld a,b
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+.jumptoaddress
+ jp [hl]
+
+; displays yes/no choice
+; yes -> set carry
+YesNoChoice:: ; 35ec (0:35ec)
+ call SaveScreenTilesToBuffer1
+ call InitYesNoTextBoxParameters
+ jr DisplayYesNoChoice
+
+Func_35f4:: ; 35f4 (0:35f4)
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call InitYesNoTextBoxParameters
+ jp DisplayTextBoxID
+
+InitYesNoTextBoxParameters:: ; 35ff (0:35ff)
+ xor a ; YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ hlCoord 14, 7
+ ld bc, $80f
+ ret
+
+YesNoChoicePokeCenter:: ; 360a (0:360a)
+ call SaveScreenTilesToBuffer1
+ ld a, HEAL_CANCEL_MENU
+ ld [wTwoOptionMenuID], a
+ hlCoord 11, 6
+ ld bc, $80c
+ jr DisplayYesNoChoice
+
+Func_361a:: ; 361a (0:361a)
+ call SaveScreenTilesToBuffer1
+ ld a, WIDE_YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ hlCoord 12, 7
+ ld bc, $080d
+DisplayYesNoChoice:: ; 3628 (0:3628)
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ jp LoadScreenTilesFromBuffer1
+
+; calculates the difference |a-b|, setting carry flag if a<b
+CalcDifference:: ; 3633 (0:3633)
+ sub b
+ ret nc
+ cpl
+ add $1
+ scf
+ ret
+
+MoveSprite:: ; 363a (0:363a)
+; move the sprite [$FF8C] with the movement pointed to by de
+; actually only copies the movement data to wcc5b for later
+ call SetSpriteMovementBytesToFF
+MoveSprite_:: ; 363d (0:363d)
+ push hl
+ push bc
+ call GetSpriteMovementByte1Pointer
+ xor a
+ ld [hl],a
+ ld hl,wcc5b
+ ld c,0
+
+.loop
+ ld a,[de]
+ ld [hli],a
+ inc de
+ inc c
+ cp a,$FF ; have we reached the end of the movement data?
+ jr nz,.loop
+
+ ld a,c
+ ld [wcf0f],a ; number of steps taken
+
+ pop bc
+ ld hl,wd730
+ set 0,[hl]
+ pop hl
+ xor a
+ ld [wOverrideSimulatedJoypadStatesMask],a
+ ld [wSimulatedJoypadStatesEnd],a
+ dec a
+ ld [wJoyIgnore],a
+ ld [wWastedByteCD3A],a
+ ret
+
+; divides [$ffe5] by [$ffe6] and stores the quotient in [$ffe7]
+DivideBytes:: ; 366b (0:366b)
+ push hl
+ ld hl, $ffe7
+ xor a
+ ld [hld], a
+ ld a, [hld]
+ and a
+ jr z, .done
+ ld a, [hli]
+.loop
+ sub [hl]
+ jr c, .done
+ inc hl
+ inc [hl]
+ dec hl
+ jr .loop
+.done
+ pop hl
+ ret
+
+
+LoadFontTilePatterns::
+ ld a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, FontGraphics
+ ld de, vFont
+ ld bc, $400
+ ld a, BANK(FontGraphics)
+ jp FarCopyDataDouble ; if LCD is off, transfer all at once
+.on
+ ld de, FontGraphics
+ ld hl, vFont
+ ld bc, BANK(FontGraphics) << 8 | $80
+ jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
+
+LoadTextBoxTilePatterns::
+ ld a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, TextBoxGraphics
+ ld de, vChars2 + $600
+ ld bc, $200
+ ld a, BANK(TextBoxGraphics)
+ jp FarCopyData2 ; if LCD is off, transfer all at once
+.on
+ ld de, TextBoxGraphics
+ ld hl, vChars2 + $600
+ ld bc, BANK(TextBoxGraphics) << 8 | $20
+ jp CopyVideoData ; if LCD is on, transfer during V-blank
+
+LoadHpBarAndStatusTilePatterns::
+ ld a, [rLCDC]
+ bit 7, a ; is the LCD enabled?
+ jr nz, .on
+.off
+ ld hl, HpBarAndStatusGraphics
+ ld de, vChars2 + $620
+ ld bc, $1e0
+ ld a, BANK(HpBarAndStatusGraphics)
+ jp FarCopyData2 ; if LCD is off, transfer all at once
+.on
+ ld de, HpBarAndStatusGraphics
+ ld hl, vChars2 + $620
+ ld bc, BANK(HpBarAndStatusGraphics) << 8 | $1e
+ jp CopyVideoData ; if LCD is on, transfer during V-blank
+
+
+UncompressSpriteFromDE:: ; 36eb (0:36eb)
+; Decompress pic at a:de.
+ ld hl, W_SPRITEINPUTPTR
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ jp UncompressSpriteData
+
+
+SaveScreenTilesToBuffer2:: ; 36f4 (0:36f4)
+ ld hl, wTileMap
+ ld de, wTileMapBackup2
+ ld bc, $168
+ call CopyData
+ ret
+
+LoadScreenTilesFromBuffer2:: ; 3701 (0:3701)
+ call LoadScreenTilesFromBuffer2DisableBGTransfer
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
+ ret
+
+; loads screen tiles stored in wTileMapBackup2 but leaves H_AUTOBGTRANSFERENABLED disabled
+LoadScreenTilesFromBuffer2DisableBGTransfer:: ; 3709 (0:3709)
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
+ ld hl, wTileMapBackup2
+ ld de, wTileMap
+ ld bc, $168
+ call CopyData
+ ret
+
+SaveScreenTilesToBuffer1:: ; 3719 (0:3719)
+ ld hl, wTileMap
+ ld de, wTileMapBackup
+ ld bc, $168
+ jp CopyData
+
+LoadScreenTilesFromBuffer1:: ; 3725 (0:3725)
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
+ ld hl, wTileMapBackup
+ ld de, wTileMap
+ ld bc, $168
+ call CopyData
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
+ ret
+
+DelayFrames:: ; 3739 (0:3739)
+; wait n frames, where n is the value in c
+ call DelayFrame
+ dec c
+ jr nz,DelayFrames
+ ret
+
+PlaySoundWaitForCurrent:: ; 3740 (0:3740)
+ push af
+ call WaitForSoundToFinish
+ pop af
+ jp PlaySound
+
+; Wait for sound to finish playing
+WaitForSoundToFinish:: ; 3748 (0:3748)
+ ld a, [wLowHealthAlarm]
+ and $80
+ ret nz
+ push hl
+.asm_374f
+ ld hl, wc02a
+ xor a
+ or [hl]
+ inc hl
+ or [hl]
+ inc hl
+ inc hl
+ or [hl]
+ jr nz, .asm_374f
+ pop hl
+ ret
+
+NamePointers:: ; 375d (0:375d)
+ dw MonsterNames
+ dw MoveNames
+ dw UnusedNames
+ dw ItemNames
+ dw wPartyMonOT ; player's OT names list
+ dw wEnemyMonOT ; enemy's OT names list
+ dw TrainerNames
+
+GetName:: ; 376b (0:376b)
+; arguments:
+; [wd0b5] = which name
+; [wNameListType] = which list
+; [wPredefBank] = bank of list
+;
+; returns pointer to name in de
+ ld a,[wd0b5]
+ ld [wd11e],a
+
+ ; TM names are separate from item names.
+ ; BUG: This applies to all names instead of just items.
+ cp HM_01
+ jp nc, GetMachineName
+
+ ld a,[H_LOADEDROMBANK]
+ push af
+ push hl
+ push bc
+ push de
+ ld a,[wNameListType] ;List3759_entrySelector
+ dec a
+ jr nz,.otherEntries
+ ;1 = MON_NAMES
+ call GetMonName
+ ld hl,11
+ add hl,de
+ ld e,l
+ ld d,h
+ jr .gotPtr
+.otherEntries ; $378d
+ ;2-7 = OTHER ENTRIES
+ ld a,[wPredefBank]
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ld a,[wNameListType] ;VariousNames' entryID
+ dec a
+ add a
+ ld d,0
+ ld e,a
+ jr nc,.skip
+ inc d
+.skip ; $37a0
+ ld hl,NamePointers
+ add hl,de
+ ld a,[hli]
+ ld [$ff96],a
+ ld a,[hl]
+ ld [$ff95],a
+ ld a,[$ff95]
+ ld h,a
+ ld a,[$ff96]
+ ld l,a
+ ld a,[wd0b5]
+ ld b,a
+ ld c,0
+.nextName
+ ld d,h
+ ld e,l
+.nextChar
+ ld a,[hli]
+ cp a, "@"
+ jr nz,.nextChar
+ inc c ;entry counter
+ ld a,b ;wanted entry
+ cp c
+ jr nz,.nextName
+ ld h,d
+ ld l,e
+ ld de,wcd6d
+ ld bc,$0014
+ call CopyData
+.gotPtr ; $37cd
+ ld a,e
+ ld [wcf8d],a
+ ld a,d
+ ld [wcf8e],a
+ pop de
+ pop bc
+ pop hl
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+GetItemPrice:: ; 37df (0:37df)
+; Stores item's price as BCD at hItemPrice (3 bytes)
+; Input: [wcf91] = item id
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, [wListMenuID]
+ cp MOVESLISTMENU
+ ld a, BANK(ItemPrices)
+ jr nz, .asm_37ed
+ ld a, $f ; hardcoded Bank
+.asm_37ed
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ld hl, wItemPrices
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wcf91] ; a contains item id
+ cp HM_01
+ jr nc, .getTMPrice
+ ld bc, $3
+.asm_3802
+ add hl, bc
+ dec a
+ jr nz, .asm_3802
+ dec hl
+ ld a, [hld]
+ ld [hItemPrice + 2], a
+ ld a, [hld]
+ ld [hItemPrice + 1], a
+ ld a, [hl]
+ ld [hItemPrice], a
+ jr .asm_381c
+.getTMPrice
+ ld a, Bank(GetMachinePrice)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ call GetMachinePrice
+.asm_381c
+ ld de, hItemPrice
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+; copies a string from [de] to [wcf4b]
+CopyStringToCF4B:: ; 3826 (0:3826)
+ ld hl, wcf4b
+ ; fall through
+
+; copies a string from [de] to [hl]
+CopyString:: ; 3829 (0:3829)
+ ld a, [de]
+ inc de
+ ld [hli], a
+ cp "@"
+ jr nz, CopyString
+ ret
+
+; this function is used when lower button sensitivity is wanted (e.g. menus)
+; OUTPUT: [hJoy5] = pressed buttons in usual format
+; there are two flags that control its functionality, [hJoy6] and [hJoy7]
+; there are esentially three modes of operation
+; 1. Get newly pressed buttons only
+; ([hJoy7] == 0, [hJoy6] == any)
+; Just copies [hJoyPressed] to [hJoy5].
+; 2. Get currently pressed buttons at low sample rate with delay
+; ([hJoy7] == 1, [hJoy6] != 0)
+; If the user holds down buttons for more than half a second,
+; report buttons as being pressed up to 12 times per second thereafter.
+; If the user holds down buttons for less than half a second,
+; report only one button press.
+; 3. Same as 2, but report no buttons as pressed if A or B is held down.
+; ([hJoy7] == 1, [hJoy6] == 0)
+JoypadLowSensitivity:: ; 3831 (0:3831)
+ call Joypad
+ ld a,[hJoy7] ; flag
+ and a ; get all currently pressed buttons or only newly pressed buttons?
+ ld a,[hJoyPressed] ; newly pressed buttons
+ jr z,.storeButtonState
+ ld a,[hJoyHeld] ; all currently pressed buttons
+.storeButtonState
+ ld [hJoy5],a
+ ld a,[hJoyPressed] ; newly pressed buttons
+ and a ; have any buttons been newly pressed since last check?
+ jr z,.noNewlyPressedButtons
+.newlyPressedButtons
+ ld a,30 ; half a second delay
+ ld [H_FRAMECOUNTER],a
+ ret
+.noNewlyPressedButtons
+ ld a,[H_FRAMECOUNTER]
+ and a ; is the delay over?
+ jr z,.delayOver
+.delayNotOver
+ xor a
+ ld [hJoy5],a ; report no buttons as pressed
+ ret
+.delayOver
+; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed
+ ld a,[hJoyHeld]
+ and A_BUTTON | B_BUTTON
+ jr z,.setShortDelay
+ ld a,[hJoy6] ; flag
+ and a
+ jr nz,.setShortDelay
+ xor a
+ ld [hJoy5],a
+.setShortDelay
+ ld a,5 ; 1/12 of a second delay
+ ld [H_FRAMECOUNTER],a
+ ret
+
+WaitForTextScrollButtonPress:: ; 3865 (0:3865)
+ ld a, [H_DOWNARROWBLINKCNT1]
+ push af
+ ld a, [H_DOWNARROWBLINKCNT2]
+ push af
+ xor a
+ ld [H_DOWNARROWBLINKCNT1], a
+ ld a, $6
+ ld [H_DOWNARROWBLINKCNT2], a
+.loop
+ push hl
+ ld a, [wTownMapSpriteBlinkingEnabled]
+ and a
+ jr z, .skipAnimation
+ call TownMapSpriteBlinkingAnimation
+.skipAnimation
+ hlCoord 18, 16
+ call HandleDownArrowBlinkTiming
+ pop hl
+ call JoypadLowSensitivity
+ predef CableClub_Run
+ ld a, [hJoy5]
+ and A_BUTTON | B_BUTTON
+ jr z, .loop
+ pop af
+ ld [H_DOWNARROWBLINKCNT2], a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1], a
+ ret
+
+; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect
+ManualTextScroll:: ; 3898 (0:3898)
+ ld a, [wLinkState]
+ cp LINK_STATE_BATTLING
+ jr z, .inLinkBattle
+ call WaitForTextScrollButtonPress
+ ld a, (SFX_02_40 - SFX_Headers_02) / 3
+ jp PlaySound
+.inLinkBattle
+ ld c, $41
+ jp DelayFrames
+
+; function to do multiplication
+; all values are big endian
+; INPUT
+; FF96-FF98 = multiplicand
+; FF99 = multiplier
+; OUTPUT
+; FF95-FF98 = product
+Multiply:: ; 38ac (0:38ac)
+ push hl
+ push bc
+ callab _Multiply
+ pop bc
+ pop hl
+ ret
+
+; function to do division
+; all values are big endian
+; INPUT
+; FF95-FF98 = dividend
+; FF99 = divisor
+; b = number of bytes in the dividend (starting from FF95)
+; OUTPUT
+; FF95-FF98 = quotient
+; FF99 = remainder
+Divide:: ; 38b9 (0:38b9)
+ push hl
+ push de
+ push bc
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,Bank(_Divide)
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ call _Divide
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; This function is used to wait a short period after printing a letter to the
+; screen unless the player presses the A/B button or the delay is turned off
+; through the [wd730] or [wd358] flags.
+PrintLetterDelay:: ; 38d3 (0:38d3)
+ ld a,[wd730]
+ bit 6,a
+ ret nz
+ ld a,[wd358]
+ bit 1,a
+ ret z
+ push hl
+ push de
+ push bc
+ ld a,[wd358]
+ bit 0,a
+ jr z,.waitOneFrame
+ ld a,[W_OPTIONS]
+ and $f
+ ld [H_FRAMECOUNTER],a
+ jr .checkButtons
+.waitOneFrame
+ ld a,1
+ ld [H_FRAMECOUNTER],a
+.checkButtons
+ call Joypad
+ ld a,[hJoyHeld]
+.checkAButton
+ bit 0,a ; is the A button pressed?
+ jr z,.checkBButton
+ jr .endWait
+.checkBButton
+ bit 1,a ; is the B button pressed?
+ jr z,.buttonsNotPressed
+.endWait
+ call DelayFrame
+ jr .done
+.buttonsNotPressed ; if neither A nor B is pressed
+ ld a,[H_FRAMECOUNTER]
+ and a
+ jr nz,.checkButtons
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; Copies [hl, bc) to [de, bc - hl).
+; In other words, the source data is from hl up to but not including bc,
+; and the destination is de.
+CopyDataUntil:: ; 3913 (0:3913)
+ ld a,[hli]
+ ld [de],a
+ inc de
+ ld a,h
+ cp b
+ jr nz,CopyDataUntil
+ ld a,l
+ cp c
+ jr nz,CopyDataUntil
+ ret
+
+; Function to remove a pokemon from the party or the current box.
+; wWhichPokemon determines the pokemon.
+; [wcf95] == 0 specifies the party.
+; [wcf95] != 0 specifies the current box.
+RemovePokemon:: ; 391f (0:391f)
+ ld hl, _RemovePokemon
+ ld b, BANK(_RemovePokemon)
+ jp Bankswitch
+
+AddPartyMon:: ; 3927 (0:3927)
+ push hl
+ push de
+ push bc
+ callba _AddPartyMon
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; calculates all 5 stats of current mon and writes them to [de]
+CalcStats:: ; 3936 (0:3936)
+ ld c, $0
+.statsLoop
+ inc c
+ call CalcStat
+ ld a, [H_MULTIPLICAND+1]
+ ld [de], a
+ inc de
+ ld a, [H_MULTIPLICAND+2]
+ ld [de], a
+ inc de
+ ld a, c
+ cp $5
+ jr nz, .statsLoop
+ ret
+
+; calculates stat c of current mon
+; c: stat to calc (HP=1,Atk=2,Def=3,Spd=4,Spc=5)
+; b: consider stat exp?
+; hl: base ptr to stat exp values ([hl + 2*c - 1] and [hl + 2*c])
+CalcStat:: ; 394a (0:394a)
+ push hl
+ push de
+ push bc
+ ld a, b
+ ld d, a
+ push hl
+ ld hl, W_MONHEADER
+ ld b, $0
+ add hl, bc
+ ld a, [hl] ; read base value of stat
+ ld e, a
+ pop hl
+ push hl
+ sla c
+ ld a, d
+ and a
+ jr z, .statExpDone ; consider stat exp?
+ add hl, bc ; skip to corresponding stat exp value
+.statExpLoop ; calculates ceil(Sqrt(stat exp)) in b
+ xor a
+ ld [H_MULTIPLICAND], a
+ ld [H_MULTIPLICAND+1], a
+ inc b ; increment current stat exp bonus
+ ld a, b
+ cp $ff
+ jr z, .statExpDone
+ ld [H_MULTIPLICAND+2], a
+ ld [H_MULTIPLIER], a
+ call Multiply
+ ld a, [hld]
+ ld d, a
+ ld a, [$ff98]
+ sub d
+ ld a, [hli]
+ ld d, a
+ ld a, [$ff97]
+ sbc d ; test if (current stat exp bonus)^2 < stat exp
+ jr c, .statExpLoop
+.statExpDone
+ srl c
+ pop hl
+ push bc
+ ld bc, $b ; skip to stat IV values
+ add hl, bc
+ pop bc
+ ld a, c
+ cp $2
+ jr z, .getAttackIV
+ cp $3
+ jr z, .getDefenseIV
+ cp $4
+ jr z, .getSpeedIV
+ cp $5
+ jr z, .getSpecialIV
+.getHpIV
+ push bc
+ ld a, [hl] ; Atk IV
+ swap a
+ and $1
+ sla a
+ sla a
+ sla a
+ ld b, a
+ ld a, [hli] ; Def IV
+ and $1
+ sla a
+ sla a
+ add b
+ ld b, a
+ ld a, [hl] ; Spd IV
+ swap a
+ and $1
+ sla a
+ add b
+ ld b, a
+ ld a, [hl] ; Spc IV
+ and $1
+ add b ; HP IV: LSB of the other 4 IVs
+ pop bc
+ jr .calcStatFromIV
+.getAttackIV
+ ld a, [hl]
+ swap a
+ and $f
+ jr .calcStatFromIV
+.getDefenseIV
+ ld a, [hl]
+ and $f
+ jr .calcStatFromIV
+.getSpeedIV
+ inc hl
+ ld a, [hl]
+ swap a
+ and $f
+ jr .calcStatFromIV
+.getSpecialIV
+ inc hl
+ ld a, [hl]
+ and $f
+.calcStatFromIV
+ ld d, $0
+ add e
+ ld e, a
+ jr nc, .noCarry
+ inc d ; de = Base + IV
+.noCarry
+ sla e
+ rl d ; de = (Base + IV) * 2
+ srl b
+ srl b ; b = ceil(Sqrt(stat exp)) / 4
+ ld a, b
+ add e
+ jr nc, .noCarry2
+ inc d ; da = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4
+.noCarry2
+ ld [H_MULTIPLICAND+2], a
+ ld a, d
+ ld [H_MULTIPLICAND+1], a
+ xor a
+ ld [H_MULTIPLICAND], a
+ ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL
+ ld [H_MULTIPLIER], a
+ call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level
+ ld a, [H_MULTIPLICAND]
+ ld [H_DIVIDEND], a
+ ld a, [H_MULTIPLICAND+1]
+ ld [H_DIVIDEND+1], a
+ ld a, [H_MULTIPLICAND+2]
+ ld [H_DIVIDEND+2], a
+ ld a, $64
+ ld [H_DIVISOR], a
+ ld a, $3
+ ld b, a
+ call Divide ; (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100
+ ld a, c
+ cp $1
+ ld a, $5
+ jr nz, .notHPStat
+ ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL
+ ld b, a
+ ld a, [H_MULTIPLICAND+2]
+ add b
+ ld [H_MULTIPLICAND+2], a
+ jr nc, .noCarry3
+ ld a, [H_MULTIPLICAND+1]
+ inc a
+ ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level
+.noCarry3
+ ld a, $a
+.notHPStat
+ ld b, a
+ ld a, [H_MULTIPLICAND+2]
+ add b
+ ld [H_MULTIPLICAND+2], a
+ jr nc, .noCarry4
+ ld a, [H_MULTIPLICAND+1]
+ inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5
+ ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10
+.noCarry4
+ ld a, [H_MULTIPLICAND+1] ; check for overflow (>999)
+ cp $4
+ jr nc, .overflow
+ cp $3
+ jr c, .noOverflow
+ ld a, [H_MULTIPLICAND+2]
+ cp $e8
+ jr c, .noOverflow
+.overflow
+ ld a, $3 ; overflow: cap at 999
+ ld [H_MULTIPLICAND+1], a
+ ld a, $e7
+ ld [H_MULTIPLICAND+2], a
+.noOverflow
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AddEnemyMonToPlayerParty:: ; 3a53 (0:3a53)
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, BANK(_AddEnemyMonToPlayerParty)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ call _AddEnemyMonToPlayerParty
+ pop bc
+ ld a, b
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+Func_3a68:: ; 3a68 (0:3a68)
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, BANK(Func_f51e)
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ call Func_f51e
+ pop bc
+ ld a, b
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ ret
+
+; skips a text entries, each of size $b (like trainer name, OT name, rival name, ...)
+; hl: base pointer, will be incremented by $b * a
+SkipFixedLengthTextEntries:: ; 3a7d (0:3a7d)
+ and a
+ ret z
+ ld bc, $b
+.skipLoop
+ add hl, bc
+ dec a
+ jr nz, .skipLoop
+ ret
+
+AddNTimes:: ; 3a87 (0:3a87)
+; add bc to hl a times
+ and a
+ ret z
+.loop
+ add hl,bc
+ dec a
+ jr nz,.loop
+ ret
+
+; Compare strings, c bytes in length, at de and hl.
+; Often used to compare big endian numbers in battle calculations.
+StringCmp:: ; 3a8e (0:3a8e)
+ ld a,[de]
+ cp [hl]
+ ret nz
+ inc de
+ inc hl
+ dec c
+ jr nz,StringCmp
+ ret
+
+; INPUT:
+; a = oam block index (each block is 4 oam entries)
+; b = Y coordinate of upper left corner of sprite
+; c = X coordinate of upper left corner of sprite
+; de = base address of 4 tile number and attribute pairs
+WriteOAMBlock:: ; 3a97 (0:3a97)
+ ld h,wOAMBuffer / $100
+ swap a ; multiply by 16
+ ld l,a
+ call .writeOneEntry ; upper left
+ push bc
+ ld a,8
+ add c
+ ld c,a
+ call .writeOneEntry ; upper right
+ pop bc
+ ld a,8
+ add b
+ ld b,a
+ call .writeOneEntry ; lower left
+ ld a,8
+ add c
+ ld c,a
+ ; lower right
+.writeOneEntry
+ ld [hl],b ; Y coordinate
+ inc hl
+ ld [hl],c ; X coordinate
+ inc hl
+ ld a,[de] ; tile number
+ inc de
+ ld [hli],a
+ ld a,[de] ; attribute
+ inc de
+ ld [hli],a
+ ret
+
+HandleMenuInput:: ; 3abe (0:3abe)
+ xor a
+ ld [wd09b],a
+
+HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2)
+ ld a,[H_DOWNARROWBLINKCNT1]
+ push af
+ ld a,[H_DOWNARROWBLINKCNT2]
+ push af ; save existing values on stack
+ xor a
+ ld [H_DOWNARROWBLINKCNT1],a ; blinking down arrow timing value 1
+ ld a,$06
+ ld [H_DOWNARROWBLINKCNT2],a ; blinking down arrow timing value 2
+.loop1
+ xor a
+ ld [wPartyMonAnimCounter],a ; counter for pokemon shaking animation
+ call PlaceMenuCursor
+ call Delay3
+.loop2
+ push hl
+ ld a,[wd09b]
+ and a ; is it a pokemon selection menu?
+ jr z,.getJoypadState
+ callba AnimatePartyMon ; shake mini sprite of selected pokemon
+.getJoypadState
+ pop hl
+ call JoypadLowSensitivity
+ ld a,[hJoy5]
+ and a ; was a key pressed?
+ jr nz,.keyPressed
+ push hl
+ hlCoord 18, 11 ; coordinates of blinking down arrow in some menus
+ call HandleDownArrowBlinkTiming ; blink down arrow (if any)
+ pop hl
+ ld a,[wMenuJoypadPollCount]
+ dec a
+ jr z,.giveUpWaiting
+ jr .loop2
+.giveUpWaiting
+; if a key wasn't pressed within the specified number of checks
+ pop af
+ ld [H_DOWNARROWBLINKCNT2],a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled],a ; disable menu wrapping
+ ret
+.keyPressed
+ xor a
+ ld [wcc4b],a
+ ld a,[hJoy5]
+ ld b,a
+ bit 6,a ; pressed Up key?
+ jr z,.checkIfDownPressed
+.upPressed
+ ld a,[wCurrentMenuItem] ; selected menu item
+ and a ; already at the top of the menu?
+ jr z,.alreadyAtTop
+.notAtTop
+ dec a
+ ld [wCurrentMenuItem],a ; move selected menu item up one space
+ jr .checkOtherKeys
+.alreadyAtTop
+ ld a,[wMenuWrappingEnabled]
+ and a ; is wrapping around enabled?
+ jr z,.noWrappingAround
+ ld a,[wMaxMenuItem]
+ ld [wCurrentMenuItem],a ; wrap to the bottom of the menu
+ jr .checkOtherKeys
+.checkIfDownPressed
+ bit 7,a
+ jr z,.checkOtherKeys
+.downPressed
+ ld a,[wCurrentMenuItem]
+ inc a
+ ld c,a
+ ld a,[wMaxMenuItem]
+ cp c
+ jr nc,.notAtBottom
+.alreadyAtBottom
+ ld a,[wMenuWrappingEnabled]
+ and a ; is wrapping around enabled?
+ jr z,.noWrappingAround
+ ld c,$00 ; wrap from bottom to top
+.notAtBottom
+ ld a,c
+ ld [wCurrentMenuItem],a
+.checkOtherKeys
+ ld a,[wMenuWatchedKeys]
+ and b ; does the menu care about any of the pressed keys?
+ jp z,.loop1
+.checkIfAButtonOrBButtonPressed
+ ld a,[hJoy5]
+ and A_BUTTON | B_BUTTON
+ jr z,.skipPlayingSound
+.AButtonOrBButtonPressed
+ push hl
+ ld hl,wFlags_0xcd60
+ bit 5,[hl]
+ pop hl
+ jr nz,.skipPlayingSound
+ ld a,(SFX_02_40 - SFX_Headers_02) / 3
+ call PlaySound ; play sound
+.skipPlayingSound
+ pop af
+ ld [H_DOWNARROWBLINKCNT2],a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled],a ; disable menu wrapping
+ ld a,[hJoy5]
+ ret
+.noWrappingAround
+ ld a,[wcc37]
+ and a ; should we return if the user tried to go past the top or bottom?
+ jr z,.checkOtherKeys
+ jr .checkIfAButtonOrBButtonPressed
+
+PlaceMenuCursor:: ; 3b7c (0:3b7c)
+ ld a,[wTopMenuItemY]
+ and a ; is the y coordinate 0?
+ jr z,.adjustForXCoord
+ ld hl,wTileMap
+ ld bc,SCREEN_WIDTH
+.topMenuItemLoop
+ add hl,bc
+ dec a
+ jr nz,.topMenuItemLoop
+.adjustForXCoord
+ ld a,[wTopMenuItemX]
+ ld b,0
+ ld c,a
+ add hl,bc
+ push hl
+ ld a,[wLastMenuItem]
+ and a ; was the previous menu id 0?
+ jr z,.checkForArrow1
+ push af
+ ld a,[hFlags_0xFFF6]
+ bit 1,a ; is the menu double spaced?
+ jr z,.doubleSpaced1
+ ld bc,20
+ jr .getOldMenuItemScreenPosition
+.doubleSpaced1
+ ld bc,40
+.getOldMenuItemScreenPosition
+ pop af
+.oldMenuItemLoop
+ add hl,bc
+ dec a
+ jr nz,.oldMenuItemLoop
+.checkForArrow1
+ ld a,[hl]
+ cp a,"▶" ; was an arrow next to the previously selected menu item?
+ jr nz,.skipClearingArrow
+.clearArrow
+ ld a,[wTileBehindCursor]
+ ld [hl],a
+.skipClearingArrow
+ pop hl
+ ld a,[wCurrentMenuItem]
+ and a
+ jr z,.checkForArrow2
+ push af
+ ld a,[hFlags_0xFFF6]
+ bit 1,a ; is the menu double spaced?
+ jr z,.doubleSpaced2
+ ld bc,20
+ jr .getCurrentMenuItemScreenPosition
+.doubleSpaced2
+ ld bc,40
+.getCurrentMenuItemScreenPosition
+ pop af
+.currentMenuItemLoop
+ add hl,bc
+ dec a
+ jr nz,.currentMenuItemLoop
+.checkForArrow2
+ ld a,[hl]
+ cp a,"▶" ; has the right arrow already been placed?
+ jr z,.skipSavingTile ; if so, don't lose the saved tile
+ ld [wTileBehindCursor],a ; save tile before overwriting with right arrow
+.skipSavingTile
+ ld a,"▶" ; place right arrow
+ ld [hl],a
+ ld a,l
+ ld [wMenuCursorLocation],a
+ ld a,h
+ ld [wMenuCursorLocation + 1],a
+ ld a,[wCurrentMenuItem]
+ ld [wLastMenuItem],a
+ ret
+
+; This is used to mark a menu cursor other than the one currently being
+; manipulated. In the case of submenus, this is used to show the location of
+; the menu cursor in the parent menu. In the case of swapping items in list,
+; this is used to mark the item that was first chosen to be swapped.
+PlaceUnfilledArrowMenuCursor:: ; 3bec (0:3bec)
+ ld b,a
+ ld a,[wMenuCursorLocation]
+ ld l,a
+ ld a,[wMenuCursorLocation + 1]
+ ld h,a
+ ld [hl],$ec ; outline of right arrow
+ ld a,b
+ ret
+
+; Replaces the menu cursor with a blank space.
+EraseMenuCursor:: ; 3bf9 (0:3bf9)
+ ld a,[wMenuCursorLocation]
+ ld l,a
+ ld a,[wMenuCursorLocation + 1]
+ ld h,a
+ ld [hl]," "
+ ret
+
+; This toggles a blinking down arrow at hl on and off after a delay has passed.
+; This is often called even when no blinking is occurring.
+; The reason is that most functions that call this initialize H_DOWNARROWBLINKCNT1 to 0.
+; The effect is that if the tile at hl is initialized with a down arrow,
+; this function will toggle that down arrow on and off, but if the tile isn't
+; initliazed with a down arrow, this function does nothing.
+; That allows this to be called without worrying about if a down arrow should
+; be blinking.
+HandleDownArrowBlinkTiming:: ; 3c04 (0:3c04)
+ ld a,[hl]
+ ld b,a
+ ld a,$ee ; down arrow
+ cp b
+ jr nz,.downArrowOff
+.downArrowOn
+ ld a,[H_DOWNARROWBLINKCNT1]
+ dec a
+ ld [H_DOWNARROWBLINKCNT1],a
+ ret nz
+ ld a,[H_DOWNARROWBLINKCNT2]
+ dec a
+ ld [H_DOWNARROWBLINKCNT2],a
+ ret nz
+ ld a," "
+ ld [hl],a
+ ld a,$ff
+ ld [H_DOWNARROWBLINKCNT1],a
+ ld a,$06
+ ld [H_DOWNARROWBLINKCNT2],a
+ ret
+.downArrowOff
+ ld a,[H_DOWNARROWBLINKCNT1]
+ and a
+ ret z
+ dec a
+ ld [H_DOWNARROWBLINKCNT1],a
+ ret nz
+ dec a
+ ld [H_DOWNARROWBLINKCNT1],a
+ ld a,[H_DOWNARROWBLINKCNT2]
+ dec a
+ ld [H_DOWNARROWBLINKCNT2],a
+ ret nz
+ ld a,$06
+ ld [H_DOWNARROWBLINKCNT2],a
+ ld a,$ee ; down arrow
+ ld [hl],a
+ ret
+
+; The following code either enables or disables the automatic drawing of
+; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait
+; for a button press after displaying text (unless [wcc47] is set).
+
+EnableAutoTextBoxDrawing:: ; 3c3c (0:3c3c)
+ xor a
+ jr AutoTextBoxDrawingCommon
+
+DisableAutoTextBoxDrawing:: ; 3c3f (0:3c3f)
+ ld a,$01
+
+AutoTextBoxDrawingCommon:: ; 3c41 (0:3c41)
+ ld [wAutoTextBoxDrawingControl],a
+ xor a
+ ld [wDoNotWaitForButtonPressAfterDisplayingText],a ; make DisplayTextID wait for button press
+ ret
+
+PrintText:: ; 3c49 (0:3c49)
+; Print text hl at (1, 14).
+ push hl
+ ld a,MESSAGE_BOX
+ ld [wTextBoxID],a
+ call DisplayTextBoxID
+ call UpdateSprites
+ call Delay3
+ pop hl
+Func_3c59:: ; 3c59 (0:3c59)
+ bcCoord 1, 14
+ jp TextCommandProcessor
+
+
+PrintNumber:: ; 3c5f
+; Print the c-digit, b-byte value at de.
+; Allows 2 to 7 digits. For 1-digit numbers, add
+; the value to char "0" instead of calling PrintNumber.
+; Flags LEADING_ZEROES and LEFT_ALIGN can be given
+; in bits 7 and 6 of b respectively.
+LEADING_ZEROES EQU 7
+LEFT_ALIGN EQU 6
+
+ push bc
+ xor a
+ ld [H_PASTLEADINGZEROES], a
+ ld [H_NUMTOPRINT], a
+ ld [H_NUMTOPRINT + 1], a
+ ld a, b
+ and $f
+ cp 1
+ jr z, .byte
+ cp 2
+ jr z, .word
+.long
+ ld a, [de]
+ ld [H_NUMTOPRINT], a
+ inc de
+ ld a, [de]
+ ld [H_NUMTOPRINT + 1], a
+ inc de
+ ld a, [de]
+ ld [H_NUMTOPRINT + 2], a
+ jr .start
+
+.word
+ ld a, [de]
+ ld [H_NUMTOPRINT + 1], a
+ inc de
+ ld a, [de]
+ ld [H_NUMTOPRINT + 2], a
+ jr .start
+
+.byte
+ ld a, [de]
+ ld [H_NUMTOPRINT + 2], a
+
+.start
+ push de
+
+ ld d, b
+ ld a, c
+ ld b, a
+ xor a
+ ld c, a
+ ld a, b
+
+ cp 2
+ jr z, .tens
+ cp 3
+ jr z, .hundreds
+ cp 4
+ jr z, .thousands
+ cp 5
+ jr z, .ten_thousands
+ cp 6
+ jr z, .hundred_thousands
+
+print_digit: macro
+
+if (\1) / $10000
+ ld a, \1 / $10000 % $100
+else xor a
+endc
+ ld [H_POWEROFTEN + 0], a
+
+if (\1) / $100
+ ld a, \1 / $100 % $100
+else xor a
+endc
+ ld [H_POWEROFTEN + 1], a
+
+ ld a, \1 / $1 % $100
+ ld [H_POWEROFTEN + 2], a
+
+ call .PrintDigit
+ call .NextDigit
+endm
+
+.millions print_digit 1000000
+.hundred_thousands print_digit 100000
+.ten_thousands print_digit 10000
+.thousands print_digit 1000
+.hundreds print_digit 100
+
+.tens
+ ld c, 0
+ ld a, [H_NUMTOPRINT + 2]
+.mod
+ cp 10
+ jr c, .ok
+ sub 10
+ inc c
+ jr .mod
+.ok
+
+ ld b, a
+ ld a, [H_PASTLEADINGZEROES]
+ or c
+ ld [H_PASTLEADINGZEROES], a
+ jr nz, .past
+ call .PrintLeadingZero
+ jr .next
+.past
+ ld a, "0"
+ add c
+ ld [hl], a
+.next
+
+ call .NextDigit
+.ones
+ ld a, "0"
+ add b
+ ld [hli], a
+ pop de
+ dec de
+ pop bc
+ ret
+
+.PrintDigit:
+; Divide by the current decimal place.
+; Print the quotient, and keep the modulus.
+ ld c, 0
+.loop
+ ld a, [H_POWEROFTEN]
+ ld b, a
+ ld a, [H_NUMTOPRINT]
+ ld [H_SAVEDNUMTOPRINT], a
+ cp b
+ jr c, .underflow0
+ sub b
+ ld [H_NUMTOPRINT], a
+ ld a, [H_POWEROFTEN + 1]
+ ld b, a
+ ld a, [H_NUMTOPRINT + 1]
+ ld [H_SAVEDNUMTOPRINT + 1], a
+ cp b
+ jr nc, .noborrow1
+
+ ld a, [H_NUMTOPRINT]
+ or 0
+ jr z, .underflow1
+ dec a
+ ld [H_NUMTOPRINT], a
+ ld a, [H_NUMTOPRINT + 1]
+.noborrow1
+
+ sub b
+ ld [H_NUMTOPRINT + 1], a
+ ld a, [H_POWEROFTEN + 2]
+ ld b, a
+ ld a, [H_NUMTOPRINT + 2]
+ ld [H_SAVEDNUMTOPRINT + 2], a
+ cp b
+ jr nc, .noborrow2
+
+ ld a, [H_NUMTOPRINT + 1]
+ and a
+ jr nz, .borrowed
+
+ ld a, [H_NUMTOPRINT]
+ and a
+ jr z, .underflow2
+ dec a
+ ld [H_NUMTOPRINT], a
+ xor a
+.borrowed
+
+ dec a
+ ld [H_NUMTOPRINT + 1], a
+ ld a, [H_NUMTOPRINT + 2]
+.noborrow2
+ sub b
+ ld [H_NUMTOPRINT + 2], a
+ inc c
+ jr .loop
+
+.underflow2
+ ld a, [H_SAVEDNUMTOPRINT + 1]
+ ld [H_NUMTOPRINT + 1], a
+.underflow1
+ ld a, [H_SAVEDNUMTOPRINT]
+ ld [H_NUMTOPRINT], a
+.underflow0
+ ld a, [H_PASTLEADINGZEROES]
+ or c
+ jr z, .PrintLeadingZero
+
+ ld a, "0"
+ add c
+ ld [hl], a
+ ld [H_PASTLEADINGZEROES], a
+ ret
+
+.PrintLeadingZero:
+ bit LEADING_ZEROES, d
+ ret z
+ ld [hl], "0"
+ ret
+
+.NextDigit:
+; Increment unless the number is left-aligned,
+; leading zeroes are not printed, and no digits
+; have been printed yet.
+ bit LEADING_ZEROES, d
+ jr nz, .inc
+ bit LEFT_ALIGN, d
+ jr z, .inc
+ ld a, [H_PASTLEADINGZEROES]
+ and a
+ ret z
+.inc
+ inc hl
+ ret
+
+
+CallFunctionInTable::
+JumpTable::
+; Call function a in jumptable hl.
+; de is not preserved.
+ push hl
+ push de
+ push bc
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .returnAddress
+ push de
+ jp [hl]
+.returnAddress
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+IsInArray::
+; Search an array at hl for the value in a.
+; Entry size is de bytes.
+; Return count b and carry if found.
+ ld b, 0
+
+IsInRestOfArray::
+ ld c, a
+.loop
+ ld a, [hl]
+ cp -1
+ jr z, .notfound
+ cp c
+ jr z, .found
+ inc b
+ add hl, de
+ jr .loop
+
+.notfound
+ and a
+ ret
+
+.found
+ scf
+ ret
+
+InitMapSprites:: ; 3dba (0:3dba)
+ ld hl, _InitMapSprites ; 1401b (5:401b)
+ ld b,BANK(_InitMapSprites)
+ jp Bankswitch
+
+RestoreScreenTilesAndReloadTilePatterns:: ; 3dbe (0:3dbe)
+ call ClearSprites
+ ld a, $1
+ ld [wUpdateSpritesEnabled], a
+ call ReloadMapSpriteTilePatterns
+ call LoadScreenTilesFromBuffer2
+ call LoadTextBoxTilePatterns
+ call GoPAL_SET_CF1C
+ jr Delay3
+
+
+GBPalWhiteOutWithDelay3::
+ call GBPalWhiteOut
+
+Delay3::
+; The bg map is updated each frame in thirds.
+; Wait three frames to let the bg map fully update.
+ ld c, 3
+ jp DelayFrames
+
+GBPalNormal::
+; Reset BGP and OBP0.
+ ld a, %11100100 ; 3210
+ ld [rBGP], a
+ ld a, %11010000 ; 3100
+ ld [rOBP0], a
+ ret
+
+GBPalWhiteOut::
+; White out all palettes.
+ xor a
+ ld [rBGP],a
+ ld [rOBP0],a
+ ld [rOBP1],a
+ ret
+
+
+GoPAL_SET_CF1C:: ; 3ded (0:3ded)
+ ld b,$ff
+GoPAL_SET:: ; 3def (0:3def)
+ ld a,[wOnSGB]
+ and a
+ ret z
+ predef_jump Func_71ddf
+
+GetHealthBarColor::
+; Return at hl the palette of
+; an HP bar e pixels long.
+ ld a, e
+ cp 27
+ ld d, 0 ; green
+ jr nc, .gotColor
+ cp 10
+ inc d ; yellow
+ jr nc, .gotColor
+ inc d ; red
+.gotColor
+ ld [hl], d
+ ret
+
+; Copy the current map's sprites' tile patterns to VRAM again after they have
+; been overwritten by other tile patterns.
+ReloadMapSpriteTilePatterns:: ; 3e08 (0:3e08)
+ ld hl, wFontLoaded
+ ld a, [hl]
+ push af
+ res 0, [hl]
+ push hl
+ xor a
+ ld [W_SPRITESETID], a
+ call DisableLCD
+ callba InitMapSprites
+ call EnableLCD
+ pop hl
+ pop af
+ ld [hl], a
+ call LoadPlayerSpriteGraphics
+ call LoadFontTilePatterns
+ jp UpdateSprites
+
+
+GiveItem::
+; Give player quantity c of item b,
+; and copy the item's name to wcf4b.
+; Return carry on success.
+ ld a, b
+ ld [wd11e], a
+ ld [wcf91], a
+ ld a, c
+ ld [wcf96], a
+ ld hl,wNumBagItems
+ call AddItemToInventory
+ ret nc
+ call GetItemName
+ call CopyStringToCF4B
+ scf
+ ret
+
+GivePokemon::
+; Give the player monster b at level c.
+ ld a, b
+ ld [wcf91], a
+ ld a, c
+ ld [W_CURENEMYLVL], a
+ xor a
+ ld [wcc49], a
+ ld b, BANK(_GivePokemon)
+ ld hl, _GivePokemon
+ jp Bankswitch
+
+
+Random::
+; Return a random number in a.
+; For battles, use BattleRandom.
+ push hl
+ push de
+ push bc
+ callba Random_
+ ld a, [hRandomAdd]
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+INCLUDE "home/predef.asm"
+
+
+Func_3ead:: ; 3ead (0:3ead)
+ ld b, BANK(CinnabarGymQuiz_1eb0a)
+ ld hl, CinnabarGymQuiz_1eb0a
+ jp Bankswitch
+
+CheckForHiddenObjectOrBookshelfOrCardKeyDoor:: ; 3eb5 (0:3eb5)
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, [hJoyHeld]
+ bit 0, a ; A button
+ jr z, .nothingFound
+; A button is pressed
+ ld a, Bank(CheckForHiddenObject)
+ ld [MBC1RomBank], a
+ ld [H_LOADEDROMBANK], a
+ call CheckForHiddenObject
+ ld a, [$ffee]
+ and a
+ jr nz, .hiddenObjectNotFound
+ ld a, [wHiddenObjectFunctionRomBank]
+ ld [MBC1RomBank], a
+ ld [H_LOADEDROMBANK], a
+ ld de, .returnAddress
+ push de
+ jp [hl]
+.returnAddress
+ xor a
+ jr .done
+.hiddenObjectNotFound
+ callba PrintBookshelfText
+ ld a, [$ffdb]
+ and a
+ jr z, .done
+.nothingFound
+ ld a, $ff
+.done
+ ld [$ffeb], a
+ pop af
+ ld [MBC1RomBank], a
+ ld [H_LOADEDROMBANK], a
+ ret
+
+PrintPredefTextID:: ; 3ef5 (0:3ef5)
+ ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
+ ld hl, TextPredefs
+ call SetMapTextPointer
+ ld hl, wcf11
+ set 0, [hl]
+ call DisplayTextID
+
+RestoreMapTextPointer:: ; 3f05 (0:3f05)
+ ld hl, W_MAPTEXTPTR
+ ld a, [$ffec]
+ ld [hli], a
+ ld a, [$ffec + 1]
+ ld [hl], a
+ ret
+
+SetMapTextPointer:: ; 3f0f (0:3f0f)
+ ld a, [W_MAPTEXTPTR]
+ ld [$ffec], a
+ ld a, [W_MAPTEXTPTR + 1]
+ ld [$ffec + 1], a
+ ld a, l
+ ld [W_MAPTEXTPTR], a
+ ld a, h
+ ld [W_MAPTEXTPTR + 1], a
+ ret
+
+TextPredefs::
+ add_tx_pre CardKeySuccessText ; 01
+ add_tx_pre CardKeyFailText ; 02
+ add_tx_pre RedBedroomPC ; 03
+ add_tx_pre RedBedroomSNESText ; 04
+ add_tx_pre PushStartText ; 05
+ add_tx_pre SaveOptionText ; 06
+ add_tx_pre StrengthsAndWeaknessesText ; 07
+ add_tx_pre OakLabEmailText ; 08
+ add_tx_pre AerodactylFossilText ; 09
+ add_tx_pre Route15UpstairsBinocularsText ; 0A
+ add_tx_pre KabutopsFossilText ; 0B
+ add_tx_pre GymStatueText1 ; 0C
+ add_tx_pre GymStatueText2 ; 0D
+ add_tx_pre BookcaseText ; 0E
+ add_tx_pre ViridianCityPokecenterBenchGuyText ; 0F
+ add_tx_pre PewterCityPokecenterBenchGuyText ; 10
+ add_tx_pre CeruleanCityPokecenterBenchGuyText ; 11
+ add_tx_pre LavenderCityPokecenterBenchGuyText ; 12
+ add_tx_pre VermilionCityPokecenterBenchGuyText ; 13
+ add_tx_pre CeladonCityPokecenterBenchGuyText ; 14
+ add_tx_pre CeladonCityHotelText ; 15
+ add_tx_pre FuchsiaCityPokecenterBenchGuyText ; 16
+ add_tx_pre CinnabarIslandPokecenterBenchGuyText ; 17
+ add_tx_pre SaffronCityPokecenterBenchGuyText ; 18
+ add_tx_pre MtMoonPokecenterBenchGuyText ; 19
+ add_tx_pre RockTunnelPokecenterBenchGuyText ; 1A
+ add_tx_pre UnusedBenchGuyText1 ; 1B
+ add_tx_pre UnusedBenchGuyText2 ; 1C
+ add_tx_pre UnusedBenchGuyText3 ; 1D
+ add_tx_pre TerminatorText_62508 ; 1E
+ add_tx_pre PredefText1f ; 1F
+ add_tx_pre ViridianSchoolNotebook ; 20
+ add_tx_pre ViridianSchoolBlackboard ; 21
+ add_tx_pre JustAMomentText ; 22
+ add_tx_pre PredefText23 ; 23
+ add_tx_pre FoundHiddenItemText ; 24
+ add_tx_pre HiddenItemBagFullText ; 25
+ add_tx_pre VermilionGymTrashText ; 26
+ add_tx_pre IndigoPlateauHQText ; 27
+ add_tx_pre GameCornerOutOfOrderText ; 28
+ add_tx_pre GameCornerOutToLunchText ; 29
+ add_tx_pre GameCornerSomeonesKeysText ; 2A
+ add_tx_pre FoundHiddenCoinsText ; 2B
+ add_tx_pre DroppedHiddenCoinsText ; 2C
+ add_tx_pre BillsHouseMonitorText ; 2D
+ add_tx_pre BillsHouseInitiatedText ; 2E
+ add_tx_pre BillsHousePokemonList ; 2F
+ add_tx_pre MagazinesText ; 30
+ add_tx_pre CinnabarGymQuiz ; 31
+ add_tx_pre GameCornerNoCoinsText ; 32
+ add_tx_pre GameCornerCoinCaseText ; 33
+ add_tx_pre LinkCableHelp ; 34
+ add_tx_pre TMNotebook ; 35
+ add_tx_pre FightingDojoText ; 36
+ add_tx_pre FightingDojoText_52a10 ; 37
+ add_tx_pre FightingDojoText_52a1d ; 38
+ add_tx_pre NewBicycleText ; 39
+ add_tx_pre IndigoPlateauStatues ; 3A
+ add_tx_pre VermilionGymTrashSuccesText1 ; 3B
+ add_tx_pre VermilionGymTrashSuccesText2 ; 3C
+ add_tx_pre VermilionGymTrashSuccesText3 ; 3D
+ add_tx_pre VermilionGymTrashFailText ; 3E
+ add_tx_pre TownMapText ; 3F
+ add_tx_pre BookOrSculptureText ; 40
+ add_tx_pre ElevatorText ; 41
+ add_tx_pre PokemonStuffText ; 42
diff --git a/home/audio.asm b/home/audio.asm index 9210924c..e062c8da 100644 --- a/home/audio.asm +++ b/home/audio.asm @@ -1,183 +1,186 @@ -PlayDefaultMusic:: ; 2307 (0:2307) - call WaitForSoundToFinish - xor a - ld c, a - ld d, a - ld [wcfca], a - jr asm_2324 - -Func_2312:: ; 2312 (0:2312) - ld c, $a - ld d, $0 - ld a, [wd72e] - bit 5, a - jr z, asm_2324 - xor a - ld [wcfca], a - ld c, $8 - ld d, c -asm_2324:: ; 2324 (0:2324) - ld a, [wWalkBikeSurfState] - and a - jr z, .asm_2343 - cp $2 - jr z, .asm_2332 - ld a, MUSIC_BIKE_RIDING - jr .asm_2334 -.asm_2332 - ld a, MUSIC_SURFING -.asm_2334 - ld b, a - ld a, d - and a - ld a, BANK(Music_BikeRiding) - jr nz, .asm_233e - ld [wc0ef], a -.asm_233e - ld [wc0f0], a - jr .asm_234c -.asm_2343 - ld a, [wd35b] - ld b, a - call Func_2385 - jr c, .asm_2351 -.asm_234c - ld a, [wcfca] - cp b - ret z -.asm_2351 - ld a, c - ld [wMusicHeaderPointer], a - ld a, b - ld [wcfca], a - ld [wc0ee], a - jp PlaySound - -Func_235f:: ; 235f (0:235f) - ld a, [wc0ef] - ld b, a - cp BANK(Music2_UpdateMusic) - jr nz, .checkForBank08 -.bank02 - ld hl, Music2_UpdateMusic - jr .asm_2378 -.checkForBank08 - cp BANK(Music8_UpdateMusic) - jr nz, .bank1F -.bank08 - ld hl, Music8_UpdateMusic - jr .asm_2378 -.bank1F - ld hl, Music1f_UpdateMusic -.asm_2378 - ld c, $6 -.asm_237a - push bc - push hl - call Bankswitch - pop hl - pop bc - dec c - jr nz, .asm_237a - ret - -Func_2385:: ; 2385 (0:2385) - ld a, [wd35c] - ld e, a - ld a, [wc0ef] - cp e - jr nz, .asm_2394 - ld [wc0f0], a - and a - ret -.asm_2394 - ld a, c - and a - ld a, e - jr nz, .asm_239c - ld [wc0ef], a -.asm_239c - ld [wc0f0], a - scf - ret - -PlayMusic:: ; 23a1 (0:23a1) - ld b, a - ld [wc0ee], a - xor a - ld [wMusicHeaderPointer], a - ld a, c - ld [wc0ef], a - ld [wc0f0], a - ld a, b - -; plays music specified by a. If value is $ff, music is stopped -PlaySound:: ; 23b1 (0:23b1) - push hl - push de - push bc - ld b, a - ld a, [wc0ee] - and a - jr z, .asm_23c8 - xor a - ld [wc02a], a - ld [wc02b], a - ld [wc02c], a - ld [wc02d], a -.asm_23c8 - ld a, [wMusicHeaderPointer] - and a - jr z, .asm_23e3 - ld a, [wc0ee] - and a - jr z, .asm_2425 - xor a - ld [wc0ee], a - ld a, [wcfca] - cp $ff - jr nz, .asm_2414 - xor a - ld [wMusicHeaderPointer], a -.asm_23e3 - xor a - ld [wc0ee], a - ld a, [H_LOADEDROMBANK] - ld [$ffb9], a - ld a, [wc0ef] - ld [H_LOADEDROMBANK], a - ld [$2000], a - cp BANK(Func_9876) - jr nz, .checkForBank08 -.bank02 - ld a, b - call Func_9876 - jr .asm_240b -.checkForBank08 - cp BANK(Func_22035) - jr nz, .bank1F -.bank08 - ld a, b - call Func_22035 - jr .asm_240b -.bank1F - ld a, b - call Func_7d8ea -.asm_240b - ld a, [$ffb9] - ld [H_LOADEDROMBANK], a - ld [$2000], a - jr .asm_2425 -.asm_2414 - ld a, b - ld [wcfca], a - ld a, [wMusicHeaderPointer] - ld [wcfc8], a - ld [wcfc9], a - ld a, b - ld [wMusicHeaderPointer], a -.asm_2425 - pop bc - pop de - pop hl - ret +PlayDefaultMusic:: ; 2307 (0:2307)
+ call WaitForSoundToFinish
+ xor a
+ ld c, a
+ ld d, a
+ ld [wcfca], a
+ jr asm_2324
+
+Func_2312:: ; 2312 (0:2312)
+ ld c, $a
+ ld d, $0
+ ld a, [wd72e]
+ bit 5, a
+ jr z, asm_2324
+ xor a
+ ld [wcfca], a
+ ld c, $8
+ ld d, c
+asm_2324:: ; 2324 (0:2324)
+ ld a, [wWalkBikeSurfState]
+ and a
+ jr z, .asm_2343
+ cp $2
+ jr z, .asm_2332
+ ld a, MUSIC_BIKE_RIDING
+ jr .asm_2334
+.asm_2332
+ ld a, MUSIC_SURFING
+.asm_2334
+ ld b, a
+ ld a, d
+ and a
+ ld a, BANK(Music_BikeRiding)
+ jr nz, .asm_233e
+ ld [wc0ef], a
+.asm_233e
+ ld [wc0f0], a
+ jr .asm_234c
+.asm_2343
+ ld a, [wd35b]
+ ld b, a
+ call Func_2385
+ jr c, .asm_2351
+.asm_234c
+ ld a, [wcfca]
+ cp b
+ ret z
+.asm_2351
+ ld a, c
+ ld [wMusicHeaderPointer], a
+ ld a, b
+ ld [wcfca], a
+ ld [wc0ee], a
+ jp PlaySound
+
+Func_235f:: ; 235f (0:235f)
+ ld a, [wc0ef]
+ ld b, a
+ cp BANK(Music2_UpdateMusic)
+ jr nz, .checkForBank08
+.bank02
+ ld hl, Music2_UpdateMusic
+ jr .asm_2378
+.checkForBank08
+ cp BANK(Music8_UpdateMusic)
+ jr nz, .bank1F
+.bank08
+ ld hl, Music8_UpdateMusic
+ jr .asm_2378
+.bank1F
+ ld hl, Music1f_UpdateMusic
+.asm_2378
+ ld c, $6
+.asm_237a
+ push bc
+ push hl
+ call Bankswitch
+ pop hl
+ pop bc
+ dec c
+ jr nz, .asm_237a
+ ret
+
+Func_2385:: ; 2385 (0:2385)
+ ld a, [wd35c]
+ ld e, a
+ ld a, [wc0ef]
+ cp e
+ jr nz, .asm_2394
+ ld [wc0f0], a
+ and a
+ ret
+.asm_2394
+ ld a, c
+ and a
+ ld a, e
+ jr nz, .asm_239c
+ ld [wc0ef], a
+.asm_239c
+ ld [wc0f0], a
+ scf
+ ret
+
+PlayMusic:: ; 23a1 (0:23a1)
+ ld b, a
+ ld [wc0ee], a
+ xor a
+ ld [wMusicHeaderPointer], a
+ ld a, c
+ ld [wc0ef], a
+ ld [wc0f0], a
+ ld a, b
+
+StopAllMusic:: ; 2233 (0:2233)
+ ld a,$FF
+ ld [wc0ee],a
+; plays music specified by a. If value is $ff, music is stopped
+PlaySound:: ; 23b1 (0:23b1)
+ push hl
+ push de
+ push bc
+ ld b, a
+ ld a, [wc0ee]
+ and a
+ jr z, .asm_23c8
+ xor a
+ ld [wc02a], a
+ ld [wc02b], a
+ ld [wc02c], a
+ ld [wc02d], a
+.asm_23c8
+ ld a, [wMusicHeaderPointer]
+ and a
+ jr z, .asm_23e3
+ ld a, [wc0ee]
+ and a
+ jr z, .asm_2425
+ xor a
+ ld [wc0ee], a
+ ld a, [wcfca]
+ cp $ff
+ jr nz, .asm_2414
+ xor a
+ ld [wMusicHeaderPointer], a
+.asm_23e3
+ xor a
+ ld [wc0ee], a
+ ld a, [H_LOADEDROMBANK]
+ ld [$ffb9], a
+ ld a, [wc0ef]
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ cp BANK(Func_9876)
+ jr nz, .checkForBank08
+.bank02
+ ld a, b
+ call Func_9876
+ jr .asm_240b
+.checkForBank08
+ cp BANK(Func_22035)
+ jr nz, .bank1F
+.bank08
+ ld a, b
+ call Func_22035
+ jr .asm_240b
+.bank1F
+ ld a, b
+ call Func_7d8ea
+.asm_240b
+ ld a, [$ffb9]
+ ld [H_LOADEDROMBANK], a
+ ld [$2000], a
+ jr .asm_2425
+.asm_2414
+ ld a, b
+ ld [wcfca], a
+ ld a, [wMusicHeaderPointer]
+ ld [wcfc8], a
+ ld [wcfc9], a
+ ld a, b
+ ld [wMusicHeaderPointer], a
+.asm_2425
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/home/init.asm b/home/init.asm index cc89ad34..701a4bb8 100644 --- a/home/init.asm +++ b/home/init.asm @@ -1,137 +1,136 @@ -SoftReset:: - call StopAllSounds - call GBPalWhiteOut - ld c, $20 - call DelayFrames - ; fallthrough - -Init:: -; Program init. - -rLCDC_DEFAULT EQU %11100011 -; * LCD enabled -; * Window tile map at $9C00 -; * Window display enabled -; * BG and window tile data at $8800 -; * BG tile map at $9800 -; * 8x8 OBJ size -; * OBJ display enabled -; * BG display enabled - - di - - xor a - ld [rIF], a - ld [rIE], a - ld [$ff43], a - ld [$ff42], a - ld [rSB], a - ld [rSC], a - ld [$ff4b], a - ld [$ff4a], a - ld [$ff06], a - ld [$ff07], a - ld [$ff47], a - ld [$ff48], a - ld [$ff49], a - - ld a, rLCDC_ENABLE_MASK - ld [rLCDC], a - call DisableLCD - - ld sp, wStack - - ld hl, $c000 ; start of WRAM - ld bc, $2000 ; size of WRAM -.loop - ld [hl], 0 - inc hl - dec bc - ld a, b - or c - jr nz, .loop - - call ClearVram - - ld hl, $ff80 - ld bc, $ffff - $ff80 - call FillMemory - - call ClearSprites - - ld a, Bank(WriteDMACodeToHRAM) - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - call WriteDMACodeToHRAM - - xor a - ld [hTilesetType], a - ld [$ff41], a - ld [hSCX], a - ld [hSCY], a - ld [$ff0f], a - ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL - ld [rIE], a - - ld a, 144 ; move the window off-screen - ld [hWY], a - ld [rWY], a - ld a, 7 - ld [rWX], a - - ld a, CONNECTION_NOT_ESTABLISHED - ld [hSerialConnectionStatus], a - - ld h, vBGMap0 / $100 - call ClearBgMap - ld h, vBGMap1 / $100 - call ClearBgMap - - ld a, rLCDC_DEFAULT - ld [rLCDC], a - ld a, 16 - ld [hSoftReset], a - call StopAllSounds - - ei - - predef LoadSGB - - ld a, BANK(SFX_1f_67) - ld [wc0ef], a - ld [wc0f0], a - ld a, $9c - ld [$ffbd], a - xor a - ld [$ffbc], a - dec a - ld [wUpdateSpritesEnabled], a - - predef PlayIntro - - call DisableLCD - call ClearVram - call GBPalNormal - call ClearSprites - ld a, rLCDC_DEFAULT - ld [rLCDC], a - - jp SetDefaultNamesBeforeTitlescreen - -ClearVram: - ld hl, $8000 - ld bc, $2000 - xor a - jp FillMemory - - -StopAllSounds:: - ld a, BANK(Music2_UpdateMusic) - ld [wc0ef], a - ld [wc0f0], a - xor a - ld [wMusicHeaderPointer], a - ld [wc0ee], a - ld [wcfca], a - dec a - jp PlaySound +SoftReset::
+ call StopAllSounds
+ call GBPalWhiteOut
+ ld c, $20
+ call DelayFrames
+ ; fallthrough
+
+Init::
+; Program init.
+
+rLCDC_DEFAULT EQU %11100011
+; * LCD enabled
+; * Window tile map at $9C00
+; * Window display enabled
+; * BG and window tile data at $8800
+; * BG tile map at $9800
+; * 8x8 OBJ size
+; * OBJ display enabled
+; * BG display enabled
+
+ di
+
+ xor a
+ ld [rIF], a
+ ld [rIE], a
+ ld [$ff43], a
+ ld [$ff42], a
+ ld [rSB], a
+ ld [rSC], a
+ ld [$ff4b], a
+ ld [$ff4a], a
+ ld [$ff06], a
+ ld [$ff07], a
+ ld [$ff47], a
+ ld [$ff48], a
+ ld [$ff49], a
+
+ ld a, rLCDC_ENABLE_MASK
+ ld [rLCDC], a
+ call DisableLCD
+
+ ld sp, wStack
+
+ ld hl, $c000 ; start of WRAM
+ ld bc, $2000 ; size of WRAM
+.loop
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+
+ call ClearVram
+
+ ld hl, $ff80
+ ld bc, $ffff - $ff80
+ call FillMemory
+
+ call ClearSprites
+
+ ld a, Bank(WriteDMACodeToHRAM)
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ call WriteDMACodeToHRAM
+
+ xor a
+ ld [hTilesetType], a
+ ld [$ff41], a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld [$ff0f], a
+ ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL
+ ld [rIE], a
+
+ ld a, 144 ; move the window off-screen
+ ld [hWY], a
+ ld [rWY], a
+ ld a, 7
+ ld [rWX], a
+
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ld [hSerialConnectionStatus], a
+
+ ld h, vBGMap0 / $100
+ call ClearBgMap
+ ld h, vBGMap1 / $100
+ call ClearBgMap
+
+ ld a, rLCDC_DEFAULT
+ ld [rLCDC], a
+ ld a, 16
+ ld [hSoftReset], a
+ call StopAllSounds
+
+ ei
+
+ predef LoadSGB
+
+ ld a, BANK(SFX_1f_67)
+ ld [wc0ef], a
+ ld [wc0f0], a
+ ld a, $9c
+ ld [$ffbd], a
+ xor a
+ ld [$ffbc], a
+ dec a
+ ld [wUpdateSpritesEnabled], a
+
+ predef PlayIntro
+
+ call DisableLCD
+ call ClearVram
+ call GBPalNormal
+ call ClearSprites
+ ld a, rLCDC_DEFAULT
+ ld [rLCDC], a
+
+ jp SetDefaultNamesBeforeTitlescreen
+
+ClearVram:
+ ld hl, $8000
+ ld bc, $2000
+ xor a
+ jp FillMemory
+
+
+StopAllSounds::
+ ld a, BANK(Music2_UpdateMusic)
+ ld [wc0ef], a
+ ld [wc0f0], a
+ xor a
+ ld [wMusicHeaderPointer], a
+ ld [wc0ee], a
+ ld [wcfca], a
+ jp StopAllMusic
diff --git a/home/overworld.asm b/home/overworld.asm index 0a92355c..3309f1cc 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -1,2225 +1,2293 @@ -EnterMap:: ; 01d7 (0:01d7) -; Load a new map. - ld a, $ff - ld [wJoyIgnore], a - call LoadMapData - callba ClearVariablesAfterLoadingMapData - ld hl, wd72c - bit 0, [hl] ; has the player already made 3 steps since the last battle? - jr z, .skipGivingThreeStepsOfNoRandomBattles - ld a, 3 ; minimum number of steps between battles - ld [wNumberOfNoRandomBattleStepsLeft], a -.skipGivingThreeStepsOfNoRandomBattles - ld hl, wd72e - bit 5, [hl] ; did a battle happen immediately before this? - res 5, [hl] ; unset the "battle just happened" flag - call z, ResetUsingStrengthOutOfBattleBit - call nz, MapEntryAfterBattle - ld hl, wd732 - ld a, [hl] - and 1 << 4 | 1 << 3 ; fly warp or dungeon warp - jr z, .didNotEnterUsingFlyWarpOrDungeonWarp - callba EnterMapAnim - call UpdateSprites - ld hl, wd732 - res 3, [hl] - ld hl, wd72e - res 4, [hl] - call Func_342a -.didNotEnterUsingFlyWarpOrDungeonWarp - callba CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road - ld hl, wd732 - bit 4, [hl] - res 4, [hl] - ld hl, wd72d - res 5, [hl] - call UpdateSprites - ld hl, wd126 - set 5, [hl] - set 6, [hl] - xor a - ld [wJoyIgnore], a - -OverworldLoop:: ; 0242 (0:0242) - call DelayFrame -OverworldLoopLessDelay:: ; 0245 (0:0245) - call DelayFrame - call Func_342a - call LoadGBPal - ld a,[wWalkCounter] - and a - jp nz,.moveAhead ; if the player sprite has not yet completed the walking animation - call JoypadOverworld ; get joypad state (which is possibly simulated) - callba SafariZoneCheck - ld a,[wSafariZoneGameOver] - and a - jp nz,WarpFound2 - ld hl,wd72d - bit 3,[hl] - res 3,[hl] - jp nz,WarpFound2 - ld a,[wd732] - and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp - jp nz,HandleFlyWarpOrDungeonWarp - ld a,[W_CUROPPONENT] - and a - jp nz,.newBattle - ld a,[wd730] - bit 7,a ; are we simulating button presses? - jr z,.notSimulating - ld a,[hJoyHeld] - jr .checkIfStartIsPressed -.notSimulating - ld a,[hJoyPressed] -.checkIfStartIsPressed - bit 3,a ; start button - jr z,.startButtonNotPressed -; if START is pressed - xor a - ld [hSpriteIndexOrTextID],a ; start menu text ID - jp .displayDialogue -.startButtonNotPressed - bit 0,a ; A button - jp z,.checkIfDownButtonIsPressed -; if A is pressed - ld a,[wd730] - bit 2,a - jp nz,.noDirectionButtonsPressed - call IsPlayerCharacterBeingControlledByGame - jr nz,.checkForOpponent - call CheckForHiddenObjectOrBookshelfOrCardKeyDoor - ld a,[$ffeb] - and a - jp z,OverworldLoop ; jump if a hidden object or bookshelf was found, but not if a card key door was found - xor a - ld [wd436],a ; new yellow address - call IsSpriteOrSignInFrontOfPlayer - call Func_0ffe - ld a,[hSpriteIndexOrTextID] - and a - jp z,OverworldLoop -.displayDialogue - predef GetTileAndCoordsInFrontOfPlayer - call UpdateSprites - ld a,[wFlags_0xcd60] - bit 2,a - jr nz,.checkForOpponent - bit 0,a - jr nz,.checkForOpponent - aCoord 8, 9 - ld [wcf0e],a - call DisplayTextID ; display either the start menu or the NPC/sign text - ld a,[wcc47] - and a - jr z,.checkForOpponent - xor a - ld [wcc47],a - jp EnterMap -; predef LoadSAV -; ld a,[W_CURMAP] -; ld [wDestinationMap],a -; call SpecialWarpIn -; ld a,[W_CURMAP] -; call SwitchToMapRomBank ; switch to the ROM bank of the current map -; ld hl,W_CURMAPTILESET -; set 7,[hl] -.checkForOpponent - ld a,[W_CUROPPONENT] - and a - jp nz,.newBattle - jp OverworldLoop -.noDirectionButtonsPressed - call UpdateSprites ; 231c - ld hl,wFlags_0xcd60 - res 2,[hl] - xor a - ld [wd435], a - ld a, $1 - ld a,$01 - ld [wcc4b],a - ld a,[wd528] ; the direction that was pressed last time - and a - jr z, .overworldloop -; if a direction was pressed last time - ld [wd529],a ; save the last direction - xor a - ld [wd528],a ; zero the direction -.overworldloop - jp OverworldLoop -.checkIfDownButtonIsPressed - ld a,[hJoyHeld] ; current joypad state - bit 7,a ; down button - jr z,.checkIfUpButtonIsPressed - ld a,$01 - ld [wSpriteStateData1 + 3],a - ld a,$04 - jr .handleDirectionButtonPress -.checkIfUpButtonIsPressed - bit 6,a ; up button - jr z,.checkIfLeftButtonIsPressed - ld a,$ff - ld [wSpriteStateData1 + 3],a - ld a,$08 - jr .handleDirectionButtonPress -.checkIfLeftButtonIsPressed - bit 5,a ; left button - jr z,.checkIfRightButtonIsPressed - ld a,$ff - ld [wSpriteStateData1 + 5],a - ld a,$02 - jr .handleDirectionButtonPress -.checkIfRightButtonIsPressed - bit 4,a ; right button - jr z,.noDirectionButtonsPressed - ld a,$01 - ld [wSpriteStateData1 + 5],a -.handleDirectionButtonPress - ld [wd52a],a ; new direction - ld a,[wd730] - bit 7,a ; are we simulating button presses? - jr nz,.noDirectionChange ; ignore direction changes if we are - ld a,[wcc4b] - and a - jr z,.noDirectionChange - ld a,[wd52a] ; new direction - ld b,a - ld a,[wd529] ; old direction - cp b - jr z,.noDirectionChange - ld a,$8 - ld [wd434],a -; unlike in red/blue, yellow does not have the 180 degrees odd code - ld hl,wFlags_0xcd60 - set 2,[hl] - xor a - ld [wcc4b],a - ld a,[wd52a] - ld [wd528],a - call NewBattle - jp c,.battleOccurred - jp OverworldLoop -.noDirectionChange - ld a,[wd52a] ; current direction - ld [wd528],a ; save direction - call UpdateSprites - ld a,[wWalkBikeSurfState] - cp a,$02 ; surfing - jr z,.surfing -; not surfing - call CollisionCheckOnLand - jr nc,.noCollision -; collision occurred - push hl - ld hl,wd736 - bit 2,[hl] ; standing on warp flag - pop hl - jp z,OverworldLoop -; collision occurred while standing on a warp - push hl - call ExtraWarpCheck ; sets carry if there is a potential to warp - pop hl - jp c,CheckWarpsCollision - jp OverworldLoop -.surfing - call CollisionCheckOnWater - jp c,OverworldLoop -.noCollision - ld a,$08 - ld [wWalkCounter],a - callab Func_fcc08 - jr .moveAhead2 -.moveAhead - call IsSpinning - call UpdateSprites ; move sprites -.moveAhead2 - ld hl,wFlags_0xcd60 - res 2,[hl] - xor a - ld [wd435],a - call DoBikeSpeedup - call AdvancePlayerSprite - ld a,[wWalkCounter] - and a - jp nz,CheckMapConnections ; it seems like this check will never succeed (the other place where CheckMapConnections is run works) -; walking animation finished - call StepCountCheck - ld a,[wd790] - bit 7,a ; in the safari zone? - jr z,.notSafariZone - callba SafariZoneCheckSteps - ld a,[wSafariZoneGameOver] - and a - jp nz,WarpFound2 -.notSafariZone - ld a,[W_ISINBATTLE] - and a - jp nz,CheckWarpsNoCollision - predef ApplyOutOfBattlePoisonDamage ; also increment daycare mon exp - ld a,[wd12d] - and a - jp nz,HandleBlackOut ; if all pokemon fainted -.newBattle - call NewBattle - ld hl,wd736 - res 2,[hl] ; standing on warp flag - jp nc,CheckWarpsNoCollision ; check for warps if there was no battle -.battleOccurred - ld hl,wd72d - res 6,[hl] - ld hl,W_FLAGS_D733 - res 3,[hl] - ld hl,wd126 - set 5,[hl] - set 6,[hl] - xor a - ld [hJoyHeld],a - ld a,[W_CURMAP] - cp a,CINNABAR_GYM - jr nz,.notCinnabarGym - ld hl,wd79b - set 7,[hl] -.notCinnabarGym - ld hl,wd72e - set 5,[hl] - ld a,[W_CURMAP] - cp a,OAKS_LAB - jp z,.noFaintCheck ; no blacking out if the player lost to the rival in Oak's lab - callab AnyPartyAlive - ld a,d - and a - jr z,.allPokemonFainted -.noFaintCheck - ld c,$0a - call DelayFrames - jp EnterMap -;.allPokemonFainted -; ld a,$ff -; ld [W_ISINBATTLE],a -; call RunMapScript -; jp HandleBlackOut - -StepCountCheck:: ; 0457 (0:0457) - ld a,[wd730] - bit 7,a - jr nz,.doneStepCounting ; if button presses are being simulated, don't count steps -; step counting - ld hl,wStepCounter - dec [hl] - ld a,[wd72c] - bit 0,a - jr z,.doneStepCounting - ld hl,wNumberOfNoRandomBattleStepsLeft - dec [hl] - jr nz,.doneStepCounting - ld hl,wd72c - res 0,[hl] ; indicate that the player has stepped thrice since the last battle -.doneStepCounting - ret - -; function to determine if there will be a battle and execute it (either a trainer battle or wild battle) -; sets carry if a battle occurred and unsets carry if not -NewBattle:: ; 0480 (0:0480) - ld a,[wd72d] - bit 4,a - jr nz,.noBattle - call IsPlayerCharacterBeingControlledByGame - jr nz,.noBattle ; no battle if the player character is under the game's control - ld a,[wd72e] - bit 4,a - jr nz,.noBattle - ld b, BANK(InitBattle) - ld hl, InitBattle ; 3d:5ff2 - jp Bankswitch -.noBattle - and a - ret - -DoBikeSpeedup:: ; 049d (0:049d) - ld a,[wWalkBikeSurfState] - dec a ; riding a bike? - ret nz - ld a,[wd736] - bit 6,a - ret nz - ld a,[wNPCMovementScriptPointerTableNum] - and a - ret nz - ld a,[W_CURMAP] - cp ROUTE_17 ; cycling road - jr nz,.goFaster - ld a,[hJoyHeld] - and a,D_UP | D_LEFT | D_RIGHT - ret nz -.goFaster - call AdvancePlayerSprite - ret - -; check if the player has stepped onto a warp after having not collided -CheckWarpsNoCollision:: ; 04bd (0:04bd) - ld a,[wNumberOfWarps] - and a - jp z,CheckMapConnections - ld b,0 - ld a,[wNumberOfWarps] - ld c,a - ld a,[W_YCOORD] - ld d,a - ld a,[W_XCOORD] - ld e,a - ld hl,wWarpEntries -CheckWarpsNoCollisionLoop:: ; 04d5 (0:04d5) - ld a,[hli] ; check if the warp's Y position matches - cp d - jr nz,CheckWarpsNoCollisionRetry1 - ld a,[hli] ; check if the warp's X position matches - cp e - jr nz,CheckWarpsNoCollisionRetry2 -; if a match was found - push hl - push bc - ld hl,wd736 - set 2,[hl] ; standing on warp flag - callba IsPlayerStandingOnDoorTileOrWarpTile - pop bc - pop hl - jr c,WarpFound1 ; jump if standing on door or warp - push hl - push bc - call ExtraWarpCheck - pop bc - pop hl - jr nc,CheckWarpsNoCollisionRetry2 -; if the extra check passed - ld a,[W_FLAGS_D733] - bit 2,a - jr nz,WarpFound1 - push de - push bc - call Joypad - pop bc - pop de - ld a,[hJoyHeld] - and a,D_DOWN | D_UP | D_LEFT | D_RIGHT - jr z,CheckWarpsNoCollisionRetry2 ; if directional buttons aren't being pressed, do not pass through the warp - jr WarpFound1 - -CheckWarpsNoCollisionRetry1:: ; 050f (0:050f) - inc hl -CheckWarpsNoCollisionRetry2:: ; 0510 (0:0510) - inc hl - inc hl -ContinueCheckWarpsNoCollisionLoop:: ; 0512 (0:0512) - inc b ; increment warp number - dec c ; decrement number of warps - jp nz,CheckWarpsNoCollisionLoop - jp CheckMapConnections - -; check if the player has stepped onto a warp after having collided -CheckWarpsCollision:: ; 0706 (0:0706) - ld a,[wNumberOfWarps] - ld c,a - ld hl,wWarpEntries -.loop - ld a,[hli] ; Y coordinate of warp - ld b,a - ld a,[W_YCOORD] - cp b - jr nz,.retry1 - ld a,[hli] ; X coordinate of warp - ld b,a - ld a,[W_XCOORD] - cp b - jr nz,.retry2 - ld a,[hli] - ld [wDestinationWarpID],a - ld a,[hl] - ld [$ff8b],a ; save target map - jr WarpFound2 -.retry1 - inc hl -.retry2 - inc hl - inc hl - dec c - jr nz,.loop - jp OverworldLoop - -WarpFound1:: ; 0735 (0:0735) - ld a,[hli] - ld [wDestinationWarpID],a - ld a,[hli] - ld [$ff8b],a ; save target map - -WarpFound2:: ; 073c (0:073c) - ld a,[wNumberOfWarps] - sub c - ld [wd73b],a ; save ID of used warp - ld a,[W_CURMAP] - ld [wd73c],a - call CheckIfInOutsideMap - jr nz,.indoorMaps -; this is for handling "outside" maps that can't have the 0xFF destination map - ld a,[W_CURMAP] - ld [wLastMap],a - ld a,[W_CURMAPWIDTH] - ld [wd366],a - ld a,[$ff8b] ; destination map number - ld [W_CURMAP],a ; change current map to destination map - cp a,ROCK_TUNNEL_1 - jr nz,.notRockTunnel - ld a,$06 - ld [wMapPalOffset],a - call GBFadeOutToBlack -.notRockTunnel - callab Func_fc5fa ; 3f:45fa - call PlayMapChangeSound - jr .done -; for maps that can have the 0xFF destination map, which means to return to the outside map; not all these maps are necessarily indoors, though -.indoorMaps - ld a,[$ff8b] ; destination map - cp a,$ff - jr z,.goBackOutside -; if not going back to the previous map - ld [W_CURMAP],a ; current map number - callba IsPlayerStandingOnWarpPadOrHole - ld a,[wcd5b] - dec a ; is the player on a warp pad? - jr nz,.notWarpPad -; if the player is on a warp pad - call LeaveMapAnim - ld hl,wd732 - set 3,[hl] - jr .skipMapChangeSound -.notWarpPad - call PlayMapChangeSound -.skipMapChangeSound - ld hl,wd736 - res 0,[hl] - res 1,[hl] - callab Func_fc65b ; 3f:465b - jr .done -.goBackOutside - callab Func_fc69a ; 3f:469a - ; continue from here - ld a,[wLastMap] - ld [W_CURMAP],a - call PlayMapChangeSound - xor a - ld [wMapPalOffset],a -.done - ld hl,wd736 - set 0,[hl] ; have the player's sprite step out from the door (if there is one) - call IgnoreInputForHalfSecond - jp EnterMap - -; if no matching warp was found -CheckMapConnections:: ; 05db (0:05db) -.checkWestMap - ld a,[W_XCOORD] - cp a,$ff - jr nz,.checkEastMap - ld a,[W_MAPCONN3PTR] - ld [W_CURMAP],a - ld a,[wd38f] ; new X coordinate upon entering west map - ld [W_XCOORD],a - ld a,[W_YCOORD] - ld c,a - ld a,[wd38e] ; Y adjustment upon entering west map - add c - ld c,a - ld [W_YCOORD],a - ld a,[wd390] ; pointer to upper left corner of map without adjustment for Y position - ld l,a - ld a,[wd391] - ld h,a - srl c - jr z,.savePointer1 -.pointerAdjustmentLoop1 - ld a,[wd38d] ; width of connected map - add a,$06 - ld e,a - ld d,$00 - ld b,$00 - add hl,de - dec c - jr nz,.pointerAdjustmentLoop1 -.savePointer1 - ld a,l - ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section - ld a,h - ld [wCurrentTileBlockMapViewPointer + 1],a - jp .loadNewMap -.checkEastMap - ld b,a - ld a,[wd525] ; map width - cp b - jr nz,.checkNorthMap - ld a,[W_MAPCONN4PTR] - ld [W_CURMAP],a - ld a,[wd39a] ; new X coordinate upon entering east map - ld [W_XCOORD],a - ld a,[W_YCOORD] - ld c,a - ld a,[wd399] ; Y adjustment upon entering east map - add c - ld c,a - ld [W_YCOORD],a - ld a,[wd39b] ; pointer to upper left corner of map without adjustment for Y position - ld l,a - ld a,[wd39c] - ld h,a - srl c - jr z,.savePointer2 -.pointerAdjustmentLoop2 - ld a,[wd398] - add a,$06 - ld e,a - ld d,$00 - ld b,$00 - add hl,de - dec c - jr nz,.pointerAdjustmentLoop2 -.savePointer2 - ld a,l - ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section - ld a,h - ld [wCurrentTileBlockMapViewPointer + 1],a - jp .loadNewMap -.checkNorthMap - ld a,[W_YCOORD] - cp a,$ff - jr nz,.checkSouthMap - ld a,[W_MAPCONN1PTR] - ld [W_CURMAP],a - ld a,[wd378] ; new Y coordinate upon entering north map - ld [W_YCOORD],a - ld a,[W_XCOORD] - ld c,a - ld a,[wd379] ; X adjustment upon entering north map - add c - ld c,a - ld [W_XCOORD],a - ld a,[wd37a] ; pointer to upper left corner of map without adjustment for X position - ld l,a - ld a,[wd37b] - ld h,a - ld b,$00 - srl c - add hl,bc - ld a,l - ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section - ld a,h - ld [wCurrentTileBlockMapViewPointer + 1],a - jp .loadNewMap -.checkSouthMap - ld b,a - ld a,[wd524] - cp b - jr nz,.didNotEnterConnectedMap - ld a,[W_MAPCONN2PTR] - ld [W_CURMAP],a - ld a,[wd383] ; new Y coordinate upon entering south map - ld [W_YCOORD],a - ld a,[W_XCOORD] - ld c,a - ld a,[wd384] ; X adjustment upon entering south map - add c - ld c,a - ld [W_XCOORD],a - ld a,[wd385] ; pointer to upper left corner of map without adjustment for X position - ld l,a - ld a,[wd386] - ld h,a - ld b,$00 - srl c - add hl,bc - ld a,l - ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section - ld a,h - ld [wCurrentTileBlockMapViewPointer + 1],a -.loadNewMap ; load the connected map that was entered - call LoadMapHeader - call Func_2312 ; music - ld b,$09 - call GoPAL_SET -; Since the sprite set shouldn't change, this will just update VRAM slots at -; $C2XE without loading any tile patterns. - callba InitMapSprites - call LoadTileBlockMap - jp OverworldLoopLessDelay -.didNotEnterConnectedMap - jp OverworldLoop - -; function to play a sound when changing maps -PlayMapChangeSound:: ; 08c9 (0:08c9) - aCoord 8, 8 ; upper left tile of the 4x4 square the player's sprite is standing on - cp a,$0b ; door tile in tileset 0 - jr nz,.didNotGoThroughDoor - ld a,(SFX_02_57 - SFX_Headers_02) / 3 - jr .playSound -.didNotGoThroughDoor - ld a,(SFX_02_5c - SFX_Headers_02) / 3 -.playSound - call PlaySound - ld a,[wMapPalOffset] - and a - ret nz - jp GBFadeOutToBlack - -CheckIfInOutsideMap:: ; 08e1 (0:08e1) -; If the player is in an outside map (a town or route), set the z flag - ld a, [W_CURMAPTILESET] - and a ; most towns/routes have tileset 0 (OVERWORLD) - ret z - cp PLATEAU ; Route 23 / Indigo Plateau - ret - -; this function is an extra check that sometimes has to pass in order to warp, beyond just standing on a warp -; the "sometimes" qualification is necessary because of CheckWarpsNoCollision's behavior -; depending on the map, either "function 1" or "function 2" is used for the check -; "function 1" passes when the player is at the edge of the map and is facing towards the outside of the map -; "function 2" passes when the the tile in front of the player is among a certain set -; sets carry if the check passes, otherwise clears carry -ExtraWarpCheck:: ; 08e9 (0:08e9) - ld a, [W_CURMAP] - cp SS_ANNE_3 - jr z, .useFunction1 - cp ROCKET_HIDEOUT_1 - jr z, .useFunction2 - cp ROCKET_HIDEOUT_2 - jr z, .useFunction2 - cp ROCKET_HIDEOUT_4 - jr z, .useFunction2 - cp ROCK_TUNNEL_1 - jr z, .useFunction2 - ld a, [W_CURMAPTILESET] - and a ; outside tileset (OVERWORLD) - jr z, .useFunction2 - cp SHIP ; S.S. Anne tileset - jr z, .useFunction2 - cp SHIP_PORT ; Vermilion Port tileset - jr z, .useFunction2 - cp PLATEAU ; Indigo Plateau tileset - jr z, .useFunction2 -.useFunction1 - ld hl, IsPlayerFacingEdgeOfMap - jr .doBankswitch -.useFunction2 - ld hl, IsWarpTileInFrontOfPlayer -.doBankswitch - ld b, BANK(IsWarpTileInFrontOfPlayer) - jp Bankswitch - -MapEntryAfterBattle:: ; 091f (0:091f) - callba IsPlayerStandingOnWarp ; for enabling warp testing after collisions - ld a,[wMapPalOffset] - and a - jp z,GBFadeInFromWhite - jp LoadGBPal - -HandleBlackOut:: -; For when all the player's pokemon faint. -; Does not print the "blacked out" message. - - call GBFadeOutToBlack - ld a, $08 - call StopMusic - ld hl, wd72e - res 5, [hl] - ld a, Bank(ResetStatusAndHalveMoneyOnBlackout) ; also Bank(SpecialWarpIn) and Bank(SpecialEnterMap) - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - call ResetStatusAndHalveMoneyOnBlackout - call SpecialWarpIn - call Func_2312 - jp SpecialEnterMap - -StopMusic:: - ld [wMusicHeaderPointer], a - ld a, $ff - ld [wc0ee], a - call PlaySound -.wait - ld a, [wMusicHeaderPointer] - and a - jr nz, .wait - jp StopAllSounds - -HandleFlyWarpOrDungeonWarp:: ; 0794 (0:0794) - call UpdateSprites - call Delay3 - xor a - ld [wBattleResult], a - ld [wWalkBikeSurfState], a - ld [W_ISINBATTLE], a - ld [wMapPalOffset], a - ld hl, wd732 - set 2, [hl] ; fly warp or dungeon warp - res 5, [hl] ; forced to ride bike - call LeaveMapAnim - ld a, Bank(SpecialWarpIn) - ld [H_LOADEDROMBANK], a - ld [$2000], a - call SpecialWarpIn - jp SpecialEnterMap - -LeaveMapAnim:: ; 07bc (0:07bc) - ld b, BANK(_LeaveMapAnim) - ld hl, _LeaveMapAnim - jp Bankswitch - -LoadPlayerSpriteGraphics:: -; Load sprite graphics based on whether the player is standing, biking, or surfing. - - ; 0: standing - ; 1: biking - ; 2: surfing - - ld a, [wWalkBikeSurfState] - dec a - jr z, .ridingBike - - ld a, [hTilesetType] - and a - jr nz, .determineGraphics - jr .startWalking - -.ridingBike - ; If the bike can't be used, - ; start walking instead. - call IsBikeRidingAllowed - jr c, .determineGraphics - -.startWalking - xor a - ld [wWalkBikeSurfState], a - ld [wWalkBikeSurfStateCopy], a - jp LoadWalkingPlayerSpriteGraphics - -.determineGraphics - ld a, [wWalkBikeSurfState] - and a - jp z, LoadWalkingPlayerSpriteGraphics - dec a - jp z, LoadBikePlayerSpriteGraphics - dec a - jp z, LoadSurfingPlayerSpriteGraphics - jp LoadWalkingPlayerSpriteGraphics - -IsBikeRidingAllowed:: -; The bike can be used on Route 23 and Indigo Plateau, -; or maps with tilesets in BikeRidingTilesets. -; Return carry if biking is allowed. - - ld a, [W_CURMAP] - cp ROUTE_23 - jr z, .allowed - cp INDIGO_PLATEAU - jr z, .allowed - - ld a, [W_CURMAPTILESET] - ld b, a - ld hl, BikeRidingTilesets -.loop - ld a, [hli] - cp b - jr z, .allowed - inc a - jr nz, .loop - and a - ret - -.allowed - scf - ret - -INCLUDE "data/bike_riding_tilesets.asm" - -; load the tile pattern data of the current tileset into VRAM -LoadTilesetTilePatternData:: ; 09e8 (0:09e8) - ld a,[W_TILESETGFXPTR] - ld l,a - ld a,[W_TILESETGFXPTR + 1] - ld h,a - ld de,vTileset - ld bc,$600 - ld a,[W_TILESETBANK] - jp FarCopyData2 - -; this loads the current maps complete tile map (which references blocks, not individual tiles) to C6E8 -; it can also load partial tile maps of connected maps into a border of length 3 around the current map -LoadTileBlockMap:: ; 09fc (0:09fc) -; fill C6E8-CBFB with the background tile - ld hl,wOverworldMap - ld a,[wd3ad] ; background tile number - ld d,a - ld bc,$0514 -.backgroundTileLoop - ld a,d - ld [hli],a - dec bc - ld a,c - or b - jr nz,.backgroundTileLoop -; load tile map of current map (made of tile block IDs) -; a 3-byte border at the edges of the map is kept so that there is space for map connections - ld hl,wOverworldMap - ld a,[W_CURMAPWIDTH] - ld [$ff8c],a - add a,$06 ; border (east and west) - ld [$ff8b],a ; map width + border - ld b,$00 - ld c,a -; make space for north border (next 3 lines) - add hl,bc - add hl,bc - add hl,bc - ld c,$03 - add hl,bc ; this puts us past the (west) border - ld a,[W_MAPDATAPTR] ; tile map pointer - ld e,a - ld a,[W_MAPDATAPTR + 1] - ld d,a ; de = tile map pointer - ld a,[W_CURMAPHEIGHT] - ld b,a -.rowLoop ; copy one row each iteration - push hl - ld a,[$ff8c] ; map width (without border) - ld c,a -.rowInnerLoop - ld a,[de] - inc de - ld [hli],a - dec c - jr nz,.rowInnerLoop -; add the map width plus the border to the base address of the current row to get the next row's address - pop hl - ld a,[$ff8b] ; map width + border - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - dec b - jr nz,.rowLoop -.northConnection - ld a,[W_MAPCONN1PTR] - cp a,$ff - jr z,.southConnection - call SwitchToMapRomBank - ld a,[wd372] - ld l,a - ld a,[wd373] - ld h,a - ld a,[wd374] - ld e,a - ld a,[wd375] - ld d,a - ld a,[wd376] - ld [$ff8b],a - ld a,[wd377] - ld [$ff8c],a - call LoadNorthSouthConnectionsTileMap -.southConnection - ld a,[W_MAPCONN2PTR] - cp a,$ff - jr z,.westConnection - call SwitchToMapRomBank - ld a,[wd37d] - ld l,a - ld a,[wd37e] - ld h,a - ld a,[wd37f] - ld e,a - ld a,[wd380] - ld d,a - ld a,[wd381] - ld [$ff8b],a - ld a,[wd382] - ld [$ff8c],a - call LoadNorthSouthConnectionsTileMap -.westConnection - ld a,[W_MAPCONN3PTR] - cp a,$ff - jr z,.eastConnection - call SwitchToMapRomBank - ld a,[wd388] - ld l,a - ld a,[wd389] - ld h,a - ld a,[wd38a] - ld e,a - ld a,[wd38b] - ld d,a - ld a,[wd38c] - ld b,a - ld a,[wd38d] - ld [$ff8b],a - call LoadEastWestConnectionsTileMap -.eastConnection - ld a,[W_MAPCONN4PTR] - cp a,$ff - jr z,.done - call SwitchToMapRomBank - ld a,[wd393] - ld l,a - ld a,[wd394] - ld h,a - ld a,[wd395] - ld e,a - ld a,[wd396] - ld d,a - ld a,[wd397] - ld b,a - ld a,[wd398] - ld [$ff8b],a - call LoadEastWestConnectionsTileMap -.done - ret - -LoadNorthSouthConnectionsTileMap:: ; 0ade (0:0ade) - ld c,$03 -.loop - push de - push hl - ld a,[$ff8b] ; width of connection - ld b,a -.innerLoop - ld a,[hli] - ld [de],a - inc de - dec b - jr nz,.innerLoop - pop hl - pop de - ld a,[$ff8c] ; width of connected map - add l - ld l,a - jr nc,.noCarry1 - inc h -.noCarry1 - ld a,[W_CURMAPWIDTH] - add a,$06 - add e - ld e,a - jr nc,.noCarry2 - inc d -.noCarry2 - dec c - jr nz,.loop - ret - -LoadEastWestConnectionsTileMap:: ; 0b02 (0:0b02) - push hl - push de - ld c,$03 -.innerLoop - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.innerLoop - pop de - pop hl - ld a,[$ff8b] ; width of connected map - add l - ld l,a - jr nc,.noCarry1 - inc h -.noCarry1 - ld a,[W_CURMAPWIDTH] - add a,$06 - add e - ld e,a - jr nc,.noCarry2 - inc d -.noCarry2 - dec b - jr nz,LoadEastWestConnectionsTileMap - ret - -; function to check if there is a sign or sprite in front of the player -; if so, it is stored in [hSpriteIndexOrTextID] -; if not, [hSpriteIndexOrTextID] is set to 0 -IsSpriteOrSignInFrontOfPlayer:: ; 0b23 (0:0b23) - xor a - ld [hSpriteIndexOrTextID],a - ld a,[wd4b0] ; number of signs in the map - and a - jr z,.extendRangeOverCounter -; if there are signs - predef GetTileAndCoordsInFrontOfPlayer ; get the coordinates in front of the player in de - ld hl,wd4b1 ; start of sign coordinates - ld a,[wd4b0] ; number of signs in the map - ld b,a - ld c,$00 -.signLoop - inc c - ld a,[hli] ; sign Y - cp d - jr z,.yCoordMatched - inc hl - jr .retry -.yCoordMatched - ld a,[hli] ; sign X - cp e - jr nz,.retry -.xCoordMatched -; found sign - push hl - push bc - ld hl,wd4d1 ; start of sign text ID's - ld b,$00 - dec c - add hl,bc - ld a,[hl] - ld [hSpriteIndexOrTextID],a ; store sign text ID - pop bc - pop hl - ret -.retry - dec b - jr nz,.signLoop -; check if the player is front of a counter in a pokemon center, pokemart, etc. and if so, extend the range at which he can talk to the NPC -.extendRangeOverCounter - predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player in c - ld hl,W_TILESETTALKINGOVERTILES ; list of tiles that extend talking range (counter tiles) - ld b,$03 - ld d,$20 ; talking range in pixels (long range) -.counterTilesLoop - ld a,[hli] - cp c - jr z,IsSpriteInFrontOfPlayer2 ; jumps if the tile in front of the player is a counter tile - dec b - jr nz,.counterTilesLoop - -; part of the above function, but sometimes its called on its own, when signs are irrelevant -; the caller must zero [hSpriteIndexOrTextID] -IsSpriteInFrontOfPlayer:: ; 0b6b (0:0b6b) - ld d,$10 ; talking range in pixels (normal range) -IsSpriteInFrontOfPlayer2:: ; 0b6d (0:0b6d) - ld bc,$3c40 ; Y and X position of player sprite - ld a,[wSpriteStateData1 + 9] ; direction the player is facing -.checkIfPlayerFacingUp - cp a,$04 - jr nz,.checkIfPlayerFacingDown -; facing up - ld a,b - sub d - ld b,a - ld a,$08 - jr .doneCheckingDirection -.checkIfPlayerFacingDown - cp a,$00 - jr nz,.checkIfPlayerFacingRight -; facing down - ld a,b - add d - ld b,a - ld a,$04 - jr .doneCheckingDirection -.checkIfPlayerFacingRight - cp a,$0c - jr nz,.playerFacingLeft -; facing right - ld a,c - add d - ld c,a - ld a,$01 - jr .doneCheckingDirection -.playerFacingLeft -; facing left - ld a,c - sub d - ld c,a - ld a,$02 -.doneCheckingDirection - ld [wd52a],a - ld a,[W_NUMSPRITES] ; number of sprites - and a - ret z -; if there are sprites - ld hl,wSpriteStateData1 + $10 - ld d,a - ld e,$01 -.spriteLoop - push hl - ld a,[hli] ; image (0 if no sprite) - and a - jr z,.nextSprite - inc l - ld a,[hli] ; sprite visibility - inc a - jr z,.nextSprite - inc l - ld a,[hli] ; Y location - cp b - jr nz,.nextSprite - inc l - ld a,[hl] ; X location - cp c - jr z,.foundSpriteInFrontOfPlayer -.nextSprite - pop hl - ld a,l - add a,$10 - ld l,a - inc e - dec d - jr nz,.spriteLoop - ret -.foundSpriteInFrontOfPlayer - pop hl - ld a,l - and a,$f0 - inc a - ld l,a - set 7,[hl] - ld a,e - ld [hSpriteIndexOrTextID],a - ret - -; function to check if the player will jump down a ledge and check if the tile ahead is passable (when not surfing) -; sets the carry flag if there is a collision, and unsets it if there isn't a collision -CollisionCheckOnLand:: ; 0bd1 (0:0bd1) - ld a,[wd736] - bit 6,a ; is the player jumping? - jr nz,.noCollision -; if not jumping a ledge - ld a,[wSimulatedJoypadStatesIndex] - and a - jr nz,.noCollision ; no collisions when the player's movements are being controlled by the game - ld a,[wd52a] ; the direction that the player is trying to go in - ld d,a - ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code) - and d ; check if a sprite is in the direction the player is trying to go - jr nz,.collision - xor a - ld [hSpriteIndexOrTextID],a - call IsSpriteInFrontOfPlayer ; check for sprite collisions again? when does the above check fail to detect a sprite collision? - ld a,[hSpriteIndexOrTextID] - and a ; was there a sprite collision? - jr nz,.collision -; if no sprite collision - ld hl,TilePairCollisionsLand - call CheckForJumpingAndTilePairCollisions - jr c,.collision - call CheckTilePassable - jr nc,.noCollision -.collision - ld a,[wc02a] - cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing - jr z,.setCarry - ld a,(SFX_02_5b - SFX_Headers_02) / 3 - call PlaySound ; play collision sound (if it's not already playing) -.setCarry - scf - ret -.noCollision - and a - ret - -; function that checks if the tile in front of the player is passable -; clears carry if it is, sets carry if not -CheckTilePassable:: ; 0c10 (0:0c10) - predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player - ld a,[wTileInFrontOfPlayer] ; tile in front of player - ld c,a - ld hl,W_TILESETCOLLISIONPTR ; pointer to list of passable tiles - ld a,[hli] - ld h,[hl] - ld l,a ; hl now points to passable tiles -.loop - ld a,[hli] - cp a,$ff - jr z,.tileNotPassable - cp c - ret z - jr .loop -.tileNotPassable - scf - ret - -; check if the player is going to jump down a small ledge -; and check for collisions that only occur between certain pairs of tiles -; Input: hl - address of directional collision data -; sets carry if there is a collision and unsets carry if not -CheckForJumpingAndTilePairCollisions:: ; 0c2a (0:0c2a) - push hl - predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player - push de - push bc - callba HandleLedges ; check if the player is trying to jump a ledge - pop bc - pop de - pop hl - and a - ld a,[wd736] - bit 6,a ; is the player jumping? - ret nz -; if not jumping - -CheckForTilePairCollisions2:: ; 0c44 (0:0c44) - aCoord 8, 9 ; tile the player is on - ld [wcf0e],a - -CheckForTilePairCollisions:: ; 0c4a (0:0c4a) - ld a,[wTileInFrontOfPlayer] - ld c,a -.tilePairCollisionLoop - ld a,[W_CURMAPTILESET] ; tileset number - ld b,a - ld a,[hli] - cp a,$ff - jr z,.noMatch - cp b - jr z,.tilesetMatches - inc hl -.retry - inc hl - jr .tilePairCollisionLoop -.tilesetMatches - ld a,[wcf0e] ; tile the player is on - ld b,a - ld a,[hl] - cp b - jr z,.currentTileMatchesFirstInPair - inc hl - ld a,[hl] - cp b - jr z,.currentTileMatchesSecondInPair - jr .retry -.currentTileMatchesFirstInPair - inc hl - ld a,[hl] - cp c - jr z,.foundMatch - jr .tilePairCollisionLoop -.currentTileMatchesSecondInPair - dec hl - ld a,[hli] - cp c - inc hl - jr nz,.tilePairCollisionLoop -.foundMatch - scf - ret -.noMatch - and a - ret - -; FORMAT: tileset number, tile 1, tile 2 -; terminated by 0xFF -; these entries indicate that the player may not cross between tile 1 and tile 2 -; it's mainly used to simulate differences in elevation - -TilePairCollisionsLand:: ; 0c7e (0:0c7e) - db CAVERN, $20, $05 - db CAVERN, $41, $05 - db FOREST, $30, $2E - db CAVERN, $2A, $05 - db CAVERN, $05, $21 - db FOREST, $52, $2E - db FOREST, $55, $2E - db FOREST, $56, $2E - db FOREST, $20, $2E - db FOREST, $5E, $2E - db FOREST, $5F, $2E - db $FF - -TilePairCollisionsWater:: ; 0ca0 (0:0ca0) - db FOREST, $14, $2E - db FOREST, $48, $2E - db CAVERN, $14, $05 - db $FF - -; this builds a tile map from the tile block map based on the current X/Y coordinates of the player's character -LoadCurrentMapView:: ; 0caa (0:0caa) - ld a,[H_LOADEDROMBANK] - push af - ld a,[W_TILESETBANK] ; tile data ROM bank - ld [H_LOADEDROMBANK],a - ld [$2000],a ; switch to ROM bank that contains tile data - ld a,[wCurrentTileBlockMapViewPointer] ; address of upper left corner of current map view - ld e,a - ld a,[wCurrentTileBlockMapViewPointer + 1] - ld d,a - ld hl,wTileMapBackup - ld b,$05 -.rowLoop ; each loop iteration fills in one row of tile blocks - push hl - push de - ld c,$06 -.rowInnerLoop ; loop to draw each tile block of the current row - push bc - push de - push hl - ld a,[de] - ld c,a ; tile block number - call DrawTileBlock - pop hl - pop de - pop bc - inc hl - inc hl - inc hl - inc hl - inc de - dec c - jr nz,.rowInnerLoop -; update tile block map pointer to next row's address - pop de - ld a,[W_CURMAPWIDTH] - add a,$06 - add e - ld e,a - jr nc,.noCarry - inc d -.noCarry -; update tile map pointer to next row's address - pop hl - ld a,$60 - add l - ld l,a - jr nc,.noCarry2 - inc h -.noCarry2 - dec b - jr nz,.rowLoop - ld hl,wTileMapBackup - ld bc,$0000 -.adjustForYCoordWithinTileBlock - ld a,[W_YBLOCKCOORD] - and a - jr z,.adjustForXCoordWithinTileBlock - ld bc,$0030 - add hl,bc -.adjustForXCoordWithinTileBlock - ld a,[W_XBLOCKCOORD] - and a - jr z,.copyToVisibleAreaBuffer - ld bc,$0002 - add hl,bc -.copyToVisibleAreaBuffer - ld de,wTileMap ; base address for the tiles that are directly transfered to VRAM during V-blank - ld b,$12 -.rowLoop2 - ld c,$14 -.rowInnerLoop2 - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.rowInnerLoop2 - ld a,$04 - add l - ld l,a - jr nc,.noCarry3 - inc h -.noCarry3 - dec b - jr nz,.rowLoop2 - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a ; restore previous ROM bank - ret - -AdvancePlayerSprite:: ; 0b7f (0:0b7f) - ld a,[wUpdateSpritesEnabled] - push af - ld a,$FF - ld [wUpdateSpritesEnabled],a - ld hl, _AdvancePlayerSorite ; 3c:410c - ld b, BANK(_AdvancePlayerSprite) - call Bankswitch - pop af - ld [wUpdateSpritesEnabled],a - ret - -; the following four functions are used to move the pointer to the upper left -; corner of the tile block map in the direction of motion - -MoveTileBlockMapPointerEast:: ; 0e65 (0:0e65) - ld a,[de] - add a,$01 - ld [de],a - ret nc - inc de - ld a,[de] - inc a - ld [de],a - ret - -MoveTileBlockMapPointerWest:: ; 0e6f (0:0e6f) - ld a,[de] - sub a,$01 - ld [de],a - ret nc - inc de - ld a,[de] - dec a - ld [de],a - ret - -MoveTileBlockMapPointerSouth:: ; 0e79 (0:0e79) - add a,$06 - ld b,a - ld a,[de] - add b - ld [de],a - ret nc - inc de - ld a,[de] - inc a - ld [de],a - ret - -MoveTileBlockMapPointerNorth:: ; 0e85 (0:0e85) - add a,$06 - ld b,a - ld a,[de] - sub b - ld [de],a - ret nc - inc de - ld a,[de] - dec a - ld [de],a - ret - -; the following 6 functions are used to tell the V-blank handler to redraw -; the portion of the map that was newly exposed due to the player's movement - -ScheduleNorthRowRedraw:: ; 0e91 (0:0e91) - hlCoord 0, 0 - call CopyToScreenEdgeTiles - ld a,[wMapViewVRAMPointer] - ld [H_SCREENEDGEREDRAWADDR],a - ld a,[wMapViewVRAMPointer + 1] - ld [H_SCREENEDGEREDRAWADDR + 1],a - ld a,REDRAWROW - ld [H_SCREENEDGEREDRAW],a - ret - -CopyToScreenEdgeTiles:: ; 0ea6 (0:0ea6) - ld de,wScreenEdgeTiles - ld c,2 * 20 -.loop - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.loop - ret - -ScheduleSouthRowRedraw:: ; 0eb2 (0:0eb2) - hlCoord 0, 16 - call CopyToScreenEdgeTiles - ld a,[wMapViewVRAMPointer] - ld l,a - ld a,[wMapViewVRAMPointer + 1] - ld h,a - ld bc,$0200 - add hl,bc - ld a,h - and a,$03 - or a,$98 - ld [H_SCREENEDGEREDRAWADDR + 1],a - ld a,l - ld [H_SCREENEDGEREDRAWADDR],a - ld a,REDRAWROW - ld [H_SCREENEDGEREDRAW],a - ret - -ScheduleEastColumnRedraw:: ; 0ed3 (0:0ed3) - hlCoord 18, 0 - call ScheduleColumnRedrawHelper - ld a,[wMapViewVRAMPointer] - ld c,a - and a,$e0 - ld b,a - ld a,c - add a,18 - and a,$1f - or b - ld [H_SCREENEDGEREDRAWADDR],a - ld a,[wMapViewVRAMPointer + 1] - ld [H_SCREENEDGEREDRAWADDR + 1],a - ld a,REDRAWCOL - ld [H_SCREENEDGEREDRAW],a - ret - -ScheduleColumnRedrawHelper:: ; 0ef2 (0:0ef2) - ld de,wScreenEdgeTiles - ld c,$12 -.loop - ld a,[hli] - ld [de],a - inc de - ld a,[hl] - ld [de],a - inc de - ld a,19 - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - dec c - jr nz,.loop - ret - -ScheduleWestColumnRedraw:: ; 0f08 (0:0f08) - hlCoord 0, 0 - call ScheduleColumnRedrawHelper - ld a,[wMapViewVRAMPointer] - ld [H_SCREENEDGEREDRAWADDR],a - ld a,[wMapViewVRAMPointer + 1] - ld [H_SCREENEDGEREDRAWADDR + 1],a - ld a,REDRAWCOL - ld [H_SCREENEDGEREDRAW],a - ret - -; function to write the tiles that make up a tile block to memory -; Input: c = tile block ID, hl = destination address -DrawTileBlock:: ; 0f1d (0:0f1d) - push hl - ld a,[W_TILESETBLOCKSPTR] ; pointer to tiles - ld l,a - ld a,[W_TILESETBLOCKSPTR + 1] - ld h,a - ld a,c - swap a - ld b,a - and a,$f0 - ld c,a - ld a,b - and a,$0f - ld b,a ; bc = tile block ID * 0x10 - add hl,bc - ld d,h - ld e,l ; de = address of the tile block's tiles - pop hl - ld c,$04 ; 4 loop iterations -.loop ; each loop iteration, write 4 tile numbers - push bc - ld a,[de] - ld [hli],a - inc de - ld a,[de] - ld [hli],a - inc de - ld a,[de] - ld [hli],a - inc de - ld a,[de] - ld [hl],a - inc de - ld bc,$0015 - add hl,bc - pop bc - dec c - jr nz,.loop - ret - -; function to update joypad state and simulate button presses -JoypadOverworld:: ; 0f4d (0:0f4d) - xor a - ld [wSpriteStateData1 + 3],a - ld [wSpriteStateData1 + 5],a - call RunMapScript - call Joypad - ld a,[W_FLAGS_D733] - bit 3,a ; check if a trainer wants a challenge - jr nz,.notForcedDownwards - ld a,[W_CURMAP] - cp a,ROUTE_17 ; Cycling Road - jr nz,.notForcedDownwards - ld a,[hJoyHeld] - and a,D_DOWN | D_UP | D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON - jr nz,.notForcedDownwards - ld a,D_DOWN - ld [hJoyHeld],a ; on the cycling road, if there isn't a trainer and the player isn't pressing buttons, simulate a down press -.notForcedDownwards - ld a,[wd730] - bit 7,a - ret z -; if simulating button presses - ld a,[hJoyHeld] - ld b,a - ld a,[wOverrideSimulatedJoypadStatesMask] ; bit mask for button presses that override simulated ones - and b - ret nz ; return if the simulated button presses are overridden - ld hl,wSimulatedJoypadStatesIndex - dec [hl] - ld a,[hl] - cp a,$ff - jr z,.doneSimulating ; if the end of the simulated button presses has been reached - ld hl,wSimulatedJoypadStatesEnd - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - ld a,[hl] - ld [hJoyHeld],a ; store simulated button press in joypad state - and a - ret nz - ld [hJoyPressed],a - ld [hJoyReleased],a - ret -; if done simulating button presses -.doneSimulating - xor a - ld [wWastedByteCD3A],a - ld [wSimulatedJoypadStatesIndex],a - ld [wSimulatedJoypadStatesEnd],a - ld [wJoyIgnore],a - ld [hJoyHeld],a - ld hl,wd736 - ld a,[hl] - and a,$f8 - ld [hl],a - ld hl,wd730 - res 7,[hl] - ret - -; function to check the tile ahead to determine if the character should get on land or keep surfing -; sets carry if there is a collision and clears carry otherwise -; It seems that this function has a bug in it, but due to luck, it doesn't -; show up. After detecting a sprite collision, it jumps to the code that -; checks if the next tile is passable instead of just directly jumping to the -; "collision detected" code. However, it doesn't store the next tile in c, -; so the old value of c is used. 2429 is always called before this function, -; and 2429 always sets c to 0xF0. There is no 0xF0 background tile, so it -; is considered impassable and it is detected as a collision. -CollisionCheckOnWater:: ; 0fb7 (0:0fb7) - ld a,[wd730] - bit 7,a - jp nz,.noCollision ; return and clear carry if button presses are being simulated - ld a,[wd52a] ; the direction that the player is trying to go in - ld d,a - ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code) - and d ; check if a sprite is in the direction the player is trying to go - jr nz,.checkIfNextTileIsPassable ; bug? - ld hl,TilePairCollisionsWater - call CheckForJumpingAndTilePairCollisions - jr c,.collision - predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player (puts it in c and [wTileInFrontOfPlayer]) - ld a,[wTileInFrontOfPlayer] ; tile in front of player - cp a,$14 ; water tile - jr z,.noCollision ; keep surfing if it's a water tile - cp a,$32 ; either the left tile of the S.S. Anne boarding platform or the tile on eastern coastlines (depending on the current tileset) - jr z,.checkIfVermilionDockTileset - cp a,$48 ; tile on right on coast lines in Safari Zone - jr z,.noCollision ; keep surfing -; check if the [land] tile in front of the player is passable -.checkIfNextTileIsPassable - ld hl,W_TILESETCOLLISIONPTR ; pointer to list of passable tiles - ld a,[hli] - ld h,[hl] - ld l,a -.loop - ld a,[hli] - cp a,$ff - jr z,.collision - cp c - jr z,.stopSurfing ; stop surfing if the tile is passable - jr .loop -.collision - ld a,[wc02a] - cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing - jr z,.setCarry - ld a,(SFX_02_5b - SFX_Headers_02) / 3 - call PlaySound ; play collision sound (if it's not already playing) -.setCarry - scf - jr .done -.noCollision - and a -.done - ret -.stopSurfing - xor a - ld [wWalkBikeSurfState],a - call LoadPlayerSpriteGraphics - call PlayDefaultMusic - jr .noCollision -.checkIfVermilionDockTileset - ld a, [W_CURMAPTILESET] ; tileset - cp SHIP_PORT ; Vermilion Dock tileset - jr nz, .noCollision ; keep surfing if it's not the boarding platform tile - jr .stopSurfing ; if it is the boarding platform tile, stop surfing - -; function to run the current map's script -RunMapScript:: ; 101b (0:101b) - push hl - push de - push bc - callba TryPushingBoulder - ld a,[wFlags_0xcd60] - bit 1,a ; play boulder dust animation - jr z,.afterBoulderEffect - callba DoBoulderDustAnimation -.afterBoulderEffect - pop bc - pop de - pop hl - call RunNPCMovementScript - ld a,[W_CURMAP] ; current map number - call SwitchToMapRomBank ; change to the ROM bank the map's data is in - ld hl,W_MAPSCRIPTPTR - ld a,[hli] - ld h,[hl] - ld l,a - ld de,.return - push de - jp [hl] ; jump to script -.return - ret - -LoadWalkingPlayerSpriteGraphics:: ; 104d (0:104d) - ld de,RedSprite ; $4180 - ld hl,vNPCSprites - jr LoadPlayerSpriteGraphicsCommon - -LoadSurfingPlayerSpriteGraphics:: ; 1055 (0:1055) - ld de,SeelSprite - ld hl,vNPCSprites - jr LoadPlayerSpriteGraphicsCommon - -LoadBikePlayerSpriteGraphics:: ; 105d (0:105d) - ld de,RedCyclingSprite - ld hl,vNPCSprites - -LoadPlayerSpriteGraphicsCommon:: ; 1063 (0:1063) - push de - push hl - ld bc,(BANK(RedSprite) << 8) + $0c - call CopyVideoData - pop hl - pop de - ld a,$c0 - add e - ld e,a - jr nc,.noCarry - inc d -.noCarry - set 3,h - ld bc,$050c - jp CopyVideoData - -; function to load data from the map header -LoadMapHeader:: ; 107c (0:107c) - callba MarkTownVisitedAndLoadMissableObjects - ld a,[W_CURMAPTILESET] - ld [wd119],a - ld a,[W_CURMAP] - call SwitchToMapRomBank - ld a,[W_CURMAPTILESET] - ld b,a - res 7,a - ld [W_CURMAPTILESET],a - ld [$ff8b],a - bit 7,b - ret nz - ld hl,MapHeaderPointers - ld a,[W_CURMAP] - sla a - jr nc,.noCarry1 - inc h -.noCarry1 - add l - ld l,a - jr nc,.noCarry2 - inc h -.noCarry2 - ld a,[hli] - ld h,[hl] - ld l,a ; hl = base of map header -; copy the first 10 bytes (the fixed area) of the map data to D367-D370 - ld de,W_CURMAPTILESET - ld c,$0a -.copyFixedHeaderLoop - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.copyFixedHeaderLoop -; initialize all the connected maps to disabled at first, before loading the actual values - ld a,$ff - ld [W_MAPCONN1PTR],a - ld [W_MAPCONN2PTR],a - ld [W_MAPCONN3PTR],a - ld [W_MAPCONN4PTR],a -; copy connection data (if any) to WRAM - ld a,[W_MAPCONNECTIONS] - ld b,a -.checkNorth - bit 3,b - jr z,.checkSouth - ld de,W_MAPCONN1PTR - call CopyMapConnectionHeader -.checkSouth - bit 2,b - jr z,.checkWest - ld de,W_MAPCONN2PTR - call CopyMapConnectionHeader -.checkWest - bit 1,b - jr z,.checkEast - ld de,W_MAPCONN3PTR - call CopyMapConnectionHeader -.checkEast - bit 0,b - jr z,.getObjectDataPointer - ld de,W_MAPCONN4PTR - call CopyMapConnectionHeader -.getObjectDataPointer - ld a,[hli] - ld [wd3a9],a - ld a,[hli] - ld [wd3aa],a - push hl - ld a,[wd3a9] - ld l,a - ld a,[wd3aa] - ld h,a ; hl = base of object data - ld de,wd3ad ; background tile ID - ld a,[hli] - ld [de],a ; save background tile ID -.loadWarpData - ld a,[hli] - ld [wNumberOfWarps],a - and a - jr z,.loadSignData - ld c,a - ld de,wWarpEntries -.warpLoop ; one warp per loop iteration - ld b,$04 -.warpInnerLoop - ld a,[hli] - ld [de],a - inc de - dec b - jr nz,.warpInnerLoop - dec c - jr nz,.warpLoop -.loadSignData - ld a,[hli] ; number of signs - ld [wd4b0],a ; save the number of signs - and a ; are there any signs? - jr z,.loadSpriteData ; if not, skip this - ld c,a - ld de,wd4d1 ; base address of sign text IDs - ld a,d - ld [$ff95],a - ld a,e - ld [$ff96],a - ld de,wd4b1 ; base address of sign coordinates -.signLoop - ld a,[hli] - ld [de],a - inc de - ld a,[hli] - ld [de],a - inc de - push de - ld a,[$ff95] - ld d,a - ld a,[$ff96] - ld e,a - ld a,[hli] - ld [de],a - inc de - ld a,d - ld [$ff95],a - ld a,e - ld [$ff96],a - pop de - dec c - jr nz,.signLoop -.loadSpriteData - ld a,[wd72e] - bit 5,a ; did a battle happen immediately before this? - jp nz,.finishUp ; if so, skip this because battles don't destroy this data - ld a,[hli] - ld [W_NUMSPRITES],a ; save the number of sprites - push hl -; zero C110-C1FF and C210-C2FF - ld hl,wSpriteStateData1 + $10 - ld de,wSpriteStateData2 + $10 - xor a - ld b,$f0 -.zeroSpriteDataLoop - ld [hli],a - ld [de],a - inc e - dec b - jr nz,.zeroSpriteDataLoop -; initialize all C100-C1FF sprite entries to disabled (other than player's) - ld hl,wSpriteStateData1 + $12 - ld de,$0010 - ld c,$0f -.disableSpriteEntriesLoop - ld [hl],$ff - add hl,de - dec c - jr nz,.disableSpriteEntriesLoop - pop hl - ld de,wSpriteStateData1 + $10 - ld a,[W_NUMSPRITES] ; number of sprites - and a ; are there any sprites? - jp z,.finishUp ; if there are no sprites, skip the rest - ld b,a - ld c,$00 -.loadSpriteLoop - ld a,[hli] - ld [de],a ; store picture ID at C1X0 - inc d - ld a,$04 - add e - ld e,a - ld a,[hli] - ld [de],a ; store Y position at C2X4 - inc e - ld a,[hli] - ld [de],a ; store X position at C2X5 - inc e - ld a,[hli] - ld [de],a ; store movement byte 1 at C2X6 - ld a,[hli] - ld [$ff8d],a ; save movement byte 2 - ld a,[hli] - ld [$ff8e],a ; save text ID and flags byte - push bc - push hl - ld b,$00 - ld hl,W_MAPSPRITEDATA - add hl,bc - ld a,[$ff8d] - ld [hli],a ; store movement byte 2 in byte 0 of sprite entry - ld a,[$ff8e] - ld [hl],a ; this appears pointless, since the value is overwritten immediately after - ld a,[$ff8e] - ld [$ff8d],a - and a,$3f - ld [hl],a ; store text ID in byte 1 of sprite entry - pop hl - ld a,[$ff8d] - bit 6,a - jr nz,.trainerSprite - bit 7,a - jr nz,.itemBallSprite - jr .regularSprite -.trainerSprite - ld a,[hli] - ld [$ff8d],a ; save trainer class - ld a,[hli] - ld [$ff8e],a ; save trainer number (within class) - push hl - ld hl,W_MAPSPRITEEXTRADATA - add hl,bc - ld a,[$ff8d] - ld [hli],a ; store trainer class in byte 0 of the entry - ld a,[$ff8e] - ld [hl],a ; store trainer number in byte 1 of the entry - pop hl - jr .nextSprite -.itemBallSprite - ld a,[hli] - ld [$ff8d],a ; save item number - push hl - ld hl,W_MAPSPRITEEXTRADATA - add hl,bc - ld a,[$ff8d] - ld [hli],a ; store item number in byte 0 of the entry - xor a - ld [hl],a ; zero byte 1, since it is not used - pop hl - jr .nextSprite -.regularSprite - push hl - ld hl,W_MAPSPRITEEXTRADATA - add hl,bc -; zero both bytes, since regular sprites don't use this extra space - xor a - ld [hli],a - ld [hl],a - pop hl -.nextSprite - pop bc - dec d - ld a,$0a - add e - ld e,a - inc c - inc c - dec b - jp nz,.loadSpriteLoop -.finishUp - predef LoadTilesetHeader - callab LoadWildData - pop hl ; restore hl from before going to the warp/sign/sprite data (this value was saved for seemingly no purpose) - ld a,[W_CURMAPHEIGHT] ; map height in 4x4 tile blocks - add a ; double it - ld [wd524],a ; store map height in 2x2 tile blocks - ld a,[W_CURMAPWIDTH] ; map width in 4x4 tile blocks - add a ; double it - ld [wd525],a ; map width in 2x2 tile blocks - ld a,[W_CURMAP] - ld c,a - ld b,$00 - ld a,[H_LOADEDROMBANK] - push af - ld a, BANK(MapSongBanks) - ld [H_LOADEDROMBANK],a - ld [$2000],a - ld hl, MapSongBanks - add hl,bc - add hl,bc - ld a,[hli] - ld [wd35b],a ; music 1 - ld a,[hl] - ld [wd35c],a ; music 2 - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; function to copy map connection data from ROM to WRAM -; Input: hl = source, de = destination -CopyMapConnectionHeader:: ; 1238 (0:1238) - ld c,$0b -.loop - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.loop - ret - -; function to load map data -LoadMapData:: ; 1241 (0:1241) - ld a,[H_LOADEDROMBANK] - push af - call DisableLCD - ld a,$98 - ld [wMapViewVRAMPointer + 1],a - xor a - ld [wMapViewVRAMPointer],a - ld [hSCY],a - ld [hSCX],a - ld [wWalkCounter],a - ld [wd119],a - ld [wWalkBikeSurfStateCopy],a - ld [W_SPRITESETID],a - call LoadTextBoxTilePatterns - call LoadMapHeader - callba InitMapSprites ; load tile pattern data for sprites - call LoadTileBlockMap - call LoadTilesetTilePatternData - call LoadCurrentMapView -; copy current map view to VRAM - ld hl,wTileMap - ld de,vBGMap0 - ld b,18 -.vramCopyLoop - ld c,20 -.vramCopyInnerLoop - ld a,[hli] - ld [de],a - inc e - dec c - jr nz,.vramCopyInnerLoop - ld a,32 - 20 - add e - ld e,a - jr nc,.noCarry - inc d -.noCarry - dec b - jr nz,.vramCopyLoop - ld a,$01 - ld [wUpdateSpritesEnabled],a - call EnableLCD - ld b,$09 - call GoPAL_SET - call LoadPlayerSpriteGraphics - ld a,[wd732] - and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp - jr nz,.restoreRomBank - ld a,[W_FLAGS_D733] - bit 1,a - jr nz,.restoreRomBank - call Func_235f ; music related - call Func_2312 ; music related -.restoreRomBank - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; function to switch to the ROM bank that a map is stored in -; Input: a = map number -SwitchToMapRomBank:: ; 12bc (0:12bc) - push hl - push bc - ld c,a - ld b,$00 - ld a,Bank(MapHeaderBanks) - call BankswitchHome ; switch to ROM bank 3 - ld hl,MapHeaderBanks - add hl,bc - ld a,[hl] - ld [$ffe8],a ; save map ROM bank - call BankswitchBack - ld a,[$ffe8] - ld [H_LOADEDROMBANK],a - ld [$2000],a ; switch to map ROM bank - pop bc - pop hl - ret - -IgnoreInputForHalfSecond: ; 12da (0:12da) - ld a, 30 - ld [wIgnoreInputCounter], a - ld hl, wd730 - ld a, [hl] - or $26 - ld [hl], a ; set ignore input bit - ret - -ResetUsingStrengthOutOfBattleBit: ; 12e7 (0:12e7) - ld hl, wd728 - res 0, [hl] - ret - -ForceBikeOrSurf:: ; 12ed (0:12ed) - ld b, BANK(RedSprite) - ld hl, LoadPlayerSpriteGraphics - call Bankswitch - jp PlayDefaultMusic ; update map/player state? - -; Handle the player jumping down -; a ledge in the overworld. -HandleMidJump:: ; 0fe1 (0:0fe1) - ld a,[wd736] - bit 7,a ; jumping down a ledge? - ret z - ld b, BANK(_HandleMidJump) - ld hl, _HandleMidJump - jp Bankswitch - -IsSpinning:: ; 0ff0 (0:0ff0) - ld a,[wd736] - bit 7,a - ret z ; no spinning - ld b, BANK(LoadSpinnerArrowTiles); spin while moving - ld hl,LoadSpinnerArrowTiles ; 11:5077 - jp Bankswitch - -Func_0ffe:: ; 0ffe (0:0ffe) - ld hl, Func_fcf0c ; 3f:4f0c - ld b, BANK(Func_fcf0c) - jp Bankswitch +EnterMap:: ; 01d7 (0:01d7)
+; Load a new map.
+ ld a, $ff
+ ld [wJoyIgnore], a
+ call LoadMapData
+ callba ClearVariablesAfterLoadingMapData
+ ld hl, wd72c
+ bit 0, [hl] ; has the player already made 3 steps since the last battle?
+ jr z, .skipGivingThreeStepsOfNoRandomBattles
+ ld a, 3 ; minimum number of steps between battles
+ ld [wNumberOfNoRandomBattleStepsLeft], a
+.skipGivingThreeStepsOfNoRandomBattles
+ ld hl, wd72e
+ bit 5, [hl] ; did a battle happen immediately before this?
+ res 5, [hl] ; unset the "battle just happened" flag
+ call z, ResetUsingStrengthOutOfBattleBit
+ call nz, MapEntryAfterBattle
+ ld hl, wd732
+ ld a, [hl]
+ and 1 << 4 | 1 << 3 ; fly warp or dungeon warp
+ jr z, .didNotEnterUsingFlyWarpOrDungeonWarp
+ callba EnterMapAnim
+ call UpdateSprites
+ ld hl, wd732
+ res 3, [hl]
+ ld hl, wd72e
+ res 4, [hl]
+ call Func_342a
+.didNotEnterUsingFlyWarpOrDungeonWarp
+ callba CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road
+ ld hl, wd732
+ bit 4, [hl]
+ res 4, [hl]
+ ld hl, wd72d
+ res 5, [hl]
+ call UpdateSprites
+ ld hl, wd126
+ set 5, [hl]
+ set 6, [hl]
+ xor a
+ ld [wJoyIgnore], a
+
+OverworldLoop:: ; 0242 (0:0242)
+ call DelayFrame
+OverworldLoopLessDelay:: ; 0245 (0:0245)
+ call DelayFrame
+ call Func_342a
+ call LoadGBPal
+ ld a,[wWalkCounter]
+ and a
+ jp nz,.moveAhead ; if the player sprite has not yet completed the walking animation
+ call JoypadOverworld ; get joypad state (which is possibly simulated)
+ callba SafariZoneCheck
+ ld a,[wSafariZoneGameOver]
+ and a
+ jp nz,WarpFound2
+ ld hl,wd72d
+ bit 3,[hl]
+ res 3,[hl]
+ jp nz,WarpFound2
+ ld a,[wd732]
+ and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp
+ jp nz,HandleFlyWarpOrDungeonWarp
+ ld a,[W_CUROPPONENT]
+ and a
+ jp nz,.newBattle
+ ld a,[wd730]
+ bit 7,a ; are we simulating button presses?
+ jr z,.notSimulating
+ ld a,[hJoyHeld]
+ jr .checkIfStartIsPressed
+.notSimulating
+ ld a,[hJoyPressed]
+.checkIfStartIsPressed
+ bit 3,a ; start button
+ jr z,.startButtonNotPressed
+; if START is pressed
+ xor a
+ ld [hSpriteIndexOrTextID],a ; start menu text ID
+ jp .displayDialogue
+.startButtonNotPressed
+ bit 0,a ; A button
+ jp z,.checkIfDownButtonIsPressed
+; if A is pressed
+ ld a,[wd730]
+ bit 2,a
+ jp nz,.noDirectionButtonsPressed
+ call IsPlayerCharacterBeingControlledByGame
+ jr nz,.checkForOpponent
+ call CheckForHiddenObjectOrBookshelfOrCardKeyDoor
+ ld a,[$ffeb]
+ and a
+ jp z,OverworldLoop ; jump if a hidden object or bookshelf was found, but not if a card key door was found
+ xor a
+ ld [wd436],a ; new yellow address
+ call IsSpriteOrSignInFrontOfPlayer
+ call Func_0ffe
+ ld a,[hSpriteIndexOrTextID]
+ and a
+ jp z,OverworldLoop
+.displayDialogue
+ predef GetTileAndCoordsInFrontOfPlayer
+ call UpdateSprites
+ ld a,[wFlags_0xcd60]
+ bit 2,a
+ jr nz,.checkForOpponent
+ bit 0,a
+ jr nz,.checkForOpponent
+ aCoord 8, 9
+ ld [wcf0e],a
+ call DisplayTextID ; display either the start menu or the NPC/sign text
+ ld a,[wcc47]
+ and a
+ jr z,.checkForOpponent
+ xor a
+ ld [wcc47],a
+ jp EnterMap
+; predef LoadSAV
+; ld a,[W_CURMAP]
+; ld [wDestinationMap],a
+; call SpecialWarpIn
+; ld a,[W_CURMAP]
+; call SwitchToMapRomBank ; switch to the ROM bank of the current map
+; ld hl,W_CURMAPTILESET
+; set 7,[hl]
+.checkForOpponent
+ ld a,[W_CUROPPONENT]
+ and a
+ jp nz,.newBattle
+ jp OverworldLoop
+.noDirectionButtonsPressed
+ call UpdateSprites ; 231c
+ ld hl,wFlags_0xcd60
+ res 2,[hl]
+ xor a
+ ld [wd435], a
+ ld a, $1
+ ld a,$01
+ ld [wcc4b],a
+ ld a,[wd528] ; the direction that was pressed last time
+ and a
+ jr z, .overworldloop
+; if a direction was pressed last time
+ ld [wd529],a ; save the last direction
+ xor a
+ ld [wd528],a ; zero the direction
+.overworldloop
+ jp OverworldLoop
+.checkIfDownButtonIsPressed
+ ld a,[hJoyHeld] ; current joypad state
+ bit 7,a ; down button
+ jr z,.checkIfUpButtonIsPressed
+ ld a,$01
+ ld [wSpriteStateData1 + 3],a
+ ld a,$04
+ jr .handleDirectionButtonPress
+.checkIfUpButtonIsPressed
+ bit 6,a ; up button
+ jr z,.checkIfLeftButtonIsPressed
+ ld a,$ff
+ ld [wSpriteStateData1 + 3],a
+ ld a,$08
+ jr .handleDirectionButtonPress
+.checkIfLeftButtonIsPressed
+ bit 5,a ; left button
+ jr z,.checkIfRightButtonIsPressed
+ ld a,$ff
+ ld [wSpriteStateData1 + 5],a
+ ld a,$02
+ jr .handleDirectionButtonPress
+.checkIfRightButtonIsPressed
+ bit 4,a ; right button
+ jr z,.noDirectionButtonsPressed
+ ld a,$01
+ ld [wSpriteStateData1 + 5],a
+.handleDirectionButtonPress
+ ld [wd52a],a ; new direction
+ ld a,[wd730]
+ bit 7,a ; are we simulating button presses?
+ jr nz,.noDirectionChange ; ignore direction changes if we are
+ ld a,[wcc4b]
+ and a
+ jr z,.noDirectionChange
+ ld a,[wd52a] ; new direction
+ ld b,a
+ ld a,[wd529] ; old direction
+ cp b
+ jr z,.noDirectionChange
+ ld a,$8
+ ld [wd434],a
+; unlike in red/blue, yellow does not have the 180 degrees odd code
+ ld hl,wFlags_0xcd60
+ set 2,[hl]
+ xor a
+ ld [wcc4b],a
+ ld a,[wd52a]
+ ld [wd528],a
+ call NewBattle
+ jp c,.battleOccurred
+ jp OverworldLoop
+.noDirectionChange
+ ld a,[wd52a] ; current direction
+ ld [wd528],a ; save direction
+ call UpdateSprites
+ ld a,[wWalkBikeSurfState]
+ cp a,$02 ; surfing
+ jr z,.surfing
+; not surfing
+ call CollisionCheckOnLand
+ jr nc,.noCollision
+; collision occurred
+ push hl
+ ld hl,wd736
+ bit 2,[hl] ; standing on warp flag
+ pop hl
+ jp z,OverworldLoop
+; collision occurred while standing on a warp
+ push hl
+ call ExtraWarpCheck ; sets carry if there is a potential to warp
+ pop hl
+ jp c,CheckWarpsCollision
+ jp OverworldLoop
+.surfing
+ call CollisionCheckOnWater
+ jp c,OverworldLoop
+.noCollision
+ ld a,$08
+ ld [wWalkCounter],a
+ callab Func_fcc08
+ jr .moveAhead2
+.moveAhead
+ call IsSpinning
+ call UpdateSprites ; move sprites
+.moveAhead2
+ ld hl,wFlags_0xcd60
+ res 2,[hl]
+ xor a
+ ld [wd435],a
+ call DoBikeSpeedup
+ call AdvancePlayerSprite
+ ld a,[wWalkCounter]
+ and a
+ jp nz,CheckMapConnections ; it seems like this check will never succeed (the other place where CheckMapConnections is run works)
+; walking animation finished
+ call StepCountCheck
+ ld a,[wd790]
+ bit 7,a ; in the safari zone?
+ jr z,.notSafariZone
+ callba SafariZoneCheckSteps
+ ld a,[wSafariZoneGameOver]
+ and a
+ jp nz,WarpFound2
+.notSafariZone
+ ld a,[W_ISINBATTLE]
+ and a
+ jp nz,CheckWarpsNoCollision
+ predef ApplyOutOfBattlePoisonDamage ; also increment daycare mon exp
+ ld a,[wd12d]
+ and a
+ jp nz,HandleBlackOut ; if all pokemon fainted
+.newBattle
+ call NewBattle
+ ld hl,wd736
+ res 2,[hl] ; standing on warp flag
+ jp nc,CheckWarpsNoCollision ; check for warps if there was no battle
+.battleOccurred
+ ld hl,wd72d
+ res 6,[hl]
+ ld hl,W_FLAGS_D733
+ res 3,[hl]
+ ld hl,wd126
+ set 5,[hl]
+ set 6,[hl]
+ xor a
+ ld [hJoyHeld],a
+ ld a,[W_CURMAP]
+ cp a,CINNABAR_GYM
+ jr nz,.notCinnabarGym
+ ld hl,wd79b
+ set 7,[hl]
+.notCinnabarGym
+ ld hl,wd72e
+ set 5,[hl]
+ ld a,[W_CURMAP]
+ cp a,OAKS_LAB
+ jp z,.noFaintCheck ; no blacking out if the player lost to the rival in Oak's lab
+ callab AnyPartyAlive
+ ld a,d
+ and a
+ jr z,.allPokemonFainted
+.noFaintCheck
+ ld c,$0a
+ call DelayFrames
+ jp EnterMap
+;.allPokemonFainted
+; ld a,$ff
+; ld [W_ISINBATTLE],a
+; call RunMapScript
+; jp HandleBlackOut
+
+StepCountCheck:: ; 0457 (0:0457)
+ ld a,[wd730]
+ bit 7,a
+ jr nz,.doneStepCounting ; if button presses are being simulated, don't count steps
+; step counting
+ ld hl,wStepCounter
+ dec [hl]
+ ld a,[wd72c]
+ bit 0,a
+ jr z,.doneStepCounting
+ ld hl,wNumberOfNoRandomBattleStepsLeft
+ dec [hl]
+ jr nz,.doneStepCounting
+ ld hl,wd72c
+ res 0,[hl] ; indicate that the player has stepped thrice since the last battle
+.doneStepCounting
+ ret
+
+; function to determine if there will be a battle and execute it (either a trainer battle or wild battle)
+; sets carry if a battle occurred and unsets carry if not
+NewBattle:: ; 0480 (0:0480)
+ ld a,[wd72d]
+ bit 4,a
+ jr nz,.noBattle
+ call IsPlayerCharacterBeingControlledByGame
+ jr nz,.noBattle ; no battle if the player character is under the game's control
+ ld a,[wd72e]
+ bit 4,a
+ jr nz,.noBattle
+ ld b, BANK(InitBattle)
+ ld hl, InitBattle ; 3d:5ff2
+ jp Bankswitch
+.noBattle
+ and a
+ ret
+
+DoBikeSpeedup:: ; 049d (0:049d)
+ ld a,[wWalkBikeSurfState]
+ dec a ; riding a bike?
+ ret nz
+ ld a,[wd736]
+ bit 6,a
+ ret nz
+ ld a,[wNPCMovementScriptPointerTableNum]
+ and a
+ ret nz
+ ld a,[W_CURMAP]
+ cp ROUTE_17 ; cycling road
+ jr nz,.goFaster
+ ld a,[hJoyHeld]
+ and a,D_UP | D_LEFT | D_RIGHT
+ ret nz
+.goFaster
+ call AdvancePlayerSprite
+ ret
+
+; check if the player has stepped onto a warp after having not collided
+CheckWarpsNoCollision:: ; 04bd (0:04bd)
+ ld a,[wNumberOfWarps]
+ and a
+ jp z,CheckMapConnections
+ ld b,0
+ ld a,[wNumberOfWarps]
+ ld c,a
+ ld a,[W_YCOORD]
+ ld d,a
+ ld a,[W_XCOORD]
+ ld e,a
+ ld hl,wWarpEntries
+CheckWarpsNoCollisionLoop:: ; 04d5 (0:04d5)
+ ld a,[hli] ; check if the warp's Y position matches
+ cp d
+ jr nz,CheckWarpsNoCollisionRetry1
+ ld a,[hli] ; check if the warp's X position matches
+ cp e
+ jr nz,CheckWarpsNoCollisionRetry2
+; if a match was found
+ push hl
+ push bc
+ ld hl,wd736
+ set 2,[hl] ; standing on warp flag
+ callba IsPlayerStandingOnDoorTileOrWarpTile
+ pop bc
+ pop hl
+ jr c,WarpFound1 ; jump if standing on door or warp
+ push hl
+ push bc
+ call ExtraWarpCheck
+ pop bc
+ pop hl
+ jr nc,CheckWarpsNoCollisionRetry2
+; if the extra check passed
+ ld a,[W_FLAGS_D733]
+ bit 2,a
+ jr nz,WarpFound1
+ push de
+ push bc
+ call Joypad
+ pop bc
+ pop de
+ ld a,[hJoyHeld]
+ and a,D_DOWN | D_UP | D_LEFT | D_RIGHT
+ jr z,CheckWarpsNoCollisionRetry2 ; if directional buttons aren't being pressed, do not pass through the warp
+ jr WarpFound1
+
+CheckWarpsNoCollisionRetry1:: ; 050f (0:050f)
+ inc hl
+CheckWarpsNoCollisionRetry2:: ; 0510 (0:0510)
+ inc hl
+ inc hl
+ContinueCheckWarpsNoCollisionLoop:: ; 0512 (0:0512)
+ inc b ; increment warp number
+ dec c ; decrement number of warps
+ jp nz,CheckWarpsNoCollisionLoop
+ jp CheckMapConnections
+
+; check if the player has stepped onto a warp after having collided
+CheckWarpsCollision:: ; 051a (0:051a)
+ ld a,[wNumberOfWarps]
+ ld c,a
+ ld hl,wWarpEntries
+.loop
+ ld a,[hli] ; Y coordinate of warp
+ ld b,a
+ ld a,[W_YCOORD]
+ cp b
+ jr nz,.retry1
+ ld a,[hli] ; X coordinate of warp
+ ld b,a
+ ld a,[W_XCOORD]
+ cp b
+ jr nz,.retry2
+ ld a,[hli]
+ ld [wDestinationWarpID],a
+ ld a,[hl]
+ ld [$ff8b],a ; save target map
+ jr WarpFound2
+.retry1
+ inc hl
+.retry2
+ inc hl
+ inc hl
+ dec c
+ jr nz,.loop
+ jp OverworldLoop
+
+WarpFound1:: ; 0543 (0:0543)
+ ld a,[hli]
+ ld [wDestinationWarpID],a
+ ld a,[hli]
+ ld [$ff8b],a ; save target map
+
+WarpFound2:: ; 054a (0:054a)
+ ld a,[wNumberOfWarps]
+ sub c
+ ld [wd73b],a ; save ID of used warp
+ ld a,[W_CURMAP]
+ ld [wd73c],a
+ call CheckIfInOutsideMap
+ jr nz,.indoorMaps
+; this is for handling "outside" maps that can't have the 0xFF destination map
+ ld a,[W_CURMAP]
+ ld [wLastMap],a
+ ld a,[W_CURMAPWIDTH]
+ ld [wd366],a
+ ld a,[$ff8b] ; destination map number
+ ld [W_CURMAP],a ; change current map to destination map
+ cp a,ROCK_TUNNEL_1
+ jr nz,.notRockTunnel
+ ld a,$06
+ ld [wMapPalOffset],a
+ call GBFadeOutToBlack
+.notRockTunnel
+ callab Func_fc5fa ; 3f:45fa
+ call PlayMapChangeSound
+ jr .done
+; for maps that can have the 0xFF destination map, which means to return to the outside map; not all these maps are necessarily indoors, though
+.indoorMaps
+ ld a,[$ff8b] ; destination map
+ cp a,$ff
+ jr z,.goBackOutside
+; if not going back to the previous map
+ ld [W_CURMAP],a ; current map number
+ callba IsPlayerStandingOnWarpPadOrHole
+ ld a,[wcd5b]
+ dec a ; is the player on a warp pad?
+ jr nz,.notWarpPad
+; if the player is on a warp pad
+ call LeaveMapAnim
+ ld hl,wd732
+ set 3,[hl]
+ jr .skipMapChangeSound
+.notWarpPad
+ call PlayMapChangeSound
+.skipMapChangeSound
+ ld hl,wd736
+ res 0,[hl]
+ res 1,[hl]
+ callab Func_fc65b ; 3f:465b
+ jr .done
+.goBackOutside
+ callab Func_fc69a ; 3f:469a
+ ld a,[wLastMap]
+ ld [W_CURMAP],a
+ call PlayMapChangeSound
+ xor a
+ ld [wMapPalOffset],a
+.done
+ ld hl,wd736
+ set 0,[hl] ; have the player's sprite step out from the door (if there is one)
+ call IgnoreInputForHalfSecond
+ jp EnterMap
+
+; if no matching warp was found
+CheckMapConnections:: ; 05db (0:05db)
+.checkWestMap
+ ld a,[W_XCOORD]
+ cp a,$ff
+ jr nz,.checkEastMap
+ ld a,[W_MAPCONN3PTR]
+ ld [W_CURMAP],a
+ ld a,[wd38f] ; new X coordinate upon entering west map
+ ld [W_XCOORD],a
+ ld a,[W_YCOORD]
+ ld c,a
+ ld a,[wd38e] ; Y adjustment upon entering west map
+ add c
+ ld c,a
+ ld [W_YCOORD],a
+ ld a,[wd390] ; pointer to upper left corner of map without adjustment for Y position
+ ld l,a
+ ld a,[wd391]
+ ld h,a
+ srl c
+ jr z,.savePointer1
+.pointerAdjustmentLoop1
+ ld a,[wd38d] ; width of connected map
+ add a,$06
+ ld e,a
+ ld d,$00
+ ld b,$00
+ add hl,de
+ dec c
+ jr nz,.pointerAdjustmentLoop1
+.savePointer1
+ ld a,l
+ ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
+ ld a,h
+ ld [wCurrentTileBlockMapViewPointer + 1],a
+ jp .loadNewMap
+.checkEastMap
+ ld b,a
+ ld a,[wd525] ; map width
+ cp b
+ jr nz,.checkNorthMap
+ ld a,[W_MAPCONN4PTR]
+ ld [W_CURMAP],a
+ ld a,[wd39a] ; new X coordinate upon entering east map
+ ld [W_XCOORD],a
+ ld a,[W_YCOORD]
+ ld c,a
+ ld a,[wd399] ; Y adjustment upon entering east map
+ add c
+ ld c,a
+ ld [W_YCOORD],a
+ ld a,[wd39b] ; pointer to upper left corner of map without adjustment for Y position
+ ld l,a
+ ld a,[wd39c]
+ ld h,a
+ srl c
+ jr z,.savePointer2
+.pointerAdjustmentLoop2
+ ld a,[wd398]
+ add a,$06
+ ld e,a
+ ld d,$00
+ ld b,$00
+ add hl,de
+ dec c
+ jr nz,.pointerAdjustmentLoop2
+.savePointer2
+ ld a,l
+ ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
+ ld a,h
+ ld [wCurrentTileBlockMapViewPointer + 1],a
+ jp .loadNewMap
+.checkNorthMap
+ ld a,[W_YCOORD]
+ cp a,$ff
+ jr nz,.checkSouthMap
+ ld a,[W_MAPCONN1PTR]
+ ld [W_CURMAP],a
+ ld a,[wd378] ; new Y coordinate upon entering north map
+ ld [W_YCOORD],a
+ ld a,[W_XCOORD]
+ ld c,a
+ ld a,[wd379] ; X adjustment upon entering north map
+ add c
+ ld c,a
+ ld [W_XCOORD],a
+ ld a,[wd37a] ; pointer to upper left corner of map without adjustment for X position
+ ld l,a
+ ld a,[wd37b]
+ ld h,a
+ ld b,$00
+ srl c
+ add hl,bc
+ ld a,l
+ ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
+ ld a,h
+ ld [wCurrentTileBlockMapViewPointer + 1],a
+ jp .loadNewMap
+.checkSouthMap
+ ld b,a
+ ld a,[wd524]
+ cp b
+ jr nz,.didNotEnterConnectedMap
+ ld a,[W_MAPCONN2PTR]
+ ld [W_CURMAP],a
+ ld a,[wd383] ; new Y coordinate upon entering south map
+ ld [W_YCOORD],a
+ ld a,[W_XCOORD]
+ ld c,a
+ ld a,[wd384] ; X adjustment upon entering south map
+ add c
+ ld c,a
+ ld [W_XCOORD],a
+ ld a,[wd385] ; pointer to upper left corner of map without adjustment for X position
+ ld l,a
+ ld a,[wd386]
+ ld h,a
+ ld b,$00
+ srl c
+ add hl,bc
+ ld a,l
+ ld [wCurrentTileBlockMapViewPointer],a ; pointer to upper left corner of current tile block map section
+ ld a,h
+ ld [wCurrentTileBlockMapViewPointer + 1],a
+.loadNewMap ; 06ce (0:06ce)
+; load the connected map that was entered
+ ld hl,[wd430]
+ set 4,[hl]
+ ld a,$2
+ ld [wd431],a
+ call LoadMapHeader ; 0dab (0:0dab)
+ call Func_2312 ; music
+ ld b,$09
+ call GoPAL_SET
+; Since the sprite set shouldn't change, this will just update VRAM slots at
+; $C2XE without loading any tile patterns.
+ call InitMapSprites
+ call LoadTileBlockMap
+ jp OverworldLoopLessDelay
+.didNotEnterConnectedMap
+ jp OverworldLoop
+
+; function to play a sound when changing maps
+PlayMapChangeSound:: ; 06ef (0:06ef)
+ ld a,[W_CURMAPTILESET]
+ cp FACILITY
+ jr z,.didNotGoThroughDoor
+ cp CEMETERY
+ jr z,.didNotGoThroughDoor
+ cp UNDERGROUND
+ jr nz,.didNotGoThroughDoor
+ aCoord 8, 8 ; upper left tile of the 4x4 square the player's sprite is standing on
+ cp a,$0b ; door tile in tileset 0
+ jr nz,.didNotGoThroughDoor
+ ld a,(SFX_02_57 - SFX_Headers_02) / 3
+ jr .playSound
+.didNotGoThroughDoor
+ ld a,(SFX_02_5c - SFX_Headers_02) / 3
+.playSound
+ call PlaySound
+ ld a,[wMapPalOffset]
+ and a
+ ret nz
+ jp GBFadeOutToBlack
+
+CheckIfInOutsideMap:: ; 0712 (0:0712)
+; If the player is in an outside map (a town or route), set the z flag
+ ld a, [W_CURMAPTILESET]
+ and a ; most towns/routes have tileset 0 (OVERWORLD)
+ ret z
+ cp PLATEAU ; Route 23 / Indigo Plateau
+ ret
+
+; this function is an extra check that sometimes has to pass in order to warp, beyond just standing on a warp
+; the "sometimes" qualification is necessary because of CheckWarpsNoCollision's behavior
+; depending on the map, either "function 1" or "function 2" is used for the check
+; "function 1" passes when the player is at the edge of the map and is facing towards the outside of the map
+; "function 2" passes when the the tile in front of the player is among a certain set
+; sets carry if the check passes, otherwise clears carry
+ExtraWarpCheck:: ; 071a (0:071a)
+ ld a, [W_CURMAP]
+ cp SS_ANNE_3
+ jr z, .useFunction1
+ cp ROCKET_HIDEOUT_1
+ jr z, .useFunction2
+ cp ROCKET_HIDEOUT_2
+ jr z, .useFunction2
+ cp ROCKET_HIDEOUT_4
+ jr z, .useFunction2
+ cp ROCK_TUNNEL_1
+ jr z, .useFunction2
+ ld a, [W_CURMAPTILESET]
+ and a ; outside tileset (OVERWORLD)
+ jr z, .useFunction2
+ cp SHIP ; S.S. Anne tileset
+ jr z, .useFunction2
+ cp SHIP_PORT ; Vermilion Port tileset
+ jr z, .useFunction2
+ cp PLATEAU ; Indigo Plateau tileset
+ jr z, .useFunction2
+.useFunction1
+ ld hl, IsPlayerFacingEdgeOfMap
+ jr .doBankswitch
+.useFunction2
+ ld hl, IsWarpTileInFrontOfPlayer
+.doBankswitch
+ ld b, BANK(IsWarpTileInFrontOfPlayer)
+ jp Bankswitch
+
+MapEntryAfterBattle:: ; 0750 (0:0750)
+ callba IsPlayerStandingOnWarp ; for enabling warp testing after collisions
+ ld a,[wMapPalOffset]
+ and a
+ jp z,GBFadeInFromWhite
+ jp LoadGBPal
+
+HandleBlackOut:: ; 0762 (0:0762)
+; For when all the player's pokemon faint.
+; Does not print the "blacked out" message.
+
+ call GBFadeOutToBlack
+ ld a, $08
+ call StopMusic
+ ld hl, wd72e
+ res 5, [hl]
+ callsb ResetStatusAndHalveMoneyOnBlackout ; also Bank(SpecialWarpIn) and Bank(SpecialEnterMap)
+ callab Func_f0274 ; 3c:4274
+ call SpecialWarpIn
+ call Func_2312
+ jp SpecialEnterMap
+
+StopMusic:: ; 0788 (0:0788)
+ ld [wMusicHeaderPointer], a
+ call StopAllMusic
+.wait
+ ld a, [wMusicHeaderPointer]
+ and a
+ jr nz, .wait
+ jp StopAllSounds
+
+HandleFlyWarpOrDungeonWarp:: ; 0794 (0:0794)
+ call UpdateSprites
+ call Delay3
+ xor a
+ ld [wBattleResult], a
+ ld [wWalkBikeSurfState], a
+ ld [W_ISINBATTLE], a
+ ld [wMapPalOffset], a
+ ld hl, wd732
+ set 2, [hl] ; fly warp or dungeon warp
+ res 5, [hl] ; forced to ride bike
+ call LeaveMapAnim
+ call LoadPlayerSpriteGraphics
+ callsb SpecialWarpIn
+ jp SpecialEnterMap
+
+LeaveMapAnim:: ; 07bc (0:07bc)
+ ld b, BANK(_LeaveMapAnim)
+ ld hl, _LeaveMapAnim
+ jp Bankswitch
+
+Func_07c4:: ; 07c4 (0:07c4)
+ ld a, [wWalkBikeSurfState]
+ and a
+ ret z
+ xor a
+ ld [wWalkBikeSurfState],a
+ ld hl,wd732
+ bit 4,[hl]
+ ret z
+ call PlayDefaultMusic
+ ret
+
+LoadPlayerSpriteGraphics:: ; 07d7 (0:07d7)
+; Load sprite graphics based on whether the player is standing, biking, or surfing.
+
+ ; 0: standing
+ ; 1: biking
+ ; 2: surfing
+
+ ld a, [wWalkBikeSurfState]
+ dec a
+ jr z, .ridingBike
+
+ ld a, [hTilesetType]
+ and a
+ jr nz, .determineGraphics
+ jr .startWalking
+
+.ridingBike
+ ; If the bike can't be used,
+ ; start walking instead.
+ call IsBikeRidingAllowed
+ jr c, .determineGraphics
+
+.startWalking
+ xor a
+ ld [wWalkBikeSurfState], a
+ ld [wWalkBikeSurfStateCopy], a
+ jp LoadWalkingPlayerSpriteGraphics
+
+.determineGraphics
+ ld a, [wWalkBikeSurfState]
+ and a
+ jp z, LoadWalkingPlayerSpriteGraphics
+ dec a
+ jp z, LoadBikePlayerSpriteGraphics
+ dec a
+ jp z, LoadSurfingPlayerSpriteGraphics
+ jp LoadWalkingPlayerSpriteGraphics
+
+IsBikeRidingAllowed:: ; 0805 (0:0805)
+; The bike can be used on Route 23 and Indigo Plateau,
+; or maps with tilesets in BikeRidingTilesets.
+; Return carry if biking is allowed.
+
+ ld a, [W_CURMAP]
+ cp ROUTE_23
+ jr z, .allowed
+ cp INDIGO_PLATEAU
+ jr z, .allowed
+
+ ld a, [W_CURMAPTILESET]
+ ld b, a
+ ld hl, BikeRidingTilesets
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .allowed
+ inc a
+ jr nz, .loop
+ and a
+ ret
+
+.allowed
+ scf
+ ret
+
+INCLUDE "data/bike_riding_tilesets.asm"
+
+; load the tile pattern data of the current tileset into VRAM
+LoadTilesetTilePatternData:: ; 0828 (0:0828)
+ ld a,[W_TILESETGFXPTR]
+ ld l,a
+ ld a,[W_TILESETGFXPTR + 1]
+ ld h,a
+ ld de,vTileset
+ ld bc,$600
+ ld a,[W_TILESETBANK]
+ jp FarCopyData2
+
+; this loads the current maps complete tile map (which references blocks, not individual tiles) to C6E8
+; it can also load partial tile maps of connected maps into a border of length 3 around the current map
+LoadTileBlockMap:: ; 083c (0:083c)
+; fill C6E8-CBFB with the background tile
+ ld hl,wOverworldMap
+ ld bc,$0514
+ ld a,[wd3ad] ; background tile number
+ call FillMemory
+; load tile map of current map (made of tile block IDs)
+; a 3-byte border at the edges of the map is kept so that there is space for map connections
+ ld hl,wOverworldMap
+ ld a,[W_CURMAPWIDTH]
+ ld [$ff8c],a
+ add a,$06 ; border (east and west)
+ ld [$ff8b],a ; map width + border
+ ld b,$00
+ ld c,a
+; make space for north border (next 3 lines)
+ add hl,bc
+ add hl,bc
+ add hl,bc
+ ld c,$03
+ add hl,bc ; this puts us past the (west) border
+ ld a,[W_MAPDATAPTR] ; tile map pointer
+ ld e,a
+ ld a,[W_MAPDATAPTR + 1]
+ ld d,a ; de = tile map pointer
+ ld a,[W_CURMAPHEIGHT]
+ ld b,a
+.rowLoop ; copy one row each iteration
+ push hl
+ ld a,[$ff8c] ; map width (without border)
+ ld c,a
+.rowInnerLoop
+ ld a,[de]
+ inc de
+ ld [hli],a
+ dec c
+ jr nz,.rowInnerLoop
+; add the map width plus the border to the base address of the current row to get the next row's address
+ pop hl
+ ld a,[$ff8b] ; map width + border
+ add l
+ ld l,a
+ jr nc,.noCarry
+ inc h
+.noCarry
+ dec b
+ jr nz,.rowLoop
+.northConnection
+ ld a,[W_MAPCONN1PTR]
+ cp a,$ff
+ jr z,.southConnection
+ call SwitchToMapRomBank
+ ld a,[wd372]
+ ld l,a
+ ld a,[wd373]
+ ld h,a
+ ld a,[wd374]
+ ld e,a
+ ld a,[wd375]
+ ld d,a
+ ld a,[wd376]
+ ld [$ff8b],a
+ ld a,[wd377]
+ ld [$ff8c],a
+ call LoadNorthSouthConnectionsTileMap
+.southConnection
+ ld a,[W_MAPCONN2PTR]
+ cp a,$ff
+ jr z,.westConnection
+ call SwitchToMapRomBank
+ ld a,[wd37d]
+ ld l,a
+ ld a,[wd37e]
+ ld h,a
+ ld a,[wd37f]
+ ld e,a
+ ld a,[wd380]
+ ld d,a
+ ld a,[wd381]
+ ld [$ff8b],a
+ ld a,[wd382]
+ ld [$ff8c],a
+ call LoadNorthSouthConnectionsTileMap
+.westConnection
+ ld a,[W_MAPCONN3PTR]
+ cp a,$ff
+ jr z,.eastConnection
+ call SwitchToMapRomBank
+ ld a,[wd388]
+ ld l,a
+ ld a,[wd389]
+ ld h,a
+ ld a,[wd38a]
+ ld e,a
+ ld a,[wd38b]
+ ld d,a
+ ld a,[wd38c]
+ ld b,a
+ ld a,[wd38d]
+ ld [$ff8b],a
+ call LoadEastWestConnectionsTileMap
+.eastConnection
+ ld a,[W_MAPCONN4PTR]
+ cp a,$ff
+ jr z,.done
+ call SwitchToMapRomBank
+ ld a,[wd393]
+ ld l,a
+ ld a,[wd394]
+ ld h,a
+ ld a,[wd395]
+ ld e,a
+ ld a,[wd396]
+ ld d,a
+ ld a,[wd397]
+ ld b,a
+ ld a,[wd398]
+ ld [$ff8b],a
+ call LoadEastWestConnectionsTileMap
+.done
+ ret
+
+LoadNorthSouthConnectionsTileMap:: ; 0919 (0:0919)
+ ld c,$03
+.loop
+ push de
+ push hl
+ ld a,[$ff8b] ; width of connection
+ ld b,a
+.innerLoop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec b
+ jr nz,.innerLoop
+ pop hl
+ pop de
+ ld a,[$ff8c] ; width of connected map
+ add l
+ ld l,a
+ jr nc,.noCarry1
+ inc h
+.noCarry1
+ ld a,[W_CURMAPWIDTH]
+ add a,$06
+ add e
+ ld e,a
+ jr nc,.noCarry2
+ inc d
+.noCarry2
+ dec c
+ jr nz,.loop
+ ret
+
+LoadEastWestConnectionsTileMap:: ; 093d (0:093d)
+ push hl
+ push de
+ ld c,$03
+.innerLoop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.innerLoop
+ pop de
+ pop hl
+ ld a,[$ff8b] ; width of connected map
+ add l
+ ld l,a
+ jr nc,.noCarry1
+ inc h
+.noCarry1
+ ld a,[W_CURMAPWIDTH]
+ add a,$06
+ add e
+ ld e,a
+ jr nc,.noCarry2
+ inc d
+.noCarry2
+ dec b
+ jr nz,LoadEastWestConnectionsTileMap
+ ret
+
+; function to check if there is a sign or sprite in front of the player
+; if so, carry is set. otherwise, carry is cleared
+IsSpriteOrSignInFrontOfPlayer:: ; 095e (0:095e)
+ xor a
+ ld [hSpriteIndexOrTextID],a
+ ld a,[wd4b0] ; number of signs in the map
+ and a
+ jr z,.extendRangeOverCounter
+; if there are signs
+ predef GetTileAndCoordsInFrontOfPlayer ; get the coordinates in front of the player in de
+ call SignLoop
+ ret c
+.extendRangeOverCounter
+; check if the player is front of a counter in a pokemon center, pokemart, etc. and if so, extend the range at which he can talk to the NPC
+ predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player in c
+ ld hl,W_TILESETTALKINGOVERTILES ; list of tiles that extend talking range (counter tiles)
+ ld b,$03
+ ld d,$20 ; talking range in pixels (long range)
+.counterTilesLoop
+ ld a,[hli]
+ cp c
+ jr z,IsSpriteInFrontOfPlayer2 ; jumps if the tile in front of the player is a counter tile
+ dec b
+ jr nz,.counterTilesLoop
+
+; sets carry flag if a sprite is in front of the player, resets if not
+IsSpriteInFrontOfPlayer:: ; 0983 (0:0983)
+ ld d,$10 ; talking range in pixels (normal range)
+IsSpriteInFrontOfPlayer2:: ; 0985 (0:0985)
+ ld bc,$3c40 ; Y and X position of player sprite
+ ld a,[wSpriteStateData1 + 9] ; direction the player is facing
+.checkIfPlayerFacingUp
+ cp a,$04
+ jr nz,.checkIfPlayerFacingDown
+; facing up
+ ld a,b
+ sub d
+ ld b,a
+ ld a,$08
+ jr .doneCheckingDirection
+.checkIfPlayerFacingDown
+ cp a,$00
+ jr nz,.checkIfPlayerFacingRight
+; facing down
+ ld a,b
+ add d
+ ld b,a
+ ld a,$04
+ jr .doneCheckingDirection
+.checkIfPlayerFacingRight
+ cp a,$0c
+ jr nz,.playerFacingLeft
+; facing right
+ ld a,c
+ add d
+ ld c,a
+ ld a,$01
+ jr .doneCheckingDirection
+.playerFacingLeft
+; facing left
+ ld a,c
+ sub d
+ ld c,a
+ ld a,$02
+.doneCheckingDirection
+ ld [wd52a],a
+ ld hl,wSpriteStateData1 + $10
+; yellow does not have the "if sprites are existant" check
+ ld e,$01
+ ld d,$f
+.spriteLoop
+ push hl
+ ld a,[hli] ; image (0 if no sprite)
+ and a
+ jr z,.nextSprite
+ inc l
+ ld a,[hli] ; sprite visibility
+ inc a
+ jr z,.nextSprite
+ inc l
+ ld a,[hli] ; Y location
+ cp b
+ jr nz,.nextSprite
+ inc l
+ ld a,[hl] ; X location
+ cp c
+ jr z,.foundSpriteInFrontOfPlayer
+.nextSprite
+ pop hl
+ ld a,l
+ add a,$10
+ ld l,a
+ inc e
+ dec d
+ jr nz,.spriteLoop
+ xor a
+ ret
+.foundSpriteInFrontOfPlayer
+ pop hl
+ ld a,l
+ and a,$f0
+ inc a
+ ld l,a
+ set 7,[hl]
+ ld a,e
+ ld [hSpriteIndexOrTextID],a
+ ld a,[hSpriteIndexOrTextID] ; possible useless read because a already has the value of the read address
+ cp a,$f
+ jr nz,.dontwritetowd436
+ ld a,$FF
+ ld [wd436],a
+.dontwritetowd436
+ scf
+ ret
+
+SignLoop:: ; 09f2 (0:09f2)
+; search if a player is facing a sign
+ ld hl,wd4b1 ; start of sign coordinates
+ ld a,[wd4b0] ; number of signs in the map
+ ld b,a
+ ld c,$00
+.signLoop
+ inc c
+ ld a,[hli] ; sign Y
+ cp d
+ jr z,.yCoordMatched
+ inc hl
+ jr .retry
+.yCoordMatched
+ ld a,[hli] ; sign X
+ cp e
+ jr nz,.retry
+.xCoordMatched
+; found sign
+ push hl
+ push bc
+ ld hl,wd4d1 ; start of sign text ID's
+ ld b,$00
+ dec c
+ add hl,bc
+ ld a,[hl]
+ ld [hSpriteIndexOrTextID],a ; store sign text ID
+ pop bc
+ pop hl
+ scf
+ ret
+.retry
+ dec b
+ jr nz,.signLoop
+ xor a
+ ret
+
+; function to check if the player will jump down a ledge and check if the tile ahead is passable (when not surfing)
+; sets the carry flag if there is a collision, and unsets it if there isn't a collision
+CollisionCheckOnLand:: ; 0a1c (0:0a1c)
+ ld a,[wd736]
+ bit 6,a ; is the player jumping?
+ jr nz,.noCollision
+; if not jumping a ledge
+ ld a,[wSimulatedJoypadStatesIndex]
+ and a
+ jr nz,.noCollision ; no collisions when the player's movements are being controlled by the game
+ ld a,[wd52a] ; the direction that the player is trying to go in
+ ld d,a
+ ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
+ and d ; check if a sprite is in the direction the player is trying to go
+ nop ; ??? why is this in the code
+ jr nz,.collision
+ xor a
+ ld [hSpriteIndexOrTextID],a
+ call IsSpriteInFrontOfPlayer ; check for sprite collisions again? when does the above check fail to detect a sprite collision?
+ jr nc,.asm_0a5c
+ res 7,[hl]
+ ld a,[hSpriteIndexOrTextID]
+ and a ; was there a sprite collision?
+ jr z,.asm_0a5c
+; if no sprite collision
+ cp $f
+ jr nz,.collision
+ call CheckForJumpingAndTilePairCollisions
+ jr nz,.collision
+ ld a,[hJoyHeld]
+ and $2
+ jr nz,.asm_0a5c
+ ld hl,wd435
+ ld a,[hl]
+ and a
+ jr z,.asm_0a5c
+ dec [hl]
+ jr nz,.collision
+.asm_0a5c
+ ld hl,TilePairCollisionsLand
+ call CheckForJumpingAndTilePairCollisions
+ jr c,.collision
+ call CheckTilePassable
+ jr nc,.noCollision
+.collision
+ ld a,[wc02a]
+ cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing
+ jr z,.setCarry
+ ld a,(SFX_02_5b - SFX_Headers_02) / 3
+ call PlaySound ; play collision sound (if it's not already playing)
+.setCarry
+ scf
+ ret
+.noCollision
+ and a
+ ret
+
+; function that checks if the tile in front of the player is passable
+; clears carry if it is, sets carry if not
+CheckTilePassable:: ; 0a79 (0:0a79)
+ predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player
+ ld a,[wTileInFrontOfPlayer] ; tile in front of player
+ ld c,a
+ call IsTilePassable
+ ret
+
+; check if the player is going to jump down a small ledge
+; and check for collisions that only occur between certain pairs of tiles
+; Input: hl - address of directional collision data
+; sets carry if there is a collision and unsets carry if not
+CheckForJumpingAndTilePairCollisions:: ; 0a86 (0:0a86)
+ push hl
+ predef GetTileAndCoordsInFrontOfPlayer ; get the tile in front of the player
+ push de
+ push bc
+ callba HandleLedges ; check if the player is trying to jump a ledge
+ pop bc
+ pop de
+ pop hl
+ and a
+ ld a,[wd736]
+ bit 6,a ; is the player jumping?
+ ret nz
+; if not jumping
+
+CheckForTilePairCollisions2:: ; 0aa0 (0:0aa0)
+ aCoord 8, 9 ; tile the player is on
+ ld [wcf0e],a
+
+CheckForTilePairCollisions:: ; 0aa6 (0:0aa6)
+ ld a,[wTileInFrontOfPlayer]
+ ld c,a
+.tilePairCollisionLoop
+ ld a,[W_CURMAPTILESET] ; tileset number
+ ld b,a
+ ld a,[hli]
+ cp a,$ff
+ jr z,.noMatch
+ cp b
+ jr z,.tilesetMatches
+ inc hl
+.retry
+ inc hl
+ jr .tilePairCollisionLoop
+.tilesetMatches
+ ld a,[wcf0e] ; tile the player is on
+ ld b,a
+ ld a,[hl]
+ cp b
+ jr z,.currentTileMatchesFirstInPair
+ inc hl
+ ld a,[hl]
+ cp b
+ jr z,.currentTileMatchesSecondInPair
+ jr .retry
+.currentTileMatchesFirstInPair
+ inc hl
+ ld a,[hl]
+ cp c
+ jr z,.foundMatch
+ jr .tilePairCollisionLoop
+.currentTileMatchesSecondInPair
+ dec hl
+ ld a,[hli]
+ cp c
+ inc hl
+ jr nz,.tilePairCollisionLoop
+.foundMatch
+ scf
+ ret
+.noMatch
+ and a
+ ret
+
+; FORMAT: tileset number, tile 1, tile 2
+; terminated by 0xFF
+; these entries indicate that the player may not cross between tile 1 and tile 2
+; it's mainly used to simulate differences in elevation
+
+TilePairCollisionsLand:: ; 0ada (0:0ada)
+ db CAVERN, $20, $05
+ db CAVERN, $41, $05
+ db FOREST, $30, $2E
+ db CAVERN, $2A, $05
+ db CAVERN, $05, $21
+ db FOREST, $52, $2E
+ db FOREST, $55, $2E
+ db FOREST, $56, $2E
+ db FOREST, $20, $2E
+ db FOREST, $5E, $2E
+ db FOREST, $5F, $2E
+ db $FF
+
+TilePairCollisionsWater:: ; 0afc (0:0afc)
+ db FOREST, $14, $2E
+ db FOREST, $48, $2E
+ db CAVERN, $14, $05
+ db $FF
+
+; this builds a tile map from the tile block map based on the current X/Y coordinates of the player's character
+LoadCurrentMapView:: ; 0b06 (0:0b06)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[W_TILESETBANK] ; tile data ROM bank
+ call BankswitchCommon ; switch to ROM bank that contains tile data
+ ld a,[wCurrentTileBlockMapViewPointer] ; address of upper left corner of current map view
+ ld e,a
+ ld a,[wCurrentTileBlockMapViewPointer + 1]
+ ld d,a
+ ld hl,wTileMapBackup
+ ld b,$05
+.rowLoop ; each loop iteration fills in one row of tile blocks
+ push hl
+ push de
+ ld c,$06
+.rowInnerLoop ; loop to draw each tile block of the current row
+ push bc
+ push de
+ push hl
+ ld a,[de]
+ ld c,a ; tile block number
+ call DrawTileBlock
+ pop hl
+ pop de
+ pop bc
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ inc de
+ dec c
+ jr nz,.rowInnerLoop
+; update tile block map pointer to next row's address
+ pop de
+ ld a,[W_CURMAPWIDTH]
+ add a,$06
+ add e
+ ld e,a
+ jr nc,.noCarry
+ inc d
+.noCarry
+; update tile map pointer to next row's address
+ pop hl
+ ld a,$60
+ add l
+ ld l,a
+ jr nc,.noCarry2
+ inc h
+.noCarry2
+ dec b
+ jr nz,.rowLoop
+ ld hl,wTileMapBackup
+ ld bc,$0000
+.adjustForYCoordWithinTileBlock
+ ld a,[W_YBLOCKCOORD]
+ and a
+ jr z,.adjustForXCoordWithinTileBlock
+ ld bc,$0030
+ add hl,bc
+.adjustForXCoordWithinTileBlock
+ ld a,[W_XBLOCKCOORD]
+ and a
+ jr z,.copyToVisibleAreaBuffer
+ ld bc,$0002
+ add hl,bc
+.copyToVisibleAreaBuffer
+ ld de,wTileMap ; base address for the tiles that are directly transfered to VRAM during V-blank
+ ld b,$12
+.rowLoop2
+ ld c,$14
+.rowInnerLoop2
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.rowInnerLoop2
+ ld a,$04
+ add l
+ ld l,a
+ jr nc,.noCarry3
+ inc h
+.noCarry3
+ dec b
+ jr nz,.rowLoop2
+ pop af
+ call BankswitchCommon ; restore previous ROM bank
+ ret
+
+AdvancePlayerSprite:: ; 0b7f (0:0b7f)
+ ld a,[wUpdateSpritesEnabled]
+ push af
+ ld a,$FF
+ ld [wUpdateSpritesEnabled],a
+ ld hl, _AdvancePlayerSorite ; 3c:410c
+ ld b, BANK(_AdvancePlayerSprite)
+ call Bankswitch
+ pop af
+ ld [wUpdateSpritesEnabled],a
+ ret
+
+; the following 6 functions are used to tell the V-blank handler to redraw
+; the portion of the map that was newly exposed due to the player's movement
+
+ScheduleNorthRowRedraw:: ; 0b95 (0:0b95)
+ hlCoord 0, 0
+ call CopyToScreenEdgeTiles
+ ld a,[wMapViewVRAMPointer]
+ ld [H_SCREENEDGEREDRAWADDR],a
+ ld a,[wMapViewVRAMPointer + 1]
+ ld [H_SCREENEDGEREDRAWADDR + 1],a
+ ld a,REDRAWROW
+ ld [H_SCREENEDGEREDRAW],a
+ ret
+
+CopyToScreenEdgeTiles:: ; 0baa (0:0baa)
+ ld de,wScreenEdgeTiles
+ ld c,2 * 20
+.loop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.loop
+ ret
+
+ScheduleSouthRowRedraw:: ; 0bb6 (0:0bb6)
+ hlCoord 0, 16
+ call CopyToScreenEdgeTiles
+ ld a,[wMapViewVRAMPointer]
+ ld l,a
+ ld a,[wMapViewVRAMPointer + 1]
+ ld h,a
+ ld bc,$0200
+ add hl,bc
+ ld a,h
+ and a,$03
+ or a,$98
+ ld [H_SCREENEDGEREDRAWADDR + 1],a
+ ld a,l
+ ld [H_SCREENEDGEREDRAWADDR],a
+ ld a,REDRAWROW
+ ld [H_SCREENEDGEREDRAW],a
+ ret
+
+ScheduleEastColumnRedraw:: ; 0bd6 (0:0bd7)
+ hlCoord 18, 0
+ call ScheduleColumnRedrawHelper
+ ld a,[wMapViewVRAMPointer]
+ ld c,a
+ and a,$e0
+ ld b,a
+ ld a,c
+ add a,18
+ and a,$1f
+ or b
+ ld [H_SCREENEDGEREDRAWADDR],a
+ ld a,[wMapViewVRAMPointer + 1]
+ ld [H_SCREENEDGEREDRAWADDR + 1],a
+ ld a,REDRAWCOL
+ ld [H_SCREENEDGEREDRAW],a
+ ret
+
+ScheduleColumnRedrawHelper:: ; 0bf6 (0:0bf6)
+ ld de,wScreenEdgeTiles
+ ld c,$12
+.loop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ ld a,[hl]
+ ld [de],a
+ inc de
+ ld a,19
+ add l
+ ld l,a
+ jr nc,.noCarry
+ inc h
+.noCarry
+ dec c
+ jr nz,.loop
+ ret
+
+ScheduleWestColumnRedraw:: ; 0c0c (0:0c0c)
+ hlCoord 0, 0
+ call ScheduleColumnRedrawHelper
+ ld a,[wMapViewVRAMPointer]
+ ld [H_SCREENEDGEREDRAWADDR],a
+ ld a,[wMapViewVRAMPointer + 1]
+ ld [H_SCREENEDGEREDRAWADDR + 1],a
+ ld a,REDRAWCOL
+ ld [H_SCREENEDGEREDRAW],a
+ ret
+
+; function to write the tiles that make up a tile block to memory
+; Input: c = tile block ID, hl = destination address
+DrawTileBlock:: ; 0c21 (0:0c21)
+ push hl
+ ld a,[W_TILESETBLOCKSPTR] ; pointer to tiles
+ ld l,a
+ ld a,[W_TILESETBLOCKSPTR + 1]
+ ld h,a
+ ld a,c
+ swap a
+ ld b,a
+ and a,$f0
+ ld c,a
+ ld a,b
+ and a,$0f
+ ld b,a ; bc = tile block ID * 0x10
+ add hl,bc
+ ld d,h
+ ld e,l ; de = address of the tile block's tiles
+ pop hl
+ ld c,$04 ; 4 loop iterations
+.loop ; each loop iteration, write 4 tile numbers
+ push bc
+ ld a,[de]
+ ld [hli],a
+ inc de
+ ld a,[de]
+ ld [hli],a
+ inc de
+ ld a,[de]
+ ld [hli],a
+ inc de
+ ld a,[de]
+ ld [hl],a
+ inc de
+ ld bc,$0015
+ add hl,bc
+ pop bc
+ dec c
+ jr nz,.loop
+ ret
+
+; function to update joypad state and simulate button presses
+JoypadOverworld:: ; 0c51 (0:0c51)
+ xor a
+ ld [wSpriteStateData1 + 3],a
+ ld [wSpriteStateData1 + 5],a
+ call RunMapScript
+ call Joypad
+ call ForceBikeDown
+ call AreInputsSimulated
+ ret
+
+ForceBikeDown:: ; 0c65 (0:0c65)
+ ld a,[W_FLAGS_D733]
+ bit 3,a ; check if a trainer wants a challenge
+ ret nz
+ ld a,[W_CURMAP]
+ cp a,ROUTE_17 ; Cycling Road
+ ret nz
+ ld a,[hJoyHeld]
+ and a,D_DOWN | D_UP | D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON
+ jr nz,.notForcedDownwards
+ ld a,D_DOWN
+ ld [hJoyHeld],a ; on the cycling road, if there isn't a trainer and the player isn't pressing buttons, simulate a down press
+ ret
+
+AreInputsSimulated:: ; 0c7b (0:0c7b)
+ ld a,[wd730]
+ bit 7,a
+ ret z
+; if simulating button presses
+ ld a,[hJoyHeld]
+ ld b,a
+ ld a,[wOverrideSimulatedJoypadStatesMask] ; bit mask for button presses that override simulated ones
+ and b
+ ret nz ; return if the simulated button presses are overridden
+ call GetSimulatedInput
+ jr nc,.doneSimulating
+ ld [hJoyHeld],a ; store simulated button press in joypad state
+ and a
+ ret nz
+ ld [hJoyPressed],a
+ ld [hJoyReleased],a
+ ret
+
+; if done simulating button presses
+.doneSimulating
+ xor a
+ ld [wWastedByteCD3A],a
+ ld [wSimulatedJoypadStatesIndex],a
+ ld [wSimulatedJoypadStatesEnd],a
+ ld [wJoyIgnore],a
+ ld [hJoyHeld],a
+ ld hl,wd736
+ ld a,[hl]
+ and a,$f8
+ ld [hl],a
+ ld hl,wd730
+ res 7,[hl]
+ ret
+
+GetSimulatedInput:: ; 0cb3 (0:0cb3)
+ ld hl,wSimulatedJoypadStatesIndex
+ dec [hl]
+ ld a,[hl]
+ cp a,$ff
+ jr z,.endofsimulatedinputs ; if the end of the simulated button presses has been reached
+ push de
+ ld e,a
+ ld d,$0
+ ld hl,wSimulatedJoypadStatesEnd
+ add hl,de
+ ld a,[hl]
+ pop de
+ scf
+ ret
+.endofsimulatedinputs
+ and a
+ ret
+
+
+; function to check the tile ahead to determine if the character should get on land or keep surfing
+; sets carry if there is a collision and clears carry otherwise
+; It seems that this function has a bug in it, but due to luck, it doesn't
+; show up. After detecting a sprite collision, it jumps to the code that
+; checks if the next tile is passable instead of just directly jumping to the
+; "collision detected" code. However, it doesn't store the next tile in c,
+; so the old value of c is used. 2429 is always called before this function,
+; and 2429 always sets c to 0xF0. There is no 0xF0 background tile, so it
+; is considered impassable and it is detected as a collision.
+CollisionCheckOnWater:: ; 0cca (0:0cca)
+ ld a,[wd730]
+ bit 7,a
+ jp nz,.noCollision ; return and clear carry if button presses are being simulated
+ ld a,[wd52a] ; the direction that the player is trying to go in
+ ld d,a
+ ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
+ and d ; check if a sprite is in the direction the player is trying to go
+ jr nz,.checkIfNextTileIsPassable ; bug?
+ ld hl,TilePairCollisionsWater
+ call CheckForJumpingAndTilePairCollisions
+ jr c,.collision
+ predef GetTileAndCoordsInFrontOfPlayer ; get tile in front of player (puts it in c and [wTileInFrontOfPlayer])
+ callab IsNextTileShoreOrWater ; 3:6808
+ jr c,.noCollsion
+ ld a,[wTileInFrontOfPlayer] ; tile in front of player
+ ld c,a
+ call IsTilePassable
+ jr nc,.stopSurfing
+.collision
+ ld a,[wc02a]
+ cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing
+ jr z,.setCarry
+ ld a,(SFX_02_5b - SFX_Headers_02) / 3
+ call PlaySound ; play collision sound (if it's not already playing)
+.setCarry
+ scf
+ jr .done
+.checkIfVermilionDockTileset
+ ld a, [W_CURMAPTILESET] ; tileset
+ cp SHIP_PORT ; Vermilion Dock tileset
+ jr nz, .noCollision ; keep surfing if it's not the boarding platform tile
+ jr .stopSurfing ; if it is the boarding platform tile, stop surfing
+.stopSurfing ; based game freak
+ ld a,$3
+ ld [wd431],a
+ ld hl,wd430
+ set 5,[hl]
+ xor a
+ ld [wWalkBikeSurfState],a
+ call LoadPlayerSpriteGraphics
+ call PlayDefaultMusic
+ jr .noCollision
+.noCollision ; ...and they do the same mistake twice
+ and a
+.done
+ ret
+
+; function to run the current map's script
+RunMapScript:: ; 0d2c (0:0d2c)
+ push hl
+ push de
+ push bc
+ callba TryPushingBoulder
+ ld a,[wFlags_0xcd60]
+ bit 1,a ; play boulder dust animation
+ jr z,.afterBoulderEffect
+ callba DoBoulderDustAnimation
+.afterBoulderEffect
+ pop bc
+ pop de
+ pop hl
+ call RunNPCMovementScript
+ ld a,[W_CURMAP] ; current map number
+ call SwitchToMapRomBank ; change to the ROM bank the map's data is in
+ ld hl,W_MAPSCRIPTPTR
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a
+ ld de,.return
+ push de
+ jp [hl] ; jump to script
+.return
+ ret
+
+Func_0d5e:: ; 0d5e (0:0d5e)
+; new sprite copy stuff
+ xor a
+ ld [wd473],a
+ ld b,BANK(RedSprite)
+ ld de,RedSprite ; $4180
+ jr LoadPlayerSpriteGraphicsCommon
+
+Func_0d69:: ; 0d69 (0:0d69)
+ ld a,[wd473]
+ and a
+ jr z,.asm_0d75
+ dec a
+ jr z,.asm_0d83
+ dec a
+ jr z,.asm_0d7c
+.asm_0d75
+ ld a,[wd472]
+ bit 6,a
+ jr z,LoadSurfingPlayerSpriteGraphics
+.asm_0d7c
+ ld b,BANK(Pointer_fedef)
+ ld de,Pointer_fedef ; 3f:6def
+ jr LoadPlayerSpriteGraphicsCommon
+
+LoadSurfingPlayerSpriteGraphics:: ; 0d83 (0:0d83)
+ ld b,BANK(RedSprite) ; not sure, but probably same bank (5)
+ ld de,SeelSprite
+ jr LoadPlayerSpriteGraphicsCommon
+
+LoadBikePlayerSpriteGraphics:: ; 0d8a (0:0d8a)
+ ld de,RedCyclingSprite
+LoadPlayerSpriteGraphicsCommon:: ; 0d8f (0:0d8f)
+ ld hl,vNPCSprites
+ push de
+ push hl
+ ld c, $c
+ call CopyVideoData
+ pop hl
+ pop de
+ ld a,$c0
+ add e
+ ld e,a
+ jr nc,.noCarry
+ inc d
+.noCarry
+ set 3,h
+ ld c,$c
+ jp CopyVideoData
+
+; function to load data from the map header
+LoadMapHeader:: ; 0dab (0:0dab)
+ callba MarkTownVisitedAndLoadMissableObjects
+ jr .asm_0dbd
+ callba Func_f0a55 ; 3c:4a55
+.asm_0dbd
+ ld a,[W_CURMAPTILESET]
+ ld [wd119],a
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ ld a,[W_CURMAPTILESET]
+ ld b,a
+ res 7,a
+ ld [W_CURMAPTILESET],a
+ ld [$ff8b],a
+ bit 7,b
+ ret nz
+ call GetMapHeaderPointer
+; copy the first 10 bytes (the fixed area) of the map data to D367-D370
+ ld de,W_CURMAPTILESET
+ ld c,$0a
+.copyFixedHeaderLoop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.copyFixedHeaderLoop
+; initialize all the connected maps to disabled at first, before loading the actual values
+ ld a,$ff
+ ld [W_MAPCONN1PTR],a
+ ld [W_MAPCONN2PTR],a
+ ld [W_MAPCONN3PTR],a
+ ld [W_MAPCONN4PTR],a
+; copy connection data (if any) to WRAM
+ ld a,[W_MAPCONNECTIONS]
+ ld b,a
+.checkNorth
+ bit 3,b
+ jr z,.checkSouth
+ ld de,W_MAPCONN1PTR
+ call CopyMapConnectionHeader
+.checkSouth
+ bit 2,b
+ jr z,.checkWest
+ ld de,W_MAPCONN2PTR
+ call CopyMapConnectionHeader
+.checkWest
+ bit 1,b
+ jr z,.checkEast
+ ld de,W_MAPCONN3PTR
+ call CopyMapConnectionHeader
+.checkEast
+ bit 0,b
+ jr z,.getObjectDataPointer
+ ld de,W_MAPCONN4PTR
+ call CopyMapConnectionHeader
+.getObjectDataPointer
+ ld a,[hli]
+ ld [wd3a9],a
+ ld a,[hli]
+ ld [wd3aa],a
+ push hl
+ ld a,[wd3a9]
+ ld l,a
+ ld a,[wd3aa]
+ ld h,a ; hl = base of object data
+ ld de,wd3ad ; background tile ID
+ ld a,[hli]
+ ld [de],a ; save background tile ID
+.loadWarpData
+ ld a,[hli]
+ ld [wNumberOfWarps],a
+ and a
+ jr z,.loadSignData
+ ld c,a
+ ld de,wWarpEntries
+.warpLoop ; one warp per loop iteration
+ ld b,$04
+.warpInnerLoop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec b
+ jr nz,.warpInnerLoop
+ dec c
+ jr nz,.warpLoop
+.loadSignData
+ ld a,[hli] ; number of signs
+ ld [wd4b0],a ; save the number of signs
+ and a ; are there any signs?
+ jr z,.loadSpriteData ; if not, skip this
+ call CopySignData ; 0eb3 (0:0eb3)
+.loadSpriteData
+ ld a,[wd72e]
+ bit 5,a ; did a battle happen immediately before this?
+ jp nz,.finishUp ; if so, skip this because battles don't destroy this data
+ call InitSprites
+.finishUp
+ predef LoadTilesetHeader
+ ld a,[wd72e]
+ bit 5,a ; did a battle happen immediately before this?
+ jr nz,.asm_0e73
+ callab Func_fc4fa ; 3f:44fa
+ callab LoadWildData
+ pop hl ; restore hl from before going to the warp/sign/sprite data (this value was saved for seemingly no purpose)
+ ld a,[W_CURMAPHEIGHT] ; map height in 4x4 tile blocks
+ add a ; double it
+ ld [wd524],a ; store map height in 2x2 tile blocks
+ ld a,[W_CURMAPWIDTH] ; map width in 4x4 tile blocks
+ add a ; double it
+ ld [wd525],a ; map width in 2x2 tile blocks
+ ld a,[W_CURMAP]
+ ld c,a
+ ld b,$00
+ ld a,[H_LOADEDROMBANK]
+ push af
+ switchbank MapSongBanks
+ ld hl, MapSongBanks ; 3f:4000
+ add hl,bc
+ add hl,bc
+ ld a,[hli]
+ ld [wd35b],a ; music 1
+ ld a,[hl]
+ ld [wd35c],a ; music 2
+ pop af
+ call BankswitchCommon
+ ret
+
+; function to copy map connection data from ROM to WRAM
+; Input: hl = source, de = destination
+CopyMapConnectionHeader:: ; 1238 (0:1238)
+ ld c,$0b
+.loop
+ ld a,[hli]
+ ld [de],a
+ inc de
+ dec c
+ jr nz,.loop
+ ret
+
+CopySignData:: ; 0eb3 (0:0eb3)
+ ld de,wd4b1 ; start of sign coords
+ ld bc,wd4d1 ; start of sign text ids
+ ld a,[wd4b0] ; number of signs
+.signcopyloop
+ push af
+ ld a,[hli]
+ ld [de],a ; copy y coord
+ inc de
+ ld a,[hli]
+ ld [de],a ; copy x coord
+ inc de
+ ld a,[hli]
+ ld [bc],a ; copy sign text id
+ inc bc
+ pop af
+ dec a
+ jr nz,.signcopyloop
+ ret
+
+; function to load map data
+LoadMapData:: ; 1241 (0:1241)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ call DisableLCD
+ call ResetMapVariables
+ call LoadTextBoxTilePatterns
+ call LoadMapHeader
+ call InitMapSprites ; load tile pattern data for sprites
+ call LoadScreenRelatedData
+ call CopyMapViewToVRAM
+ ld a,$01
+ ld [wUpdateSpritesEnabled],a
+ call EnableLCD
+ ld b,$09
+ call GoPAL_SET
+ call LoadPlayerSpriteGraphics
+ ld a,[wd732]
+ and a,1 << 4 | 1 << 3 ; fly warp or dungeon warp
+ jr nz,.restoreRomBank
+ ld a,[W_FLAGS_D733]
+ bit 1,a
+ jr nz,.restoreRomBank
+ call Func_235f ; music related
+ call Func_2312 ; music related
+.restoreRomBank
+ pop af
+ ld [H_LOADEDROMBANK],a
+ ld [$2000],a
+ ret
+
+LoadScreenRelatedData:: ; 0f0c (0:0f0c)
+ call LoadTileBlockMap
+ call LoadTilesetTilePatternData
+ call LoadCurrentMapView
+ ret
+
+Func_0f16:: ; 0f16 (0:0f16)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ call DisableLCD
+ call ResetMapVariables
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ call LoadScreenRelatedData
+ call CopyMapViewToVRAM
+ ld de,vBGMap1
+ call CopyMapViewToVRAM2
+ call EnableLCD
+ call ReloadMapSpriteTilePatterns
+ pop af
+ call BankswitchCommon
+ jr .asm_0f4d
+Func_0f3d:: ; 0f3d (0:0f3d)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ ld a,[W_CURMAP]
+ call SwitchToMapRomBank
+ call LoadTileBlockMap
+ pop af
+ call BankswitchCommon
+.asm_0f4d
+ ld hl, Func_f02da
+ ld b,BANK(Func_f02da) ; 3c:42da
+ jp Bankswitch
+ ret ; useless?
+
+ResetMapVariables:: ; 0f56 (0:0f56)
+ ld a,$98
+ ld [wMapViewVRAMPointer + 1],a
+ xor a
+ ld [wMapViewVRAMPointer],a
+ ld [hSCY],a
+ ld [hSCX],a
+ ld [wWalkCounter],a
+ ld [wd119],a
+ ld [W_SPRITESETID],a
+ ld [wWalkBikeSurfStateCopy],a
+ ret
+
+CopyMapViewToVRAM:: ; 0f70 (0:0f70)
+; copy current map view to VRAM
+ ld de,vBGMap0
+CopyMapViewToVRAM2: ; 0f73 (0:0f73)
+ ld hl,wTileMap
+ ld b,18
+.vramCopyLoop
+ ld c,20
+.vramCopyInnerLoop
+ ld a,[hli]
+ ld [de],a
+ inc e
+ dec c
+ jr nz,.vramCopyInnerLoop
+ ld a,32 - 20 ; total vram map width in tiles - screen width in tiles
+ add e
+ ld e,a
+ jr nc,.noCarry
+ inc d
+.noCarry
+ dec b
+ jr nz,.vramCopyLoop
+ ret
+
+; function to switch to the ROM bank that a map is stored in
+; Input: a = map number
+SwitchToMapRomBank:: ; 0f8b (0:0f8b)
+ push hl
+ push bc
+ ld c,a
+ ld b,$00
+ ld a,BANK(MapHeaderBanks)
+ call BankswitchHome ; switch to ROM bank 3F
+ ld hl,MapHeaderBanks
+ add hl,bc
+ ld a,[hl]
+ ld [$ffe8],a ; save map ROM bank
+ call BankswitchCommon
+ pop bc
+ pop hl
+ ret
+
+GetMapHeaderPointer:: ; 0fa7 (0:0fa7)
+ ld a,[H_LOADEDROMBANK]
+ push af
+ switchbank Pointer_fc1f2 ; 3f:41f2
+ push de
+ ld a,[W_CURMAP]
+ ld e,a
+ ld d,$0
+ ld hl,Pointer_fc1f2
+ add hl,de
+ add hl,de
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a
+ pop de
+ pop af
+ jp BankswitchCommon
+
+IgnoreInputForHalfSecond: ; 0fc3 (0:0fc3)
+ ld a, 30
+ ld [wIgnoreInputCounter], a
+ ld hl, wd730
+ ld a, [hl]
+ or $26
+ ld [hl], a ; set ignore input bit
+ ret
+
+ResetUsingStrengthOutOfBattleBit: ; 0fd0 (0:0fd0)
+ ld hl, wd728
+ res 0, [hl]
+ ret
+
+ForceBikeOrSurf:: ; 0fd6 (0:0fd6)
+ ld b, BANK(RedSprite)
+ ld hl, LoadPlayerSpriteGraphics
+ call Bankswitch
+ jp PlayDefaultMusic ; update map/player state?
+
+; Handle the player jumping down
+; a ledge in the overworld.
+HandleMidJump:: ; 0fe1 (0:0fe1)
+ ld a,[wd736]
+ bit 7,a ; jumping down a ledge?
+ ret z
+ ld b, BANK(_HandleMidJump)
+ ld hl, _HandleMidJump
+ jp Bankswitch
+
+IsSpinning:: ; 0ff0 (0:0ff0)
+ ld a,[wd736]
+ bit 7,a
+ ret z ; no spinning
+ ld b, BANK(LoadSpinnerArrowTiles); spin while moving
+ ld hl,LoadSpinnerArrowTiles ; 11:5077
+ jp Bankswitch
+
+Func_0ffe:: ; 0ffe (0:0ffe)
+ ld hl, Func_fcf0c ; 3f:4f0c
+ ld b, BANK(Func_fcf0c)
+ jp Bankswitch
+
+InitSprites:: ; 1006 (0:1006)
+ ld a,[hli]
+ ld [W_NUMSPRITES],a ; save the number of sprites
+ push hl
+ push hl
+ push de
+ push bc
+ call ZeroSpriteStateData
+ call DisableRegularSprites
+ ld hl,W_MAPSPRITEDATA
+ ld bc,$20
+ xor a
+ call FillMemory
+ pop bc
+ pop de
+ pop hl
+ ld a,[W_NUMSPRITES]
+ and a ; are sprites existant?
+ ret z ; don't copy sprite data if not
+ ld b,a
+ ld c,$0
+ ld de,wSpriteStateData1 + $10
+; copy sprite stuff?
+.loadSpriteLoop
+ ld a,[hli]
+ ld [de],a ; store picture ID at C1X0
+ inc d
+ ld a,$04
+ add e
+ ld e,a
+ ld a,[hli]
+ ld [de],a ; store Y position at C2X4
+ inc e
+ ld a,[hli]
+ ld [de],a ; store X position at C2X5
+ inc e
+ ld a,[hli]
+ ld [de],a ; store movement byte 1 at C2X6
+ ld a,[hli]
+ ld [$ff8d],a ; save movement byte 2
+ ld a,[hli]
+ ld [$ff8e],a ; save text ID and flags byte
+ push bc
+ call LoadSprite
+ pop bc
+ dec d
+ ld a,e
+ add a,$a
+ ld e,a
+ inc c
+ inc c
+ dec b
+ jr nz,.loadSpriteLoop
+ ret
+
+ZeroSpriteStateData:: ; 1050 (0:1050)
+; zero C110-C1EF and C210-C2EF
+; C1F0-C1FF and C2F0-C2FF is probably used for Pikachu
+ ld hl,wSpriteStateData1 + $10
+ ld de,wSpriteStateData2 + $10
+ xor a
+ ld b,$e0
+.loop
+ ld [hli],a
+ ld [de],a
+ inc e
+ dec b
+ jr nz,.loop
+ ret
+
+DisableRegularSprites:: ; 1060 (0:1060)
+; initialize all C100-C1FF sprite entries to disabled (other than player's and pikachu)
+ ld hl,wSpriteStateData1 + $12
+ ld de,$10
+ ld c,$e
+.loop
+ ld [hl],$ff
+ add hl,de
+ dec c
+ jr nz,.loop
+ ret
+
+LoadSprite:: ; 106f (0:106f)
+ push hl
+ ld b,$0
+ ld hl,W_MAPSPRITEDATA
+ add hl,bc
+ ld a,[$ff8d]
+ ld [hli],a ; store movement byte 2 in byte 0 of sprite entry
+ ld a,[$ff8e]
+ ld [hl],a ; this appears pointless, since the value is overwritten immediately after
+ ld a,[$ff8e]
+ ld [$ff8d],a
+ and a,$3f
+ ld [hl],a ; store text ID in byte 1 of sprite entry
+ pop hl
+ ld a,[$ff8d]
+ bit 6,a
+ jr nz,.trainerSprite
+ bit 7,a
+ jr nz,.itemBallSprite
+; for regular sprites
+ push hl
+ ld hl,W_MAPSPRITEEXTRADATA
+ add hl,bc
+; zero both bytes, since regular sprites don't use this extra space
+ xor a
+ ld [hli],a
+ ld [hl],a
+ pop hl
+ ret
+
+.trainerSprite
+ ld a,[hli]
+ ld [$ff8d],a ; save trainer class
+ ld a,[hli]
+ ld [$ff8e],a ; save trainer number (within class)
+ push hl
+ ld hl,W_MAPSPRITEEXTRADATA
+ add hl,bc
+ ld a,[$ff8d]
+ ld [hli],a ; store trainer class in byte 0 of the entry
+ ld a,[$ff8e]
+ ld [hl],a ; store trainer number in byte 1 of the entry
+ pop hl
+ ret
+
+.itemBallSprite
+ ld a,[hli]
+ ld [$ff8d],a ; save item number
+ push hl
+ ld hl,W_MAPSPRITEEXTRADATA
+ add hl,bc
+ ld a,[$ff8d]
+ ld [hli],a ; store item number in byte 0 of the entry
+ xor a
+ ld [hl],a ; zero byte 1, since it is not used
+ pop hl
+ ret ; end of home/overworld.asm = 10b9 (0:10b9)
\ No newline at end of file |
