ref: 053afc46349952688c0ce2116cc76f8d4733895e
parent: 6ef36800b0dcb86100a7c716172015667e60dc99
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Fri Jul 3 18:57:43 EDT 2020
Move more code from home.asm to home/
--- a/data/moves/hm_moves.asm
+++ b/data/moves/hm_moves.asm
@@ -1,7 +1,10 @@
-HMMoveArray:
+; This file is INCLUDEd twice:
+; - for HMMoves in home/names.asm
+; - for HMMoveArray in engine/pokemon/bills_pc.asm
+
db CUT
db FLY
db SURF
db STRENGTH
db FLASH
- db -1
+ db -1 ; end
--- a/data/predef_pointers.asm
+++ b/data/predef_pointers.asm
@@ -1,3 +1,9 @@
+add_predef: MACRO
+\1Predef::
+ db BANK(\1)
+ dw \1
+ENDM
+
PredefPointers::
; these are pointers to ASM routines.
; they appear to be used in overworld map scripts.
--- /dev/null
+++ b/data/text_predef_pointers.asm
@@ -1,0 +1,71 @@
+add_tx_pre: MACRO
+\1_id:: dw \1
+ENDM
+
+TextPredefs::
+ add_tx_pre CardKeySuccessText ; 01
+ add_tx_pre CardKeyFailText ; 02
+ add_tx_pre RedBedroomPCText ; 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 XXX unused
+ add_tx_pre UnusedBenchGuyText2 ; 1C XXX unused
+ add_tx_pre UnusedBenchGuyText3 ; 1D XXX unused
+ add_tx_pre UnusedPredefText ; 1E XXX unused
+ add_tx_pre PokemonCenterPCText ; 1F
+ add_tx_pre ViridianSchoolNotebook ; 20
+ add_tx_pre ViridianSchoolBlackboard ; 21
+ add_tx_pre JustAMomentText ; 22
+ add_tx_pre OpenBillsPCText ; 23
+ add_tx_pre FoundHiddenItemText ; 24
+ add_tx_pre HiddenItemBagFullText ; 25 XXX unused
+ 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 EnemiesOnEverySideText ; 37
+ add_tx_pre WhatGoesAroundComesAroundText ; 38
+ add_tx_pre NewBicycleText ; 39
+ add_tx_pre IndigoPlateauStatues ; 3A
+ add_tx_pre VermilionGymTrashSuccessText1 ; 3B
+ add_tx_pre VermilionGymTrashSuccessText2 ; 3C XXX unused
+ add_tx_pre VermilionGymTrashSuccessText3 ; 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
--- a/engine/pokemon/bills_pc.asm
+++ b/engine/pokemon/bills_pc.asm
@@ -376,6 +376,7 @@
and a
ret
+HMMoveArray:
INCLUDE "data/moves/hm_moves.asm"
DisplayDepositWithdrawMenu:
--- a/home.asm
+++ b/home.asm
@@ -72,748 +72,9 @@
ld [MBC1RomBank], a
ret
-
-DrawHPBar::
-; Draw an HP bar d tiles long, and fill it to e pixels.
-; If c is nonzero, show at least a sliver regardless.
-; The right end of the bar changes with [wHPBarType].
-
- push hl
- push de
- push bc
-
- ; Left
- ld a, $71 ; "HP:"
- ld [hli], a
- ld a, $62
- ld [hli], a
-
- push hl
-
- ; Middle
- ld a, $63 ; empty
-.draw
- ld [hli], a
- dec d
- jr nz, .draw
-
- ; Right
- ld a, [wHPBarType]
- dec a
- ld a, $6d ; status screen and battle
- jr z, .ok
- dec a ; pokemon menu
-.ok
- ld [hl], a
-
- pop hl
-
- ld a, e
- and a
- jr nz, .fill
-
- ; If c is nonzero, draw a pixel anyway.
- ld a, c
- and a
- jr z, .done
- ld e, 1
-
-.fill
- ld a, e
- sub 8
- jr c, .partial
- ld e, a
- ld a, $6b ; full
- ld [hli], a
- ld a, e
- and a
- jr z, .done
- jr .fill
-
-.partial
- ; Fill remaining pixels at the end if necessary.
- ld a, $63 ; empty
- add e
- ld [hl], a
-.done
- pop bc
- pop de
- pop hl
- ret
-
-
-; loads pokemon data from one of multiple sources to wLoadedMon
-; loads base stats to wMonHeader
-; INPUT:
-; [wWhichPokemon] = index of pokemon within party/box
-; [wMonDataLocation] = source
-; 00: player's party
-; 01: enemy's party
-; 02: current box
-; 03: daycare
-; OUTPUT:
-; [wcf91] = pokemon ID
-; wLoadedMon = base address of pokemon data
-; wMonHeader = base address of base stats
-LoadMonData::
- jpab LoadMonData_
-
-OverwritewMoves::
-; Write c to [wMoves + b]. Unused.
- ld hl, wMoves
- ld e, b
- ld d, 0
- add hl, de
- ld a, c
- ld [hl], a
- ret
-
-LoadFlippedFrontSpriteByMonIndex::
- ld a, 1
- ld [wSpriteFlipped], a
-
-LoadFrontSpriteByMonIndex::
- push hl
- ld a, [wd11e]
- push af
- ld a, [wcf91]
- ld [wd11e], a
- predef IndexToPokedex
- ld hl, wd11e
- ld a, [hl]
- pop bc
- ld [hl], b
- and a
- pop hl
- jr z, .invalidDexNumber ; dex #0 invalid
- cp NUM_POKEMON + 1
- jr c, .validDexNumber ; dex >#151 invalid
-.invalidDexNumber
- ld a, RHYDON ; $1
- ld [wcf91], a
- ret
-.validDexNumber
- push hl
- ld de, vFrontPic
- call LoadMonFrontSprite
- pop hl
- ld a, [hLoadedROMBank]
- push af
- ld a, BANK(CopyUncompressedPicToHL)
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- xor a
- ld [hStartTileID], a
- call CopyUncompressedPicToHL
- xor a
- ld [wSpriteFlipped], a
- pop af
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ret
-
-
-PlayCry::
-; Play monster a's cry.
- call GetCryData
- call PlaySound
- jp WaitForSoundToFinish
-
-GetCryData::
-; Load cry data for monster a.
- dec a
- ld c, a
- ld b, 0
- ld hl, CryData
- add hl, bc
- add hl, bc
- add hl, bc
-
- ld a, BANK(CryData)
- call BankswitchHome
- ld a, [hli]
- ld b, a ; cry id
- ld a, [hli]
- ld [wFrequencyModifier], a
- ld a, [hl]
- ld [wTempoModifier], a
- call BankswitchBack
-
- ; Cry headers have 3 channels,
- ; and start from index CRY_SFX_START,
- ; so add 3 times the cry id.
- ld a, b
- ld c, CRY_SFX_START
- rlca ; * 2
- add b
- add c
- ret
-
-DisplayPartyMenu::
- ld a, [hTilesetType]
- push af
- xor a
- ld [hTilesetType], a
- call GBPalWhiteOutWithDelay3
- call ClearSprites
- call PartyMenuInit
- call DrawPartyMenu
- jp HandlePartyMenuInput
-
-GoBackToPartyMenu::
- ld a, [hTilesetType]
- push af
- xor a
- ld [hTilesetType], a
- call PartyMenuInit
- call RedrawPartyMenu
- jp HandlePartyMenuInput
-
-PartyMenuInit::
- ld a, 1 ; hardcoded bank
- call BankswitchHome
- call LoadHpBarAndStatusTilePatterns
- ld hl, wd730
- set 6, [hl] ; turn off letter printing delay
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
- ld [wMenuWatchMovingOutOfBounds], a
- ld hl, wTopMenuItemY
- inc a
- ld [hli], a ; top menu item Y
- xor a
- ld [hli], a ; top menu item X
- ld a, [wPartyAndBillsPCSavedMenuItem]
- push af
- ld [hli], a ; current menu item ID
- inc hl
- ld a, [wPartyCount]
- and a ; are there more than 0 pokemon in the party?
- jr z, .storeMaxMenuItemID
- dec a
-; if party is not empty, the max menu item ID is ([wPartyCount] - 1)
-; otherwise, it is 0
-.storeMaxMenuItemID
- ld [hli], a ; max menu item ID
- ld a, [wForcePlayerToChooseMon]
- and a
- ld a, A_BUTTON | B_BUTTON
- jr z, .next
- xor a
- ld [wForcePlayerToChooseMon], a
- inc a ; a = A_BUTTON
-.next
- ld [hli], a ; menu watched keys
- pop af
- ld [hl], a ; old menu item ID
- ret
-
-HandlePartyMenuInput::
- ld a, 1
- ld [wMenuWrappingEnabled], a
- ld a, $40
- ld [wPartyMenuAnimMonEnabled], a
- call HandleMenuInput_
- call PlaceUnfilledArrowMenuCursor
- ld b, a
- xor a
- ld [wPartyMenuAnimMonEnabled], a
- ld a, [wCurrentMenuItem]
- ld [wPartyAndBillsPCSavedMenuItem], 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 [wPartyMenuTypeOrMessageID], a
- call RedrawPartyMenu
- jr HandlePartyMenuInput
-.handleSwap
- ld a, [wCurrentMenuItem]
- ld [wWhichPokemon], a
- callba SwitchPartyMon
- jr HandlePartyMenuInput
-
-DrawPartyMenu::
- ld hl, DrawPartyMenu_
- jr DrawPartyMenuCommon
-
-RedrawPartyMenu::
- ld hl, RedrawPartyMenu_
-
-DrawPartyMenuCommon::
- ld b, BANK(RedrawPartyMenu_)
- jp Bankswitch
-
-; prints a pokemon's status condition
-; INPUT:
-; de = address of status condition
-; hl = destination address
-PrintStatusCondition::
- push de
- dec de
- dec de ; de = address of current HP
- ld a, [de]
- ld b, a
- dec de
- ld a, [de]
- or b ; is the pokemon's HP zero?
- pop de
- jr nz, PrintStatusConditionNotFainted
-; if the pokemon's HP is 0, print "FNT"
- ld a, "F"
- ld [hli], a
- ld a, "N"
- ld [hli], a
- ld [hl], "T"
- and a
- ret
-
-PrintStatusConditionNotFainted::
- ld a, [hLoadedROMBank]
- push af
- ld a, BANK(PrintStatusAilment)
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- call PrintStatusAilment ; print status condition
- pop bc
- ld a, b
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], 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::
- ld a, $6e ; ":L" tile ID
- ld [hli], a
- ld c, 2 ; number of digits
- ld a, [wLoadedMonLevel] ; level
- cp 100
- jr c, PrintLevelCommon
-; if level at least 100, write over the ":L" tile
- dec hl
- inc c ; increment number of digits to 3
- jr PrintLevelCommon
-
-; prints the level without leaving off ":L" regardless of level
-; INPUT:
-; hl = destination address
-; [wLoadedMonLevel] = level
-PrintLevelFull::
- ld a, $6e ; ":L" tile ID
- ld [hli], a
- ld c, 3 ; number of digits
- ld a, [wLoadedMonLevel] ; level
-
-PrintLevelCommon::
- ld [wd11e], a
- ld de, wd11e
- ld b, LEFT_ALIGN | 1 ; 1 byte
- jp PrintNumber
-
-GetwMoves::
-; Unused. Returns the move at index a from wMoves in a
- ld hl, wMoves
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hl]
- ret
-
-; copies the base stat data of a pokemon to wMonHeader
-; INPUT:
-; [wd0b5] = pokemon ID
-GetMonHeader::
- ld a, [hLoadedROMBank]
- push af
- ld a, BANK(BaseStats)
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], 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 FOSSIL_KABUTOPS ; Kabutops fossil
- jr z, .specialID
- ld de, GhostPic
- cp MON_GHOST ; Ghost
- jr z, .specialID
- ld de, FossilAerodactylPic
- ld b, $77 ; size of Aerodactyl fossil sprite
- cp FOSSIL_AERODACTYL ; Aerodactyl fossil
- jr z, .specialID
- cp MEW
- jr z, .mew
- predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number
- ld a, [wd11e]
- dec a
- ld bc, MonBaseStatsEnd - MonBaseStats
- ld hl, BaseStats
- call AddNTimes
- ld de, wMonHeader
- ld bc, MonBaseStatsEnd - MonBaseStats
- call CopyData
- jr .done
-.specialID
- ld hl, wMonHSpriteDim
- ld [hl], b ; write sprite dimensions
- inc hl
- ld [hl], e ; write front sprite pointer
- inc hl
- ld [hl], d
- jr .done
-.mew
- ld hl, MewBaseStats
- ld de, wMonHeader
- ld bc, MonBaseStatsEnd - MonBaseStats
- ld a, BANK(MewBaseStats)
- call FarCopyData
-.done
- ld a, [wd0b5]
- ld [wMonHIndex], a
- pop af
- ld [wd11e], a
- pop hl
- pop de
- pop bc
- pop af
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ret
-
-; copy party pokemon's name to wcd6d
-GetPartyMonName2::
- ld a, [wWhichPokemon] ; index within party
- ld hl, wPartyMonNicks
-
-; this is called more often
-GetPartyMonName::
- push hl
- push bc
- call SkipFixedLengthTextEntries ; add NAME_LENGTH to hl, a times
- ld de, wcd6d
- push de
- ld bc, NAME_LENGTH
- call CopyData
- pop de
- pop bc
- pop hl
- ret
-
-; function to print a BCD (Binary-coded decimal) number
-; de = address of BCD number
-; hl = destination address
-; c = flags and length
-; bit 7: if set, do not print leading zeroes
-; if unset, print leading zeroes
-; bit 6: if set, left-align the string (do not pad empty digits with spaces)
-; if unset, right-align the string
-; bit 5: if set, print currency symbol at the beginning of the string
-; if unset, do not print the currency symbol
-; bits 0-4: length of BCD number in bytes
-; Note that bits 5 and 7 are modified during execution. The above reflects
-; their meaning at the beginning of the functions's execution.
-PrintBCDNumber::
- ld b, c ; save flags in b
- res 7, c
- res 6, c
- res 5, c ; c now holds the length
- bit 5, b
- jr z, .loop
- bit 7, b
- jr nz, .loop
- ld [hl], "¥"
- inc hl
-.loop
- ld a, [de]
- swap a
- call PrintBCDDigit ; print upper digit
- ld a, [de]
- call PrintBCDDigit ; print lower digit
- inc de
- dec c
- jr nz, .loop
- bit 7, b ; were any non-zero digits printed?
- jr z, .done ; if so, we are done
-.numberEqualsZero ; if every digit of the BCD number is zero
- bit 6, b ; left or right alignment?
- jr nz, .skipRightAlignmentAdjustment
- dec hl ; if the string is right-aligned, it needs to be moved back one space
-.skipRightAlignmentAdjustment
- bit 5, b
- jr z, .skipCurrencySymbol
- ld [hl], "¥"
- inc hl
-.skipCurrencySymbol
- ld [hl], "0"
- call PrintLetterDelay
- inc hl
-.done
- ret
-
-PrintBCDDigit::
- and $f
- and a
- jr z, .zeroDigit
-.nonzeroDigit
- bit 7, b ; have any non-space characters been printed?
- jr z, .outputDigit
-; if bit 7 is set, then no numbers have been printed yet
- bit 5, b ; print the currency symbol?
- jr z, .skipCurrencySymbol
- ld [hl], "¥"
- inc hl
- res 5, b
-.skipCurrencySymbol
- res 7, b ; unset 7 to indicate that a nonzero digit has been reached
-.outputDigit
- add "0"
- ld [hli], a
- jp PrintLetterDelay
-.zeroDigit
- bit 7, b ; either printing leading zeroes or already reached a nonzero digit?
- jr z, .outputDigit ; if so, print a zero digit
- bit 6, b ; left or right alignment?
- ret nz
- inc hl ; if right-aligned, "print" a space by advancing the pointer
- ret
-
-; uncompresses the front or back sprite of the specified mon
-; assumes the corresponding mon header is already loaded
-; hl contains offset to sprite pointer ($b for front or $d for back)
-UncompressMonSprite::
- ld bc, wMonHeader
- add hl, bc
- ld a, [hli]
- ld [wSpriteInputPtr], a ; fetch sprite input pointer
- ld a, [hl]
- ld [wSpriteInputPtr+1], a
-; define (by index number) the bank that a pokemon's image is in
-; index = Mew, bank 1
-; index = Kabutops fossil, bank $B
-; index < $1F, bank 9
-; $1F ≤ index < $4A, bank $A
-; $4A ≤ index < $74, bank $B
-; $74 ≤ index < $99, bank $C
-; $99 ≤ index, bank $D
- ld a, [wcf91] ; XXX name for this ram location
- ld b, a
- cp MEW
- ld a, BANK(MewPicFront)
- jr z, .GotBank
- ld a, b
- cp FOSSIL_KABUTOPS
- ld a, BANK(FossilKabutopsPic)
- jr z, .GotBank
- ld a, b
- cp TANGELA + 1
- ld a, BANK(TangelaPicFront)
- jr c, .GotBank
- ld a, b
- cp MOLTRES + 1
- ld a, BANK(MoltresPicFront)
- jr c, .GotBank
- ld a, b
- cp BEEDRILL + 2
- ld a, BANK(BeedrillPicFront)
- jr c, .GotBank
- ld a, b
- cp STARMIE + 1
- ld a, BANK(StarmiePicFront)
- jr c, .GotBank
- ld a, BANK(VictreebelPicFront)
-.GotBank
- jp UncompressSpriteData
-
-; de: destination location
-LoadMonFrontSprite::
- push de
- ld hl, wMonHFrontSprite - wMonHeader
- call UncompressMonSprite
- ld hl, wMonHSpriteDim
- ld a, [hli]
- ld c, a
- pop de
- ; fall through
-
-; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram
-; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers
-; de: destination location
-; a,c: sprite dimensions (in tiles of 8x8 each)
-LoadUncompressedSpriteData::
- push de
- and $f
- ld [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
- ld b, a
- ld a, $7
- sub b ; 7-w
- inc a ; 8-w
- srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up)
- ld b, a
- add a
- add a
- add a
- sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles)
- ld [hSpriteOffset], a
- ld a, c
- swap a
- and $f
- ld b, a
- add a
- add a
- add a ; 8*tiles is height in bytes
- ld [hSpriteHeight], a
- ld a, $7
- sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
- ld b, a
- ld a, [hSpriteOffset]
- add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles)
- add a
- add a
- add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes)
- ld [hSpriteOffset], a
- xor a
- ld [$4000], a
- ld hl, sSpriteBuffer0
- call ZeroSpriteBuffer ; zero buffer 0
- ld de, sSpriteBuffer1
- ld hl, sSpriteBuffer0
- call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
- ld hl, sSpriteBuffer1
- call ZeroSpriteBuffer ; zero buffer 1
- ld de, sSpriteBuffer2
- ld hl, sSpriteBuffer1
- call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
- 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::
- ld a, [hSpriteOffset]
- ld b, $0
- ld c, a
- add hl, bc
- ld a, [hSpriteWidth]
-.columnLoop
- push af
- push hl
- ld a, [hSpriteHeight]
- ld c, a
-.columnInnerLoop
- ld a, [de]
- inc de
- ld [hli], a
- dec c
- jr nz, .columnInnerLoop
- pop hl
- ld bc, 7*8 ; 7 tiles
- add hl, bc ; advance one full column
- pop af
- dec a
- jr nz, .columnLoop
- ret
-
-; fills the sprite buffer (pointed to in hl) with zeros
-ZeroSpriteBuffer::
- ld bc, SPRITEBUFFERSIZE
-.nextByteLoop
- xor a
- ld [hli], a
- dec bc
- ld a, b
- or c
- jr nz, .nextByteLoop
- ret
-
-; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2
-; in the resulting sprite, the rows of the two source sprites are interlaced
-; de: output address
-InterlaceMergeSpriteBuffers::
- xor a
- ld [$4000], a
- push de
- ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
- ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
- ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
- ld a, SPRITEBUFFERSIZE/2 ; $c4
- ld [hSpriteInterlaceCounter], a
-.interlaceLoop
- ld a, [de]
- dec de
- ld [hld], a ; write byte of source 2
- ld a, [bc]
- dec bc
- ld [hld], a ; write byte of source 1
- ld a, [de]
- dec de
- ld [hld], a ; write byte of source 2
- ld a, [bc]
- dec bc
- ld [hld], a ; write byte of source 1
- ld a, [hSpriteInterlaceCounter]
- dec a
- ld [hSpriteInterlaceCounter], a
- jr nz, .interlaceLoop
- ld a, [wSpriteFlipped]
- and a
- jr z, .notFlipped
- ld bc, 2*SPRITEBUFFERSIZE
- ld hl, sSpriteBuffer1
-.swapLoop
- swap [hl] ; if flipped swap nybbles in all bytes
- inc hl
- dec bc
- ld a, b
- or c
- jr nz, .swapLoop
-.notFlipped
- pop hl
- ld de, sSpriteBuffer1
- ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
- ld a, [hLoadedROMBank]
- ld b, a
- jp CopyVideoData
-
-
+INCLUDE "home/pokemon.asm"
+INCLUDE "home/print_bcd.asm"
+INCLUDE "home/uncompress.asm"
INCLUDE "data/tilesets/collision_tile_ids.asm"
INCLUDE "home/copy2.asm"
INCLUDE "home/text.asm"
@@ -825,7 +86,6 @@
INCLUDE "home/timer.asm"
INCLUDE "home/audio.asm"
-
UpdateSprites::
ld a, [wUpdateSpritesEnabled]
dec a
@@ -842,42 +102,9 @@
ret
INCLUDE "data/items/marts.asm"
-
-TextScriptEndingChar::
- db "@"
-TextScriptEnd::
- ld hl, TextScriptEndingChar
- ret
-
-ExclamationText::
- TX_FAR _ExclamationText
- db "@"
-
-GroundRoseText::
- TX_FAR _GroundRoseText
- db "@"
-
-BoulderText::
- TX_FAR _BoulderText
- db "@"
-
-MartSignText::
- TX_FAR _MartSignText
- db "@"
-
-PokeCenterSignText::
- TX_FAR _PokeCenterSignText
- db "@"
-
-PickUpItemText::
- TX_ASM
- predef PickUpItem
- jp TextScriptEnd
-
-
+INCLUDE "home/overworld_text.asm"
INCLUDE "home/pic.asm"
-
ResetPlayerSpriteData::
ld hl, wSpriteStateData1
call ResetPlayerSpriteData_ClearSpriteData
@@ -948,244 +175,7 @@
ld [wNewSoundID], a
jp PlaySound
-; this function is used to display sign messages, sprite dialog, etc.
-; INPUT: [hSpriteIndexOrTextID] = sprite ID or text ID
-DisplayTextID::
- ld a, [hLoadedROMBank]
- push af
- callba DisplayTextIDInit ; initialization
- ld hl, wTextPredefFlag
- bit 0, [hl]
- res 0, [hl]
- jr nz, .skipSwitchToMapBank
- ld a, [wCurMap]
- call SwitchToMapRomBank
-.skipSwitchToMapBank
- ld a, 30 ; half a second
- ld [hFrameCounter], a ; used as joypad poll timer
- ld hl, wMapTextPtr
- ld a, [hli]
- ld h, [hl]
- ld l, a ; hl = map text pointer
- ld d, $00
- ld a, [hSpriteIndexOrTextID] ; text ID
- ld [wSpriteIndex], a
- and a
- jp z, DisplayStartMenu
- cp TEXT_SAFARI_GAME_OVER
- jp z, DisplaySafariGameOverText
- cp TEXT_MON_FAINTED
- jp z, DisplayPokemonFaintedText
- cp TEXT_BLACKED_OUT
- jp z, DisplayPlayerBlackedOutText
- cp TEXT_REPEL_WORE_OFF
- jp z, DisplayRepelWoreOffText
- ld a, [wNumSprites]
- ld e, a
- ld a, [hSpriteIndexOrTextID] ; sprite ID
- cp e
- jr z, .spriteHandling
- jr nc, .skipSpriteHandling
-.spriteHandling
-; get the text ID of the sprite
- push hl
- push de
- push bc
- callba UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction)
- pop bc
- pop de
- ld hl, wMapSpriteData ; NPC text entries
- ld a, [hSpriteIndexOrTextID]
- 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 $fe ; Pokemart NPC
- jp z, DisplayPokemartDialogue
- cp $ff ; Pokemon Center NPC
- jp z, DisplayPokemonCenterDialogue
- cp $fc ; Item Storage PC
- jp z, FuncTX_ItemStoragePC
- cp $fd ; Bill's PC
- jp z, FuncTX_BillsPC
- cp $f9 ; Pokemon Center PC
- jp z, FuncTX_PokemonCenterPC
- cp $f5 ; Vending Machine
- jr nz, .notVendingMachine
- callba VendingMachineMenu ; jump banks to vending machine routine
- jr AfterDisplayingTextID
-.notVendingMachine
- cp $f7 ; prize menu
- jp z, FuncTX_GameCornerPrizeMenu
- cp $f6 ; cable connection NPC in Pokemon Center
- jr nz, .notSpecialCase
- callab CableClubNPC
- jr AfterDisplayingTextID
-.notSpecialCase
- call PrintText_NoCreatingTextBox ; display the text
- ld a, [wDoNotWaitForButtonPressAfterDisplayingText]
- and a
- jr nz, HoldTextDisplayOpen
-
-AfterDisplayingTextID::
- ld a, [wEnteringCableClub]
- and a
- jr nz, HoldTextDisplayOpen
- call WaitForTextScrollButtonPress ; wait for a button press after displaying all the text
-
-; loop to hold the dialogue box open as long as the player keeps holding down the A button
-HoldTextDisplayOpen::
- call Joypad
- ld a, [hJoyHeld]
- bit 0, a ; is the A button being pressed?
- jr nz, HoldTextDisplayOpen
-
-CloseTextDisplay::
- ld a, [wCurMap]
- call SwitchToMapRomBank
- ld a, $90
- ld [hWY], a ; move the window off the screen
- call DelayFrame
- call LoadGBPal
- xor a
- ld [hAutoBGTransferEnabled], a ; disable continuous WRAM to VRAM transfer each V-blank
-; loop to make sprites face the directions they originally faced before the dialogue
- ld hl, 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 [hLoadedROMBank], a
- ld [MBC1RomBank], 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 [hLoadedROMBank], a
- ld [MBC1RomBank], a
- jp UpdateSprites
-
-DisplayPokemartDialogue::
- push hl
- ld hl, PokemartGreetingText
- call PrintText
- pop hl
- inc hl
- call LoadItemList
- ld a, PRICEDITEMLISTMENU
- ld [wListMenuID], a
- ld a, [hLoadedROMBank]
- push af
- ld a, BANK(DisplayPokemartDialogue_)
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- call DisplayPokemartDialogue_
- pop af
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- jp AfterDisplayingTextID
-
-PokemartGreetingText::
- TX_FAR _PokemartGreetingText
- db "@"
-
-LoadItemList::
- ld a, 1
- ld [wUpdateSpritesEnabled], a
- ld a, h
- ld [wItemListPointer], a
- ld a, l
- ld [wItemListPointer + 1], a
- ld de, wItemList
-.loop
- ld a, [hli]
- ld [de], a
- inc de
- cp $ff
- jr nz, .loop
- ret
-
-DisplayPokemonCenterDialogue::
-; zeroing these doesn't appear to serve any purpose
- xor a
- ld [hItemPrice], a
- ld [hItemPrice + 1], a
- ld [hItemPrice + 2], a
-
- inc hl
- ld a, [hLoadedROMBank]
- push af
- ld a, BANK(DisplayPokemonCenterDialogue_)
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- call DisplayPokemonCenterDialogue_
- pop af
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- jp AfterDisplayingTextID
-
-DisplaySafariGameOverText::
- callab PrintSafariGameOverText
- jp AfterDisplayingTextID
-
-DisplayPokemonFaintedText::
- ld hl, PokemonFaintedText
- call PrintText
- jp AfterDisplayingTextID
-
-PokemonFaintedText::
- TX_FAR _PokemonFaintedText
- db "@"
-
-DisplayPlayerBlackedOutText::
- ld hl, PlayerBlackedOutText
- call PrintText
- ld a, [wd732]
- res 5, a ; reset forced to use bike bit
- ld [wd732], a
- jp HoldTextDisplayOpen
-
-PlayerBlackedOutText::
- TX_FAR _PlayerBlackedOutText
- db "@"
-
-DisplayRepelWoreOffText::
- ld hl, RepelWoreOffText
- call PrintText
- jp AfterDisplayingTextID
-
-RepelWoreOffText::
- TX_FAR _RepelWoreOffText
- db "@"
-
+INCLUDE "home/predef_text.asm"
INCLUDE "home/start_menu.asm"
; function to count how many bits are set in a string of bytes
@@ -1269,676 +259,9 @@
pop bc
ret
-; INPUT:
-; [wListMenuID] = list menu ID
-; [wListPointer] = address of the list (2 bytes)
-DisplayListMenuID::
- xor a
- ld [hAutoBGTransferEnabled], a ; disable auto-transfer
- ld a, 1
- ld [hJoy7], a ; joypad state update flag
- ld a, [wBattleType]
- and a ; is it the Old Man battle?
- jr nz, .specialBattleType
- ld a, $01 ; hardcoded bank
- jr .bankswitch
-.specialBattleType ; Old Man battle
- ld a, BANK(DisplayBattleMenu)
-.bankswitch
- call BankswitchHome
- ld hl, wd730
- set 6, [hl] ; turn off letter printing delay
- xor a
- ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
- ld [wListCount], a
- ld a, [wListPointer]
- ld l, a
- ld a, [wListPointer + 1]
- ld h, a ; hl = address of the list
- ld a, [hl] ; the first byte is the number of entries in the list
- ld [wListCount], a
- ld a, LIST_MENU_BOX
- ld [wTextBoxID], a
- call DisplayTextBoxID ; draw the menu text box
- call UpdateSprites ; disable sprites behind the text box
-; the code up to .skipMovingSprites appears to be useless
- coord hl, 4, 2 ; coordinates of upper left corner of menu text box
- lb de, 9, 14 ; height and width of menu text box
- ld a, [wListMenuID]
- and a ; is it a PC pokemon list?
- jr nz, .skipMovingSprites
- call UpdateSprites
-.skipMovingSprites
- ld a, 1 ; max menu item ID is 1 if the list has less than 2 entries
- ld [wMenuWatchMovingOutOfBounds], a
- ld a, [wListCount]
- cp 2 ; does the list have less than 2 entries?
- jr c, .setMenuVariables
- ld a, 2 ; max menu item ID is 2 if the list has at least 2 entries
-.setMenuVariables
- ld [wMaxMenuItem], a
- ld a, 4
- ld [wTopMenuItemY], a
- ld a, 5
- ld [wTopMenuItemX], a
- ld a, A_BUTTON | B_BUTTON | SELECT
- ld [wMenuWatchedKeys], a
- ld c, 10
- call DelayFrames
+INCLUDE "home/list_menu.asm"
+INCLUDE "home/names.asm"
-DisplayListMenuIDLoop::
- xor a
- ld [hAutoBGTransferEnabled], a ; disable transfer
- call PrintListMenuEntries
- ld a, 1
- ld [hAutoBGTransferEnabled], a ; enable transfer
- call Delay3
- ld a, [wBattleType]
- 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
- coord hl, 5, 4
- ld a, l
- ld [wMenuCursorLocation], a
- ld a, h
- ld [wMenuCursorLocation + 1], a
- jr .buttonAPressed
-.notOldManBattle
- call LoadGBPal
- call HandleMenuInput
- push af
- call PlaceMenuCursor
- pop af
- bit 0, a ; was the A button pressed?
- jp z, .checkOtherKeys
-.buttonAPressed
- ld a, [wCurrentMenuItem]
- call PlaceUnfilledArrowMenuCursor
-
-; pointless because both values are overwritten before they are read
- ld a, $01
- ld [wMenuExitMethod], a
- ld [wChosenMenuItem], a
-
- xor a
- ld [wMenuWatchMovingOutOfBounds], a
- ld a, [wCurrentMenuItem]
- ld c, a
- ld a, [wListScrollOffset]
- add c
- ld c, a
- ld a, [wListCount]
- and a ; is the list empty?
- jp z, ExitListMenu ; if so, exit the menu
- dec a
- cp c ; did the player select Cancel?
- jp c, ExitListMenu ; if so, exit the menu
- ld a, c
- ld [wWhichPokemon], a
- ld a, [wListMenuID]
- cp ITEMLISTMENU
- jr nz, .skipMultiplying
-; if it's an item menu
- sla c ; item entries are 2 bytes long, so multiply by 2
-.skipMultiplying
- ld a, [wListPointer]
- ld l, a
- ld a, [wListPointer + 1]
- ld h, a
- inc hl ; hl = beginning of list entries
- ld b, 0
- add hl, bc
- ld a, [hl]
- ld [wcf91], a
- ld a, [wListMenuID]
- and a ; is it a PC pokemon list?
- jr z, .pokemonList
- push hl
- call GetItemPrice
- pop hl
- ld a, [wListMenuID]
- cp ITEMLISTMENU
- jr nz, .skipGettingQuantity
-; if it's an item menu
- inc hl
- ld a, [hl] ; a = item quantity
- ld [wMaxItemQuantity], a
-.skipGettingQuantity
- ld a, [wcf91]
- ld [wd0b5], a
- ld a, BANK(ItemNames)
- ld [wPredefBank], a
- call GetName
- jr .storeChosenEntry
-.pokemonList
- ld hl, wPartyCount
- ld a, [wListPointer]
- cp l ; is it a list of party pokemon or box pokemon?
- ld hl, wPartyMonNicks
- jr z, .getPokemonName
- ld hl, wBoxMonNicks ; box pokemon names
-.getPokemonName
- ld a, [wWhichPokemon]
- call GetPartyMonName
-.storeChosenEntry ; store the menu entry that the player chose and return
- ld de, wcd6d
- call CopyStringToCF4B ; copy name to wcf4b
- ld a, CHOSE_MENU_ITEM
- ld [wMenuExitMethod], a
- ld a, [wCurrentMenuItem]
- ld [wChosenMenuItem], a
- xor a
- 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 3
- ld b, a
- ld a, [wListCount]
- cp b ; will going down scroll past the Cancel button?
- jp c, DisplayListMenuIDLoop
- inc [hl] ; if not, go down
- jp DisplayListMenuIDLoop
-.upPressed
- ld a, [hl]
- and a
- jp z, DisplayListMenuIDLoop
- dec [hl]
- jp DisplayListMenuIDLoop
-
-DisplayChooseQuantityMenu::
-; text box dimensions/coordinates for just quantity
- coord hl, 15, 9
- ld b, 1 ; height
- ld c, 3 ; width
- ld a, [wListMenuID]
- cp PRICEDITEMLISTMENU
- jr nz, .drawTextBox
-; text box dimensions/coordinates for quantity and price
- coord hl, 7, 9
- ld b, 1 ; height
- ld c, 11 ; width
-.drawTextBox
- call TextBoxBorder
- coord hl, 16, 10
- ld a, [wListMenuID]
- cp PRICEDITEMLISTMENU
- jr nz, .printInitialQuantity
- coord hl, 8, 10
-.printInitialQuantity
- ld de, InitialQuantityText
- call PlaceString
- xor a
- ld [wItemQuantity], 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, [wMaxItemQuantity]
- inc a
- ld b, a
- ld hl, wItemQuantity ; current quantity
- inc [hl]
- ld a, [hl]
- cp b
- jr nz, .handleNewQuantity
-; wrap to 1 if the player goes above the max quantity
- ld a, 1
- ld [hl], a
- jr .handleNewQuantity
-.decrementQuantity
- ld hl, wItemQuantity ; current quantity
- dec [hl]
- jr nz, .handleNewQuantity
-; wrap to the max quantity if the player goes below 1
- ld a, [wMaxItemQuantity]
- ld [hl], a
-.handleNewQuantity
- coord hl, 17, 10
- ld a, [wListMenuID]
- cp PRICEDITEMLISTMENU
- jr nz, .printQuantity
-.printPrice
- ld c, $03
- ld a, [wItemQuantity]
- ld b, a
- ld hl, hMoney ; total price
-; initialize total price to 0
- xor a
- ld [hli], a
- ld [hli], a
- ld [hl], a
-.addLoop ; loop to multiply the individual price by the quantity to get the total price
- ld de, hMoney + 2
- ld hl, hItemPrice + 2
- push bc
- predef AddBCDPredef ; add the individual price to the current sum
- pop bc
- dec b
- jr nz, .addLoop
- ld a, [hHalveItemPrices]
- and a ; should the price be halved (for selling items)?
- jr z, .skipHalvingPrice
- xor a
- ld [hDivideBCDDivisor], a
- ld [hDivideBCDDivisor + 1], a
- ld a, $02
- ld [hDivideBCDDivisor + 2], a
- predef DivideBCDPredef3 ; halves the price
-; store the halved price
- ld a, [hDivideBCDQuotient]
- ld [hMoney], a
- ld a, [hDivideBCDQuotient + 1]
- ld [hMoney + 1], a
- ld a, [hDivideBCDQuotient + 2]
- ld [hMoney + 2], a
-.skipHalvingPrice
- coord hl, 12, 10
- ld de, SpacesBetweenQuantityAndPriceText
- call PlaceString
- ld de, hMoney ; total price
- ld c, $a3
- call PrintBCDNumber
- coord hl, 9, 10
-.printQuantity
- ld de, wItemQuantity ; current quantity
- lb bc, LEADING_ZEROES | 1, 2 ; 1 byte, 2 digits
- call PrintNumber
- jp .waitForKeyPressLoop
-.buttonAPressed ; the player chose to make the transaction
- xor a
- ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
- ret
-.buttonBPressed ; the player chose to cancel the transaction
- xor a
- ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
- ld a, $ff
- ret
-
-InitialQuantityText::
- db "×01@"
-
-SpacesBetweenQuantityAndPriceText::
- db " @"
-
-ExitListMenu::
- ld a, [wCurrentMenuItem]
- ld [wChosenMenuItem], a
- ld a, CANCELLED_MENU
- ld [wMenuExitMethod], a
- ld [wMenuWatchMovingOutOfBounds], a
- xor a
- 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::
- coord hl, 5, 3
- ld b, 9
- ld c, 14
- call ClearScreenArea
- ld a, [wListPointer]
- ld e, a
- ld a, [wListPointer + 1]
- ld d, a
- inc de ; de = beginning of list entries
- ld a, [wListScrollOffset]
- ld c, a
- ld a, [wListMenuID]
- cp ITEMLISTMENU
- ld a, c
- jr nz, .skipMultiplying
-; if it's an item menu
-; item entries are 2 bytes long, so multiply by 2
- sla a
- sla c
-.skipMultiplying
- add e
- ld e, a
- jr nc, .noCarry
- inc d
-.noCarry
- coord hl, 6, 4 ; coordinates of first list entry name
- ld b, 4 ; print 4 names
-.loop
- ld a, b
- ld [wWhichPokemon], a
- ld a, [de]
- ld [wd11e], a
- cp $ff
- jp z, .printCancelMenuItem
- push bc
- push de
- push hl
- push hl
- push de
- ld a, [wListMenuID]
- and a
- jr z, .pokemonPCMenu
- cp MOVESLISTMENU
- jr z, .movesMenu
-.itemMenu
- call GetItemName
- jr .placeNameString
-.pokemonPCMenu
- push hl
- ld hl, wPartyCount
- ld a, [wListPointer]
- cp l ; is it a list of party pokemon or box pokemon?
- ld hl, wPartyMonNicks
- jr z, .getPokemonName
- ld hl, wBoxMonNicks ; box pokemon names
-.getPokemonName
- ld a, [wWhichPokemon]
- ld b, a
- ld a, 4
- sub b
- ld b, a
- ld a, [wListScrollOffset]
- add b
- call GetPartyMonName
- pop hl
- jr .placeNameString
-.movesMenu
- call GetMoveName
-.placeNameString
- call PlaceString
- pop de
- pop hl
- ld a, [wPrintItemPrices]
- and a ; should prices be printed?
- jr z, .skipPrintingItemPrice
-.printItemPrice
- push hl
- ld a, [de]
- ld de, ItemPrices
- ld [wcf91], a
- call GetItemPrice ; get price
- pop hl
- ld bc, SCREEN_WIDTH + 5 ; 1 row down and 5 columns right
- add hl, bc
- ld c, $a3 ; no leading zeroes, right-aligned, print currency symbol, 3 bytes
- call PrintBCDNumber
-.skipPrintingItemPrice
- ld a, [wListMenuID]
- and a
- jr nz, .skipPrintingPokemonLevel
-.printPokemonLevel
- ld a, [wd11e]
- push af
- push hl
- ld hl, wPartyCount
- ld a, [wListPointer]
- cp l ; is it a list of party pokemon or box pokemon?
- ld a, PLAYER_PARTY_DATA
- jr z, .next
- ld a, BOX_DATA
-.next
- ld [wMonDataLocation], a
- ld hl, wWhichPokemon
- ld a, [hl]
- ld b, a
- ld a, $04
- sub b
- ld b, a
- ld a, [wListScrollOffset]
- add b
- ld [hl], a
- call LoadMonData
- ld a, [wMonDataLocation]
- and a ; is it a list of party pokemon or box pokemon?
- jr z, .skipCopyingLevel
-.copyLevel
- ld a, [wLoadedMonBoxLevel]
- ld [wLoadedMonLevel], a
-.skipCopyingLevel
- pop hl
- ld bc, $001c
- add hl, bc
- call PrintLevel
- pop af
- ld [wd11e], a
-.skipPrintingPokemonLevel
- pop hl
- pop de
- inc de
- ld a, [wListMenuID]
- cp ITEMLISTMENU
- jr nz, .nextListEntry
-.printItemQuantity
- ld a, [wd11e]
- ld [wcf91], a
- call IsKeyItem ; check if item is unsellable
- ld a, [wIsKeyItem]
- and a ; is the item unsellable?
- jr nz, .skipPrintingItemQuantity ; if so, don't print the quantity
- push hl
- ld bc, SCREEN_WIDTH + 8 ; 1 row down and 8 columns right
- add hl, bc
- ld a, "×"
- ld [hli], a
- ld a, [wd11e]
- push af
- ld a, [de]
- ld [wMaxItemQuantity], a
- push de
- ld de, wd11e
- ld [de], a
- lb bc, 1, 2
- call PrintNumber
- pop de
- pop af
- ld [wd11e], a
- pop hl
-.skipPrintingItemQuantity
- inc de
- pop bc
- inc c
- push bc
- inc c
- ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
- and a ; is an item being swapped?
- jr z, .nextListEntry
- 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 * SCREEN_WIDTH ; 2 rows
- add hl, bc
- pop bc
- inc c
- dec b
- jp nz, .loop
- ld bc, -8
- add hl, bc
- ld a, "▼"
- ld [hl], a
- ret
-.printCancelMenuItem
- ld de, ListMenuCancelText
- jp PlaceString
-
-ListMenuCancelText::
- db "CANCEL@"
-
-GetMonName::
- push hl
- ld a, [hLoadedROMBank]
- push af
- ld a, BANK(MonsterNames)
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ld a, [wd11e]
- dec a
- ld hl, MonsterNames
- ld c, 10
- ld b, 0
- call AddNTimes
- ld de, wcd6d
- push de
- ld bc, 10
- call CopyData
- ld hl, wcd6d + 10
- ld [hl], "@"
- pop de
- pop af
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- pop hl
- ret
-
-GetItemName::
-; given an item ID at [wd11e], store the name of the item into a string
-; starting at wcd6d
- push hl
- push bc
- ld a, [wd11e]
- cp 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::
-; 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, "0"
-.FirstDigit
- sub 10
- jr c, .SecondDigit
- inc b
- jr .FirstDigit
-.SecondDigit
- add 10
- push af
- ld a, b
- ld [de], a
- inc de
- pop af
- ld b, "0"
- add b
- ld [de], a
- inc de
- ld a, "@"
- ld [de], a
- pop af
- ld [wd11e], a
- pop bc
- pop de
- pop hl
- ret
-
-TechnicalPrefix::
- db "TM"
-HiddenPrefix::
- db "HM"
-
-; sets carry if item is HM, clears carry if item is not HM
-; Input: a = item ID
-IsItemHM::
- cp HM_01
- jr c, .notHM
- cp 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::
- ld hl, HMMoves
- ld de, 1
- jp IsInArray
-
-HMMoves::
- db CUT,FLY,SURF,STRENGTH,FLASH
- db $ff ; terminator
-
-GetMoveName::
- push hl
- ld a, MOVE_NAME
- ld [wNameListType], a
- ld a, [wd11e]
- ld [wd0b5], a
- ld a, BANK(MoveNames)
- ld [wPredefBank], a
- call GetName
- ld de, wcd6d ; pointer to where move name is stored in RAM
- pop hl
- ret
-
; reloads text box tile patterns, current map view, and tileset tile patterns
ReloadMapData::
ld a, [hLoadedROMBank]
@@ -2103,443 +426,8 @@
EmptyFunc2::
ret
-; stores hl in [wTrainerHeaderPtr]
-StoreTrainerHeaderPointer::
- ld a, h
- ld [wTrainerHeaderPtr], a
- ld a, l
- ld [wTrainerHeaderPtr+1], a
- ret
+INCLUDE "home/trainers.asm"
-; 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::
- push af
- push de
- call StoreTrainerHeaderPointer
- pop hl
- pop af
- push hl
- ld hl, wFlags_D733
- bit 4, [hl]
- res 4, [hl]
- jr z, .useProvidedIndex ; test if map script index was overridden manually
- ld a, [wCurMapScript]
-.useProvidedIndex
- pop hl
- ld [wCurMapScript], a
- call CallFunctionInTable
- ld a, [wCurMapScript]
- ret
-
-LoadGymLeaderAndCityName::
- push de
- ld de, wGymCityName
- ld bc, $11
- call CopyData ; load city name
- pop hl
- ld de, wGymLeaderName
- ld bc, NAME_LENGTH
- jp CopyData ; load gym leader name
-
-; reads specific information from trainer header (pointed to at wTrainerHeaderPtr)
-; a: offset in header data
-; 0 -> flag's bit (into wTrainerHeaderFlagBit)
-; 2 -> flag's byte ptr (into hl)
-; 4 -> before battle text (into hl)
-; 6 -> after battle text (into hl)
-; 8 -> end battle text (into hl)
-ReadTrainerHeaderInfo::
- push de
- push af
- ld d, $0
- ld e, a
- ld hl, wTrainerHeaderPtr
- ld a, [hli]
- ld l, [hl]
- ld h, a
- add hl, de
- pop af
- and a
- jr nz, .nonZeroOffset
- ld a, [hl]
- ld [wTrainerHeaderFlagBit], a ; store flag's bit
- jr .done
-.nonZeroOffset
- cp $2
- jr z, .readPointer ; read flag's byte ptr
- cp $4
- jr z, .readPointer ; read before battle text
- cp $6
- jr z, .readPointer ; read after battle text
- cp $8
- jr z, .readPointer ; read end battle text
- cp $a
- jr nz, .done
- ld a, [hli] ; read end battle text (2) but override the result afterwards (XXX why, bug?)
- ld d, [hl]
- ld e, a
- jr .done
-.readPointer
- ld a, [hli]
- ld h, [hl]
- ld l, a
-.done
- pop de
- ret
-
-TrainerFlagAction::
- predef_jump FlagActionPredef
-
-TalkToTrainer::
- call StoreTrainerHeaderPointer
- xor a
- call ReadTrainerHeaderInfo ; read flag's bit
- ld a, $2
- call ReadTrainerHeaderInfo ; read flag's byte ptr
- ld a, [wTrainerHeaderFlagBit]
- ld c, a
- ld b, FLAG_TEST
- call TrainerFlagAction ; read trainer's flag
- ld a, c
- and a
- jr z, .trainerNotYetFought ; test trainer's flag
- ld a, $6
- call ReadTrainerHeaderInfo ; print after battle text
- jp PrintText
-.trainerNotYetFought
- ld a, $4
- call ReadTrainerHeaderInfo ; print before battle text
- call PrintText
- ld a, $a
- call ReadTrainerHeaderInfo ; (?) does nothing apparently (maybe bug in ReadTrainerHeaderInfo)
- push de
- ld a, $8
- call ReadTrainerHeaderInfo ; read end battle text
- pop de
- call SaveEndBattleTextPointers
- ld hl, wFlags_D733
- set 4, [hl] ; activate map script index override (index is set below)
- ld hl, wFlags_0xcd60
- bit 0, [hl] ; test if player is already engaging the trainer (because the trainer saw the player)
- ret nz
-; if the player talked to the trainer of his own volition
- call EngageMapTrainer
- ld hl, wCurMapScript
- inc [hl] ; increment map script index before StartTrainerBattle increments it again (next script function is usually EndTrainerBattle)
- jp StartTrainerBattle
-
-; checks if any trainers are seeing the player and wanting to fight
-CheckFightingMapTrainers::
- call CheckForEngagingTrainers
- ld a, [wSpriteIndex]
- cp $ff
- jr nz, .trainerEngaging
- xor a
- ld [wSpriteIndex], a
- ld [wTrainerHeaderFlagBit], a
- ret
-.trainerEngaging
- ld hl, wFlags_D733
- set 3, [hl]
- ld [wEmotionBubbleSpriteIndex], a
- xor a ; EXCLAMATION_BUBBLE
- ld [wWhichEmotionBubble], a
- predef EmotionBubble
- ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
- ld [wJoyIgnore], a
- xor a
- ld [hJoyHeld], a
- call TrainerWalkUpToPlayer_Bank0
- ld hl, wCurMapScript
- inc [hl] ; increment map script index (next script function is usually DisplayEnemyTrainerTextAndStartBattle)
- ret
-
-; display the before battle text after the enemy trainer has walked up to the player's sprite
-DisplayEnemyTrainerTextAndStartBattle::
- ld a, [wd730]
- and $1
- ret nz ; return if the enemy trainer hasn't finished walking to the player's sprite
- ld [wJoyIgnore], a
- ld a, [wSpriteIndex]
- ld [hSpriteIndexOrTextID], a
- call DisplayTextID
- ; fall through
-
-StartTrainerBattle::
- xor a
- ld [wJoyIgnore], a
- call InitBattleEnemyParameters
- ld hl, wd72d
- set 6, [hl]
- set 7, [hl]
- ld hl, wd72e
- set 1, [hl]
- ld hl, wCurMapScript
- inc [hl] ; increment map script index (next script function is usually EndTrainerBattle)
- ret
-
-EndTrainerBattle::
- ld hl, wCurrentMapScriptFlags
- set 5, [hl]
- set 6, [hl]
- ld hl, wd72d
- res 7, [hl]
- ld hl, wFlags_0xcd60
- res 0, [hl] ; player is no longer engaged by any trainer
- ld a, [wIsInBattle]
- cp $ff
- jp z, ResetButtonPressedAndMapScript
- ld a, $2
- call ReadTrainerHeaderInfo
- ld a, [wTrainerHeaderFlagBit]
- ld c, a
- ld b, FLAG_SET
- call TrainerFlagAction ; flag trainer as fought
- ld a, [wEnemyMonOrTrainerClass]
- cp OPP_ID_OFFSET
- jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite)
- ld hl, wMissableObjectList
- ld de, $2
- ld a, [wSpriteIndex]
- call IsInArray ; search for sprite ID
- inc hl
- ld a, [hl]
- ld [wMissableObjectIndex], a ; load corresponding missable object index and remove it
- predef HideObject
-.skipRemoveSprite
- ld hl, wd730
- bit 4, [hl]
- res 4, [hl]
- ret nz
-
-ResetButtonPressedAndMapScript::
- xor a
- ld [wJoyIgnore], a
- ld [hJoyHeld], a
- ld [hJoyPressed], a
- ld [hJoyReleased], a
- ld [wCurMapScript], a ; reset battle status
- ret
-
-; calls TrainerWalkUpToPlayer
-TrainerWalkUpToPlayer_Bank0::
- jpba TrainerWalkUpToPlayer
-
-; sets opponent type and mon set/lvl based on the engaging trainer data
-InitBattleEnemyParameters::
- ld a, [wEngagedTrainerClass]
- ld [wCurOpponent], a
- ld [wEnemyMonOrTrainerClass], a
- cp OPP_ID_OFFSET
- ld a, [wEngagedTrainerSet]
- jr c, .noTrainer
- ld [wTrainerNo], a
- ret
-.noTrainer
- ld [wCurEnemyLVL], a
- ret
-
-GetSpritePosition1::
- ld hl, _GetSpritePosition1
- jr SpritePositionBankswitch
-
-GetSpritePosition2::
- ld hl, _GetSpritePosition2
- jr SpritePositionBankswitch
-
-SetSpritePosition1::
- ld hl, _SetSpritePosition1
- jr SpritePositionBankswitch
-
-SetSpritePosition2::
- ld hl, _SetSpritePosition2
-SpritePositionBankswitch::
- ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2)
- jp Bankswitch ; indirect jump to one of the four functions
-
-CheckForEngagingTrainers::
- xor a
- call ReadTrainerHeaderInfo ; read trainer flag's bit (unused)
- ld d, h ; store trainer header address in de
- ld e, l
-.trainerLoop
- call StoreTrainerHeaderPointer ; set trainer header pointer to current trainer
- ld a, [de]
- ld [wSpriteIndex], a ; store trainer flag's bit
- ld [wTrainerHeaderFlagBit], a
- cp $ff
- ret z
- ld a, $2
- call ReadTrainerHeaderInfo ; read trainer flag's byte ptr
- ld b, FLAG_TEST
- ld a, [wTrainerHeaderFlagBit]
- ld c, a
- call TrainerFlagAction ; read trainer flag
- ld a, c
- and a ; has the trainer already been defeated?
- jr nz, .continue
- push hl
- push de
- push hl
- xor a
- call ReadTrainerHeaderInfo ; get trainer header pointer
- inc hl
- ld a, [hl] ; read trainer engage distance
- pop hl
- ld [wTrainerEngageDistance], a
- ld a, [wSpriteIndex]
- swap a
- ld [wTrainerSpriteOffset], a
- predef TrainerEngage
- pop de
- pop hl
- ld a, [wTrainerSpriteOffset]
- and a
- ret nz ; break if the trainer is engaging
-.continue
- ld hl, $c
- add hl, de
- ld d, h
- ld e, l
- jr .trainerLoop
-
-; hl = text if the player wins
-; de = text if the player loses
-SaveEndBattleTextPointers::
- ld a, [hLoadedROMBank]
- ld [wEndBattleTextRomBank], a
- ld a, h
- ld [wEndBattleWinTextPointer], a
- ld a, l
- ld [wEndBattleWinTextPointer + 1], a
- ld a, d
- ld [wEndBattleLoseTextPointer], a
- ld a, e
- ld [wEndBattleLoseTextPointer + 1], a
- ret
-
-; loads data of some trainer on the current map and plays pre-battle music
-; [wSpriteIndex]: sprite ID of trainer who is engaged
-EngageMapTrainer::
- ld hl, wMapSpriteExtraData
- ld d, $0
- ld a, [wSpriteIndex]
- dec a
- add a
- ld e, a
- add hl, de ; seek to engaged trainer data
- ld a, [hli] ; load trainer class
- ld [wEngagedTrainerClass], a
- ld a, [hl] ; load trainer mon set
- ld [wEngagedTrainerSet], a
- jp PlayTrainerMusic
-
-PrintEndBattleText::
- push hl
- ld hl, wd72d
- bit 7, [hl]
- res 7, [hl]
- pop hl
- ret z
- ld a, [hLoadedROMBank]
- push af
- ld a, [wEndBattleTextRomBank]
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- push hl
- callba SaveTrainerName
- ld hl, TrainerEndBattleText
- call PrintText
- pop hl
- pop af
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- callba FreezeEnemyTrainerSprite
- jp WaitForSoundToFinish
-
-GetSavedEndBattleTextPointer::
- ld a, [wBattleResult]
- and a
-; won battle
- jr nz, .lostBattle
- ld a, [wEndBattleWinTextPointer]
- ld h, a
- ld a, [wEndBattleWinTextPointer + 1]
- ld l, a
- ret
-.lostBattle
- ld a, [wEndBattleLoseTextPointer]
- ld h, a
- ld a, [wEndBattleLoseTextPointer + 1]
- ld l, a
- ret
-
-TrainerEndBattleText::
- TX_FAR _TrainerNameText
- TX_ASM
- call GetSavedEndBattleTextPointer
- call TextCommandProcessor
- jp TextScriptEnd
-
-; only engage withe trainer if the player is not already
-; engaged with another trainer
-; XXX unused?
-CheckIfAlreadyEngaged::
- ld a, [wFlags_0xcd60]
- bit 0, a
- ret nz
- call EngageMapTrainer
- xor a
- ret
-
-PlayTrainerMusic::
- ld a, [wEngagedTrainerClass]
- cp OPP_SONY1
- ret z
- cp OPP_SONY2
- ret z
- cp OPP_SONY3
- ret z
- ld a, [wGymLeaderNo]
- and a
- ret nz
- xor a
- ld [wAudioFadeOutControl], a
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
- ld a, BANK(Music_MeetEvilTrainer)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
- ld a, [wEngagedTrainerClass]
- ld b, a
- ld hl, EvilTrainerList
-.evilTrainerListLoop
- ld a, [hli]
- cp $ff
- jr z, .noEvilTrainer
- cp b
- jr nz, .evilTrainerListLoop
- ld a, MUSIC_MEET_EVIL_TRAINER
- jr .PlaySound
-.noEvilTrainer
- ld hl, FemaleTrainerList
-.femaleTrainerListLoop
- ld a, [hli]
- cp $ff
- jr z, .maleTrainer
- cp b
- jr nz, .femaleTrainerListLoop
- ld a, MUSIC_MEET_FEMALE_TRAINER
- jr .PlaySound
-.maleTrainer
- ld a, MUSIC_MEET_MALE_TRAINER
-.PlaySound
- ld [wNewSoundID], a
- jp PlaySound
-
-INCLUDE "data/trainers/encounter_types.asm"
-
; checks if the player's coordinates match an arrow movement tile's coordinates
; and if so, decodes the RLE movement data
; b = player Y
@@ -2841,84 +729,9 @@
ld c, 2
jp StringCmp
+INCLUDE "home/bankswitch.asm"
+INCLUDE "home/yes_no.asm"
-BankswitchHome::
-; switches to bank # in a
-; Only use this when in the home bank!
- ld [wBankswitchHomeTemp], a
- ld a, [hLoadedROMBank]
- ld [wBankswitchHomeSavedROMBank], a
- ld a, [wBankswitchHomeTemp]
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ret
-
-BankswitchBack::
-; returns from BankswitchHome
- ld a, [wBankswitchHomeSavedROMBank]
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ret
-
-Bankswitch::
-; self-contained bankswitch, use this when not in the home bank
-; switches to the bank in b
- ld a, [hLoadedROMBank]
- push af
- ld a, b
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ld bc, .Return
- push bc
- jp hl
-.Return
- pop bc
- ld a, b
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ret
-
-; displays yes/no choice
-; yes -> set carry
-YesNoChoice::
- call SaveScreenTilesToBuffer1
- call InitYesNoTextBoxParameters
- jr DisplayYesNoChoice
-
-Func_35f4::
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call InitYesNoTextBoxParameters
- jp DisplayTextBoxID
-
-InitYesNoTextBoxParameters::
- xor a ; YES_NO_MENU
- ld [wTwoOptionMenuID], a
- coord hl, 14, 7
- ld bc, $80f
- ret
-
-YesNoChoicePokeCenter::
- call SaveScreenTilesToBuffer1
- ld a, HEAL_CANCEL_MENU
- ld [wTwoOptionMenuID], a
- coord hl, 11, 6
- lb bc, 8, 12
- jr DisplayYesNoChoice
-
-WideYesNoChoice:: ; unused
- call SaveScreenTilesToBuffer1
- ld a, WIDE_YES_NO_MENU
- ld [wTwoOptionMenuID], a
- coord hl, 12, 7
- lb bc, 8, 13
-
-DisplayYesNoChoice::
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID
- jp LoadScreenTilesFromBuffer1
-
; calculates the difference |a-b|, setting carry flag if a<b
CalcDifference::
sub b
@@ -2985,7 +798,6 @@
pop hl
ret
-
LoadFontTilePatterns::
ld a, [rLCDC]
bit 7, a ; is the LCD enabled?
@@ -3034,7 +846,6 @@
lb bc, BANK(HpBarAndStatusGraphics), (HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics) / $10
jp CopyVideoData ; if LCD is on, transfer during V-blank
-
FillMemory::
; Fill bc bytes at hl with a.
push de
@@ -3049,7 +860,6 @@
pop de
ret
-
UncompressSpriteFromDE::
; Decompress pic at a:de.
ld hl, wSpriteInputPtr
@@ -3130,100 +940,8 @@
pop hl
ret
-NamePointers::
- dw MonsterNames
- dw MoveNames
- dw UnusedNames
- dw ItemNames
- dw wPartyMonOT ; player's OT names list
- dw wEnemyMonOT ; enemy's OT names list
- dw TrainerNames
+INCLUDE "home/names2.asm"
-GetName::
-; arguments:
-; [wd0b5] = which name
-; [wNameListType] = which list
-; [wPredefBank] = bank of list
-;
-; returns pointer to name in de
- ld a, [wd0b5]
- ld [wd11e], a
-
- ; TM names are separate from item names.
- ; BUG: This applies to all names instead of just items.
- cp HM_01
- jp nc, GetMachineName
-
- ld a, [hLoadedROMBank]
- push af
- push hl
- push bc
- push de
- ld a, [wNameListType] ;List3759_entrySelector
- dec a
- jr nz, .otherEntries
- ;1 = MON_NAMES
- call GetMonName
- ld hl, NAME_LENGTH
- add hl, de
- ld e, l
- ld d, h
- jr .gotPtr
-.otherEntries
- ;2-7 = OTHER ENTRIES
- ld a, [wPredefBank]
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ld a, [wNameListType] ;VariousNames' entryID
- dec a
- add a
- ld d, 0
- ld e, a
- jr nc, .skip
- inc d
-.skip
- ld hl, NamePointers
- add hl, de
- ld a, [hli]
- ld [hSwapTemp + 1], a
- ld a, [hl]
- ld [hSwapTemp], a
- ld a, [hSwapTemp]
- ld h, a
- ld a, [hSwapTemp + 1]
- ld l, a
- ld a, [wd0b5]
- ld b, a
- ld c, 0
-.nextName
- ld d, h
- ld e, l
-.nextChar
- ld a, [hli]
- cp "@"
- jr nz, .nextChar
- inc c ;entry counter
- ld a, b ;wanted entry
- cp c
- jr nz, .nextName
- ld h, d
- ld l, e
- ld de, wcd6d
- ld bc, $0014
- call CopyData
-.gotPtr
- ld a, e
- ld [wUnusedCF8D], a
- ld a, d
- ld [wUnusedCF8D + 1], a
- pop de
- pop bc
- pop hl
- pop af
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ret
-
GetItemPrice::
; Stores item's price as BCD at hItemPrice (3 bytes)
; Input: [wcf91] = item id
@@ -3482,249 +1200,8 @@
jr nz, CopyDataUntil
ret
-; Function to remove a pokemon from the party or the current box.
-; wWhichPokemon determines the pokemon.
-; [wRemoveMonFromBox] == 0 specifies the party.
-; [wRemoveMonFromBox] != 0 specifies the current box.
-RemovePokemon::
- jpab _RemovePokemon
+INCLUDE "home/move_mon.asm"
-AddPartyMon::
- 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::
- ld c, $0
-.statsLoop
- inc c
- call CalcStat
- ld a, [hMultiplicand+1]
- ld [de], a
- inc de
- ld a, [hMultiplicand+2]
- ld [de], a
- inc de
- ld a, c
- cp NUM_STATS
- jr nz, .statsLoop
- ret
-
-; calculates stat c of current mon
-; c: stat to calc (HP=1,Atk=2,Def=3,Spd=4,Spc=5)
-; b: consider stat exp?
-; hl: base ptr to stat exp values ([hl + 2*c - 1] and [hl + 2*c])
-CalcStat::
- push hl
- push de
- push bc
- ld a, b
- ld d, a
- push hl
- ld hl, wMonHeader
- ld b, $0
- add hl, bc
- ld a, [hl] ; read base value of stat
- ld e, a
- pop hl
- push hl
- sla c
- ld a, d
- and a
- jr z, .statExpDone ; consider stat exp?
- add hl, bc ; skip to corresponding stat exp value
-.statExpLoop ; calculates ceil(Sqrt(stat exp)) in b
- xor a
- ld [hMultiplicand], a
- ld [hMultiplicand+1], a
- inc b ; increment current stat exp bonus
- ld a, b
- cp $ff
- jr z, .statExpDone
- ld [hMultiplicand+2], a
- ld [hMultiplier], a
- call Multiply
- ld a, [hld]
- ld d, a
- ld a, [hProduct + 3]
- sub d
- ld a, [hli]
- ld d, a
- ld a, [hProduct + 2]
- sbc d ; test if (current stat exp bonus)^2 < stat exp
- jr c, .statExpLoop
-.statExpDone
- srl c
- pop hl
- push bc
- ld bc, wPartyMon1DVs - (wPartyMon1HPExp - 1) ; also wEnemyMonDVs - wEnemyMonHP
- add hl, bc
- pop bc
- ld a, c
- cp $2
- jr z, .getAttackIV
- cp $3
- jr z, .getDefenseIV
- cp $4
- jr z, .getSpeedIV
- cp $5
- jr z, .getSpecialIV
-.getHpIV
- push bc
- ld a, [hl] ; Atk IV
- swap a
- and $1
- sla a
- sla a
- sla a
- ld b, a
- ld a, [hli] ; Def IV
- and $1
- sla a
- sla a
- add b
- ld b, a
- ld a, [hl] ; Spd IV
- swap a
- and $1
- sla a
- add b
- ld b, a
- ld a, [hl] ; Spc IV
- and $1
- add b ; HP IV: LSB of the other 4 IVs
- pop bc
- jr .calcStatFromIV
-.getAttackIV
- ld a, [hl]
- swap a
- and $f
- jr .calcStatFromIV
-.getDefenseIV
- ld a, [hl]
- and $f
- jr .calcStatFromIV
-.getSpeedIV
- inc hl
- ld a, [hl]
- swap a
- and $f
- jr .calcStatFromIV
-.getSpecialIV
- inc hl
- ld a, [hl]
- and $f
-.calcStatFromIV
- ld d, $0
- add e
- ld e, a
- jr nc, .noCarry
- inc d ; de = Base + IV
-.noCarry
- sla e
- rl d ; de = (Base + IV) * 2
- srl b
- srl b ; b = ceil(Sqrt(stat exp)) / 4
- ld a, b
- add e
- jr nc, .noCarry2
- inc d ; de = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4
-.noCarry2
- ld [hMultiplicand+2], a
- ld a, d
- ld [hMultiplicand+1], a
- xor a
- ld [hMultiplicand], a
- ld a, [wCurEnemyLVL]
- ld [hMultiplier], a
- call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level
- ld a, [hMultiplicand]
- ld [hDividend], a
- ld a, [hMultiplicand+1]
- ld [hDividend+1], a
- ld a, [hMultiplicand+2]
- ld [hDividend+2], a
- ld a, $64
- ld [hDivisor], a
- ld a, $3
- ld b, a
- call Divide ; (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100
- ld a, c
- cp $1
- ld a, 5 ; + 5 for non-HP stat
- jr nz, .notHPStat
- ld a, [wCurEnemyLVL]
- ld b, a
- ld a, [hMultiplicand+2]
- add b
- ld [hMultiplicand+2], a
- jr nc, .noCarry3
- ld a, [hMultiplicand+1]
- inc a
- ld [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level
-.noCarry3
- ld a, 10 ; +10 for HP stat
-.notHPStat
- ld b, a
- ld a, [hMultiplicand+2]
- add b
- ld [hMultiplicand+2], a
- jr nc, .noCarry4
- ld a, [hMultiplicand+1]
- inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5
- ld [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10
-.noCarry4
- ld a, [hMultiplicand+1] ; check for overflow (>999)
- cp 999 / $100 + 1
- jr nc, .overflow
- cp 999 / $100
- jr c, .noOverflow
- ld a, [hMultiplicand+2]
- cp 999 % $100 + 1
- jr c, .noOverflow
-.overflow
- ld a, 999 / $100 ; overflow: cap at 999
- ld [hMultiplicand+1], a
- ld a, 999 % $100
- ld [hMultiplicand+2], a
-.noOverflow
- pop bc
- pop de
- pop hl
- ret
-
-AddEnemyMonToPlayerParty::
- ld a, [hLoadedROMBank]
- push af
- ld a, BANK(_AddEnemyMonToPlayerParty)
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- call _AddEnemyMonToPlayerParty
- pop bc
- ld a, b
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ret
-
-MoveMon::
- ld a, [hLoadedROMBank]
- push af
- ld a, BANK(_MoveMon)
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- call _MoveMon
- pop bc
- ld a, b
- ld [hLoadedROMBank], a
- ld [MBC1RomBank], a
- ret
-
; skips a text entries, each of size NAME_LENGTH (like trainer name, OT name, rival name, ...)
; hl: base pointer, will be incremented by NAME_LENGTH * a
SkipFixedLengthTextEntries::
@@ -4091,226 +1568,8 @@
coord bc, 1, 14
jp TextCommandProcessor
+INCLUDE "home/print_num.asm"
-PrintNumber::
-; Print the c-digit, b-byte value at de.
-; Allows 2 to 7 digits. For 1-digit numbers, add
-; the value to char "0" instead of calling PrintNumber.
-; Flags LEADING_ZEROES and LEFT_ALIGN can be given
-; in bits 7 and 6 of b respectively.
- push bc
- xor a
- ld [hPastLeadingZeros], a
- ld [hNumToPrint], a
- ld [hNumToPrint + 1], a
- ld a, b
- and $f
- cp 1
- jr z, .byte
- cp 2
- jr z, .word
-.long
- ld a, [de]
- ld [hNumToPrint], a
- inc de
- ld a, [de]
- ld [hNumToPrint + 1], a
- inc de
- ld a, [de]
- ld [hNumToPrint + 2], a
- jr .start
-
-.word
- ld a, [de]
- ld [hNumToPrint + 1], a
- inc de
- ld a, [de]
- ld [hNumToPrint + 2], a
- jr .start
-
-.byte
- ld a, [de]
- ld [hNumToPrint + 2], a
-
-.start
- push de
-
- ld d, b
- ld a, c
- ld b, a
- xor a
- ld c, a
- ld a, b
-
- cp 2
- jr z, .tens
- cp 3
- jr z, .hundreds
- cp 4
- jr z, .thousands
- cp 5
- jr z, .ten_thousands
- cp 6
- jr z, .hundred_thousands
-
-print_digit: macro
-
-if (\1) / $10000
- ld a, \1 / $10000 % $100
-else xor a
-endc
- ld [hPowerOf10 + 0], a
-
-if (\1) / $100
- ld a, \1 / $100 % $100
-else xor a
-endc
- ld [hPowerOf10 + 1], a
-
- ld a, \1 / $1 % $100
- ld [hPowerOf10 + 2], a
-
- call .PrintDigit
- call .NextDigit
-endm
-
-.millions print_digit 1000000
-.hundred_thousands print_digit 100000
-.ten_thousands print_digit 10000
-.thousands print_digit 1000
-.hundreds print_digit 100
-
-.tens
- ld c, 0
- ld a, [hNumToPrint + 2]
-.mod
- cp 10
- jr c, .ok
- sub 10
- inc c
- jr .mod
-.ok
-
- ld b, a
- ld a, [hPastLeadingZeros]
- or c
- ld [hPastLeadingZeros], a
- jr nz, .past
- call .PrintLeadingZero
- jr .next
-.past
- ld a, "0"
- add c
- ld [hl], a
-.next
-
- call .NextDigit
-.ones
- ld a, "0"
- add b
- ld [hli], a
- pop de
- dec de
- pop bc
- ret
-
-.PrintDigit:
-; Divide by the current decimal place.
-; Print the quotient, and keep the modulus.
- ld c, 0
-.loop
- ld a, [hPowerOf10]
- ld b, a
- ld a, [hNumToPrint]
- ld [hSavedNumToPrint], a
- cp b
- jr c, .underflow0
- sub b
- ld [hNumToPrint], a
- ld a, [hPowerOf10 + 1]
- ld b, a
- ld a, [hNumToPrint + 1]
- ld [hSavedNumToPrint + 1], a
- cp b
- jr nc, .noborrow1
-
- ld a, [hNumToPrint]
- or 0
- jr z, .underflow1
- dec a
- ld [hNumToPrint], a
- ld a, [hNumToPrint + 1]
-.noborrow1
-
- sub b
- ld [hNumToPrint + 1], a
- ld a, [hPowerOf10 + 2]
- ld b, a
- ld a, [hNumToPrint + 2]
- ld [hSavedNumToPrint + 2], a
- cp b
- jr nc, .noborrow2
-
- ld a, [hNumToPrint + 1]
- and a
- jr nz, .borrowed
-
- ld a, [hNumToPrint]
- and a
- jr z, .underflow2
- dec a
- ld [hNumToPrint], a
- xor a
-.borrowed
-
- dec a
- ld [hNumToPrint + 1], a
- ld a, [hNumToPrint + 2]
-.noborrow2
- sub b
- ld [hNumToPrint + 2], a
- inc c
- jr .loop
-
-.underflow2
- ld a, [hSavedNumToPrint + 1]
- ld [hNumToPrint + 1], a
-.underflow1
- ld a, [hSavedNumToPrint]
- ld [hNumToPrint], a
-.underflow0
- ld a, [hPastLeadingZeros]
- or c
- jr z, .PrintLeadingZero
-
- ld a, "0"
- add c
- ld [hl], a
- ld [hPastLeadingZeros], a
- ret
-
-.PrintLeadingZero:
- bit BIT_LEADING_ZEROES, d
- ret z
- ld [hl], "0"
- ret
-
-.NextDigit:
-; Increment unless the number is left-aligned,
-; leading zeroes are not printed, and no digits
-; have been printed yet.
- bit BIT_LEADING_ZEROES, d
- jr nz, .inc
- bit BIT_LEFT_ALIGN, d
- jr z, .inc
- ld a, [hPastLeadingZeros]
- and a
- ret z
-.inc
- inc hl
- ret
-
-
CallFunctionInTable::
; Call function a in jumptable hl.
; de is not preserved.
@@ -4333,7 +1592,6 @@
pop hl
ret
-
IsInArray::
; Search an array at hl for the value in a.
; Entry size is de bytes.
@@ -4360,7 +1618,6 @@
scf
ret
-
RestoreScreenTilesAndReloadTilePatterns::
call ClearSprites
ld a, $1
@@ -4371,7 +1628,6 @@
call RunDefaultPaletteCommand
jr Delay3
-
GBPalWhiteOutWithDelay3::
call GBPalWhiteOut
@@ -4397,7 +1653,6 @@
ld [rOBP1], a
ret
-
RunDefaultPaletteCommand::
ld b, $ff
RunPaletteCommand::
@@ -4441,7 +1696,6 @@
call LoadFontTilePatterns
jp UpdateSprites
-
GiveItem::
; Give player quantity c of item b,
; and copy the item's name to wcf4b.
@@ -4469,7 +1723,6 @@
ld [wMonDataLocation], a
jpba _GivePokemon
-
Random::
; Return a random number in a.
; For battles, use BattleRandom.
@@ -4483,10 +1736,8 @@
pop hl
ret
-
INCLUDE "home/predef.asm"
-
UpdateCinnabarGymGateTileBlocks::
jpba UpdateCinnabarGymGateTileBlocks_
@@ -4554,72 +1805,4 @@
ld [wMapTextPtr + 1], a
ret
-TextPredefs::
-const_value = 1
-
- add_tx_pre CardKeySuccessText ; 01
- add_tx_pre CardKeyFailText ; 02
- add_tx_pre RedBedroomPCText ; 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 XXX unused
- add_tx_pre UnusedBenchGuyText2 ; 1C XXX unused
- add_tx_pre UnusedBenchGuyText3 ; 1D XXX unused
- add_tx_pre UnusedPredefText ; 1E XXX unused
- add_tx_pre PokemonCenterPCText ; 1F
- add_tx_pre ViridianSchoolNotebook ; 20
- add_tx_pre ViridianSchoolBlackboard ; 21
- add_tx_pre JustAMomentText ; 22
- add_tx_pre OpenBillsPCText ; 23
- add_tx_pre FoundHiddenItemText ; 24
- add_tx_pre HiddenItemBagFullText ; 25 XXX unused
- 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 EnemiesOnEverySideText ; 37
- add_tx_pre WhatGoesAroundComesAroundText ; 38
- add_tx_pre NewBicycleText ; 39
- add_tx_pre IndigoPlateauStatues ; 3A
- add_tx_pre VermilionGymTrashSuccessText1 ; 3B
- add_tx_pre VermilionGymTrashSuccessText2 ; 3C XXX unused
- add_tx_pre VermilionGymTrashSuccessText3 ; 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
+INCLUDE "data/text_predef_pointers.asm"
--- /dev/null
+++ b/home/bankswitch.asm
@@ -1,0 +1,35 @@
+BankswitchHome::
+; switches to bank # in a
+; Only use this when in the home bank!
+ ld [wBankswitchHomeTemp], a
+ ld a, [hLoadedROMBank]
+ ld [wBankswitchHomeSavedROMBank], a
+ ld a, [wBankswitchHomeTemp]
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
+
+BankswitchBack::
+; returns from BankswitchHome
+ ld a, [wBankswitchHomeSavedROMBank]
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
+
+Bankswitch::
+; self-contained bankswitch, use this when not in the home bank
+; switches to the bank in b
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, b
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ld bc, .Return
+ push bc
+ jp hl
+.Return
+ pop bc
+ ld a, b
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
--- /dev/null
+++ b/home/list_menu.asm
@@ -1,0 +1,526 @@
+; INPUT:
+; [wListMenuID] = list menu ID
+; [wListPointer] = address of the list (2 bytes)
+DisplayListMenuID::
+ xor a
+ ld [hAutoBGTransferEnabled], a ; disable auto-transfer
+ ld a, 1
+ ld [hJoy7], a ; joypad state update flag
+ ld a, [wBattleType]
+ and a ; is it the Old Man battle?
+ jr nz, .specialBattleType
+ ld a, $01 ; hardcoded bank
+ jr .bankswitch
+.specialBattleType ; Old Man battle
+ ld a, BANK(DisplayBattleMenu)
+.bankswitch
+ call BankswitchHome
+ ld hl, wd730
+ set 6, [hl] ; turn off letter printing delay
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ ld [wListCount], a
+ ld a, [wListPointer]
+ ld l, a
+ ld a, [wListPointer + 1]
+ ld h, a ; hl = address of the list
+ ld a, [hl] ; the first byte is the number of entries in the list
+ ld [wListCount], a
+ ld a, LIST_MENU_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; draw the menu text box
+ call UpdateSprites ; disable sprites behind the text box
+; the code up to .skipMovingSprites appears to be useless
+ coord hl, 4, 2 ; coordinates of upper left corner of menu text box
+ lb de, 9, 14 ; height and width of menu text box
+ ld a, [wListMenuID]
+ and a ; is it a PC pokemon list?
+ jr nz, .skipMovingSprites
+ call UpdateSprites
+.skipMovingSprites
+ ld a, 1 ; max menu item ID is 1 if the list has less than 2 entries
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld a, [wListCount]
+ cp 2 ; does the list have less than 2 entries?
+ jr c, .setMenuVariables
+ ld a, 2 ; max menu item ID is 2 if the list has at least 2 entries
+.setMenuVariables
+ ld [wMaxMenuItem], a
+ ld a, 4
+ ld [wTopMenuItemY], a
+ ld a, 5
+ ld [wTopMenuItemX], a
+ ld a, A_BUTTON | B_BUTTON | SELECT
+ ld [wMenuWatchedKeys], a
+ ld c, 10
+ call DelayFrames
+
+DisplayListMenuIDLoop::
+ xor a
+ ld [hAutoBGTransferEnabled], a ; disable transfer
+ call PrintListMenuEntries
+ ld a, 1
+ ld [hAutoBGTransferEnabled], a ; enable transfer
+ call Delay3
+ ld a, [wBattleType]
+ 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
+ coord hl, 5, 4
+ ld a, l
+ ld [wMenuCursorLocation], a
+ ld a, h
+ ld [wMenuCursorLocation + 1], a
+ jr .buttonAPressed
+.notOldManBattle
+ call LoadGBPal
+ call HandleMenuInput
+ push af
+ call PlaceMenuCursor
+ pop af
+ bit 0, a ; was the A button pressed?
+ jp z, .checkOtherKeys
+.buttonAPressed
+ ld a, [wCurrentMenuItem]
+ call PlaceUnfilledArrowMenuCursor
+
+; pointless because both values are overwritten before they are read
+ ld a, $01
+ ld [wMenuExitMethod], a
+ ld [wChosenMenuItem], a
+
+ xor a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld a, [wCurrentMenuItem]
+ ld c, a
+ ld a, [wListScrollOffset]
+ add c
+ ld c, a
+ ld a, [wListCount]
+ and a ; is the list empty?
+ jp z, ExitListMenu ; if so, exit the menu
+ dec a
+ cp c ; did the player select Cancel?
+ jp c, ExitListMenu ; if so, exit the menu
+ ld a, c
+ ld [wWhichPokemon], a
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ jr nz, .skipMultiplying
+; if it's an item menu
+ sla c ; item entries are 2 bytes long, so multiply by 2
+.skipMultiplying
+ ld a, [wListPointer]
+ ld l, a
+ ld a, [wListPointer + 1]
+ ld h, a
+ inc hl ; hl = beginning of list entries
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wcf91], a
+ ld a, [wListMenuID]
+ and a ; is it a PC pokemon list?
+ jr z, .pokemonList
+ push hl
+ call GetItemPrice
+ pop hl
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ jr nz, .skipGettingQuantity
+; if it's an item menu
+ inc hl
+ ld a, [hl] ; a = item quantity
+ ld [wMaxItemQuantity], a
+.skipGettingQuantity
+ ld a, [wcf91]
+ ld [wd0b5], a
+ ld a, BANK(ItemNames)
+ ld [wPredefBank], a
+ call GetName
+ jr .storeChosenEntry
+.pokemonList
+ ld hl, wPartyCount
+ ld a, [wListPointer]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld hl, wPartyMonNicks
+ jr z, .getPokemonName
+ ld hl, wBoxMonNicks ; box pokemon names
+.getPokemonName
+ ld a, [wWhichPokemon]
+ call GetPartyMonName
+.storeChosenEntry ; store the menu entry that the player chose and return
+ ld de, wcd6d
+ call CopyStringToCF4B ; copy name to wcf4b
+ ld a, CHOSE_MENU_ITEM
+ ld [wMenuExitMethod], a
+ ld a, [wCurrentMenuItem]
+ ld [wChosenMenuItem], a
+ xor a
+ 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 3
+ ld b, a
+ ld a, [wListCount]
+ cp b ; will going down scroll past the Cancel button?
+ jp c, DisplayListMenuIDLoop
+ inc [hl] ; if not, go down
+ jp DisplayListMenuIDLoop
+.upPressed
+ ld a, [hl]
+ and a
+ jp z, DisplayListMenuIDLoop
+ dec [hl]
+ jp DisplayListMenuIDLoop
+
+DisplayChooseQuantityMenu::
+; text box dimensions/coordinates for just quantity
+ coord hl, 15, 9
+ ld b, 1 ; height
+ ld c, 3 ; width
+ ld a, [wListMenuID]
+ cp PRICEDITEMLISTMENU
+ jr nz, .drawTextBox
+; text box dimensions/coordinates for quantity and price
+ coord hl, 7, 9
+ ld b, 1 ; height
+ ld c, 11 ; width
+.drawTextBox
+ call TextBoxBorder
+ coord hl, 16, 10
+ ld a, [wListMenuID]
+ cp PRICEDITEMLISTMENU
+ jr nz, .printInitialQuantity
+ coord hl, 8, 10
+.printInitialQuantity
+ ld de, InitialQuantityText
+ call PlaceString
+ xor a
+ ld [wItemQuantity], 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, [wMaxItemQuantity]
+ inc a
+ ld b, a
+ ld hl, wItemQuantity ; current quantity
+ inc [hl]
+ ld a, [hl]
+ cp b
+ jr nz, .handleNewQuantity
+; wrap to 1 if the player goes above the max quantity
+ ld a, 1
+ ld [hl], a
+ jr .handleNewQuantity
+.decrementQuantity
+ ld hl, wItemQuantity ; current quantity
+ dec [hl]
+ jr nz, .handleNewQuantity
+; wrap to the max quantity if the player goes below 1
+ ld a, [wMaxItemQuantity]
+ ld [hl], a
+.handleNewQuantity
+ coord hl, 17, 10
+ ld a, [wListMenuID]
+ cp PRICEDITEMLISTMENU
+ jr nz, .printQuantity
+.printPrice
+ ld c, $03
+ ld a, [wItemQuantity]
+ ld b, a
+ ld hl, hMoney ; total price
+; initialize total price to 0
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+.addLoop ; loop to multiply the individual price by the quantity to get the total price
+ ld de, hMoney + 2
+ ld hl, hItemPrice + 2
+ push bc
+ predef AddBCDPredef ; add the individual price to the current sum
+ pop bc
+ dec b
+ jr nz, .addLoop
+ ld a, [hHalveItemPrices]
+ and a ; should the price be halved (for selling items)?
+ jr z, .skipHalvingPrice
+ xor a
+ ld [hDivideBCDDivisor], a
+ ld [hDivideBCDDivisor + 1], a
+ ld a, $02
+ ld [hDivideBCDDivisor + 2], a
+ predef DivideBCDPredef3 ; halves the price
+; store the halved price
+ ld a, [hDivideBCDQuotient]
+ ld [hMoney], a
+ ld a, [hDivideBCDQuotient + 1]
+ ld [hMoney + 1], a
+ ld a, [hDivideBCDQuotient + 2]
+ ld [hMoney + 2], a
+.skipHalvingPrice
+ coord hl, 12, 10
+ ld de, SpacesBetweenQuantityAndPriceText
+ call PlaceString
+ ld de, hMoney ; total price
+ ld c, $a3
+ call PrintBCDNumber
+ coord hl, 9, 10
+.printQuantity
+ ld de, wItemQuantity ; current quantity
+ lb bc, LEADING_ZEROES | 1, 2 ; 1 byte, 2 digits
+ call PrintNumber
+ jp .waitForKeyPressLoop
+.buttonAPressed ; the player chose to make the transaction
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ ret
+.buttonBPressed ; the player chose to cancel the transaction
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ ld a, $ff
+ ret
+
+InitialQuantityText::
+ db "×01@"
+
+SpacesBetweenQuantityAndPriceText::
+ db " @"
+
+ExitListMenu::
+ ld a, [wCurrentMenuItem]
+ ld [wChosenMenuItem], a
+ ld a, CANCELLED_MENU
+ ld [wMenuExitMethod], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ xor a
+ 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::
+ coord hl, 5, 3
+ ld b, 9
+ ld c, 14
+ call ClearScreenArea
+ ld a, [wListPointer]
+ ld e, a
+ ld a, [wListPointer + 1]
+ ld d, a
+ inc de ; de = beginning of list entries
+ ld a, [wListScrollOffset]
+ ld c, a
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ ld a, c
+ jr nz, .skipMultiplying
+; if it's an item menu
+; item entries are 2 bytes long, so multiply by 2
+ sla a
+ sla c
+.skipMultiplying
+ add e
+ ld e, a
+ jr nc, .noCarry
+ inc d
+.noCarry
+ coord hl, 6, 4 ; coordinates of first list entry name
+ ld b, 4 ; print 4 names
+.loop
+ ld a, b
+ ld [wWhichPokemon], a
+ ld a, [de]
+ ld [wd11e], a
+ cp $ff
+ jp z, .printCancelMenuItem
+ push bc
+ push de
+ push hl
+ push hl
+ push de
+ ld a, [wListMenuID]
+ and a
+ jr z, .pokemonPCMenu
+ cp MOVESLISTMENU
+ jr z, .movesMenu
+.itemMenu
+ call GetItemName
+ jr .placeNameString
+.pokemonPCMenu
+ push hl
+ ld hl, wPartyCount
+ ld a, [wListPointer]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld hl, wPartyMonNicks
+ jr z, .getPokemonName
+ ld hl, wBoxMonNicks ; box pokemon names
+.getPokemonName
+ ld a, [wWhichPokemon]
+ ld b, a
+ ld a, 4
+ sub b
+ ld b, a
+ ld a, [wListScrollOffset]
+ add b
+ call GetPartyMonName
+ pop hl
+ jr .placeNameString
+.movesMenu
+ call GetMoveName
+.placeNameString
+ call PlaceString
+ pop de
+ pop hl
+ ld a, [wPrintItemPrices]
+ and a ; should prices be printed?
+ jr z, .skipPrintingItemPrice
+.printItemPrice
+ push hl
+ ld a, [de]
+ ld de, ItemPrices
+ ld [wcf91], a
+ call GetItemPrice ; get price
+ pop hl
+ ld bc, SCREEN_WIDTH + 5 ; 1 row down and 5 columns right
+ add hl, bc
+ ld c, $a3 ; no leading zeroes, right-aligned, print currency symbol, 3 bytes
+ call PrintBCDNumber
+.skipPrintingItemPrice
+ ld a, [wListMenuID]
+ and a
+ jr nz, .skipPrintingPokemonLevel
+.printPokemonLevel
+ ld a, [wd11e]
+ push af
+ push hl
+ ld hl, wPartyCount
+ ld a, [wListPointer]
+ cp l ; is it a list of party pokemon or box pokemon?
+ ld a, PLAYER_PARTY_DATA
+ jr z, .next
+ ld a, BOX_DATA
+.next
+ ld [wMonDataLocation], a
+ ld hl, wWhichPokemon
+ ld a, [hl]
+ ld b, a
+ ld a, $04
+ sub b
+ ld b, a
+ ld a, [wListScrollOffset]
+ add b
+ ld [hl], a
+ call LoadMonData
+ ld a, [wMonDataLocation]
+ and a ; is it a list of party pokemon or box pokemon?
+ jr z, .skipCopyingLevel
+.copyLevel
+ ld a, [wLoadedMonBoxLevel]
+ ld [wLoadedMonLevel], a
+.skipCopyingLevel
+ pop hl
+ ld bc, $001c
+ add hl, bc
+ call PrintLevel
+ pop af
+ ld [wd11e], a
+.skipPrintingPokemonLevel
+ pop hl
+ pop de
+ inc de
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ jr nz, .nextListEntry
+.printItemQuantity
+ ld a, [wd11e]
+ ld [wcf91], a
+ call IsKeyItem ; check if item is unsellable
+ ld a, [wIsKeyItem]
+ and a ; is the item unsellable?
+ jr nz, .skipPrintingItemQuantity ; if so, don't print the quantity
+ push hl
+ ld bc, SCREEN_WIDTH + 8 ; 1 row down and 8 columns right
+ add hl, bc
+ ld a, "×"
+ ld [hli], a
+ ld a, [wd11e]
+ push af
+ ld a, [de]
+ ld [wMaxItemQuantity], a
+ push de
+ ld de, wd11e
+ ld [de], a
+ lb bc, 1, 2
+ call PrintNumber
+ pop de
+ pop af
+ ld [wd11e], a
+ pop hl
+.skipPrintingItemQuantity
+ inc de
+ pop bc
+ inc c
+ push bc
+ inc c
+ ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
+ and a ; is an item being swapped?
+ jr z, .nextListEntry
+ 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 * SCREEN_WIDTH ; 2 rows
+ add hl, bc
+ pop bc
+ inc c
+ dec b
+ jp nz, .loop
+ ld bc, -8
+ add hl, bc
+ ld a, "▼"
+ ld [hl], a
+ ret
+.printCancelMenuItem
+ ld de, ListMenuCancelText
+ jp PlaceString
+
+ListMenuCancelText::
+ db "CANCEL@"
--- /dev/null
+++ b/home/move_mon.asm
@@ -1,0 +1,242 @@
+; Function to remove a pokemon from the party or the current box.
+; wWhichPokemon determines the pokemon.
+; [wRemoveMonFromBox] == 0 specifies the party.
+; [wRemoveMonFromBox] != 0 specifies the current box.
+RemovePokemon::
+ jpab _RemovePokemon
+
+AddPartyMon::
+ 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::
+ ld c, $0
+.statsLoop
+ inc c
+ call CalcStat
+ ld a, [hMultiplicand+1]
+ ld [de], a
+ inc de
+ ld a, [hMultiplicand+2]
+ ld [de], a
+ inc de
+ ld a, c
+ cp NUM_STATS
+ jr nz, .statsLoop
+ ret
+
+; calculates stat c of current mon
+; c: stat to calc (HP=1,Atk=2,Def=3,Spd=4,Spc=5)
+; b: consider stat exp?
+; hl: base ptr to stat exp values ([hl + 2*c - 1] and [hl + 2*c])
+CalcStat::
+ push hl
+ push de
+ push bc
+ ld a, b
+ ld d, a
+ push hl
+ ld hl, wMonHeader
+ ld b, $0
+ add hl, bc
+ ld a, [hl] ; read base value of stat
+ ld e, a
+ pop hl
+ push hl
+ sla c
+ ld a, d
+ and a
+ jr z, .statExpDone ; consider stat exp?
+ add hl, bc ; skip to corresponding stat exp value
+.statExpLoop ; calculates ceil(Sqrt(stat exp)) in b
+ xor a
+ ld [hMultiplicand], a
+ ld [hMultiplicand+1], a
+ inc b ; increment current stat exp bonus
+ ld a, b
+ cp $ff
+ jr z, .statExpDone
+ ld [hMultiplicand+2], a
+ ld [hMultiplier], a
+ call Multiply
+ ld a, [hld]
+ ld d, a
+ ld a, [hProduct + 3]
+ sub d
+ ld a, [hli]
+ ld d, a
+ ld a, [hProduct + 2]
+ sbc d ; test if (current stat exp bonus)^2 < stat exp
+ jr c, .statExpLoop
+.statExpDone
+ srl c
+ pop hl
+ push bc
+ ld bc, wPartyMon1DVs - (wPartyMon1HPExp - 1) ; also wEnemyMonDVs - wEnemyMonHP
+ add hl, bc
+ pop bc
+ ld a, c
+ cp $2
+ jr z, .getAttackIV
+ cp $3
+ jr z, .getDefenseIV
+ cp $4
+ jr z, .getSpeedIV
+ cp $5
+ jr z, .getSpecialIV
+.getHpIV
+ push bc
+ ld a, [hl] ; Atk IV
+ swap a
+ and $1
+ sla a
+ sla a
+ sla a
+ ld b, a
+ ld a, [hli] ; Def IV
+ and $1
+ sla a
+ sla a
+ add b
+ ld b, a
+ ld a, [hl] ; Spd IV
+ swap a
+ and $1
+ sla a
+ add b
+ ld b, a
+ ld a, [hl] ; Spc IV
+ and $1
+ add b ; HP IV: LSB of the other 4 IVs
+ pop bc
+ jr .calcStatFromIV
+.getAttackIV
+ ld a, [hl]
+ swap a
+ and $f
+ jr .calcStatFromIV
+.getDefenseIV
+ ld a, [hl]
+ and $f
+ jr .calcStatFromIV
+.getSpeedIV
+ inc hl
+ ld a, [hl]
+ swap a
+ and $f
+ jr .calcStatFromIV
+.getSpecialIV
+ inc hl
+ ld a, [hl]
+ and $f
+.calcStatFromIV
+ ld d, $0
+ add e
+ ld e, a
+ jr nc, .noCarry
+ inc d ; de = Base + IV
+.noCarry
+ sla e
+ rl d ; de = (Base + IV) * 2
+ srl b
+ srl b ; b = ceil(Sqrt(stat exp)) / 4
+ ld a, b
+ add e
+ jr nc, .noCarry2
+ inc d ; de = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4
+.noCarry2
+ ld [hMultiplicand+2], a
+ ld a, d
+ ld [hMultiplicand+1], a
+ xor a
+ ld [hMultiplicand], a
+ ld a, [wCurEnemyLVL]
+ ld [hMultiplier], a
+ call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level
+ ld a, [hMultiplicand]
+ ld [hDividend], a
+ ld a, [hMultiplicand+1]
+ ld [hDividend+1], a
+ ld a, [hMultiplicand+2]
+ ld [hDividend+2], a
+ ld a, $64
+ ld [hDivisor], a
+ ld a, $3
+ ld b, a
+ call Divide ; (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100
+ ld a, c
+ cp $1
+ ld a, 5 ; + 5 for non-HP stat
+ jr nz, .notHPStat
+ ld a, [wCurEnemyLVL]
+ ld b, a
+ ld a, [hMultiplicand+2]
+ add b
+ ld [hMultiplicand+2], a
+ jr nc, .noCarry3
+ ld a, [hMultiplicand+1]
+ inc a
+ ld [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level
+.noCarry3
+ ld a, 10 ; +10 for HP stat
+.notHPStat
+ ld b, a
+ ld a, [hMultiplicand+2]
+ add b
+ ld [hMultiplicand+2], a
+ jr nc, .noCarry4
+ ld a, [hMultiplicand+1]
+ inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5
+ ld [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10
+.noCarry4
+ ld a, [hMultiplicand+1] ; check for overflow (>999)
+ cp 999 / $100 + 1
+ jr nc, .overflow
+ cp 999 / $100
+ jr c, .noOverflow
+ ld a, [hMultiplicand+2]
+ cp 999 % $100 + 1
+ jr c, .noOverflow
+.overflow
+ ld a, 999 / $100 ; overflow: cap at 999
+ ld [hMultiplicand+1], a
+ ld a, 999 % $100
+ ld [hMultiplicand+2], a
+.noOverflow
+ pop bc
+ pop de
+ pop hl
+ ret
+
+AddEnemyMonToPlayerParty::
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, BANK(_AddEnemyMonToPlayerParty)
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ call _AddEnemyMonToPlayerParty
+ pop bc
+ ld a, b
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
+
+MoveMon::
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, BANK(_MoveMon)
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ call _MoveMon
+ pop bc
+ ld a, b
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
--- /dev/null
+++ b/home/names.asm
@@ -1,0 +1,141 @@
+GetMonName::
+ push hl
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, BANK(MonsterNames)
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ld a, [wd11e]
+ dec a
+ ld hl, MonsterNames
+ ld c, 10
+ ld b, 0
+ call AddNTimes
+ ld de, wcd6d
+ push de
+ ld bc, 10
+ call CopyData
+ ld hl, wcd6d + 10
+ ld [hl], "@"
+ pop de
+ pop af
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ pop hl
+ ret
+
+GetItemName::
+; given an item ID at [wd11e], store the name of the item into a string
+; starting at wcd6d
+ push hl
+ push bc
+ ld a, [wd11e]
+ cp 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::
+; 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, "0"
+.FirstDigit
+ sub 10
+ jr c, .SecondDigit
+ inc b
+ jr .FirstDigit
+.SecondDigit
+ add 10
+ push af
+ ld a, b
+ ld [de], a
+ inc de
+ pop af
+ ld b, "0"
+ add b
+ ld [de], a
+ inc de
+ ld a, "@"
+ ld [de], a
+ pop af
+ ld [wd11e], a
+ pop bc
+ pop de
+ pop hl
+ ret
+
+TechnicalPrefix::
+ db "TM"
+HiddenPrefix::
+ db "HM"
+
+; sets carry if item is HM, clears carry if item is not HM
+; Input: a = item ID
+IsItemHM::
+ cp HM_01
+ jr c, .notHM
+ cp 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::
+ ld hl, HMMoves
+ ld de, 1
+ jp IsInArray
+
+HMMoves::
+INCLUDE "data/moves/hm_moves.asm"
+
+GetMoveName::
+ push hl
+ ld a, MOVE_NAME
+ ld [wNameListType], a
+ ld a, [wd11e]
+ ld [wd0b5], a
+ ld a, BANK(MoveNames)
+ ld [wPredefBank], a
+ call GetName
+ ld de, wcd6d ; pointer to where move name is stored in RAM
+ pop hl
+ ret
--- /dev/null
+++ b/home/names2.asm
@@ -1,0 +1,93 @@
+NamePointers::
+ 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::
+; 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, [hLoadedROMBank]
+ push af
+ push hl
+ push bc
+ push de
+ ld a, [wNameListType] ;List3759_entrySelector
+ dec a
+ jr nz, .otherEntries
+ ;1 = MON_NAMES
+ call GetMonName
+ ld hl, NAME_LENGTH
+ add hl, de
+ ld e, l
+ ld d, h
+ jr .gotPtr
+.otherEntries
+ ;2-7 = OTHER ENTRIES
+ ld a, [wPredefBank]
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ld a, [wNameListType] ;VariousNames' entryID
+ dec a
+ add a
+ ld d, 0
+ ld e, a
+ jr nc, .skip
+ inc d
+.skip
+ ld hl, NamePointers
+ add hl, de
+ ld a, [hli]
+ ld [hSwapTemp + 1], a
+ ld a, [hl]
+ ld [hSwapTemp], a
+ ld a, [hSwapTemp]
+ ld h, a
+ ld a, [hSwapTemp + 1]
+ ld l, a
+ ld a, [wd0b5]
+ ld b, a
+ ld c, 0
+.nextName
+ ld d, h
+ ld e, l
+.nextChar
+ ld a, [hli]
+ cp "@"
+ jr nz, .nextChar
+ inc c ;entry counter
+ ld a, b ;wanted entry
+ cp c
+ jr nz, .nextName
+ ld h, d
+ ld l, e
+ ld de, wcd6d
+ ld bc, $0014
+ call CopyData
+.gotPtr
+ ld a, e
+ ld [wUnusedCF8D], a
+ ld a, d
+ ld [wUnusedCF8D + 1], a
+ pop de
+ pop bc
+ pop hl
+ pop af
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
--- /dev/null
+++ b/home/overworld_text.asm
@@ -1,0 +1,31 @@
+TextScriptEndingChar::
+ db "@"
+
+TextScriptEnd::
+ ld hl, TextScriptEndingChar
+ ret
+
+ExclamationText::
+ TX_FAR _ExclamationText
+ db "@"
+
+GroundRoseText::
+ TX_FAR _GroundRoseText
+ db "@"
+
+BoulderText::
+ TX_FAR _BoulderText
+ db "@"
+
+MartSignText::
+ TX_FAR _MartSignText
+ db "@"
+
+PokeCenterSignText::
+ TX_FAR _PokeCenterSignText
+ db "@"
+
+PickUpItemText::
+ TX_ASM
+ predef PickUpItem
+ jp TextScriptEnd
--- /dev/null
+++ b/home/pokemon.asm
@@ -1,0 +1,464 @@
+DrawHPBar::
+; Draw an HP bar d tiles long, and fill it to e pixels.
+; If c is nonzero, show at least a sliver regardless.
+; The right end of the bar changes with [wHPBarType].
+
+ push hl
+ push de
+ push bc
+
+ ; Left
+ ld a, $71 ; "HP:"
+ ld [hli], a
+ ld a, $62
+ ld [hli], a
+
+ push hl
+
+ ; Middle
+ ld a, $63 ; empty
+.draw
+ ld [hli], a
+ dec d
+ jr nz, .draw
+
+ ; Right
+ ld a, [wHPBarType]
+ dec a
+ ld a, $6d ; status screen and battle
+ jr z, .ok
+ dec a ; pokemon menu
+.ok
+ ld [hl], a
+
+ pop hl
+
+ ld a, e
+ and a
+ jr nz, .fill
+
+ ; If c is nonzero, draw a pixel anyway.
+ ld a, c
+ and a
+ jr z, .done
+ ld e, 1
+
+.fill
+ ld a, e
+ sub 8
+ jr c, .partial
+ ld e, a
+ ld a, $6b ; full
+ ld [hli], a
+ ld a, e
+ and a
+ jr z, .done
+ jr .fill
+
+.partial
+ ; Fill remaining pixels at the end if necessary.
+ ld a, $63 ; empty
+ add e
+ ld [hl], a
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+; loads pokemon data from one of multiple sources to wLoadedMon
+; loads base stats to wMonHeader
+; INPUT:
+; [wWhichPokemon] = index of pokemon within party/box
+; [wMonDataLocation] = source
+; 00: player's party
+; 01: enemy's party
+; 02: current box
+; 03: daycare
+; OUTPUT:
+; [wcf91] = pokemon ID
+; wLoadedMon = base address of pokemon data
+; wMonHeader = base address of base stats
+LoadMonData::
+ jpab LoadMonData_
+
+OverwritewMoves::
+; Write c to [wMoves + b]. Unused.
+ ld hl, wMoves
+ ld e, b
+ ld d, 0
+ add hl, de
+ ld a, c
+ ld [hl], a
+ ret
+
+LoadFlippedFrontSpriteByMonIndex::
+ ld a, 1
+ ld [wSpriteFlipped], a
+
+LoadFrontSpriteByMonIndex::
+ push hl
+ ld a, [wd11e]
+ push af
+ ld a, [wcf91]
+ ld [wd11e], a
+ predef IndexToPokedex
+ ld hl, wd11e
+ ld a, [hl]
+ pop bc
+ ld [hl], b
+ and a
+ pop hl
+ jr z, .invalidDexNumber ; dex #0 invalid
+ cp NUM_POKEMON + 1
+ jr c, .validDexNumber ; dex >#151 invalid
+.invalidDexNumber
+ ld a, RHYDON ; $1
+ ld [wcf91], a
+ ret
+.validDexNumber
+ push hl
+ ld de, vFrontPic
+ call LoadMonFrontSprite
+ pop hl
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, BANK(CopyUncompressedPicToHL)
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ xor a
+ ld [hStartTileID], a
+ call CopyUncompressedPicToHL
+ xor a
+ ld [wSpriteFlipped], a
+ pop af
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
+
+
+PlayCry::
+; Play monster a's cry.
+ call GetCryData
+ call PlaySound
+ jp WaitForSoundToFinish
+
+GetCryData::
+; Load cry data for monster a.
+ dec a
+ ld c, a
+ ld b, 0
+ ld hl, CryData
+ add hl, bc
+ add hl, bc
+ add hl, bc
+
+ ld a, BANK(CryData)
+ call BankswitchHome
+ ld a, [hli]
+ ld b, a ; cry id
+ ld a, [hli]
+ ld [wFrequencyModifier], a
+ ld a, [hl]
+ ld [wTempoModifier], a
+ call BankswitchBack
+
+ ; Cry headers have 3 channels,
+ ; and start from index CRY_SFX_START,
+ ; so add 3 times the cry id.
+ ld a, b
+ ld c, CRY_SFX_START
+ rlca ; * 2
+ add b
+ add c
+ ret
+
+DisplayPartyMenu::
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ call GBPalWhiteOutWithDelay3
+ call ClearSprites
+ call PartyMenuInit
+ call DrawPartyMenu
+ jp HandlePartyMenuInput
+
+GoBackToPartyMenu::
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ call PartyMenuInit
+ call RedrawPartyMenu
+ jp HandlePartyMenuInput
+
+PartyMenuInit::
+ ld a, 1 ; hardcoded bank
+ call BankswitchHome
+ call LoadHpBarAndStatusTilePatterns
+ ld hl, wd730
+ set 6, [hl] ; turn off letter printing delay
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld hl, wTopMenuItemY
+ inc a
+ ld [hli], a ; top menu item Y
+ xor a
+ ld [hli], a ; top menu item X
+ ld a, [wPartyAndBillsPCSavedMenuItem]
+ push af
+ ld [hli], a ; current menu item ID
+ inc hl
+ ld a, [wPartyCount]
+ and a ; are there more than 0 pokemon in the party?
+ jr z, .storeMaxMenuItemID
+ dec a
+; if party is not empty, the max menu item ID is ([wPartyCount] - 1)
+; otherwise, it is 0
+.storeMaxMenuItemID
+ ld [hli], a ; max menu item ID
+ ld a, [wForcePlayerToChooseMon]
+ and a
+ ld a, A_BUTTON | B_BUTTON
+ jr z, .next
+ xor a
+ ld [wForcePlayerToChooseMon], a
+ inc a ; a = A_BUTTON
+.next
+ ld [hli], a ; menu watched keys
+ pop af
+ ld [hl], a ; old menu item ID
+ ret
+
+HandlePartyMenuInput::
+ ld a, 1
+ ld [wMenuWrappingEnabled], a
+ ld a, $40
+ ld [wPartyMenuAnimMonEnabled], a
+ call HandleMenuInput_
+ call PlaceUnfilledArrowMenuCursor
+ ld b, a
+ xor a
+ ld [wPartyMenuAnimMonEnabled], a
+ ld a, [wCurrentMenuItem]
+ ld [wPartyAndBillsPCSavedMenuItem], 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 [wPartyMenuTypeOrMessageID], a
+ call RedrawPartyMenu
+ jr HandlePartyMenuInput
+.handleSwap
+ ld a, [wCurrentMenuItem]
+ ld [wWhichPokemon], a
+ callba SwitchPartyMon
+ jr HandlePartyMenuInput
+
+DrawPartyMenu::
+ ld hl, DrawPartyMenu_
+ jr DrawPartyMenuCommon
+
+RedrawPartyMenu::
+ ld hl, RedrawPartyMenu_
+
+DrawPartyMenuCommon::
+ ld b, BANK(RedrawPartyMenu_)
+ jp Bankswitch
+
+; prints a pokemon's status condition
+; INPUT:
+; de = address of status condition
+; hl = destination address
+PrintStatusCondition::
+ push de
+ dec de
+ dec de ; de = address of current HP
+ ld a, [de]
+ ld b, a
+ dec de
+ ld a, [de]
+ or b ; is the pokemon's HP zero?
+ pop de
+ jr nz, PrintStatusConditionNotFainted
+; if the pokemon's HP is 0, print "FNT"
+ ld a, "F"
+ ld [hli], a
+ ld a, "N"
+ ld [hli], a
+ ld [hl], "T"
+ and a
+ ret
+
+PrintStatusConditionNotFainted::
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, BANK(PrintStatusAilment)
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ call PrintStatusAilment ; print status condition
+ pop bc
+ ld a, b
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], 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::
+ ld a, $6e ; ":L" tile ID
+ ld [hli], a
+ ld c, 2 ; number of digits
+ ld a, [wLoadedMonLevel] ; level
+ cp 100
+ jr c, PrintLevelCommon
+; if level at least 100, write over the ":L" tile
+ dec hl
+ inc c ; increment number of digits to 3
+ jr PrintLevelCommon
+
+; prints the level without leaving off ":L" regardless of level
+; INPUT:
+; hl = destination address
+; [wLoadedMonLevel] = level
+PrintLevelFull::
+ ld a, $6e ; ":L" tile ID
+ ld [hli], a
+ ld c, 3 ; number of digits
+ ld a, [wLoadedMonLevel] ; level
+
+PrintLevelCommon::
+ ld [wd11e], a
+ ld de, wd11e
+ ld b, LEFT_ALIGN | 1 ; 1 byte
+ jp PrintNumber
+
+GetwMoves::
+; Unused. Returns the move at index a from wMoves in a
+ ld hl, wMoves
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ret
+
+; copies the base stat data of a pokemon to wMonHeader
+; INPUT:
+; [wd0b5] = pokemon ID
+GetMonHeader::
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, BANK(BaseStats)
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], 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 FOSSIL_KABUTOPS ; Kabutops fossil
+ jr z, .specialID
+ ld de, GhostPic
+ cp MON_GHOST ; Ghost
+ jr z, .specialID
+ ld de, FossilAerodactylPic
+ ld b, $77 ; size of Aerodactyl fossil sprite
+ cp FOSSIL_AERODACTYL ; Aerodactyl fossil
+ jr z, .specialID
+ cp MEW
+ jr z, .mew
+ predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number
+ ld a, [wd11e]
+ dec a
+ ld bc, MonBaseStatsEnd - MonBaseStats
+ ld hl, BaseStats
+ call AddNTimes
+ ld de, wMonHeader
+ ld bc, MonBaseStatsEnd - MonBaseStats
+ call CopyData
+ jr .done
+.specialID
+ ld hl, wMonHSpriteDim
+ ld [hl], b ; write sprite dimensions
+ inc hl
+ ld [hl], e ; write front sprite pointer
+ inc hl
+ ld [hl], d
+ jr .done
+.mew
+ ld hl, MewBaseStats
+ ld de, wMonHeader
+ ld bc, MonBaseStatsEnd - MonBaseStats
+ ld a, BANK(MewBaseStats)
+ call FarCopyData
+.done
+ ld a, [wd0b5]
+ ld [wMonHIndex], a
+ pop af
+ ld [wd11e], a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ ret
+
+; copy party pokemon's name to wcd6d
+GetPartyMonName2::
+ ld a, [wWhichPokemon] ; index within party
+ ld hl, wPartyMonNicks
+
+; this is called more often
+GetPartyMonName::
+ push hl
+ push bc
+ call SkipFixedLengthTextEntries ; add NAME_LENGTH to hl, a times
+ ld de, wcd6d
+ push de
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop de
+ pop bc
+ pop hl
+ ret
--- /dev/null
+++ b/home/predef_text.asm
@@ -1,0 +1,237 @@
+; this function is used to display sign messages, sprite dialog, etc.
+; INPUT: [hSpriteIndexOrTextID] = sprite ID or text ID
+DisplayTextID::
+ ld a, [hLoadedROMBank]
+ push af
+ callba DisplayTextIDInit ; initialization
+ ld hl, wTextPredefFlag
+ bit 0, [hl]
+ res 0, [hl]
+ jr nz, .skipSwitchToMapBank
+ ld a, [wCurMap]
+ call SwitchToMapRomBank
+.skipSwitchToMapBank
+ ld a, 30 ; half a second
+ ld [hFrameCounter], a ; used as joypad poll timer
+ ld hl, wMapTextPtr
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; hl = map text pointer
+ ld d, $00
+ ld a, [hSpriteIndexOrTextID] ; text ID
+ ld [wSpriteIndex], a
+ and a
+ jp z, DisplayStartMenu
+ cp TEXT_SAFARI_GAME_OVER
+ jp z, DisplaySafariGameOverText
+ cp TEXT_MON_FAINTED
+ jp z, DisplayPokemonFaintedText
+ cp TEXT_BLACKED_OUT
+ jp z, DisplayPlayerBlackedOutText
+ cp TEXT_REPEL_WORE_OFF
+ jp z, DisplayRepelWoreOffText
+ ld a, [wNumSprites]
+ ld e, a
+ ld a, [hSpriteIndexOrTextID] ; sprite ID
+ cp e
+ jr z, .spriteHandling
+ jr nc, .skipSpriteHandling
+.spriteHandling
+; get the text ID of the sprite
+ push hl
+ push de
+ push bc
+ callba UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction)
+ pop bc
+ pop de
+ ld hl, wMapSpriteData ; NPC text entries
+ ld a, [hSpriteIndexOrTextID]
+ 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 $fe ; Pokemart NPC
+ jp z, DisplayPokemartDialogue
+ cp $ff ; Pokemon Center NPC
+ jp z, DisplayPokemonCenterDialogue
+ cp $fc ; Item Storage PC
+ jp z, FuncTX_ItemStoragePC
+ cp $fd ; Bill's PC
+ jp z, FuncTX_BillsPC
+ cp $f9 ; Pokemon Center PC
+ jp z, FuncTX_PokemonCenterPC
+ cp $f5 ; Vending Machine
+ jr nz, .notVendingMachine
+ callba VendingMachineMenu ; jump banks to vending machine routine
+ jr AfterDisplayingTextID
+.notVendingMachine
+ cp $f7 ; prize menu
+ jp z, FuncTX_GameCornerPrizeMenu
+ cp $f6 ; cable connection NPC in Pokemon Center
+ jr nz, .notSpecialCase
+ callab CableClubNPC
+ jr AfterDisplayingTextID
+.notSpecialCase
+ call PrintText_NoCreatingTextBox ; display the text
+ ld a, [wDoNotWaitForButtonPressAfterDisplayingText]
+ and a
+ jr nz, HoldTextDisplayOpen
+
+AfterDisplayingTextID::
+ ld a, [wEnteringCableClub]
+ and a
+ jr nz, HoldTextDisplayOpen
+ call WaitForTextScrollButtonPress ; wait for a button press after displaying all the text
+
+; loop to hold the dialogue box open as long as the player keeps holding down the A button
+HoldTextDisplayOpen::
+ call Joypad
+ ld a, [hJoyHeld]
+ bit 0, a ; is the A button being pressed?
+ jr nz, HoldTextDisplayOpen
+
+CloseTextDisplay::
+ ld a, [wCurMap]
+ call SwitchToMapRomBank
+ ld a, $90
+ ld [hWY], a ; move the window off the screen
+ call DelayFrame
+ call LoadGBPal
+ xor a
+ ld [hAutoBGTransferEnabled], a ; disable continuous WRAM to VRAM transfer each V-blank
+; loop to make sprites face the directions they originally faced before the dialogue
+ ld hl, 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 [hLoadedROMBank], a
+ ld [MBC1RomBank], 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 [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ jp UpdateSprites
+
+DisplayPokemartDialogue::
+ push hl
+ ld hl, PokemartGreetingText
+ call PrintText
+ pop hl
+ inc hl
+ call LoadItemList
+ ld a, PRICEDITEMLISTMENU
+ ld [wListMenuID], a
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, BANK(DisplayPokemartDialogue_)
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ call DisplayPokemartDialogue_
+ pop af
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ jp AfterDisplayingTextID
+
+PokemartGreetingText::
+ TX_FAR _PokemartGreetingText
+ db "@"
+
+LoadItemList::
+ ld a, 1
+ ld [wUpdateSpritesEnabled], a
+ ld a, h
+ ld [wItemListPointer], a
+ ld a, l
+ ld [wItemListPointer + 1], a
+ ld de, wItemList
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ cp $ff
+ jr nz, .loop
+ ret
+
+DisplayPokemonCenterDialogue::
+; zeroing these doesn't appear to serve any purpose
+ xor a
+ ld [hItemPrice], a
+ ld [hItemPrice + 1], a
+ ld [hItemPrice + 2], a
+
+ inc hl
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, BANK(DisplayPokemonCenterDialogue_)
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ call DisplayPokemonCenterDialogue_
+ pop af
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ jp AfterDisplayingTextID
+
+DisplaySafariGameOverText::
+ callab PrintSafariGameOverText
+ jp AfterDisplayingTextID
+
+DisplayPokemonFaintedText::
+ ld hl, PokemonFaintedText
+ call PrintText
+ jp AfterDisplayingTextID
+
+PokemonFaintedText::
+ TX_FAR _PokemonFaintedText
+ db "@"
+
+DisplayPlayerBlackedOutText::
+ ld hl, PlayerBlackedOutText
+ call PrintText
+ ld a, [wd732]
+ res 5, a ; reset forced to use bike bit
+ ld [wd732], a
+ jp HoldTextDisplayOpen
+
+PlayerBlackedOutText::
+ TX_FAR _PlayerBlackedOutText
+ db "@"
+
+DisplayRepelWoreOffText::
+ ld hl, RepelWoreOffText
+ call PrintText
+ jp AfterDisplayingTextID
+
+RepelWoreOffText::
+ TX_FAR _RepelWoreOffText
+ db "@"
--- /dev/null
+++ b/home/print_bcd.asm
@@ -1,0 +1,77 @@
+; function to print a BCD (Binary-coded decimal) number
+; de = address of BCD number
+; hl = destination address
+; c = flags and length
+; bit 7: if set, do not print leading zeroes
+; if unset, print leading zeroes
+; bit 6: if set, left-align the string (do not pad empty digits with spaces)
+; if unset, right-align the string
+; bit 5: if set, print currency symbol at the beginning of the string
+; if unset, do not print the currency symbol
+; bits 0-4: length of BCD number in bytes
+; Note that bits 5 and 7 are modified during execution. The above reflects
+; their meaning at the beginning of the functions's execution.
+PrintBCDNumber::
+ ld b, c ; save flags in b
+ res 7, c
+ res 6, c
+ res 5, c ; c now holds the length
+ bit 5, b
+ jr z, .loop
+ bit 7, b
+ jr nz, .loop
+ ld [hl], "¥"
+ inc hl
+.loop
+ ld a, [de]
+ swap a
+ call PrintBCDDigit ; print upper digit
+ ld a, [de]
+ call PrintBCDDigit ; print lower digit
+ inc de
+ dec c
+ jr nz, .loop
+ bit 7, b ; were any non-zero digits printed?
+ jr z, .done ; if so, we are done
+.numberEqualsZero ; if every digit of the BCD number is zero
+ bit 6, b ; left or right alignment?
+ jr nz, .skipRightAlignmentAdjustment
+ dec hl ; if the string is right-aligned, it needs to be moved back one space
+.skipRightAlignmentAdjustment
+ bit 5, b
+ jr z, .skipCurrencySymbol
+ ld [hl], "¥"
+ inc hl
+.skipCurrencySymbol
+ ld [hl], "0"
+ call PrintLetterDelay
+ inc hl
+.done
+ ret
+
+PrintBCDDigit::
+ and $f
+ and a
+ jr z, .zeroDigit
+.nonzeroDigit
+ bit 7, b ; have any non-space characters been printed?
+ jr z, .outputDigit
+; if bit 7 is set, then no numbers have been printed yet
+ bit 5, b ; print the currency symbol?
+ jr z, .skipCurrencySymbol
+ ld [hl], "¥"
+ inc hl
+ res 5, b
+.skipCurrencySymbol
+ res 7, b ; unset 7 to indicate that a nonzero digit has been reached
+.outputDigit
+ add "0"
+ ld [hli], a
+ jp PrintLetterDelay
+.zeroDigit
+ bit 7, b ; either printing leading zeroes or already reached a nonzero digit?
+ jr z, .outputDigit ; if so, print a zero digit
+ bit 6, b ; left or right alignment?
+ ret nz
+ inc hl ; if right-aligned, "print" a space by advancing the pointer
+ ret
--- /dev/null
+++ b/home/print_num.asm
@@ -1,0 +1,217 @@
+PrintNumber::
+; Print the c-digit, b-byte value at de.
+; Allows 2 to 7 digits. For 1-digit numbers, add
+; the value to char "0" instead of calling PrintNumber.
+; Flags LEADING_ZEROES and LEFT_ALIGN can be given
+; in bits 7 and 6 of b respectively.
+ push bc
+ xor a
+ ld [hPastLeadingZeros], a
+ ld [hNumToPrint], a
+ ld [hNumToPrint + 1], a
+ ld a, b
+ and $f
+ cp 1
+ jr z, .byte
+ cp 2
+ jr z, .word
+.long
+ ld a, [de]
+ ld [hNumToPrint], a
+ inc de
+ ld a, [de]
+ ld [hNumToPrint + 1], a
+ inc de
+ ld a, [de]
+ ld [hNumToPrint + 2], a
+ jr .start
+
+.word
+ ld a, [de]
+ ld [hNumToPrint + 1], a
+ inc de
+ ld a, [de]
+ ld [hNumToPrint + 2], a
+ jr .start
+
+.byte
+ ld a, [de]
+ ld [hNumToPrint + 2], a
+
+.start
+ push de
+
+ ld d, b
+ ld a, c
+ ld b, a
+ xor a
+ ld c, a
+ ld a, b
+
+ cp 2
+ jr z, .tens
+ cp 3
+ jr z, .hundreds
+ cp 4
+ jr z, .thousands
+ cp 5
+ jr z, .ten_thousands
+ cp 6
+ jr z, .hundred_thousands
+
+print_digit: macro
+
+if (\1) / $10000
+ ld a, \1 / $10000 % $100
+else xor a
+endc
+ ld [hPowerOf10 + 0], a
+
+if (\1) / $100
+ ld a, \1 / $100 % $100
+else xor a
+endc
+ ld [hPowerOf10 + 1], a
+
+ ld a, \1 / $1 % $100
+ ld [hPowerOf10 + 2], a
+
+ call .PrintDigit
+ call .NextDigit
+endm
+
+.millions print_digit 1000000
+.hundred_thousands print_digit 100000
+.ten_thousands print_digit 10000
+.thousands print_digit 1000
+.hundreds print_digit 100
+
+.tens
+ ld c, 0
+ ld a, [hNumToPrint + 2]
+.mod
+ cp 10
+ jr c, .ok
+ sub 10
+ inc c
+ jr .mod
+.ok
+
+ ld b, a
+ ld a, [hPastLeadingZeros]
+ or c
+ ld [hPastLeadingZeros], a
+ jr nz, .past
+ call .PrintLeadingZero
+ jr .next
+.past
+ ld a, "0"
+ add c
+ ld [hl], a
+.next
+
+ call .NextDigit
+.ones
+ ld a, "0"
+ add b
+ ld [hli], a
+ pop de
+ dec de
+ pop bc
+ ret
+
+.PrintDigit:
+; Divide by the current decimal place.
+; Print the quotient, and keep the modulus.
+ ld c, 0
+.loop
+ ld a, [hPowerOf10]
+ ld b, a
+ ld a, [hNumToPrint]
+ ld [hSavedNumToPrint], a
+ cp b
+ jr c, .underflow0
+ sub b
+ ld [hNumToPrint], a
+ ld a, [hPowerOf10 + 1]
+ ld b, a
+ ld a, [hNumToPrint + 1]
+ ld [hSavedNumToPrint + 1], a
+ cp b
+ jr nc, .noborrow1
+
+ ld a, [hNumToPrint]
+ or 0
+ jr z, .underflow1
+ dec a
+ ld [hNumToPrint], a
+ ld a, [hNumToPrint + 1]
+.noborrow1
+
+ sub b
+ ld [hNumToPrint + 1], a
+ ld a, [hPowerOf10 + 2]
+ ld b, a
+ ld a, [hNumToPrint + 2]
+ ld [hSavedNumToPrint + 2], a
+ cp b
+ jr nc, .noborrow2
+
+ ld a, [hNumToPrint + 1]
+ and a
+ jr nz, .borrowed
+
+ ld a, [hNumToPrint]
+ and a
+ jr z, .underflow2
+ dec a
+ ld [hNumToPrint], a
+ xor a
+.borrowed
+
+ dec a
+ ld [hNumToPrint + 1], a
+ ld a, [hNumToPrint + 2]
+.noborrow2
+ sub b
+ ld [hNumToPrint + 2], a
+ inc c
+ jr .loop
+
+.underflow2
+ ld a, [hSavedNumToPrint + 1]
+ ld [hNumToPrint + 1], a
+.underflow1
+ ld a, [hSavedNumToPrint]
+ ld [hNumToPrint], a
+.underflow0
+ ld a, [hPastLeadingZeros]
+ or c
+ jr z, .PrintLeadingZero
+
+ ld a, "0"
+ add c
+ ld [hl], a
+ ld [hPastLeadingZeros], a
+ ret
+
+.PrintLeadingZero:
+ bit BIT_LEADING_ZEROES, d
+ ret z
+ ld [hl], "0"
+ ret
+
+.NextDigit:
+; Increment unless the number is left-aligned,
+; leading zeroes are not printed, and no digits
+; have been printed yet.
+ bit BIT_LEADING_ZEROES, d
+ jr nz, .inc
+ bit BIT_LEFT_ALIGN, d
+ jr z, .inc
+ ld a, [hPastLeadingZeros]
+ and a
+ ret z
+.inc
+ inc hl
+ ret
--- /dev/null
+++ b/home/trainers.asm
@@ -1,0 +1,436 @@
+; stores hl in [wTrainerHeaderPtr]
+StoreTrainerHeaderPointer::
+ ld a, h
+ ld [wTrainerHeaderPtr], a
+ ld a, l
+ ld [wTrainerHeaderPtr+1], a
+ ret
+
+; executes the current map script from the function pointer array provided in hl.
+; a: map script index to execute (unless overridden by [wd733] bit 4)
+ExecuteCurMapScriptInTable::
+ push af
+ push de
+ call StoreTrainerHeaderPointer
+ pop hl
+ pop af
+ push hl
+ ld hl, wFlags_D733
+ bit 4, [hl]
+ res 4, [hl]
+ jr z, .useProvidedIndex ; test if map script index was overridden manually
+ ld a, [wCurMapScript]
+.useProvidedIndex
+ pop hl
+ ld [wCurMapScript], a
+ call CallFunctionInTable
+ ld a, [wCurMapScript]
+ ret
+
+LoadGymLeaderAndCityName::
+ push de
+ ld de, wGymCityName
+ ld bc, $11
+ call CopyData ; load city name
+ pop hl
+ ld de, wGymLeaderName
+ ld bc, NAME_LENGTH
+ jp CopyData ; load gym leader name
+
+; reads specific information from trainer header (pointed to at wTrainerHeaderPtr)
+; a: offset in header data
+; 0 -> flag's bit (into wTrainerHeaderFlagBit)
+; 2 -> flag's byte ptr (into hl)
+; 4 -> before battle text (into hl)
+; 6 -> after battle text (into hl)
+; 8 -> end battle text (into hl)
+ReadTrainerHeaderInfo::
+ push de
+ push af
+ ld d, $0
+ ld e, a
+ ld hl, wTrainerHeaderPtr
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+ add hl, de
+ pop af
+ and a
+ jr nz, .nonZeroOffset
+ ld a, [hl]
+ ld [wTrainerHeaderFlagBit], a ; store flag's bit
+ jr .done
+.nonZeroOffset
+ cp $2
+ jr z, .readPointer ; read flag's byte ptr
+ cp $4
+ jr z, .readPointer ; read before battle text
+ cp $6
+ jr z, .readPointer ; read after battle text
+ cp $8
+ jr z, .readPointer ; read end battle text
+ cp $a
+ jr nz, .done
+ ld a, [hli] ; read end battle text (2) but override the result afterwards (XXX why, bug?)
+ ld d, [hl]
+ ld e, a
+ jr .done
+.readPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.done
+ pop de
+ ret
+
+TrainerFlagAction::
+ predef_jump FlagActionPredef
+
+TalkToTrainer::
+ call StoreTrainerHeaderPointer
+ xor a
+ call ReadTrainerHeaderInfo ; read flag's bit
+ ld a, $2
+ call ReadTrainerHeaderInfo ; read flag's byte ptr
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ ld b, FLAG_TEST
+ call TrainerFlagAction ; read trainer's flag
+ ld a, c
+ and a
+ jr z, .trainerNotYetFought ; test trainer's flag
+ ld a, $6
+ call ReadTrainerHeaderInfo ; print after battle text
+ jp PrintText
+.trainerNotYetFought
+ ld a, $4
+ call ReadTrainerHeaderInfo ; print before battle text
+ call PrintText
+ ld a, $a
+ call ReadTrainerHeaderInfo ; (?) does nothing apparently (maybe bug in ReadTrainerHeaderInfo)
+ push de
+ ld a, $8
+ call ReadTrainerHeaderInfo ; read end battle text
+ pop de
+ call SaveEndBattleTextPointers
+ ld hl, wFlags_D733
+ set 4, [hl] ; activate map script index override (index is set below)
+ ld hl, wFlags_0xcd60
+ bit 0, [hl] ; test if player is already engaging the trainer (because the trainer saw the player)
+ ret nz
+; if the player talked to the trainer of his own volition
+ call EngageMapTrainer
+ ld hl, wCurMapScript
+ inc [hl] ; increment map script index before StartTrainerBattle increments it again (next script function is usually EndTrainerBattle)
+ jp StartTrainerBattle
+
+; checks if any trainers are seeing the player and wanting to fight
+CheckFightingMapTrainers::
+ call CheckForEngagingTrainers
+ ld a, [wSpriteIndex]
+ cp $ff
+ jr nz, .trainerEngaging
+ xor a
+ ld [wSpriteIndex], a
+ ld [wTrainerHeaderFlagBit], a
+ ret
+.trainerEngaging
+ ld hl, wFlags_D733
+ set 3, [hl]
+ ld [wEmotionBubbleSpriteIndex], a
+ xor a ; EXCLAMATION_BUBBLE
+ ld [wWhichEmotionBubble], a
+ predef EmotionBubble
+ ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
+ ld [wJoyIgnore], a
+ xor a
+ ld [hJoyHeld], a
+ call TrainerWalkUpToPlayer_Bank0
+ ld hl, wCurMapScript
+ inc [hl] ; increment map script index (next script function is usually DisplayEnemyTrainerTextAndStartBattle)
+ ret
+
+; display the before battle text after the enemy trainer has walked up to the player's sprite
+DisplayEnemyTrainerTextAndStartBattle::
+ ld a, [wd730]
+ and $1
+ ret nz ; return if the enemy trainer hasn't finished walking to the player's sprite
+ ld [wJoyIgnore], a
+ ld a, [wSpriteIndex]
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ ; fall through
+
+StartTrainerBattle::
+ xor a
+ ld [wJoyIgnore], a
+ call InitBattleEnemyParameters
+ ld hl, wd72d
+ set 6, [hl]
+ set 7, [hl]
+ ld hl, wd72e
+ set 1, [hl]
+ ld hl, wCurMapScript
+ inc [hl] ; increment map script index (next script function is usually EndTrainerBattle)
+ ret
+
+EndTrainerBattle::
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+ set 6, [hl]
+ ld hl, wd72d
+ res 7, [hl]
+ ld hl, wFlags_0xcd60
+ res 0, [hl] ; player is no longer engaged by any trainer
+ ld a, [wIsInBattle]
+ cp $ff
+ jp z, ResetButtonPressedAndMapScript
+ ld a, $2
+ call ReadTrainerHeaderInfo
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ ld b, FLAG_SET
+ call TrainerFlagAction ; flag trainer as fought
+ ld a, [wEnemyMonOrTrainerClass]
+ cp OPP_ID_OFFSET
+ jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite)
+ ld hl, wMissableObjectList
+ ld de, $2
+ ld a, [wSpriteIndex]
+ call IsInArray ; search for sprite ID
+ inc hl
+ ld a, [hl]
+ ld [wMissableObjectIndex], a ; load corresponding missable object index and remove it
+ predef HideObject
+.skipRemoveSprite
+ ld hl, wd730
+ bit 4, [hl]
+ res 4, [hl]
+ ret nz
+
+ResetButtonPressedAndMapScript::
+ xor a
+ ld [wJoyIgnore], a
+ ld [hJoyHeld], a
+ ld [hJoyPressed], a
+ ld [hJoyReleased], a
+ ld [wCurMapScript], a ; reset battle status
+ ret
+
+; calls TrainerWalkUpToPlayer
+TrainerWalkUpToPlayer_Bank0::
+ jpba TrainerWalkUpToPlayer
+
+; sets opponent type and mon set/lvl based on the engaging trainer data
+InitBattleEnemyParameters::
+ ld a, [wEngagedTrainerClass]
+ ld [wCurOpponent], a
+ ld [wEnemyMonOrTrainerClass], a
+ cp OPP_ID_OFFSET
+ ld a, [wEngagedTrainerSet]
+ jr c, .noTrainer
+ ld [wTrainerNo], a
+ ret
+.noTrainer
+ ld [wCurEnemyLVL], a
+ ret
+
+GetSpritePosition1::
+ ld hl, _GetSpritePosition1
+ jr SpritePositionBankswitch
+
+GetSpritePosition2::
+ ld hl, _GetSpritePosition2
+ jr SpritePositionBankswitch
+
+SetSpritePosition1::
+ ld hl, _SetSpritePosition1
+ jr SpritePositionBankswitch
+
+SetSpritePosition2::
+ ld hl, _SetSpritePosition2
+SpritePositionBankswitch::
+ ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2)
+ jp Bankswitch ; indirect jump to one of the four functions
+
+CheckForEngagingTrainers::
+ xor a
+ call ReadTrainerHeaderInfo ; read trainer flag's bit (unused)
+ ld d, h ; store trainer header address in de
+ ld e, l
+.trainerLoop
+ call StoreTrainerHeaderPointer ; set trainer header pointer to current trainer
+ ld a, [de]
+ ld [wSpriteIndex], a ; store trainer flag's bit
+ ld [wTrainerHeaderFlagBit], a
+ cp $ff
+ ret z
+ ld a, $2
+ call ReadTrainerHeaderInfo ; read trainer flag's byte ptr
+ ld b, FLAG_TEST
+ ld a, [wTrainerHeaderFlagBit]
+ ld c, a
+ call TrainerFlagAction ; read trainer flag
+ ld a, c
+ and a ; has the trainer already been defeated?
+ jr nz, .continue
+ push hl
+ push de
+ push hl
+ xor a
+ call ReadTrainerHeaderInfo ; get trainer header pointer
+ inc hl
+ ld a, [hl] ; read trainer engage distance
+ pop hl
+ ld [wTrainerEngageDistance], a
+ ld a, [wSpriteIndex]
+ swap a
+ ld [wTrainerSpriteOffset], a
+ predef TrainerEngage
+ pop de
+ pop hl
+ ld a, [wTrainerSpriteOffset]
+ and a
+ ret nz ; break if the trainer is engaging
+.continue
+ ld hl, $c
+ add hl, de
+ ld d, h
+ ld e, l
+ jr .trainerLoop
+
+; hl = text if the player wins
+; de = text if the player loses
+SaveEndBattleTextPointers::
+ ld a, [hLoadedROMBank]
+ ld [wEndBattleTextRomBank], a
+ ld a, h
+ ld [wEndBattleWinTextPointer], a
+ ld a, l
+ ld [wEndBattleWinTextPointer + 1], a
+ ld a, d
+ ld [wEndBattleLoseTextPointer], a
+ ld a, e
+ ld [wEndBattleLoseTextPointer + 1], a
+ ret
+
+; loads data of some trainer on the current map and plays pre-battle music
+; [wSpriteIndex]: sprite ID of trainer who is engaged
+EngageMapTrainer::
+ ld hl, wMapSpriteExtraData
+ ld d, $0
+ ld a, [wSpriteIndex]
+ dec a
+ add a
+ ld e, a
+ add hl, de ; seek to engaged trainer data
+ ld a, [hli] ; load trainer class
+ ld [wEngagedTrainerClass], a
+ ld a, [hl] ; load trainer mon set
+ ld [wEngagedTrainerSet], a
+ jp PlayTrainerMusic
+
+PrintEndBattleText::
+ push hl
+ ld hl, wd72d
+ bit 7, [hl]
+ res 7, [hl]
+ pop hl
+ ret z
+ ld a, [hLoadedROMBank]
+ push af
+ ld a, [wEndBattleTextRomBank]
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ push hl
+ callba SaveTrainerName
+ ld hl, TrainerEndBattleText
+ call PrintText
+ pop hl
+ pop af
+ ld [hLoadedROMBank], a
+ ld [MBC1RomBank], a
+ callba FreezeEnemyTrainerSprite
+ jp WaitForSoundToFinish
+
+GetSavedEndBattleTextPointer::
+ ld a, [wBattleResult]
+ and a
+; won battle
+ jr nz, .lostBattle
+ ld a, [wEndBattleWinTextPointer]
+ ld h, a
+ ld a, [wEndBattleWinTextPointer + 1]
+ ld l, a
+ ret
+.lostBattle
+ ld a, [wEndBattleLoseTextPointer]
+ ld h, a
+ ld a, [wEndBattleLoseTextPointer + 1]
+ ld l, a
+ ret
+
+TrainerEndBattleText::
+ TX_FAR _TrainerNameText
+ TX_ASM
+ call GetSavedEndBattleTextPointer
+ call TextCommandProcessor
+ jp TextScriptEnd
+
+; only engage with the trainer if the player is not already
+; engaged with another trainer
+; XXX unused?
+CheckIfAlreadyEngaged::
+ ld a, [wFlags_0xcd60]
+ bit 0, a
+ ret nz
+ call EngageMapTrainer
+ xor a
+ ret
+
+PlayTrainerMusic::
+ ld a, [wEngagedTrainerClass]
+ cp OPP_SONY1
+ ret z
+ cp OPP_SONY2
+ ret z
+ cp OPP_SONY3
+ ret z
+ ld a, [wGymLeaderNo]
+ and a
+ ret nz
+ xor a
+ ld [wAudioFadeOutControl], a
+ ld a, SFX_STOP_ALL_MUSIC
+ call PlaySound
+ ld a, BANK(Music_MeetEvilTrainer)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ ld a, [wEngagedTrainerClass]
+ ld b, a
+ ld hl, EvilTrainerList
+.evilTrainerListLoop
+ ld a, [hli]
+ cp $ff
+ jr z, .noEvilTrainer
+ cp b
+ jr nz, .evilTrainerListLoop
+ ld a, MUSIC_MEET_EVIL_TRAINER
+ jr .PlaySound
+.noEvilTrainer
+ ld hl, FemaleTrainerList
+.femaleTrainerListLoop
+ ld a, [hli]
+ cp $ff
+ jr z, .maleTrainer
+ cp b
+ jr nz, .femaleTrainerListLoop
+ ld a, MUSIC_MEET_FEMALE_TRAINER
+ jr .PlaySound
+.maleTrainer
+ ld a, MUSIC_MEET_MALE_TRAINER
+.PlaySound
+ ld [wNewSoundID], a
+ jp PlaySound
+
+INCLUDE "data/trainers/encounter_types.asm"
--- /dev/null
+++ b/home/uncompress.asm
@@ -1,0 +1,196 @@
+; uncompresses the front or back sprite of the specified mon
+; assumes the corresponding mon header is already loaded
+; hl contains offset to sprite pointer ($b for front or $d for back)
+UncompressMonSprite::
+ ld bc, wMonHeader
+ add hl, bc
+ ld a, [hli]
+ ld [wSpriteInputPtr], a ; fetch sprite input pointer
+ ld a, [hl]
+ ld [wSpriteInputPtr+1], a
+; define (by index number) the bank that a pokemon's image is in
+; index = Mew, bank 1
+; index = Kabutops fossil, bank $B
+; index < $1F, bank 9
+; $1F ≤ index < $4A, bank $A
+; $4A ≤ index < $74, bank $B
+; $74 ≤ index < $99, bank $C
+; $99 ≤ index, bank $D
+ ld a, [wcf91] ; XXX name for this ram location
+ ld b, a
+ cp MEW
+ ld a, BANK(MewPicFront)
+ jr z, .GotBank
+ ld a, b
+ cp FOSSIL_KABUTOPS
+ ld a, BANK(FossilKabutopsPic)
+ jr z, .GotBank
+ ld a, b
+ cp TANGELA + 1
+ ld a, BANK(TangelaPicFront)
+ jr c, .GotBank
+ ld a, b
+ cp MOLTRES + 1
+ ld a, BANK(MoltresPicFront)
+ jr c, .GotBank
+ ld a, b
+ cp BEEDRILL + 2
+ ld a, BANK(BeedrillPicFront)
+ jr c, .GotBank
+ ld a, b
+ cp STARMIE + 1
+ ld a, BANK(StarmiePicFront)
+ jr c, .GotBank
+ ld a, BANK(VictreebelPicFront)
+.GotBank
+ jp UncompressSpriteData
+
+; de: destination location
+LoadMonFrontSprite::
+ push de
+ ld hl, wMonHFrontSprite - wMonHeader
+ call UncompressMonSprite
+ ld hl, wMonHSpriteDim
+ ld a, [hli]
+ ld c, a
+ pop de
+ ; fall through
+
+; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram
+; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers
+; de: destination location
+; a,c: sprite dimensions (in tiles of 8x8 each)
+LoadUncompressedSpriteData::
+ push de
+ and $f
+ ld [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
+ ld b, a
+ ld a, $7
+ sub b ; 7-w
+ inc a ; 8-w
+ srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up)
+ ld b, a
+ add a
+ add a
+ add a
+ sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles)
+ ld [hSpriteOffset], a
+ ld a, c
+ swap a
+ and $f
+ ld b, a
+ add a
+ add a
+ add a ; 8*tiles is height in bytes
+ ld [hSpriteHeight], a
+ ld a, $7
+ sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
+ ld b, a
+ ld a, [hSpriteOffset]
+ add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles)
+ add a
+ add a
+ add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes)
+ ld [hSpriteOffset], a
+ xor a
+ ld [$4000], a
+ ld hl, sSpriteBuffer0
+ call ZeroSpriteBuffer ; zero buffer 0
+ ld de, sSpriteBuffer1
+ ld hl, sSpriteBuffer0
+ call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
+ ld hl, sSpriteBuffer1
+ call ZeroSpriteBuffer ; zero buffer 1
+ ld de, sSpriteBuffer2
+ ld hl, sSpriteBuffer1
+ call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
+ 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::
+ ld a, [hSpriteOffset]
+ ld b, $0
+ ld c, a
+ add hl, bc
+ ld a, [hSpriteWidth]
+.columnLoop
+ push af
+ push hl
+ ld a, [hSpriteHeight]
+ ld c, a
+.columnInnerLoop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .columnInnerLoop
+ pop hl
+ ld bc, 7*8 ; 7 tiles
+ add hl, bc ; advance one full column
+ pop af
+ dec a
+ jr nz, .columnLoop
+ ret
+
+; fills the sprite buffer (pointed to in hl) with zeros
+ZeroSpriteBuffer::
+ ld bc, SPRITEBUFFERSIZE
+.nextByteLoop
+ xor a
+ ld [hli], a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .nextByteLoop
+ ret
+
+; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2
+; in the resulting sprite, the rows of the two source sprites are interlaced
+; de: output address
+InterlaceMergeSpriteBuffers::
+ xor a
+ ld [$4000], a
+ push de
+ ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
+ ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
+ ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
+ ld a, SPRITEBUFFERSIZE/2 ; $c4
+ ld [hSpriteInterlaceCounter], a
+.interlaceLoop
+ ld a, [de]
+ dec de
+ ld [hld], a ; write byte of source 2
+ ld a, [bc]
+ dec bc
+ ld [hld], a ; write byte of source 1
+ ld a, [de]
+ dec de
+ ld [hld], a ; write byte of source 2
+ ld a, [bc]
+ dec bc
+ ld [hld], a ; write byte of source 1
+ ld a, [hSpriteInterlaceCounter]
+ dec a
+ ld [hSpriteInterlaceCounter], a
+ jr nz, .interlaceLoop
+ ld a, [wSpriteFlipped]
+ and a
+ jr z, .notFlipped
+ ld bc, 2*SPRITEBUFFERSIZE
+ ld hl, sSpriteBuffer1
+.swapLoop
+ swap [hl] ; if flipped swap nybbles in all bytes
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .swapLoop
+.notFlipped
+ pop hl
+ ld de, sSpriteBuffer1
+ ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
+ ld a, [hLoadedROMBank]
+ ld b, a
+ jp CopyVideoData
--- /dev/null
+++ b/home/yes_no.asm
@@ -1,0 +1,40 @@
+; displays yes/no choice
+; yes -> set carry
+YesNoChoice::
+ call SaveScreenTilesToBuffer1
+ call InitYesNoTextBoxParameters
+ jr DisplayYesNoChoice
+
+Func_35f4::
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call InitYesNoTextBoxParameters
+ jp DisplayTextBoxID
+
+InitYesNoTextBoxParameters::
+ xor a ; YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ coord hl, 14, 7
+ ld bc, $80f
+ ret
+
+YesNoChoicePokeCenter::
+ call SaveScreenTilesToBuffer1
+ ld a, HEAL_CANCEL_MENU
+ ld [wTwoOptionMenuID], a
+ coord hl, 11, 6
+ lb bc, 8, 12
+ jr DisplayYesNoChoice
+
+WideYesNoChoice:: ; unused
+ call SaveScreenTilesToBuffer1
+ ld a, WIDE_YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ coord hl, 12, 7
+ lb bc, 8, 13
+
+DisplayYesNoChoice::
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ jp LoadScreenTilesFromBuffer1
--- a/macros/predef.asm
+++ b/macros/predef.asm
@@ -1,13 +1,3 @@
-predef_const: MACRO
- const \1PredefID
-ENDM
-
-add_predef: MACRO
-\1Predef::
- db BANK(\1)
- dw \1
-ENDM
-
predef_id: MACRO
ld a, (\1Predef - PredefPointers) / 3
ENDM
@@ -22,18 +12,7 @@
jp Predef
ENDM
-tx_pre_const: MACRO
- const \1_id
-ENDM
-add_tx_pre: MACRO
-\1_id:: dw \1
-ENDM
-
-db_tx_pre: MACRO
- db (\1_id - TextPredefs) / 2 + 1
-ENDM
-
tx_pre_id: MACRO
ld a, (\1_id - TextPredefs) / 2 + 1
ENDM
@@ -46,4 +25,8 @@
tx_pre_jump: MACRO
tx_pre_id \1
jp PrintPredefTextID
+ENDM
+
+db_tx_pre: MACRO
+ db (\1_id - TextPredefs) / 2 + 1
ENDM