shithub: pokered

Download patch

ref: bbf2f51a02b2544f1bef32a5868503b474ae2fef
parent: 51ac538c25f8c0a6d88101569a17f02d09855d31
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Tue Jul 7 14:50:58 EDT 2020

Move all code out of home.asm into home/

This results in 64 home/*.asm files, comparable to pokecrystal's 57.

--- a/home.asm
+++ b/home.asm
@@ -18,64 +18,16 @@
 
 INCLUDE "home/start.asm"
 INCLUDE "home/joypad.asm"
+
 INCLUDE "data/maps/map_header_pointers.asm"
-INCLUDE "home/overworld.asm"
 
-CheckForUserInterruption::
-; Return carry if Up+Select+B, Start or A are pressed in c frames.
-; Used only in the intro and title screen.
-	call DelayFrame
-
-	push bc
-	call JoypadLowSensitivity
-	pop bc
-
-	ldh a, [hJoyHeld]
-	cp D_UP + SELECT + B_BUTTON
-	jr z, .input
-
-	ldh a, [hJoy5]
-	and START | A_BUTTON
-	jr nz, .input
-
-	dec c
-	jr nz, CheckForUserInterruption
-
-	and a
-	ret
-
-.input
-	scf
-	ret
-
-; function to load position data for destination warp when switching maps
-; INPUT:
-; a = ID of destination warp within destination map
-LoadDestinationWarpPosition::
-	ld b, a
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, [wPredefParentBank]
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ld a, b
-	add a
-	add a
-	ld c, a
-	ld b, 0
-	add hl, bc
-	ld bc, 4
-	ld de, wCurrentTileBlockMapViewPointer
-	call CopyData
-	pop af
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
+INCLUDE "home/overworld.asm"
 INCLUDE "home/pokemon.asm"
 INCLUDE "home/print_bcd.asm"
 INCLUDE "home/pics.asm"
+
 INCLUDE "data/tilesets/collision_tile_ids.asm"
+
 INCLUDE "home/copy2.asm"
 INCLUDE "home/text.asm"
 INCLUDE "home/vcopy.asm"
@@ -85,1724 +37,51 @@
 INCLUDE "home/serial.asm"
 INCLUDE "home/timer.asm"
 INCLUDE "home/audio.asm"
+INCLUDE "home/update_sprites.asm"
 
-UpdateSprites::
-	ld a, [wUpdateSpritesEnabled]
-	dec a
-	ret nz
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, BANK(_UpdateSprites)
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	call _UpdateSprites
-	pop af
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
 INCLUDE "data/items/marts.asm"
+
 INCLUDE "home/overworld_text.asm"
 INCLUDE "home/uncompress.asm"
-
-ResetPlayerSpriteData::
-	ld hl, wSpriteStateData1
-	call ResetPlayerSpriteData_ClearSpriteData
-	ld hl, wSpriteStateData2
-	call ResetPlayerSpriteData_ClearSpriteData
-	ld a, $1
-	ld [wSpritePlayerStateData1PictureID], a
-	ld [wSpritePlayerStateData2ImageBaseOffset], a
-	ld hl, wSpritePlayerStateData1YPixels
-	ld [hl], $3c     ; set Y screen pos
-	inc hl
-	inc hl
-	ld [hl], $40     ; set X screen pos
-	ret
-
-; overwrites sprite data with zeroes
-ResetPlayerSpriteData_ClearSpriteData::
-	ld bc, $10
-	xor a
-	jp FillMemory
-
-FadeOutAudio::
-	ld a, [wAudioFadeOutControl]
-	and a ; currently fading out audio?
-	jr nz, .fadingOut
-	ld a, [wd72c]
-	bit 1, a
-	ret nz
-	ld a, $77
-	ldh [rNR50], a
-	ret
-.fadingOut
-	ld a, [wAudioFadeOutCounter]
-	and a
-	jr z, .counterReachedZero
-	dec a
-	ld [wAudioFadeOutCounter], a
-	ret
-.counterReachedZero
-	ld a, [wAudioFadeOutCounterReloadValue]
-	ld [wAudioFadeOutCounter], a
-	ldh a, [rNR50]
-	and a ; has the volume reached 0?
-	jr z, .fadeOutComplete
-	ld b, a
-	and $f
-	dec a
-	ld c, a
-	ld a, b
-	and $f0
-	swap a
-	dec a
-	swap a
-	or c
-	ldh [rNR50], a
-	ret
-.fadeOutComplete
-	ld a, [wAudioFadeOutControl]
-	ld b, a
-	xor a
-	ld [wAudioFadeOutControl], a
-	ld a, SFX_STOP_ALL_MUSIC
-	ld [wNewSoundID], a
-	call PlaySound
-	ld a, [wAudioSavedROMBank]
-	ld [wAudioROMBank], a
-	ld a, b
-	ld [wNewSoundID], a
-	jp PlaySound
-
+INCLUDE "home/reset_player_sprite.asm"
+INCLUDE "home/fade_audio.asm"
 INCLUDE "home/text_script.asm"
 INCLUDE "home/start_menu.asm"
-
-; function to count how many bits are set in a string of bytes
-; INPUT:
-; hl = address of string of bytes
-; b = length of string of bytes
-; OUTPUT:
-; [wNumSetBits] = number of set bits
-CountSetBits::
-	ld c, 0
-.loop
-	ld a, [hli]
-	ld e, a
-	ld d, 8
-.innerLoop ; count how many bits are set in the current byte
-	srl e
-	ld a, 0
-	adc c
-	ld c, a
-	dec d
-	jr nz, .innerLoop
-	dec b
-	jr nz, .loop
-	ld a, c
-	ld [wNumSetBits], a
-	ret
-
-; subtracts the amount the player paid from their money
-; OUTPUT: carry = 0(success) or 1(fail because there is not enough money)
-SubtractAmountPaidFromMoney::
-	farjp SubtractAmountPaidFromMoney_
-
-; adds the amount the player sold to their money
-AddAmountSoldToMoney::
-	ld de, wPlayerMoney + 2
-	ld hl, hMoney + 2 ; total price of items
-	ld c, 3 ; length of money in bytes
-	predef AddBCDPredef ; add total price to money
-	ld a, MONEY_BOX
-	ld [wTextBoxID], a
-	call DisplayTextBoxID ; redraw money text box
-	ld a, SFX_PURCHASE
-	call PlaySoundWaitForCurrent
-	jp WaitForSoundToFinish
-
-; function to remove an item (in varying quantities) from the player's bag or PC box
-; INPUT:
-; HL = address of inventory (either wNumBagItems or wNumBoxItems)
-; [wWhichPokemon] = index (within the inventory) of the item to remove
-; [wItemQuantity] = quantity to remove
-RemoveItemFromInventory::
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, BANK(RemoveItemFromInventory_)
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	call RemoveItemFromInventory_
-	pop af
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
-; function to add an item (in varying quantities) to the player's bag or PC box
-; INPUT:
-; HL = address of inventory (either wNumBagItems or wNumBoxItems)
-; [wcf91] = item ID
-; [wItemQuantity] = item quantity
-; sets carry flag if successful, unsets carry flag if unsuccessful
-AddItemToInventory::
-	push bc
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, BANK(AddItemToInventory_)
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	call AddItemToInventory_
-	pop bc
-	ld a, b
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	pop bc
-	ret
-
+INCLUDE "home/count_set_bits.asm"
+INCLUDE "home/inventory.asm"
 INCLUDE "home/list_menu.asm"
 INCLUDE "home/names.asm"
-
-; reloads text box tile patterns, current map view, and tileset tile patterns
-ReloadMapData::
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, [wCurMap]
-	call SwitchToMapRomBank
-	call DisableLCD
-	call LoadTextBoxTilePatterns
-	call LoadCurrentMapView
-	call LoadTilesetTilePatternData
-	call EnableLCD
-	pop af
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
-; reloads tileset tile patterns
-ReloadTilesetTilePatterns::
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, [wCurMap]
-	call SwitchToMapRomBank
-	call DisableLCD
-	call LoadTilesetTilePatternData
-	call EnableLCD
-	pop af
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
-; shows the town map and lets the player choose a destination to fly to
-ChooseFlyDestination::
-	ld hl, wd72e
-	res 4, [hl]
-	farjp LoadTownMap_Fly
-
-; causes the text box to close without waiting for a button press after displaying text
-DisableWaitingAfterTextDisplay::
-	ld a, $01
-	ld [wDoNotWaitForButtonPressAfterDisplayingText], a
-	ret
-
-; uses an item
-; UseItem is used with dummy items to perform certain other functions as well
-; INPUT:
-; [wcf91] = item ID
-; OUTPUT:
-; [wActionResultOrTookBattleTurn] = success
-; 00: unsuccessful
-; 01: successful
-; 02: not able to be used right now, no extra menu displayed (only certain items use this)
-UseItem::
-	farjp UseItem_
-
-; confirms the item toss and then tosses the item
-; INPUT:
-; hl = address of inventory (either wNumBagItems or wNumBoxItems)
-; [wcf91] = item ID
-; [wWhichPokemon] = index of item within inventory
-; [wItemQuantity] = quantity to toss
-; OUTPUT:
-; clears carry flag if the item is tossed, sets carry flag if not
-TossItem::
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, BANK(TossItem_)
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	call TossItem_
-	pop de
-	ld a, d
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
-; checks if an item is a key item
-; INPUT:
-; [wcf91] = item ID
-; OUTPUT:
-; [wIsKeyItem] = result
-; 00: item is not key item
-; 01: item is key item
-IsKeyItem::
-	push hl
-	push de
-	push bc
-	farcall IsKeyItem_
-	pop bc
-	pop de
-	pop hl
-	ret
-
-; function to draw various text boxes
-; INPUT:
-; [wTextBoxID] = text box ID
-; b, c = y, x cursor position (TWO_OPTION_MENU only)
-DisplayTextBoxID::
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, BANK(DisplayTextBoxID_)
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	call DisplayTextBoxID_
-	pop bc
-	ld a, b
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
-; not zero if an NPC movement script is running, the player character is
-; automatically stepping down from a door, or joypad states are being simulated
-IsPlayerCharacterBeingControlledByGame::
-	ld a, [wNPCMovementScriptPointerTableNum]
-	and a
-	ret nz
-	ld a, [wd736]
-	bit 1, a ; currently stepping down from door bit
-	ret nz
-	ld a, [wd730]
-	and $80
-	ret
-
-RunNPCMovementScript::
-	ld hl, wd736
-	bit 0, [hl]
-	res 0, [hl]
-	jr nz, .playerStepOutFromDoor
-	ld a, [wNPCMovementScriptPointerTableNum]
-	and a
-	ret z
-	dec a
-	add a
-	ld d, 0
-	ld e, a
-	ld hl, .NPCMovementScriptPointerTables
-	add hl, de
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, [wNPCMovementScriptBank]
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ld a, [wNPCMovementScriptFunctionNum]
-	call CallFunctionInTable
-	pop af
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
-.NPCMovementScriptPointerTables
-	dw PalletMovementScriptPointerTable
-	dw PewterMuseumGuyMovementScriptPointerTable
-	dw PewterGymGuyMovementScriptPointerTable
-.playerStepOutFromDoor
-	farjp PlayerStepOutFromDoor
-
-EndNPCMovementScript::
-	farjp _EndNPCMovementScript
-
-EmptyFunc2::
-	ret
-
+INCLUDE "home/reload_tiles.asm"
+INCLUDE "home/item.asm"
+INCLUDE "home/textbox.asm"
+INCLUDE "home/npc_movement.asm"
 INCLUDE "home/trainers.asm"
-
-; checks if the player's coordinates match an arrow movement tile's coordinates
-; and if so, decodes the RLE movement data
-; b = player Y
-; c = player X
-DecodeArrowMovementRLE::
-	ld a, [hli]
-	cp $ff
-	ret z ; no match in the list
-	cp b
-	jr nz, .nextArrowMovementTileEntry1
-	ld a, [hli]
-	cp c
-	jr nz, .nextArrowMovementTileEntry2
-	ld a, [hli]
-	ld d, [hl]
-	ld e, a
-	ld hl, wSimulatedJoypadStatesEnd
-	call DecodeRLEList
-	dec a
-	ld [wSimulatedJoypadStatesIndex], a
-	ret
-.nextArrowMovementTileEntry1
-	inc hl
-.nextArrowMovementTileEntry2
-	inc hl
-	inc hl
-	jr DecodeArrowMovementRLE
-
-TextScript_ItemStoragePC::
-	call SaveScreenTilesToBuffer2
-	ld b, BANK(PlayerPC)
-	ld hl, PlayerPC
-	jr bankswitchAndContinue
-
-TextScript_BillsPC::
-	call SaveScreenTilesToBuffer2
-	ld b, BANK(BillsPC_)
-	ld hl, BillsPC_
-	jr bankswitchAndContinue
-
-TextScript_GameCornerPrizeMenu::
-; XXX find a better name for this function
-; special_F7
-	ld b, BANK(CeladonPrizeMenu)
-	ld hl, CeladonPrizeMenu
-bankswitchAndContinue::
-	call Bankswitch
-	jp HoldTextDisplayOpen        ; continue to main text-engine function
-
-TextScript_PokemonCenterPC::
-	ld b, BANK(ActivatePC)
-	ld hl, ActivatePC
-	jr bankswitchAndContinue
-
-StartSimulatingJoypadStates::
-	xor a
-	ld [wOverrideSimulatedJoypadStatesMask], a
-	ld [wSpritePlayerStateData2MovementByte1], a
-	ld hl, wd730
-	set 7, [hl]
-	ret
-
-IsItemInBag::
-; given an item_id in b
-; set zero flag if item isn't in player's bag
-; else reset zero flag
-; related to Pokémon Tower and ghosts
-	predef GetQuantityOfItemInBag
-	ld a, b
-	and a
-	ret
-
-DisplayPokedex::
-	ld [wd11e], a
-	farjp _DisplayPokedex
-
-SetSpriteFacingDirectionAndDelay::
-	call SetSpriteFacingDirection
-	ld c, 6
-	jp DelayFrames
-
-SetSpriteFacingDirection::
-	ld a, $9
-	ldh [hSpriteDataOffset], a
-	call GetPointerWithinSpriteStateData1
-	ldh a, [hSpriteFacingDirection]
-	ld [hl], a
-	ret
-
-SetSpriteImageIndexAfterSettingFacingDirection::
-	ld de, -7
-	add hl, de
-	ld [hl], a
-	ret
-
-; tests if the player's coordinates are in a specified array
-; INPUT:
-; hl = address of array
-; OUTPUT:
-; [wCoordIndex] = if there is match, the matching array index
-; sets carry if the coordinates are in the array, clears carry if not
-ArePlayerCoordsInArray::
-	ld a, [wYCoord]
-	ld b, a
-	ld a, [wXCoord]
-	ld c, a
-	; fallthrough
-
-CheckCoords::
-	xor a
-	ld [wCoordIndex], a
-.loop
-	ld a, [hli]
-	cp $ff ; reached terminator?
-	jr z, .notInArray
-	push hl
-	ld hl, wCoordIndex
-	inc [hl]
-	pop hl
-.compareYCoord
-	cp b
-	jr z, .compareXCoord
-	inc hl
-	jr .loop
-.compareXCoord
-	ld a, [hli]
-	cp c
-	jr nz, .loop
-.inArray
-	scf
-	ret
-.notInArray
-	and a
-	ret
-
-; tests if a boulder's coordinates are in a specified array
-; INPUT:
-; hl = address of array
-; [hSpriteIndex] = index of boulder sprite
-; OUTPUT:
-; [wCoordIndex] = if there is match, the matching array index
-; sets carry if the coordinates are in the array, clears carry if not
-CheckBoulderCoords::
-	push hl
-	ld hl, wSpritePlayerStateData2MapY
-	ldh a, [hSpriteIndex]
-	swap a
-	ld d, $0
-	ld e, a
-	add hl, de
-	ld a, [hli]
-	sub $4 ; because sprite coordinates are offset by 4
-	ld b, a
-	ld a, [hl]
-	sub $4 ; because sprite coordinates are offset by 4
-	ld c, a
-	pop hl
-	jp CheckCoords
-
-GetPointerWithinSpriteStateData1::
-	ld h, $c1
-	jr _GetPointerWithinSpriteStateData
-
-GetPointerWithinSpriteStateData2::
-	ld h, $c2
-
-_GetPointerWithinSpriteStateData:
-	ldh a, [hSpriteDataOffset]
-	ld b, a
-	ldh a, [hSpriteIndex]
-	swap a
-	add b
-	ld l, a
-	ret
-
-; decodes a $ff-terminated RLEncoded list
-; each entry is a pair of bytes <byte value> <repetitions>
-; the final $ff will be replicated in the output list and a contains the number of bytes written
-; de: input list
-; hl: output list
-DecodeRLEList::
-	xor a
-	ld [wRLEByteCount], a     ; count written bytes here
-.listLoop
-	ld a, [de]
-	cp $ff
-	jr z, .endOfList
-	ldh [hRLEByteValue], a ; store byte value to be written
-	inc de
-	ld a, [de]
-	ld b, $0
-	ld c, a                      ; number of bytes to be written
-	ld a, [wRLEByteCount]
-	add c
-	ld [wRLEByteCount], a     ; update total number of written bytes
-	ldh a, [hRLEByteValue]
-	call FillMemory              ; write a c-times to output
-	inc de
-	jr .listLoop
-.endOfList
-	ld a, $ff
-	ld [hl], a                   ; write final $ff
-	ld a, [wRLEByteCount]
-	inc a                        ; include sentinel in counting
-	ret
-
-; sets movement byte 1 for sprite [hSpriteIndex] to $FE and byte 2 to [hSpriteMovementByte2]
-SetSpriteMovementBytesToFE::
-	push hl
-	call GetSpriteMovementByte1Pointer
-	ld [hl], $fe
-	call GetSpriteMovementByte2Pointer
-	ldh a, [hSpriteMovementByte2]
-	ld [hl], a
-	pop hl
-	ret
-
-; sets both movement bytes for sprite [hSpriteIndex] to $FF
-SetSpriteMovementBytesToFF::
-	push hl
-	call GetSpriteMovementByte1Pointer
-	ld [hl], $FF
-	call GetSpriteMovementByte2Pointer
-	ld [hl], $FF ; prevent person from walking?
-	pop hl
-	ret
-
-; returns the sprite movement byte 1 pointer for sprite [hSpriteIndex] in hl
-GetSpriteMovementByte1Pointer::
-	ld h, $C2
-	ldh a, [hSpriteIndex]
-	swap a
-	add 6
-	ld l, a
-	ret
-
-; returns the sprite movement byte 2 pointer for sprite [hSpriteIndex] in hl
-GetSpriteMovementByte2Pointer::
-	push de
-	ld hl, wMapSpriteData
-	ldh a, [hSpriteIndex]
-	dec a
-	add a
-	ld d, 0
-	ld e, a
-	add hl, de
-	pop de
-	ret
-
-GetTrainerInformation::
-	call GetTrainerName
-	ld a, [wLinkState]
-	and a
-	jr nz, .linkBattle
-	ld a, BANK(TrainerPicAndMoneyPointers)
-	call BankswitchHome
-	ld a, [wTrainerClass]
-	dec a
-	ld hl, TrainerPicAndMoneyPointers
-	ld bc, $5
-	call AddNTimes
-	ld de, wTrainerPicPointer
-	ld a, [hli]
-	ld [de], a
-	inc de
-	ld a, [hli]
-	ld [de], a
-	ld de, wTrainerBaseMoney
-	ld a, [hli]
-	ld [de], a
-	inc de
-	ld a, [hli]
-	ld [de], a
-	jp BankswitchBack
-.linkBattle
-	ld hl, wTrainerPicPointer
-	ld de, RedPicFront
-	ld [hl], e
-	inc hl
-	ld [hl], d
-	ret
-
-GetTrainerName::
-	farjp GetTrainerName_
-
-HasEnoughMoney::
-; Check if the player has at least as much
-; money as the 3-byte BCD value at hMoney.
-	ld de, wPlayerMoney
-	ld hl, hMoney
-	ld c, 3
-	jp StringCmp
-
-HasEnoughCoins::
-; Check if the player has at least as many
-; coins as the 2-byte BCD value at hCoins.
-	ld de, wPlayerCoins
-	ld hl, hCoins
-	ld c, 2
-	jp StringCmp
-
+INCLUDE "home/map_objects.asm"
+INCLUDE "home/trainers2.asm"
+INCLUDE "home/money.asm"
 INCLUDE "home/bankswitch.asm"
 INCLUDE "home/yes_no.asm"
-
-; calculates the difference |a-b|, setting carry flag if a<b
-CalcDifference::
-	sub b
-	ret nc
-	cpl
-	add $1
-	scf
-	ret
-
-MoveSprite::
-; move the sprite [hSpriteIndex] with the movement pointed to by de
-; actually only copies the movement data to wNPCMovementDirections for later
-	call SetSpriteMovementBytesToFF
-MoveSprite_::
-	push hl
-	push bc
-	call GetSpriteMovementByte1Pointer
-	xor a
-	ld [hl], a
-	ld hl, wNPCMovementDirections
-	ld c, 0
-
-.loop
-	ld a, [de]
-	ld [hli], a
-	inc de
-	inc c
-	cp $FF ; have we reached the end of the movement data?
-	jr nz, .loop
-
-	ld a, c
-	ld [wNPCNumScriptedSteps], a ; number of steps taken
-
-	pop bc
-	ld hl, wd730
-	set 0, [hl]
-	pop hl
-	xor a
-	ld [wOverrideSimulatedJoypadStatesMask], a
-	ld [wSimulatedJoypadStatesEnd], a
-	dec a
-	ld [wJoyIgnore], a
-	ld [wWastedByteCD3A], a
-	ret
-
-; divides [hDividend2] by [hDivisor2] and stores the quotient in [hQuotient2]
-DivideBytes::
-	push hl
-	ld hl, hQuotient2
-	xor a
-	ld [hld], a
-	ld a, [hld]
-	and a
-	jr z, .done
-	ld a, [hli]
-.loop
-	sub [hl]
-	jr c, .done
-	inc hl
-	inc [hl]
-	dec hl
-	jr .loop
-.done
-	pop hl
-	ret
-
-LoadFontTilePatterns::
-	ldh a, [rLCDC]
-	bit 7, a ; is the LCD enabled?
-	jr nz, .on
-.off
-	ld hl, FontGraphics
-	ld de, vFont
-	ld bc, FontGraphicsEnd - FontGraphics
-	ld a, BANK(FontGraphics)
-	jp FarCopyDataDouble ; if LCD is off, transfer all at once
-.on
-	ld de, FontGraphics
-	ld hl, vFont
-	lb bc, BANK(FontGraphics), (FontGraphicsEnd - FontGraphics) / $8
-	jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
-
-LoadTextBoxTilePatterns::
-	ldh a, [rLCDC]
-	bit 7, a ; is the LCD enabled?
-	jr nz, .on
-.off
-	ld hl, TextBoxGraphics
-	ld de, vChars2 tile $60
-	ld bc, TextBoxGraphicsEnd - TextBoxGraphics
-	ld a, BANK(TextBoxGraphics)
-	jp FarCopyData2 ; if LCD is off, transfer all at once
-.on
-	ld de, TextBoxGraphics
-	ld hl, vChars2 tile $60
-	lb bc, BANK(TextBoxGraphics), (TextBoxGraphicsEnd - TextBoxGraphics) / $10
-	jp CopyVideoData ; if LCD is on, transfer during V-blank
-
-LoadHpBarAndStatusTilePatterns::
-	ldh a, [rLCDC]
-	bit 7, a ; is the LCD enabled?
-	jr nz, .on
-.off
-	ld hl, HpBarAndStatusGraphics
-	ld de, vChars2 tile $62
-	ld bc, HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics
-	ld a, BANK(HpBarAndStatusGraphics)
-	jp FarCopyData2 ; if LCD is off, transfer all at once
-.on
-	ld de, HpBarAndStatusGraphics
-	ld hl, vChars2 tile $62
-	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
-	ld d, a
-.loop
-	ld a, d
-	ld [hli], a
-	dec bc
-	ld a, b
-	or c
-	jr nz, .loop
-	pop de
-	ret
-
-UncompressSpriteFromDE::
-; Decompress pic at a:de.
-	ld hl, wSpriteInputPtr
-	ld [hl], e
-	inc hl
-	ld [hl], d
-	jp UncompressSpriteData
-
-SaveScreenTilesToBuffer2::
-	hlcoord 0, 0
-	ld de, wTileMapBackup2
-	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
-	call CopyData
-	ret
-
-LoadScreenTilesFromBuffer2::
-	call LoadScreenTilesFromBuffer2DisableBGTransfer
-	ld a, 1
-	ldh [hAutoBGTransferEnabled], a
-	ret
-
-; loads screen tiles stored in wTileMapBackup2 but leaves hAutoBGTransferEnabled disabled
-LoadScreenTilesFromBuffer2DisableBGTransfer::
-	xor a
-	ldh [hAutoBGTransferEnabled], a
-	ld hl, wTileMapBackup2
-	decoord 0, 0
-	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
-	call CopyData
-	ret
-
-SaveScreenTilesToBuffer1::
-	hlcoord 0, 0
-	ld de, wTileMapBackup
-	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
-	jp CopyData
-
-LoadScreenTilesFromBuffer1::
-	xor a
-	ldh [hAutoBGTransferEnabled], a
-	ld hl, wTileMapBackup
-	decoord 0, 0
-	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
-	call CopyData
-	ld a, 1
-	ldh [hAutoBGTransferEnabled], a
-	ret
-
-DelayFrames::
-; wait c frames
-	call DelayFrame
-	dec c
-	jr nz, DelayFrames
-	ret
-
-PlaySoundWaitForCurrent::
-	push af
-	call WaitForSoundToFinish
-	pop af
-	jp PlaySound
-
-; Wait for sound to finish playing
-WaitForSoundToFinish::
-	ld a, [wLowHealthAlarm]
-	and $80
-	ret nz
-	push hl
-.waitLoop
-	ld hl, wChannelSoundIDs + Ch5
-	xor a
-	or [hl]
-	inc hl
-	or [hl]
-	inc hl
-	inc hl
-	or [hl]
-	jr nz, .waitLoop
-	pop hl
-	ret
-
+INCLUDE "home/pathfinding.asm"
+INCLUDE "home/load_font.asm"
+INCLUDE "home/tilemap.asm"
+INCLUDE "home/delay.asm"
 INCLUDE "home/names2.asm"
-
-GetItemPrice::
-; Stores item's price as BCD at hItemPrice (3 bytes)
-; Input: [wcf91] = item id
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, [wListMenuID]
-	cp MOVESLISTMENU
-	ld a, BANK(ItemPrices)
-	jr nz, .ok
-	ld a, $f ; hardcoded Bank
-.ok
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ld hl, wItemPrices
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-	ld a, [wcf91] ; a contains item id
-	cp HM01
-	jr nc, .getTMPrice
-	ld bc, $3
-.loop
-	add hl, bc
-	dec a
-	jr nz, .loop
-	dec hl
-	ld a, [hld]
-	ldh [hItemPrice + 2], a
-	ld a, [hld]
-	ldh [hItemPrice + 1], a
-	ld a, [hl]
-	ldh [hItemPrice], a
-	jr .done
-.getTMPrice
-	ld a, BANK(GetMachinePrice)
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	call GetMachinePrice
-.done
-	ld de, hItemPrice
-	pop af
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	ret
-
-; copies a string from [de] to [wcf4b]
-CopyStringToCF4B::
-	ld hl, wcf4b
-	; fall through
-
-; copies a string from [de] to [hl]
-CopyString::
-	ld a, [de]
-	inc de
-	ld [hli], a
-	cp "@"
-	jr nz, CopyString
-	ret
-
-; this function is used when lower button sensitivity is wanted (e.g. menus)
-; OUTPUT: [hJoy5] = pressed buttons in usual format
-; there are two flags that control its functionality, [hJoy6] and [hJoy7]
-; there are essentially three modes of operation
-; 1. Get newly pressed buttons only
-;    ([hJoy7] == 0, [hJoy6] == any)
-;    Just copies [hJoyPressed] to [hJoy5].
-; 2. Get currently pressed buttons at low sample rate with delay
-;    ([hJoy7] == 1, [hJoy6] != 0)
-;    If the user holds down buttons for more than half a second,
-;    report buttons as being pressed up to 12 times per second thereafter.
-;    If the user holds down buttons for less than half a second,
-;    report only one button press.
-; 3. Same as 2, but report no buttons as pressed if A or B is held down.
-;    ([hJoy7] == 1, [hJoy6] == 0)
-JoypadLowSensitivity::
-	call Joypad
-	ldh a, [hJoy7] ; flag
-	and a ; get all currently pressed buttons or only newly pressed buttons?
-	ldh a, [hJoyPressed] ; newly pressed buttons
-	jr z, .storeButtonState
-	ldh a, [hJoyHeld] ; all currently pressed buttons
-.storeButtonState
-	ldh [hJoy5], a
-	ldh a, [hJoyPressed] ; newly pressed buttons
-	and a ; have any buttons been newly pressed since last check?
-	jr z, .noNewlyPressedButtons
-.newlyPressedButtons
-	ld a, 30 ; half a second delay
-	ldh [hFrameCounter], a
-	ret
-.noNewlyPressedButtons
-	ldh a, [hFrameCounter]
-	and a ; is the delay over?
-	jr z, .delayOver
-.delayNotOver
-	xor a
-	ldh [hJoy5], a ; report no buttons as pressed
-	ret
-.delayOver
-; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed
-	ldh a, [hJoyHeld]
-	and A_BUTTON | B_BUTTON
-	jr z, .setShortDelay
-	ldh a, [hJoy6] ; flag
-	and a
-	jr nz, .setShortDelay
-	xor a
-	ldh [hJoy5], a
-.setShortDelay
-	ld a, 5 ; 1/12 of a second delay
-	ldh [hFrameCounter], a
-	ret
-
-WaitForTextScrollButtonPress::
-	ldh a, [hDownArrowBlinkCount1]
-	push af
-	ldh a, [hDownArrowBlinkCount2]
-	push af
-	xor a
-	ldh [hDownArrowBlinkCount1], a
-	ld a, $6
-	ldh [hDownArrowBlinkCount2], a
-.loop
-	push hl
-	ld a, [wTownMapSpriteBlinkingEnabled]
-	and a
-	jr z, .skipAnimation
-	call TownMapSpriteBlinkingAnimation
-.skipAnimation
-	hlcoord 18, 16
-	call HandleDownArrowBlinkTiming
-	pop hl
-	call JoypadLowSensitivity
-	predef CableClub_Run
-	ldh a, [hJoy5]
-	and A_BUTTON | B_BUTTON
-	jr z, .loop
-	pop af
-	ldh [hDownArrowBlinkCount2], a
-	pop af
-	ldh [hDownArrowBlinkCount1], a
-	ret
-
-; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect
-ManualTextScroll::
-	ld a, [wLinkState]
-	cp LINK_STATE_BATTLING
-	jr z, .inLinkBattle
-	call WaitForTextScrollButtonPress
-	ld a, SFX_PRESS_AB
-	jp PlaySound
-.inLinkBattle
-	ld c, 65
-	jp DelayFrames
-
-; function to do multiplication
-; all values are big endian
-; INPUT
-; FF96-FF98 =  multiplicand
-; FF99 = multiplier
-; OUTPUT
-; FF95-FF98 = product
-Multiply::
-	push hl
-	push bc
-	callfar _Multiply
-	pop bc
-	pop hl
-	ret
-
-; function to do division
-; all values are big endian
-; INPUT
-; FF95-FF98 = dividend
-; FF99 = divisor
-; b = number of bytes in the dividend (starting from FF95)
-; OUTPUT
-; FF95-FF98 = quotient
-; FF99 = remainder
-Divide::
-	push hl
-	push de
-	push bc
-	ldh a, [hLoadedROMBank]
-	push af
-	ld a, BANK(_Divide)
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	call _Divide
-	pop af
-	ldh [hLoadedROMBank], a
-	ld [MBC1RomBank], a
-	pop bc
-	pop de
-	pop hl
-	ret
-
-; This function is used to wait a short period after printing a letter to the
-; screen unless the player presses the A/B button or the delay is turned off
-; through the [wd730] or [wLetterPrintingDelayFlags] flags.
-PrintLetterDelay::
-	ld a, [wd730]
-	bit 6, a
-	ret nz
-	ld a, [wLetterPrintingDelayFlags]
-	bit 1, a
-	ret z
-	push hl
-	push de
-	push bc
-	ld a, [wLetterPrintingDelayFlags]
-	bit 0, a
-	jr z, .waitOneFrame
-	ld a, [wOptions]
-	and $f
-	ldh [hFrameCounter], a
-	jr .checkButtons
-.waitOneFrame
-	ld a, 1
-	ldh [hFrameCounter], a
-.checkButtons
-	call Joypad
-	ldh a, [hJoyHeld]
-.checkAButton
-	bit 0, a ; is the A button pressed?
-	jr z, .checkBButton
-	jr .endWait
-.checkBButton
-	bit 1, a ; is the B button pressed?
-	jr z, .buttonsNotPressed
-.endWait
-	call DelayFrame
-	jr .done
-.buttonsNotPressed ; if neither A nor B is pressed
-	ldh a, [hFrameCounter]
-	and a
-	jr nz, .checkButtons
-.done
-	pop bc
-	pop de
-	pop hl
-	ret
-
-; Copies [hl, bc) to [de, de + bc - hl).
-; In other words, the source data is from hl up to but not including bc,
-; and the destination is de.
-CopyDataUntil::
-	ld a, [hli]
-	ld [de], a
-	inc de
-	ld a, h
-	cp b
-	jr nz, CopyDataUntil
-	ld a, l
-	cp c
-	jr nz, CopyDataUntil
-	ret
-
+INCLUDE "home/item_price.asm"
+INCLUDE "home/copy_string.asm"
+INCLUDE "home/joypad2.asm"
+INCLUDE "home/math.asm"
+INCLUDE "home/print_text.asm"
 INCLUDE "home/move_mon.asm"
-
-; 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::
-	and a
-	ret z
-	ld bc, NAME_LENGTH
-.skipLoop
-	add hl, bc
-	dec a
-	jr nz, .skipLoop
-	ret
-
-AddNTimes::
-; add bc to hl a times
-	and a
-	ret z
-.loop
-	add hl, bc
-	dec a
-	jr nz, .loop
-	ret
-
-; Compare strings, c bytes in length, at de and hl.
-; Often used to compare big endian numbers in battle calculations.
-StringCmp::
-	ld a, [de]
-	cp [hl]
-	ret nz
-	inc de
-	inc hl
-	dec c
-	jr nz, StringCmp
-	ret
-
-; INPUT:
-; a = oam block index (each block is 4 oam entries)
-; b = Y coordinate of upper left corner of sprite
-; c = X coordinate of upper left corner of sprite
-; de = base address of 4 tile number and attribute pairs
-WriteOAMBlock::
-	ld h, HIGH(wOAMBuffer)
-	swap a ; multiply by 16
-	ld l, a
-	call .writeOneEntry ; upper left
-	push bc
-	ld a, 8
-	add c
-	ld c, a
-	call .writeOneEntry ; upper right
-	pop bc
-	ld a, 8
-	add b
-	ld b, a
-	call .writeOneEntry ; lower left
-	ld a, 8
-	add c
-	ld c, a
-	                      ; lower right
-.writeOneEntry
-	ld [hl], b ; Y coordinate
-	inc hl
-	ld [hl], c ; X coordinate
-	inc hl
-	ld a, [de] ; tile number
-	inc de
-	ld [hli], a
-	ld a, [de] ; attribute
-	inc de
-	ld [hli], a
-	ret
-
-HandleMenuInput::
-	xor a
-	ld [wPartyMenuAnimMonEnabled], a
-
-HandleMenuInput_::
-	ldh a, [hDownArrowBlinkCount1]
-	push af
-	ldh a, [hDownArrowBlinkCount2]
-	push af ; save existing values on stack
-	xor a
-	ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1
-	ld a, 6
-	ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2
-.loop1
-	xor a
-	ld [wAnimCounter], a ; counter for pokemon shaking animation
-	call PlaceMenuCursor
-	call Delay3
-.loop2
-	push hl
-	ld a, [wPartyMenuAnimMonEnabled]
-	and a ; is it a pokemon selection menu?
-	jr z, .getJoypadState
-	farcall AnimatePartyMon ; shake mini sprite of selected pokemon
-.getJoypadState
-	pop hl
-	call JoypadLowSensitivity
-	ldh a, [hJoy5]
-	and a ; was a key pressed?
-	jr nz, .keyPressed
-	push hl
-	hlcoord 18, 11 ; coordinates of blinking down arrow in some menus
-	call HandleDownArrowBlinkTiming ; blink down arrow (if any)
-	pop hl
-	ld a, [wMenuJoypadPollCount]
-	dec a
-	jr z, .giveUpWaiting
-	jr .loop2
-.giveUpWaiting
-; if a key wasn't pressed within the specified number of checks
-	pop af
-	ldh [hDownArrowBlinkCount2], a
-	pop af
-	ldh [hDownArrowBlinkCount1], a ; restore previous values
-	xor a
-	ld [wMenuWrappingEnabled], a ; disable menu wrapping
-	ret
-.keyPressed
-	xor a
-	ld [wCheckFor180DegreeTurn], a
-	ldh a, [hJoy5]
-	ld b, a
-	bit 6, a ; pressed Up key?
-	jr z, .checkIfDownPressed
-.upPressed
-	ld a, [wCurrentMenuItem] ; selected menu item
-	and a ; already at the top of the menu?
-	jr z, .alreadyAtTop
-.notAtTop
-	dec a
-	ld [wCurrentMenuItem], a ; move selected menu item up one space
-	jr .checkOtherKeys
-.alreadyAtTop
-	ld a, [wMenuWrappingEnabled]
-	and a ; is wrapping around enabled?
-	jr z, .noWrappingAround
-	ld a, [wMaxMenuItem]
-	ld [wCurrentMenuItem], a ; wrap to the bottom of the menu
-	jr .checkOtherKeys
-.checkIfDownPressed
-	bit 7, a
-	jr z, .checkOtherKeys
-.downPressed
-	ld a, [wCurrentMenuItem]
-	inc a
-	ld c, a
-	ld a, [wMaxMenuItem]
-	cp c
-	jr nc, .notAtBottom
-.alreadyAtBottom
-	ld a, [wMenuWrappingEnabled]
-	and a ; is wrapping around enabled?
-	jr z, .noWrappingAround
-	ld c, $00 ; wrap from bottom to top
-.notAtBottom
-	ld a, c
-	ld [wCurrentMenuItem], a
-.checkOtherKeys
-	ld a, [wMenuWatchedKeys]
-	and b ; does the menu care about any of the pressed keys?
-	jp z, .loop1
-.checkIfAButtonOrBButtonPressed
-	ldh a, [hJoy5]
-	and A_BUTTON | B_BUTTON
-	jr z, .skipPlayingSound
-.AButtonOrBButtonPressed
-	push hl
-	ld hl, wFlags_0xcd60
-	bit 5, [hl]
-	pop hl
-	jr nz, .skipPlayingSound
-	ld a, SFX_PRESS_AB
-	call PlaySound
-.skipPlayingSound
-	pop af
-	ldh [hDownArrowBlinkCount2], a
-	pop af
-	ldh [hDownArrowBlinkCount1], a ; restore previous values
-	xor a
-	ld [wMenuWrappingEnabled], a ; disable menu wrapping
-	ldh a, [hJoy5]
-	ret
-.noWrappingAround
-	ld a, [wMenuWatchMovingOutOfBounds]
-	and a ; should we return if the user tried to go past the top or bottom?
-	jr z, .checkOtherKeys
-	jr .checkIfAButtonOrBButtonPressed
-
-PlaceMenuCursor::
-	ld a, [wTopMenuItemY]
-	and a ; is the y coordinate 0?
-	jr z, .adjustForXCoord
-	hlcoord 0, 0
-	ld bc, SCREEN_WIDTH
-.topMenuItemLoop
-	add hl, bc
-	dec a
-	jr nz, .topMenuItemLoop
-.adjustForXCoord
-	ld a, [wTopMenuItemX]
-	ld b, 0
-	ld c, a
-	add hl, bc
-	push hl
-	ld a, [wLastMenuItem]
-	and a ; was the previous menu id 0?
-	jr z, .checkForArrow1
-	push af
-	ldh a, [hFlagsFFF6]
-	bit 1, a ; is the menu double spaced?
-	jr z, .doubleSpaced1
-	ld bc, 20
-	jr .getOldMenuItemScreenPosition
-.doubleSpaced1
-	ld bc, 40
-.getOldMenuItemScreenPosition
-	pop af
-.oldMenuItemLoop
-	add hl, bc
-	dec a
-	jr nz, .oldMenuItemLoop
-.checkForArrow1
-	ld a, [hl]
-	cp "▶" ; was an arrow next to the previously selected menu item?
-	jr nz, .skipClearingArrow
-.clearArrow
-	ld a, [wTileBehindCursor]
-	ld [hl], a
-.skipClearingArrow
-	pop hl
-	ld a, [wCurrentMenuItem]
-	and a
-	jr z, .checkForArrow2
-	push af
-	ldh a, [hFlagsFFF6]
-	bit 1, a ; is the menu double spaced?
-	jr z, .doubleSpaced2
-	ld bc, 20
-	jr .getCurrentMenuItemScreenPosition
-.doubleSpaced2
-	ld bc, 40
-.getCurrentMenuItemScreenPosition
-	pop af
-.currentMenuItemLoop
-	add hl, bc
-	dec a
-	jr nz, .currentMenuItemLoop
-.checkForArrow2
-	ld a, [hl]
-	cp "▶" ; has the right arrow already been placed?
-	jr z, .skipSavingTile ; if so, don't lose the saved tile
-	ld [wTileBehindCursor], a ; save tile before overwriting with right arrow
-.skipSavingTile
-	ld a, "▶" ; place right arrow
-	ld [hl], a
-	ld a, l
-	ld [wMenuCursorLocation], a
-	ld a, h
-	ld [wMenuCursorLocation + 1], a
-	ld a, [wCurrentMenuItem]
-	ld [wLastMenuItem], a
-	ret
-
-; This is used to mark a menu cursor other than the one currently being
-; manipulated. In the case of submenus, this is used to show the location of
-; the menu cursor in the parent menu. In the case of swapping items in list,
-; this is used to mark the item that was first chosen to be swapped.
-PlaceUnfilledArrowMenuCursor::
-	ld b, a
-	ld a, [wMenuCursorLocation]
-	ld l, a
-	ld a, [wMenuCursorLocation + 1]
-	ld h, a
-	ld [hl], $ec ; outline of right arrow
-	ld a, b
-	ret
-
-; Replaces the menu cursor with a blank space.
-EraseMenuCursor::
-	ld a, [wMenuCursorLocation]
-	ld l, a
-	ld a, [wMenuCursorLocation + 1]
-	ld h, a
-	ld [hl], " "
-	ret
-
-; This toggles a blinking down arrow at hl on and off after a delay has passed.
-; This is often called even when no blinking is occurring.
-; The reason is that most functions that call this initialize hDownArrowBlinkCount1 to 0.
-; The effect is that if the tile at hl is initialized with a down arrow,
-; this function will toggle that down arrow on and off, but if the tile isn't
-; initialized with a down arrow, this function does nothing.
-; That allows this to be called without worrying about if a down arrow should
-; be blinking.
-HandleDownArrowBlinkTiming::
-	ld a, [hl]
-	ld b, a
-	ld a, "▼"
-	cp b
-	jr nz, .downArrowOff
-.downArrowOn
-	ldh a, [hDownArrowBlinkCount1]
-	dec a
-	ldh [hDownArrowBlinkCount1], a
-	ret nz
-	ldh a, [hDownArrowBlinkCount2]
-	dec a
-	ldh [hDownArrowBlinkCount2], a
-	ret nz
-	ld a, " "
-	ld [hl], a
-	ld a, $ff
-	ldh [hDownArrowBlinkCount1], a
-	ld a, $06
-	ldh [hDownArrowBlinkCount2], a
-	ret
-.downArrowOff
-	ldh a, [hDownArrowBlinkCount1]
-	and a
-	ret z
-	dec a
-	ldh [hDownArrowBlinkCount1], a
-	ret nz
-	dec a
-	ldh [hDownArrowBlinkCount1], a
-	ldh a, [hDownArrowBlinkCount2]
-	dec a
-	ldh [hDownArrowBlinkCount2], a
-	ret nz
-	ld a, $06
-	ldh [hDownArrowBlinkCount2], a
-	ld a, "▼"
-	ld [hl], a
-	ret
-
-; The following code either enables or disables the automatic drawing of
-; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait
-; for a button press after displaying text (unless [wEnteringCableClub] is set).
-
-EnableAutoTextBoxDrawing::
-	xor a
-	jr AutoTextBoxDrawingCommon
-
-DisableAutoTextBoxDrawing::
-	ld a, $01
-
-AutoTextBoxDrawingCommon::
-	ld [wAutoTextBoxDrawingControl], a
-	xor a
-	ld [wDoNotWaitForButtonPressAfterDisplayingText], a ; make DisplayTextID wait for button press
-	ret
-
-PrintText::
-; Print text hl at (1, 14).
-	push hl
-	ld a, MESSAGE_BOX
-	ld [wTextBoxID], a
-	call DisplayTextBoxID
-	call UpdateSprites
-	call Delay3
-	pop hl
-PrintText_NoCreatingTextBox::
-	bccoord 1, 14
-	jp TextCommandProcessor
-
+INCLUDE "home/array.asm"
+INCLUDE "home/compare.asm"
+INCLUDE "home/oam.asm"
+INCLUDE "home/window.asm"
 INCLUDE "home/print_num.asm"
-
-CallFunctionInTable::
-; Call function a in jumptable hl.
-; de is not preserved.
-	push hl
-	push de
-	push bc
-	add a
-	ld d, 0
-	ld e, a
-	add hl, de
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-	ld de, .returnAddress
-	push de
-	jp hl
-.returnAddress
-	pop bc
-	pop de
-	pop hl
-	ret
-
-IsInArray::
-; Search an array at hl for the value in a.
-; Entry size is de bytes.
-; Return count b and carry if found.
-	ld b, 0
-
-IsInRestOfArray::
-	ld c, a
-.loop
-	ld a, [hl]
-	cp -1
-	jr z, .notfound
-	cp c
-	jr z, .found
-	inc b
-	add hl, de
-	jr .loop
-
-.notfound
-	and a
-	ret
-
-.found
-	scf
-	ret
-
-RestoreScreenTilesAndReloadTilePatterns::
-	call ClearSprites
-	ld a, $1
-	ld [wUpdateSpritesEnabled], a
-	call ReloadMapSpriteTilePatterns
-	call LoadScreenTilesFromBuffer2
-	call LoadTextBoxTilePatterns
-	call RunDefaultPaletteCommand
-	jr Delay3
-
-GBPalWhiteOutWithDelay3::
-	call GBPalWhiteOut
-
-Delay3::
-; The bg map is updated each frame in thirds.
-; Wait three frames to let the bg map fully update.
-	ld c, 3
-	jp DelayFrames
-
-GBPalNormal::
-; Reset BGP and OBP0.
-	ld a, %11100100 ; 3210
-	ldh [rBGP], a
-	ld a, %11010000 ; 3100
-	ldh [rOBP0], a
-	ret
-
-GBPalWhiteOut::
-; White out all palettes.
-	xor a
-	ldh [rBGP], a
-	ldh [rOBP0], a
-	ldh [rOBP1], a
-	ret
-
-RunDefaultPaletteCommand::
-	ld b, SET_PAL_DEFAULT
-RunPaletteCommand::
-	ld a, [wOnSGB]
-	and a
-	ret z
-	predef_jump _RunPaletteCommand
-
-GetHealthBarColor::
-; Return at hl the palette of
-; an HP bar e pixels long.
-	ld a, e
-	cp 27
-	ld d, 0 ; green
-	jr nc, .gotColor
-	cp 10
-	inc d ; yellow
-	jr nc, .gotColor
-	inc d ; red
-.gotColor
-	ld [hl], d
-	ret
-
-; Copy the current map's sprites' tile patterns to VRAM again after they have
-; been overwritten by other tile patterns.
-ReloadMapSpriteTilePatterns::
-	ld hl, wFontLoaded
-	ld a, [hl]
-	push af
-	res 0, [hl]
-	push hl
-	xor a
-	ld [wSpriteSetID], a
-	call DisableLCD
-	farcall InitMapSprites
-	call EnableLCD
-	pop hl
-	pop af
-	ld [hl], a
-	call LoadPlayerSpriteGraphics
-	call LoadFontTilePatterns
-	jp UpdateSprites
-
-GiveItem::
-; Give player quantity c of item b,
-; and copy the item's name to wcf4b.
-; Return carry on success.
-	ld a, b
-	ld [wd11e], a
-	ld [wcf91], a
-	ld a, c
-	ld [wItemQuantity], a
-	ld hl, wNumBagItems
-	call AddItemToInventory
-	ret nc
-	call GetItemName
-	call CopyStringToCF4B
-	scf
-	ret
-
-GivePokemon::
-; Give the player monster b at level c.
-	ld a, b
-	ld [wcf91], a
-	ld a, c
-	ld [wCurEnemyLVL], a
-	xor a ; PLAYER_PARTY_DATA
-	ld [wMonDataLocation], a
-	farjp _GivePokemon
-
-Random::
-; Return a random number in a.
-; For battles, use BattleRandom.
-	push hl
-	push de
-	push bc
-	farcall Random_
-	ldh a, [hRandomAdd]
-	pop bc
-	pop de
-	pop hl
-	ret
-
+INCLUDE "home/array2.asm"
+INCLUDE "home/palettes.asm"
+INCLUDE "home/reload_sprites.asm"
+INCLUDE "home/give.asm"
+INCLUDE "home/random.asm"
 INCLUDE "home/predef.asm"
-
-UpdateCinnabarGymGateTileBlocks::
-	farjp UpdateCinnabarGymGateTileBlocks_
-
-CheckForHiddenObjectOrBookshelfOrCardKeyDoor::
-	ldh a, [hLoadedROMBank]
-	push af
-	ldh a, [hJoyHeld]
-	bit 0, a ; A button
-	jr z, .nothingFound
-; A button is pressed
-	ld a, BANK(CheckForHiddenObject)
-	ld [MBC1RomBank], a
-	ldh [hLoadedROMBank], a
-	call CheckForHiddenObject
-	ldh a, [hDidntFindAnyHiddenObject]
-	and a
-	jr nz, .hiddenObjectNotFound
-	ld a, [wHiddenObjectFunctionRomBank]
-	ld [MBC1RomBank], a
-	ldh [hLoadedROMBank], a
-	ld de, .returnAddress
-	push de
-	jp hl
-.returnAddress
-	xor a
-	jr .done
-.hiddenObjectNotFound
-	farcall PrintBookshelfText
-	ldh a, [hFFDB]
-	and a
-	jr z, .done
-.nothingFound
-	ld a, $ff
-.done
-	ldh [hItemAlreadyFound], a
-	pop af
-	ld [MBC1RomBank], a
-	ldh [hLoadedROMBank], a
-	ret
-
-PrintPredefTextID::
-	ldh [hSpriteIndexOrTextID], a
-	ld hl, TextPredefs
-	call SetMapTextPointer
-	ld hl, wTextPredefFlag
-	set 0, [hl]
-	call DisplayTextID
-
-RestoreMapTextPointer::
-	ld hl, wMapTextPtr
-	ldh a, [hSavedMapTextPtr]
-	ld [hli], a
-	ldh a, [hSavedMapTextPtr + 1]
-	ld [hl], a
-	ret
-
-SetMapTextPointer::
-	ld a, [wMapTextPtr]
-	ldh [hSavedMapTextPtr], a
-	ld a, [wMapTextPtr + 1]
-	ldh [hSavedMapTextPtr + 1], a
-	ld a, l
-	ld [wMapTextPtr], a
-	ld a, h
-	ld [wMapTextPtr + 1], a
-	ret
-
-INCLUDE "data/text_predef_pointers.asm"
+INCLUDE "home/hidden_objects.asm"
+INCLUDE "home/predef_text.asm"
--- /dev/null
+++ b/home/array.asm
@@ -1,0 +1,21 @@
+; 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::
+	and a
+	ret z
+	ld bc, NAME_LENGTH
+.skipLoop
+	add hl, bc
+	dec a
+	jr nz, .skipLoop
+	ret
+
+AddNTimes::
+; add bc to hl a times
+	and a
+	ret z
+.loop
+	add hl, bc
+	dec a
+	jr nz, .loop
+	ret
--- /dev/null
+++ b/home/array2.asm
@@ -1,0 +1,47 @@
+CallFunctionInTable::
+; Call function a in jumptable hl.
+; de is not preserved.
+	push hl
+	push de
+	push bc
+	add a
+	ld d, 0
+	ld e, a
+	add hl, de
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+	ld de, .returnAddress
+	push de
+	jp hl
+.returnAddress
+	pop bc
+	pop de
+	pop hl
+	ret
+
+IsInArray::
+; Search an array at hl for the value in a.
+; Entry size is de bytes.
+; Return count b and carry if found.
+	ld b, 0
+
+IsInRestOfArray::
+	ld c, a
+.loop
+	ld a, [hl]
+	cp -1
+	jr z, .notfound
+	cp c
+	jr z, .found
+	inc b
+	add hl, de
+	jr .loop
+
+.notfound
+	and a
+	ret
+
+.found
+	scf
+	ret
--- /dev/null
+++ b/home/compare.asm
@@ -1,0 +1,11 @@
+; Compare strings, c bytes in length, at de and hl.
+; Often used to compare big endian numbers in battle calculations.
+StringCmp::
+	ld a, [de]
+	cp [hl]
+	ret nz
+	inc de
+	inc hl
+	dec c
+	jr nz, StringCmp
+	ret
--- /dev/null
+++ b/home/copy_string.asm
@@ -1,0 +1,13 @@
+; copies a string from [de] to [wcf4b]
+CopyStringToCF4B::
+	ld hl, wcf4b
+	; fall through
+
+; copies a string from [de] to [hl]
+CopyString::
+	ld a, [de]
+	inc de
+	ld [hli], a
+	cp "@"
+	jr nz, CopyString
+	ret
--- /dev/null
+++ b/home/count_set_bits.asm
@@ -1,0 +1,24 @@
+; function to count how many bits are set in a string of bytes
+; INPUT:
+; hl = address of string of bytes
+; b = length of string of bytes
+; OUTPUT:
+; [wNumSetBits] = number of set bits
+CountSetBits::
+	ld c, 0
+.loop
+	ld a, [hli]
+	ld e, a
+	ld d, 8
+.innerLoop ; count how many bits are set in the current byte
+	srl e
+	ld a, 0
+	adc c
+	ld c, a
+	dec d
+	jr nz, .innerLoop
+	dec b
+	jr nz, .loop
+	ld a, c
+	ld [wNumSetBits], a
+	ret
--- /dev/null
+++ b/home/delay.asm
@@ -1,0 +1,31 @@
+DelayFrames::
+; wait c frames
+	call DelayFrame
+	dec c
+	jr nz, DelayFrames
+	ret
+
+PlaySoundWaitForCurrent::
+	push af
+	call WaitForSoundToFinish
+	pop af
+	jp PlaySound
+
+; Wait for sound to finish playing
+WaitForSoundToFinish::
+	ld a, [wLowHealthAlarm]
+	and $80
+	ret nz
+	push hl
+.waitLoop
+	ld hl, wChannelSoundIDs + Ch5
+	xor a
+	or [hl]
+	inc hl
+	or [hl]
+	inc hl
+	inc hl
+	or [hl]
+	jr nz, .waitLoop
+	pop hl
+	ret
--- /dev/null
+++ b/home/fade_audio.asm
@@ -1,0 +1,48 @@
+FadeOutAudio::
+	ld a, [wAudioFadeOutControl]
+	and a ; currently fading out audio?
+	jr nz, .fadingOut
+	ld a, [wd72c]
+	bit 1, a
+	ret nz
+	ld a, $77
+	ldh [rNR50], a
+	ret
+.fadingOut
+	ld a, [wAudioFadeOutCounter]
+	and a
+	jr z, .counterReachedZero
+	dec a
+	ld [wAudioFadeOutCounter], a
+	ret
+.counterReachedZero
+	ld a, [wAudioFadeOutCounterReloadValue]
+	ld [wAudioFadeOutCounter], a
+	ldh a, [rNR50]
+	and a ; has the volume reached 0?
+	jr z, .fadeOutComplete
+	ld b, a
+	and $f
+	dec a
+	ld c, a
+	ld a, b
+	and $f0
+	swap a
+	dec a
+	swap a
+	or c
+	ldh [rNR50], a
+	ret
+.fadeOutComplete
+	ld a, [wAudioFadeOutControl]
+	ld b, a
+	xor a
+	ld [wAudioFadeOutControl], a
+	ld a, SFX_STOP_ALL_MUSIC
+	ld [wNewSoundID], a
+	call PlaySound
+	ld a, [wAudioSavedROMBank]
+	ld [wAudioROMBank], a
+	ld a, b
+	ld [wNewSoundID], a
+	jp PlaySound
--- /dev/null
+++ b/home/give.asm
@@ -1,0 +1,26 @@
+GiveItem::
+; Give player quantity c of item b,
+; and copy the item's name to wcf4b.
+; Return carry on success.
+	ld a, b
+	ld [wd11e], a
+	ld [wcf91], a
+	ld a, c
+	ld [wItemQuantity], a
+	ld hl, wNumBagItems
+	call AddItemToInventory
+	ret nc
+	call GetItemName
+	call CopyStringToCF4B
+	scf
+	ret
+
+GivePokemon::
+; Give the player monster b at level c.
+	ld a, b
+	ld [wcf91], a
+	ld a, c
+	ld [wCurEnemyLVL], a
+	xor a ; PLAYER_PARTY_DATA
+	ld [wMonDataLocation], a
+	farjp _GivePokemon
--- /dev/null
+++ b/home/hidden_objects.asm
@@ -1,0 +1,39 @@
+UpdateCinnabarGymGateTileBlocks::
+	farjp UpdateCinnabarGymGateTileBlocks_
+
+CheckForHiddenObjectOrBookshelfOrCardKeyDoor::
+	ldh a, [hLoadedROMBank]
+	push af
+	ldh a, [hJoyHeld]
+	bit 0, a ; A button
+	jr z, .nothingFound
+; A button is pressed
+	ld a, BANK(CheckForHiddenObject)
+	ld [MBC1RomBank], a
+	ldh [hLoadedROMBank], a
+	call CheckForHiddenObject
+	ldh a, [hDidntFindAnyHiddenObject]
+	and a
+	jr nz, .hiddenObjectNotFound
+	ld a, [wHiddenObjectFunctionRomBank]
+	ld [MBC1RomBank], a
+	ldh [hLoadedROMBank], a
+	ld de, .returnAddress
+	push de
+	jp hl
+.returnAddress
+	xor a
+	jr .done
+.hiddenObjectNotFound
+	farcall PrintBookshelfText
+	ldh a, [hFFDB]
+	and a
+	jr z, .done
+.nothingFound
+	ld a, $ff
+.done
+	ldh [hItemAlreadyFound], a
+	pop af
+	ld [MBC1RomBank], a
+	ldh [hLoadedROMBank], a
+	ret
--- /dev/null
+++ b/home/inventory.asm
@@ -1,0 +1,55 @@
+; subtracts the amount the player paid from their money
+; OUTPUT: carry = 0(success) or 1(fail because there is not enough money)
+SubtractAmountPaidFromMoney::
+	farjp SubtractAmountPaidFromMoney_
+
+; adds the amount the player sold to their money
+AddAmountSoldToMoney::
+	ld de, wPlayerMoney + 2
+	ld hl, hMoney + 2 ; total price of items
+	ld c, 3 ; length of money in bytes
+	predef AddBCDPredef ; add total price to money
+	ld a, MONEY_BOX
+	ld [wTextBoxID], a
+	call DisplayTextBoxID ; redraw money text box
+	ld a, SFX_PURCHASE
+	call PlaySoundWaitForCurrent
+	jp WaitForSoundToFinish
+
+; function to remove an item (in varying quantities) from the player's bag or PC box
+; INPUT:
+; HL = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wWhichPokemon] = index (within the inventory) of the item to remove
+; [wItemQuantity] = quantity to remove
+RemoveItemFromInventory::
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, BANK(RemoveItemFromInventory_)
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	call RemoveItemFromInventory_
+	pop af
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
+
+; function to add an item (in varying quantities) to the player's bag or PC box
+; INPUT:
+; HL = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wcf91] = item ID
+; [wItemQuantity] = item quantity
+; sets carry flag if successful, unsets carry flag if unsuccessful
+AddItemToInventory::
+	push bc
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, BANK(AddItemToInventory_)
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	call AddItemToInventory_
+	pop bc
+	ld a, b
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	pop bc
+	ret
--- /dev/null
+++ b/home/item.asm
@@ -1,0 +1,49 @@
+; uses an item
+; UseItem is used with dummy items to perform certain other functions as well
+; INPUT:
+; [wcf91] = item ID
+; OUTPUT:
+; [wActionResultOrTookBattleTurn] = success
+; 00: unsuccessful
+; 01: successful
+; 02: not able to be used right now, no extra menu displayed (only certain items use this)
+UseItem::
+	farjp UseItem_
+
+; confirms the item toss and then tosses the item
+; INPUT:
+; hl = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wcf91] = item ID
+; [wWhichPokemon] = index of item within inventory
+; [wItemQuantity] = quantity to toss
+; OUTPUT:
+; clears carry flag if the item is tossed, sets carry flag if not
+TossItem::
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, BANK(TossItem_)
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	call TossItem_
+	pop de
+	ld a, d
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
+
+; checks if an item is a key item
+; INPUT:
+; [wcf91] = item ID
+; OUTPUT:
+; [wIsKeyItem] = result
+; 00: item is not key item
+; 01: item is key item
+IsKeyItem::
+	push hl
+	push de
+	push bc
+	farcall IsKeyItem_
+	pop bc
+	pop de
+	pop hl
+	ret
--- /dev/null
+++ b/home/item_price.asm
@@ -1,0 +1,44 @@
+GetItemPrice::
+; Stores item's price as BCD at hItemPrice (3 bytes)
+; Input: [wcf91] = item id
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, [wListMenuID]
+	cp MOVESLISTMENU
+	ld a, BANK(ItemPrices)
+	jr nz, .ok
+	ld a, $f ; hardcoded Bank
+.ok
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ld hl, wItemPrices
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+	ld a, [wcf91] ; a contains item id
+	cp HM01
+	jr nc, .getTMPrice
+	ld bc, $3
+.loop
+	add hl, bc
+	dec a
+	jr nz, .loop
+	dec hl
+	ld a, [hld]
+	ldh [hItemPrice + 2], a
+	ld a, [hld]
+	ldh [hItemPrice + 1], a
+	ld a, [hl]
+	ldh [hItemPrice], a
+	jr .done
+.getTMPrice
+	ld a, BANK(GetMachinePrice)
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	call GetMachinePrice
+.done
+	ld de, hItemPrice
+	pop af
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
--- /dev/null
+++ b/home/joypad2.asm
@@ -1,0 +1,95 @@
+; this function is used when lower button sensitivity is wanted (e.g. menus)
+; OUTPUT: [hJoy5] = pressed buttons in usual format
+; there are two flags that control its functionality, [hJoy6] and [hJoy7]
+; there are essentially three modes of operation
+; 1. Get newly pressed buttons only
+;    ([hJoy7] == 0, [hJoy6] == any)
+;    Just copies [hJoyPressed] to [hJoy5].
+; 2. Get currently pressed buttons at low sample rate with delay
+;    ([hJoy7] == 1, [hJoy6] != 0)
+;    If the user holds down buttons for more than half a second,
+;    report buttons as being pressed up to 12 times per second thereafter.
+;    If the user holds down buttons for less than half a second,
+;    report only one button press.
+; 3. Same as 2, but report no buttons as pressed if A or B is held down.
+;    ([hJoy7] == 1, [hJoy6] == 0)
+JoypadLowSensitivity::
+	call Joypad
+	ldh a, [hJoy7] ; flag
+	and a ; get all currently pressed buttons or only newly pressed buttons?
+	ldh a, [hJoyPressed] ; newly pressed buttons
+	jr z, .storeButtonState
+	ldh a, [hJoyHeld] ; all currently pressed buttons
+.storeButtonState
+	ldh [hJoy5], a
+	ldh a, [hJoyPressed] ; newly pressed buttons
+	and a ; have any buttons been newly pressed since last check?
+	jr z, .noNewlyPressedButtons
+.newlyPressedButtons
+	ld a, 30 ; half a second delay
+	ldh [hFrameCounter], a
+	ret
+.noNewlyPressedButtons
+	ldh a, [hFrameCounter]
+	and a ; is the delay over?
+	jr z, .delayOver
+.delayNotOver
+	xor a
+	ldh [hJoy5], a ; report no buttons as pressed
+	ret
+.delayOver
+; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed
+	ldh a, [hJoyHeld]
+	and A_BUTTON | B_BUTTON
+	jr z, .setShortDelay
+	ldh a, [hJoy6] ; flag
+	and a
+	jr nz, .setShortDelay
+	xor a
+	ldh [hJoy5], a
+.setShortDelay
+	ld a, 5 ; 1/12 of a second delay
+	ldh [hFrameCounter], a
+	ret
+
+WaitForTextScrollButtonPress::
+	ldh a, [hDownArrowBlinkCount1]
+	push af
+	ldh a, [hDownArrowBlinkCount2]
+	push af
+	xor a
+	ldh [hDownArrowBlinkCount1], a
+	ld a, $6
+	ldh [hDownArrowBlinkCount2], a
+.loop
+	push hl
+	ld a, [wTownMapSpriteBlinkingEnabled]
+	and a
+	jr z, .skipAnimation
+	call TownMapSpriteBlinkingAnimation
+.skipAnimation
+	hlcoord 18, 16
+	call HandleDownArrowBlinkTiming
+	pop hl
+	call JoypadLowSensitivity
+	predef CableClub_Run
+	ldh a, [hJoy5]
+	and A_BUTTON | B_BUTTON
+	jr z, .loop
+	pop af
+	ldh [hDownArrowBlinkCount2], a
+	pop af
+	ldh [hDownArrowBlinkCount1], a
+	ret
+
+; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect
+ManualTextScroll::
+	ld a, [wLinkState]
+	cp LINK_STATE_BATTLING
+	jr z, .inLinkBattle
+	call WaitForTextScrollButtonPress
+	ld a, SFX_PRESS_AB
+	jp PlaySound
+.inLinkBattle
+	ld c, 65
+	jp DelayFrames
--- /dev/null
+++ b/home/load_font.asm
@@ -1,0 +1,47 @@
+LoadFontTilePatterns::
+	ldh a, [rLCDC]
+	bit 7, a ; is the LCD enabled?
+	jr nz, .on
+.off
+	ld hl, FontGraphics
+	ld de, vFont
+	ld bc, FontGraphicsEnd - FontGraphics
+	ld a, BANK(FontGraphics)
+	jp FarCopyDataDouble ; if LCD is off, transfer all at once
+.on
+	ld de, FontGraphics
+	ld hl, vFont
+	lb bc, BANK(FontGraphics), (FontGraphicsEnd - FontGraphics) / $8
+	jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
+
+LoadTextBoxTilePatterns::
+	ldh a, [rLCDC]
+	bit 7, a ; is the LCD enabled?
+	jr nz, .on
+.off
+	ld hl, TextBoxGraphics
+	ld de, vChars2 tile $60
+	ld bc, TextBoxGraphicsEnd - TextBoxGraphics
+	ld a, BANK(TextBoxGraphics)
+	jp FarCopyData2 ; if LCD is off, transfer all at once
+.on
+	ld de, TextBoxGraphics
+	ld hl, vChars2 tile $60
+	lb bc, BANK(TextBoxGraphics), (TextBoxGraphicsEnd - TextBoxGraphics) / $10
+	jp CopyVideoData ; if LCD is on, transfer during V-blank
+
+LoadHpBarAndStatusTilePatterns::
+	ldh a, [rLCDC]
+	bit 7, a ; is the LCD enabled?
+	jr nz, .on
+.off
+	ld hl, HpBarAndStatusGraphics
+	ld de, vChars2 tile $62
+	ld bc, HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics
+	ld a, BANK(HpBarAndStatusGraphics)
+	jp FarCopyData2 ; if LCD is off, transfer all at once
+.on
+	ld de, HpBarAndStatusGraphics
+	ld hl, vChars2 tile $62
+	lb bc, BANK(HpBarAndStatusGraphics), (HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics) / $10
+	jp CopyVideoData ; if LCD is on, transfer during V-blank
--- /dev/null
+++ b/home/map_objects.asm
@@ -1,0 +1,248 @@
+; checks if the player's coordinates match an arrow movement tile's coordinates
+; and if so, decodes the RLE movement data
+; b = player Y
+; c = player X
+DecodeArrowMovementRLE::
+	ld a, [hli]
+	cp $ff
+	ret z ; no match in the list
+	cp b
+	jr nz, .nextArrowMovementTileEntry1
+	ld a, [hli]
+	cp c
+	jr nz, .nextArrowMovementTileEntry2
+	ld a, [hli]
+	ld d, [hl]
+	ld e, a
+	ld hl, wSimulatedJoypadStatesEnd
+	call DecodeRLEList
+	dec a
+	ld [wSimulatedJoypadStatesIndex], a
+	ret
+.nextArrowMovementTileEntry1
+	inc hl
+.nextArrowMovementTileEntry2
+	inc hl
+	inc hl
+	jr DecodeArrowMovementRLE
+
+TextScript_ItemStoragePC::
+	call SaveScreenTilesToBuffer2
+	ld b, BANK(PlayerPC)
+	ld hl, PlayerPC
+	jr bankswitchAndContinue
+
+TextScript_BillsPC::
+	call SaveScreenTilesToBuffer2
+	ld b, BANK(BillsPC_)
+	ld hl, BillsPC_
+	jr bankswitchAndContinue
+
+TextScript_GameCornerPrizeMenu::
+; XXX find a better name for this function
+; special_F7
+	ld b, BANK(CeladonPrizeMenu)
+	ld hl, CeladonPrizeMenu
+bankswitchAndContinue::
+	call Bankswitch
+	jp HoldTextDisplayOpen        ; continue to main text-engine function
+
+TextScript_PokemonCenterPC::
+	ld b, BANK(ActivatePC)
+	ld hl, ActivatePC
+	jr bankswitchAndContinue
+
+StartSimulatingJoypadStates::
+	xor a
+	ld [wOverrideSimulatedJoypadStatesMask], a
+	ld [wSpritePlayerStateData2MovementByte1], a
+	ld hl, wd730
+	set 7, [hl]
+	ret
+
+IsItemInBag::
+; given an item_id in b
+; set zero flag if item isn't in player's bag
+; else reset zero flag
+; related to Pokémon Tower and ghosts
+	predef GetQuantityOfItemInBag
+	ld a, b
+	and a
+	ret
+
+DisplayPokedex::
+	ld [wd11e], a
+	farjp _DisplayPokedex
+
+SetSpriteFacingDirectionAndDelay::
+	call SetSpriteFacingDirection
+	ld c, 6
+	jp DelayFrames
+
+SetSpriteFacingDirection::
+	ld a, $9
+	ldh [hSpriteDataOffset], a
+	call GetPointerWithinSpriteStateData1
+	ldh a, [hSpriteFacingDirection]
+	ld [hl], a
+	ret
+
+SetSpriteImageIndexAfterSettingFacingDirection::
+	ld de, -7
+	add hl, de
+	ld [hl], a
+	ret
+
+; tests if the player's coordinates are in a specified array
+; INPUT:
+; hl = address of array
+; OUTPUT:
+; [wCoordIndex] = if there is match, the matching array index
+; sets carry if the coordinates are in the array, clears carry if not
+ArePlayerCoordsInArray::
+	ld a, [wYCoord]
+	ld b, a
+	ld a, [wXCoord]
+	ld c, a
+	; fallthrough
+
+CheckCoords::
+	xor a
+	ld [wCoordIndex], a
+.loop
+	ld a, [hli]
+	cp $ff ; reached terminator?
+	jr z, .notInArray
+	push hl
+	ld hl, wCoordIndex
+	inc [hl]
+	pop hl
+.compareYCoord
+	cp b
+	jr z, .compareXCoord
+	inc hl
+	jr .loop
+.compareXCoord
+	ld a, [hli]
+	cp c
+	jr nz, .loop
+.inArray
+	scf
+	ret
+.notInArray
+	and a
+	ret
+
+; tests if a boulder's coordinates are in a specified array
+; INPUT:
+; hl = address of array
+; [hSpriteIndex] = index of boulder sprite
+; OUTPUT:
+; [wCoordIndex] = if there is match, the matching array index
+; sets carry if the coordinates are in the array, clears carry if not
+CheckBoulderCoords::
+	push hl
+	ld hl, wSpritePlayerStateData2MapY
+	ldh a, [hSpriteIndex]
+	swap a
+	ld d, $0
+	ld e, a
+	add hl, de
+	ld a, [hli]
+	sub $4 ; because sprite coordinates are offset by 4
+	ld b, a
+	ld a, [hl]
+	sub $4 ; because sprite coordinates are offset by 4
+	ld c, a
+	pop hl
+	jp CheckCoords
+
+GetPointerWithinSpriteStateData1::
+	ld h, $c1
+	jr _GetPointerWithinSpriteStateData
+
+GetPointerWithinSpriteStateData2::
+	ld h, $c2
+
+_GetPointerWithinSpriteStateData:
+	ldh a, [hSpriteDataOffset]
+	ld b, a
+	ldh a, [hSpriteIndex]
+	swap a
+	add b
+	ld l, a
+	ret
+
+; decodes a $ff-terminated RLEncoded list
+; each entry is a pair of bytes <byte value> <repetitions>
+; the final $ff will be replicated in the output list and a contains the number of bytes written
+; de: input list
+; hl: output list
+DecodeRLEList::
+	xor a
+	ld [wRLEByteCount], a     ; count written bytes here
+.listLoop
+	ld a, [de]
+	cp $ff
+	jr z, .endOfList
+	ldh [hRLEByteValue], a ; store byte value to be written
+	inc de
+	ld a, [de]
+	ld b, $0
+	ld c, a                      ; number of bytes to be written
+	ld a, [wRLEByteCount]
+	add c
+	ld [wRLEByteCount], a     ; update total number of written bytes
+	ldh a, [hRLEByteValue]
+	call FillMemory              ; write a c-times to output
+	inc de
+	jr .listLoop
+.endOfList
+	ld a, $ff
+	ld [hl], a                   ; write final $ff
+	ld a, [wRLEByteCount]
+	inc a                        ; include sentinel in counting
+	ret
+
+; sets movement byte 1 for sprite [hSpriteIndex] to $FE and byte 2 to [hSpriteMovementByte2]
+SetSpriteMovementBytesToFE::
+	push hl
+	call GetSpriteMovementByte1Pointer
+	ld [hl], $fe
+	call GetSpriteMovementByte2Pointer
+	ldh a, [hSpriteMovementByte2]
+	ld [hl], a
+	pop hl
+	ret
+
+; sets both movement bytes for sprite [hSpriteIndex] to $FF
+SetSpriteMovementBytesToFF::
+	push hl
+	call GetSpriteMovementByte1Pointer
+	ld [hl], $FF
+	call GetSpriteMovementByte2Pointer
+	ld [hl], $FF ; prevent person from walking?
+	pop hl
+	ret
+
+; returns the sprite movement byte 1 pointer for sprite [hSpriteIndex] in hl
+GetSpriteMovementByte1Pointer::
+	ld h, $C2
+	ldh a, [hSpriteIndex]
+	swap a
+	add 6
+	ld l, a
+	ret
+
+; returns the sprite movement byte 2 pointer for sprite [hSpriteIndex] in hl
+GetSpriteMovementByte2Pointer::
+	push de
+	ld hl, wMapSpriteData
+	ldh a, [hSpriteIndex]
+	dec a
+	add a
+	ld d, 0
+	ld e, a
+	add hl, de
+	pop de
+	ret
--- /dev/null
+++ b/home/math.asm
@@ -1,0 +1,41 @@
+; function to do multiplication
+; all values are big endian
+; INPUT
+; FF96-FF98 =  multiplicand
+; FF99 = multiplier
+; OUTPUT
+; FF95-FF98 = product
+Multiply::
+	push hl
+	push bc
+	callfar _Multiply
+	pop bc
+	pop hl
+	ret
+
+; function to do division
+; all values are big endian
+; INPUT
+; FF95-FF98 = dividend
+; FF99 = divisor
+; b = number of bytes in the dividend (starting from FF95)
+; OUTPUT
+; FF95-FF98 = quotient
+; FF99 = remainder
+Divide::
+	push hl
+	push de
+	push bc
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, BANK(_Divide)
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	call _Divide
+	pop af
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	pop bc
+	pop de
+	pop hl
+	ret
--- /dev/null
+++ b/home/money.asm
@@ -1,0 +1,15 @@
+HasEnoughMoney::
+; Check if the player has at least as much
+; money as the 3-byte BCD value at hMoney.
+	ld de, wPlayerMoney
+	ld hl, hMoney
+	ld c, 3
+	jp StringCmp
+
+HasEnoughCoins::
+; Check if the player has at least as many
+; coins as the 2-byte BCD value at hCoins.
+	ld de, wPlayerCoins
+	ld hl, hCoins
+	ld c, 2
+	jp StringCmp
--- a/home/move_mon.asm
+++ b/home/move_mon.asm
@@ -1,3 +1,18 @@
+; Copies [hl, bc) to [de, de + bc - hl).
+; In other words, the source data is from hl up to but not including bc,
+; and the destination is de.
+CopyDataUntil::
+	ld a, [hli]
+	ld [de], a
+	inc de
+	ld a, h
+	cp b
+	jr nz, CopyDataUntil
+	ld a, l
+	cp c
+	jr nz, CopyDataUntil
+	ret
+
 ; Function to remove a pokemon from the party or the current box.
 ; wWhichPokemon determines the pokemon.
 ; [wRemoveMonFromBox] == 0 specifies the party.
--- /dev/null
+++ b/home/npc_movement.asm
@@ -1,0 +1,54 @@
+; not zero if an NPC movement script is running, the player character is
+; automatically stepping down from a door, or joypad states are being simulated
+IsPlayerCharacterBeingControlledByGame::
+	ld a, [wNPCMovementScriptPointerTableNum]
+	and a
+	ret nz
+	ld a, [wd736]
+	bit 1, a ; currently stepping down from door bit
+	ret nz
+	ld a, [wd730]
+	and $80
+	ret
+
+RunNPCMovementScript::
+	ld hl, wd736
+	bit 0, [hl]
+	res 0, [hl]
+	jr nz, .playerStepOutFromDoor
+	ld a, [wNPCMovementScriptPointerTableNum]
+	and a
+	ret z
+	dec a
+	add a
+	ld d, 0
+	ld e, a
+	ld hl, .NPCMovementScriptPointerTables
+	add hl, de
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, [wNPCMovementScriptBank]
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ld a, [wNPCMovementScriptFunctionNum]
+	call CallFunctionInTable
+	pop af
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
+
+.NPCMovementScriptPointerTables
+	dw PalletMovementScriptPointerTable
+	dw PewterMuseumGuyMovementScriptPointerTable
+	dw PewterGymGuyMovementScriptPointerTable
+.playerStepOutFromDoor
+	farjp PlayerStepOutFromDoor
+
+EndNPCMovementScript::
+	farjp _EndNPCMovementScript
+
+EmptyFunc2::
+	ret
--- /dev/null
+++ b/home/oam.asm
@@ -1,0 +1,36 @@
+; INPUT:
+; a = oam block index (each block is 4 oam entries)
+; b = Y coordinate of upper left corner of sprite
+; c = X coordinate of upper left corner of sprite
+; de = base address of 4 tile number and attribute pairs
+WriteOAMBlock::
+	ld h, HIGH(wOAMBuffer)
+	swap a ; multiply by 16
+	ld l, a
+	call .writeOneEntry ; upper left
+	push bc
+	ld a, 8
+	add c
+	ld c, a
+	call .writeOneEntry ; upper right
+	pop bc
+	ld a, 8
+	add b
+	ld b, a
+	call .writeOneEntry ; lower left
+	ld a, 8
+	add c
+	ld c, a
+	                      ; lower right
+.writeOneEntry
+	ld [hl], b ; Y coordinate
+	inc hl
+	ld [hl], c ; X coordinate
+	inc hl
+	ld a, [de] ; tile number
+	inc de
+	ld [hli], a
+	ld a, [de] ; attribute
+	inc de
+	ld [hli], a
+	ret
--- a/home/overworld.asm
+++ b/home/overworld.asm
@@ -2421,3 +2421,54 @@
 	ld hl, LoadPlayerSpriteGraphics
 	call Bankswitch
 	jp PlayDefaultMusic ; update map/player state?
+
+CheckForUserInterruption::
+; Return carry if Up+Select+B, Start or A are pressed in c frames.
+; Used only in the intro and title screen.
+	call DelayFrame
+
+	push bc
+	call JoypadLowSensitivity
+	pop bc
+
+	ldh a, [hJoyHeld]
+	cp D_UP + SELECT + B_BUTTON
+	jr z, .input
+
+	ldh a, [hJoy5]
+	and START | A_BUTTON
+	jr nz, .input
+
+	dec c
+	jr nz, CheckForUserInterruption
+
+	and a
+	ret
+
+.input
+	scf
+	ret
+
+; function to load position data for destination warp when switching maps
+; INPUT:
+; a = ID of destination warp within destination map
+LoadDestinationWarpPosition::
+	ld b, a
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, [wPredefParentBank]
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ld a, b
+	add a
+	add a
+	ld c, a
+	ld b, 0
+	add hl, bc
+	ld bc, 4
+	ld de, wCurrentTileBlockMapViewPointer
+	call CopyData
+	pop af
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
--- /dev/null
+++ b/home/palettes.asm
@@ -1,0 +1,57 @@
+RestoreScreenTilesAndReloadTilePatterns::
+	call ClearSprites
+	ld a, $1
+	ld [wUpdateSpritesEnabled], a
+	call ReloadMapSpriteTilePatterns
+	call LoadScreenTilesFromBuffer2
+	call LoadTextBoxTilePatterns
+	call RunDefaultPaletteCommand
+	jr Delay3
+
+GBPalWhiteOutWithDelay3::
+	call GBPalWhiteOut
+
+Delay3::
+; The bg map is updated each frame in thirds.
+; Wait three frames to let the bg map fully update.
+	ld c, 3
+	jp DelayFrames
+
+GBPalNormal::
+; Reset BGP and OBP0.
+	ld a, %11100100 ; 3210
+	ldh [rBGP], a
+	ld a, %11010000 ; 3100
+	ldh [rOBP0], a
+	ret
+
+GBPalWhiteOut::
+; White out all palettes.
+	xor a
+	ldh [rBGP], a
+	ldh [rOBP0], a
+	ldh [rOBP1], a
+	ret
+
+RunDefaultPaletteCommand::
+	ld b, SET_PAL_DEFAULT
+RunPaletteCommand::
+	ld a, [wOnSGB]
+	and a
+	ret z
+	predef_jump _RunPaletteCommand
+
+GetHealthBarColor::
+; Return at hl the palette of
+; an HP bar e pixels long.
+	ld a, e
+	cp 27
+	ld d, 0 ; green
+	jr nc, .gotColor
+	cp 10
+	inc d ; yellow
+	jr nc, .gotColor
+	inc d ; red
+.gotColor
+	ld [hl], d
+	ret
--- /dev/null
+++ b/home/pathfinding.asm
@@ -1,0 +1,65 @@
+; calculates the difference |a-b|, setting carry flag if a<b
+CalcDifference::
+	sub b
+	ret nc
+	cpl
+	add $1
+	scf
+	ret
+
+MoveSprite::
+; move the sprite [hSpriteIndex] with the movement pointed to by de
+; actually only copies the movement data to wNPCMovementDirections for later
+	call SetSpriteMovementBytesToFF
+MoveSprite_::
+	push hl
+	push bc
+	call GetSpriteMovementByte1Pointer
+	xor a
+	ld [hl], a
+	ld hl, wNPCMovementDirections
+	ld c, 0
+
+.loop
+	ld a, [de]
+	ld [hli], a
+	inc de
+	inc c
+	cp $FF ; have we reached the end of the movement data?
+	jr nz, .loop
+
+	ld a, c
+	ld [wNPCNumScriptedSteps], a ; number of steps taken
+
+	pop bc
+	ld hl, wd730
+	set 0, [hl]
+	pop hl
+	xor a
+	ld [wOverrideSimulatedJoypadStatesMask], a
+	ld [wSimulatedJoypadStatesEnd], a
+	dec a
+	ld [wJoyIgnore], a
+	ld [wWastedByteCD3A], a
+	ret
+
+; divides [hDividend2] by [hDivisor2] and stores the quotient in [hQuotient2]
+DivideBytes::
+	push hl
+	ld hl, hQuotient2
+	xor a
+	ld [hld], a
+	ld a, [hld]
+	and a
+	jr z, .done
+	ld a, [hli]
+.loop
+	sub [hl]
+	jr c, .done
+	inc hl
+	inc [hl]
+	dec hl
+	jr .loop
+.done
+	pop hl
+	ret
--- /dev/null
+++ b/home/predef_text.asm
@@ -1,0 +1,28 @@
+PrintPredefTextID::
+	ldh [hSpriteIndexOrTextID], a
+	ld hl, TextPredefs
+	call SetMapTextPointer
+	ld hl, wTextPredefFlag
+	set 0, [hl]
+	call DisplayTextID
+
+RestoreMapTextPointer::
+	ld hl, wMapTextPtr
+	ldh a, [hSavedMapTextPtr]
+	ld [hli], a
+	ldh a, [hSavedMapTextPtr + 1]
+	ld [hl], a
+	ret
+
+SetMapTextPointer::
+	ld a, [wMapTextPtr]
+	ldh [hSavedMapTextPtr], a
+	ld a, [wMapTextPtr + 1]
+	ldh [hSavedMapTextPtr + 1], a
+	ld a, l
+	ld [wMapTextPtr], a
+	ld a, h
+	ld [wMapTextPtr + 1], a
+	ret
+
+INCLUDE "data/text_predef_pointers.asm"
--- /dev/null
+++ b/home/print_text.asm
@@ -1,0 +1,45 @@
+; This function is used to wait a short period after printing a letter to the
+; screen unless the player presses the A/B button or the delay is turned off
+; through the [wd730] or [wLetterPrintingDelayFlags] flags.
+PrintLetterDelay::
+	ld a, [wd730]
+	bit 6, a
+	ret nz
+	ld a, [wLetterPrintingDelayFlags]
+	bit 1, a
+	ret z
+	push hl
+	push de
+	push bc
+	ld a, [wLetterPrintingDelayFlags]
+	bit 0, a
+	jr z, .waitOneFrame
+	ld a, [wOptions]
+	and $f
+	ldh [hFrameCounter], a
+	jr .checkButtons
+.waitOneFrame
+	ld a, 1
+	ldh [hFrameCounter], a
+.checkButtons
+	call Joypad
+	ldh a, [hJoyHeld]
+.checkAButton
+	bit 0, a ; is the A button pressed?
+	jr z, .checkBButton
+	jr .endWait
+.checkBButton
+	bit 1, a ; is the B button pressed?
+	jr z, .buttonsNotPressed
+.endWait
+	call DelayFrame
+	jr .done
+.buttonsNotPressed ; if neither A nor B is pressed
+	ldh a, [hFrameCounter]
+	and a
+	jr nz, .checkButtons
+.done
+	pop bc
+	pop de
+	pop hl
+	ret
--- /dev/null
+++ b/home/random.asm
@@ -1,0 +1,12 @@
+Random::
+; Return a random number in a.
+; For battles, use BattleRandom.
+	push hl
+	push de
+	push bc
+	farcall Random_
+	ldh a, [hRandomAdd]
+	pop bc
+	pop de
+	pop hl
+	ret
--- /dev/null
+++ b/home/reload_sprites.asm
@@ -1,0 +1,19 @@
+; Copy the current map's sprites' tile patterns to VRAM again after they have
+; been overwritten by other tile patterns.
+ReloadMapSpriteTilePatterns::
+	ld hl, wFontLoaded
+	ld a, [hl]
+	push af
+	res 0, [hl]
+	push hl
+	xor a
+	ld [wSpriteSetID], a
+	call DisableLCD
+	farcall InitMapSprites
+	call EnableLCD
+	pop hl
+	pop af
+	ld [hl], a
+	call LoadPlayerSpriteGraphics
+	call LoadFontTilePatterns
+	jp UpdateSprites
--- /dev/null
+++ b/home/reload_tiles.asm
@@ -1,0 +1,41 @@
+; reloads text box tile patterns, current map view, and tileset tile patterns
+ReloadMapData::
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, [wCurMap]
+	call SwitchToMapRomBank
+	call DisableLCD
+	call LoadTextBoxTilePatterns
+	call LoadCurrentMapView
+	call LoadTilesetTilePatternData
+	call EnableLCD
+	pop af
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
+
+; reloads tileset tile patterns
+ReloadTilesetTilePatterns::
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, [wCurMap]
+	call SwitchToMapRomBank
+	call DisableLCD
+	call LoadTilesetTilePatternData
+	call EnableLCD
+	pop af
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
+
+; shows the town map and lets the player choose a destination to fly to
+ChooseFlyDestination::
+	ld hl, wd72e
+	res 4, [hl]
+	farjp LoadTownMap_Fly
+
+; causes the text box to close without waiting for a button press after displaying text
+DisableWaitingAfterTextDisplay::
+	ld a, $01
+	ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+	ret
--- /dev/null
+++ b/home/reset_player_sprite.asm
@@ -1,0 +1,20 @@
+ResetPlayerSpriteData::
+	ld hl, wSpriteStateData1
+	call ResetPlayerSpriteData_ClearSpriteData
+	ld hl, wSpriteStateData2
+	call ResetPlayerSpriteData_ClearSpriteData
+	ld a, $1
+	ld [wSpritePlayerStateData1PictureID], a
+	ld [wSpritePlayerStateData2ImageBaseOffset], a
+	ld hl, wSpritePlayerStateData1YPixels
+	ld [hl], $3c     ; set Y screen pos
+	inc hl
+	inc hl
+	ld [hl], $40     ; set X screen pos
+	ret
+
+; overwrites sprite data with zeroes
+ResetPlayerSpriteData_ClearSpriteData::
+	ld bc, $10
+	xor a
+	jp FillMemory
--- /dev/null
+++ b/home/textbox.asm
@@ -1,0 +1,16 @@
+; function to draw various text boxes
+; INPUT:
+; [wTextBoxID] = text box ID
+; b, c = y, x cursor position (TWO_OPTION_MENU only)
+DisplayTextBoxID::
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, BANK(DisplayTextBoxID_)
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	call DisplayTextBoxID_
+	pop bc
+	ld a, b
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
--- /dev/null
+++ b/home/tilemap.asm
@@ -1,0 +1,61 @@
+FillMemory::
+; Fill bc bytes at hl with a.
+	push de
+	ld d, a
+.loop
+	ld a, d
+	ld [hli], a
+	dec bc
+	ld a, b
+	or c
+	jr nz, .loop
+	pop de
+	ret
+
+UncompressSpriteFromDE::
+; Decompress pic at a:de.
+	ld hl, wSpriteInputPtr
+	ld [hl], e
+	inc hl
+	ld [hl], d
+	jp UncompressSpriteData
+
+SaveScreenTilesToBuffer2::
+	hlcoord 0, 0
+	ld de, wTileMapBackup2
+	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+	call CopyData
+	ret
+
+LoadScreenTilesFromBuffer2::
+	call LoadScreenTilesFromBuffer2DisableBGTransfer
+	ld a, 1
+	ldh [hAutoBGTransferEnabled], a
+	ret
+
+; loads screen tiles stored in wTileMapBackup2 but leaves hAutoBGTransferEnabled disabled
+LoadScreenTilesFromBuffer2DisableBGTransfer::
+	xor a
+	ldh [hAutoBGTransferEnabled], a
+	ld hl, wTileMapBackup2
+	decoord 0, 0
+	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+	call CopyData
+	ret
+
+SaveScreenTilesToBuffer1::
+	hlcoord 0, 0
+	ld de, wTileMapBackup
+	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+	jp CopyData
+
+LoadScreenTilesFromBuffer1::
+	xor a
+	ldh [hAutoBGTransferEnabled], a
+	ld hl, wTileMapBackup
+	decoord 0, 0
+	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+	call CopyData
+	ld a, 1
+	ldh [hAutoBGTransferEnabled], a
+	ret
--- /dev/null
+++ b/home/trainers2.asm
@@ -1,0 +1,35 @@
+GetTrainerInformation::
+	call GetTrainerName
+	ld a, [wLinkState]
+	and a
+	jr nz, .linkBattle
+	ld a, BANK(TrainerPicAndMoneyPointers)
+	call BankswitchHome
+	ld a, [wTrainerClass]
+	dec a
+	ld hl, TrainerPicAndMoneyPointers
+	ld bc, $5
+	call AddNTimes
+	ld de, wTrainerPicPointer
+	ld a, [hli]
+	ld [de], a
+	inc de
+	ld a, [hli]
+	ld [de], a
+	ld de, wTrainerBaseMoney
+	ld a, [hli]
+	ld [de], a
+	inc de
+	ld a, [hli]
+	ld [de], a
+	jp BankswitchBack
+.linkBattle
+	ld hl, wTrainerPicPointer
+	ld de, RedPicFront
+	ld [hl], e
+	inc hl
+	ld [hl], d
+	ret
+
+GetTrainerName::
+	farjp GetTrainerName_
--- /dev/null
+++ b/home/update_sprites.asm
@@ -1,0 +1,14 @@
+UpdateSprites::
+	ld a, [wUpdateSpritesEnabled]
+	dec a
+	ret nz
+	ldh a, [hLoadedROMBank]
+	push af
+	ld a, BANK(_UpdateSprites)
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	call _UpdateSprites
+	pop af
+	ldh [hLoadedROMBank], a
+	ld [MBC1RomBank], a
+	ret
--- /dev/null
+++ b/home/window.asm
@@ -1,0 +1,294 @@
+HandleMenuInput::
+	xor a
+	ld [wPartyMenuAnimMonEnabled], a
+
+HandleMenuInput_::
+	ldh a, [hDownArrowBlinkCount1]
+	push af
+	ldh a, [hDownArrowBlinkCount2]
+	push af ; save existing values on stack
+	xor a
+	ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1
+	ld a, 6
+	ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2
+.loop1
+	xor a
+	ld [wAnimCounter], a ; counter for pokemon shaking animation
+	call PlaceMenuCursor
+	call Delay3
+.loop2
+	push hl
+	ld a, [wPartyMenuAnimMonEnabled]
+	and a ; is it a pokemon selection menu?
+	jr z, .getJoypadState
+	farcall AnimatePartyMon ; shake mini sprite of selected pokemon
+.getJoypadState
+	pop hl
+	call JoypadLowSensitivity
+	ldh a, [hJoy5]
+	and a ; was a key pressed?
+	jr nz, .keyPressed
+	push hl
+	hlcoord 18, 11 ; coordinates of blinking down arrow in some menus
+	call HandleDownArrowBlinkTiming ; blink down arrow (if any)
+	pop hl
+	ld a, [wMenuJoypadPollCount]
+	dec a
+	jr z, .giveUpWaiting
+	jr .loop2
+.giveUpWaiting
+; if a key wasn't pressed within the specified number of checks
+	pop af
+	ldh [hDownArrowBlinkCount2], a
+	pop af
+	ldh [hDownArrowBlinkCount1], a ; restore previous values
+	xor a
+	ld [wMenuWrappingEnabled], a ; disable menu wrapping
+	ret
+.keyPressed
+	xor a
+	ld [wCheckFor180DegreeTurn], a
+	ldh a, [hJoy5]
+	ld b, a
+	bit 6, a ; pressed Up key?
+	jr z, .checkIfDownPressed
+.upPressed
+	ld a, [wCurrentMenuItem] ; selected menu item
+	and a ; already at the top of the menu?
+	jr z, .alreadyAtTop
+.notAtTop
+	dec a
+	ld [wCurrentMenuItem], a ; move selected menu item up one space
+	jr .checkOtherKeys
+.alreadyAtTop
+	ld a, [wMenuWrappingEnabled]
+	and a ; is wrapping around enabled?
+	jr z, .noWrappingAround
+	ld a, [wMaxMenuItem]
+	ld [wCurrentMenuItem], a ; wrap to the bottom of the menu
+	jr .checkOtherKeys
+.checkIfDownPressed
+	bit 7, a
+	jr z, .checkOtherKeys
+.downPressed
+	ld a, [wCurrentMenuItem]
+	inc a
+	ld c, a
+	ld a, [wMaxMenuItem]
+	cp c
+	jr nc, .notAtBottom
+.alreadyAtBottom
+	ld a, [wMenuWrappingEnabled]
+	and a ; is wrapping around enabled?
+	jr z, .noWrappingAround
+	ld c, $00 ; wrap from bottom to top
+.notAtBottom
+	ld a, c
+	ld [wCurrentMenuItem], a
+.checkOtherKeys
+	ld a, [wMenuWatchedKeys]
+	and b ; does the menu care about any of the pressed keys?
+	jp z, .loop1
+.checkIfAButtonOrBButtonPressed
+	ldh a, [hJoy5]
+	and A_BUTTON | B_BUTTON
+	jr z, .skipPlayingSound
+.AButtonOrBButtonPressed
+	push hl
+	ld hl, wFlags_0xcd60
+	bit 5, [hl]
+	pop hl
+	jr nz, .skipPlayingSound
+	ld a, SFX_PRESS_AB
+	call PlaySound
+.skipPlayingSound
+	pop af
+	ldh [hDownArrowBlinkCount2], a
+	pop af
+	ldh [hDownArrowBlinkCount1], a ; restore previous values
+	xor a
+	ld [wMenuWrappingEnabled], a ; disable menu wrapping
+	ldh a, [hJoy5]
+	ret
+.noWrappingAround
+	ld a, [wMenuWatchMovingOutOfBounds]
+	and a ; should we return if the user tried to go past the top or bottom?
+	jr z, .checkOtherKeys
+	jr .checkIfAButtonOrBButtonPressed
+
+PlaceMenuCursor::
+	ld a, [wTopMenuItemY]
+	and a ; is the y coordinate 0?
+	jr z, .adjustForXCoord
+	hlcoord 0, 0
+	ld bc, SCREEN_WIDTH
+.topMenuItemLoop
+	add hl, bc
+	dec a
+	jr nz, .topMenuItemLoop
+.adjustForXCoord
+	ld a, [wTopMenuItemX]
+	ld b, 0
+	ld c, a
+	add hl, bc
+	push hl
+	ld a, [wLastMenuItem]
+	and a ; was the previous menu id 0?
+	jr z, .checkForArrow1
+	push af
+	ldh a, [hFlagsFFF6]
+	bit 1, a ; is the menu double spaced?
+	jr z, .doubleSpaced1
+	ld bc, 20
+	jr .getOldMenuItemScreenPosition
+.doubleSpaced1
+	ld bc, 40
+.getOldMenuItemScreenPosition
+	pop af
+.oldMenuItemLoop
+	add hl, bc
+	dec a
+	jr nz, .oldMenuItemLoop
+.checkForArrow1
+	ld a, [hl]
+	cp "▶" ; was an arrow next to the previously selected menu item?
+	jr nz, .skipClearingArrow
+.clearArrow
+	ld a, [wTileBehindCursor]
+	ld [hl], a
+.skipClearingArrow
+	pop hl
+	ld a, [wCurrentMenuItem]
+	and a
+	jr z, .checkForArrow2
+	push af
+	ldh a, [hFlagsFFF6]
+	bit 1, a ; is the menu double spaced?
+	jr z, .doubleSpaced2
+	ld bc, 20
+	jr .getCurrentMenuItemScreenPosition
+.doubleSpaced2
+	ld bc, 40
+.getCurrentMenuItemScreenPosition
+	pop af
+.currentMenuItemLoop
+	add hl, bc
+	dec a
+	jr nz, .currentMenuItemLoop
+.checkForArrow2
+	ld a, [hl]
+	cp "▶" ; has the right arrow already been placed?
+	jr z, .skipSavingTile ; if so, don't lose the saved tile
+	ld [wTileBehindCursor], a ; save tile before overwriting with right arrow
+.skipSavingTile
+	ld a, "▶" ; place right arrow
+	ld [hl], a
+	ld a, l
+	ld [wMenuCursorLocation], a
+	ld a, h
+	ld [wMenuCursorLocation + 1], a
+	ld a, [wCurrentMenuItem]
+	ld [wLastMenuItem], a
+	ret
+
+; This is used to mark a menu cursor other than the one currently being
+; manipulated. In the case of submenus, this is used to show the location of
+; the menu cursor in the parent menu. In the case of swapping items in list,
+; this is used to mark the item that was first chosen to be swapped.
+PlaceUnfilledArrowMenuCursor::
+	ld b, a
+	ld a, [wMenuCursorLocation]
+	ld l, a
+	ld a, [wMenuCursorLocation + 1]
+	ld h, a
+	ld [hl], $ec ; outline of right arrow
+	ld a, b
+	ret
+
+; Replaces the menu cursor with a blank space.
+EraseMenuCursor::
+	ld a, [wMenuCursorLocation]
+	ld l, a
+	ld a, [wMenuCursorLocation + 1]
+	ld h, a
+	ld [hl], " "
+	ret
+
+; This toggles a blinking down arrow at hl on and off after a delay has passed.
+; This is often called even when no blinking is occurring.
+; The reason is that most functions that call this initialize hDownArrowBlinkCount1 to 0.
+; The effect is that if the tile at hl is initialized with a down arrow,
+; this function will toggle that down arrow on and off, but if the tile isn't
+; initialized with a down arrow, this function does nothing.
+; That allows this to be called without worrying about if a down arrow should
+; be blinking.
+HandleDownArrowBlinkTiming::
+	ld a, [hl]
+	ld b, a
+	ld a, "▼"
+	cp b
+	jr nz, .downArrowOff
+.downArrowOn
+	ldh a, [hDownArrowBlinkCount1]
+	dec a
+	ldh [hDownArrowBlinkCount1], a
+	ret nz
+	ldh a, [hDownArrowBlinkCount2]
+	dec a
+	ldh [hDownArrowBlinkCount2], a
+	ret nz
+	ld a, " "
+	ld [hl], a
+	ld a, $ff
+	ldh [hDownArrowBlinkCount1], a
+	ld a, $06
+	ldh [hDownArrowBlinkCount2], a
+	ret
+.downArrowOff
+	ldh a, [hDownArrowBlinkCount1]
+	and a
+	ret z
+	dec a
+	ldh [hDownArrowBlinkCount1], a
+	ret nz
+	dec a
+	ldh [hDownArrowBlinkCount1], a
+	ldh a, [hDownArrowBlinkCount2]
+	dec a
+	ldh [hDownArrowBlinkCount2], a
+	ret nz
+	ld a, $06
+	ldh [hDownArrowBlinkCount2], a
+	ld a, "▼"
+	ld [hl], a
+	ret
+
+; The following code either enables or disables the automatic drawing of
+; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait
+; for a button press after displaying text (unless [wEnteringCableClub] is set).
+
+EnableAutoTextBoxDrawing::
+	xor a
+	jr AutoTextBoxDrawingCommon
+
+DisableAutoTextBoxDrawing::
+	ld a, $01
+
+AutoTextBoxDrawingCommon::
+	ld [wAutoTextBoxDrawingControl], a
+	xor a
+	ld [wDoNotWaitForButtonPressAfterDisplayingText], a ; make DisplayTextID wait for button press
+	ret
+
+PrintText::
+; Print text hl at (1, 14).
+	push hl
+	ld a, MESSAGE_BOX
+	ld [wTextBoxID], a
+	call DisplayTextBoxID
+	call UpdateSprites
+	call Delay3
+	pop hl
+PrintText_NoCreatingTextBox::
+	bccoord 1, 14
+	jp TextCommandProcessor