shithub: pokered

Download patch

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