summaryrefslogtreecommitdiff
path: root/home
diff options
context:
space:
mode:
Diffstat (limited to 'home')
-rw-r--r--home/array.asm21
-rw-r--r--home/array2.asm47
-rw-r--r--home/compare.asm11
-rw-r--r--home/copy_string.asm13
-rw-r--r--home/count_set_bits.asm24
-rw-r--r--home/delay.asm31
-rw-r--r--home/fade_audio.asm48
-rw-r--r--home/give.asm26
-rw-r--r--home/hidden_objects.asm39
-rw-r--r--home/inventory.asm55
-rw-r--r--home/item.asm49
-rw-r--r--home/item_price.asm44
-rw-r--r--home/joypad2.asm95
-rw-r--r--home/load_font.asm47
-rw-r--r--home/map_objects.asm248
-rw-r--r--home/math.asm41
-rw-r--r--home/money.asm15
-rw-r--r--home/move_mon.asm15
-rw-r--r--home/npc_movement.asm54
-rw-r--r--home/oam.asm36
-rw-r--r--home/overworld.asm51
-rw-r--r--home/palettes.asm57
-rw-r--r--home/pathfinding.asm65
-rw-r--r--home/predef_text.asm28
-rw-r--r--home/print_text.asm45
-rw-r--r--home/random.asm12
-rw-r--r--home/reload_sprites.asm19
-rw-r--r--home/reload_tiles.asm41
-rw-r--r--home/reset_player_sprite.asm20
-rw-r--r--home/textbox.asm16
-rw-r--r--home/tilemap.asm61
-rw-r--r--home/trainers2.asm35
-rw-r--r--home/update_sprites.asm14
-rw-r--r--home/window.asm294
34 files changed, 1717 insertions, 0 deletions
diff --git a/home/array.asm b/home/array.asm
new file mode 100644
index 00000000..256c58e1
--- /dev/null
+++ b/home/array.asm
@@ -0,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
diff --git a/home/array2.asm b/home/array2.asm
new file mode 100644
index 00000000..f4ed8389
--- /dev/null
+++ b/home/array2.asm
@@ -0,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
diff --git a/home/compare.asm b/home/compare.asm
new file mode 100644
index 00000000..e2da7857
--- /dev/null
+++ b/home/compare.asm
@@ -0,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
diff --git a/home/copy_string.asm b/home/copy_string.asm
new file mode 100644
index 00000000..7f86e501
--- /dev/null
+++ b/home/copy_string.asm
@@ -0,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
diff --git a/home/count_set_bits.asm b/home/count_set_bits.asm
new file mode 100644
index 00000000..73f7fa9c
--- /dev/null
+++ b/home/count_set_bits.asm
@@ -0,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
diff --git a/home/delay.asm b/home/delay.asm
new file mode 100644
index 00000000..850b23e9
--- /dev/null
+++ b/home/delay.asm
@@ -0,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
diff --git a/home/fade_audio.asm b/home/fade_audio.asm
new file mode 100644
index 00000000..4ad2607d
--- /dev/null
+++ b/home/fade_audio.asm
@@ -0,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
diff --git a/home/give.asm b/home/give.asm
new file mode 100644
index 00000000..cbfd0310
--- /dev/null
+++ b/home/give.asm
@@ -0,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
diff --git a/home/hidden_objects.asm b/home/hidden_objects.asm
new file mode 100644
index 00000000..eccf1c8f
--- /dev/null
+++ b/home/hidden_objects.asm
@@ -0,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
diff --git a/home/inventory.asm b/home/inventory.asm
new file mode 100644
index 00000000..ebaa4047
--- /dev/null
+++ b/home/inventory.asm
@@ -0,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
diff --git a/home/item.asm b/home/item.asm
new file mode 100644
index 00000000..f27d46f4
--- /dev/null
+++ b/home/item.asm
@@ -0,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
diff --git a/home/item_price.asm b/home/item_price.asm
new file mode 100644
index 00000000..98eb31b1
--- /dev/null
+++ b/home/item_price.asm
@@ -0,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
diff --git a/home/joypad2.asm b/home/joypad2.asm
new file mode 100644
index 00000000..139dd3f5
--- /dev/null
+++ b/home/joypad2.asm
@@ -0,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
diff --git a/home/load_font.asm b/home/load_font.asm
new file mode 100644
index 00000000..3b56d3a8
--- /dev/null
+++ b/home/load_font.asm
@@ -0,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
diff --git a/home/map_objects.asm b/home/map_objects.asm
new file mode 100644
index 00000000..02555e35
--- /dev/null
+++ b/home/map_objects.asm
@@ -0,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
diff --git a/home/math.asm b/home/math.asm
new file mode 100644
index 00000000..b081b540
--- /dev/null
+++ b/home/math.asm
@@ -0,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
diff --git a/home/money.asm b/home/money.asm
new file mode 100644
index 00000000..a62835ea
--- /dev/null
+++ b/home/money.asm
@@ -0,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
diff --git a/home/move_mon.asm b/home/move_mon.asm
index cf7213b1..3e69e6d0 100644
--- 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.
diff --git a/home/npc_movement.asm b/home/npc_movement.asm
new file mode 100644
index 00000000..4914d3df
--- /dev/null
+++ b/home/npc_movement.asm
@@ -0,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
diff --git a/home/oam.asm b/home/oam.asm
new file mode 100644
index 00000000..8a940d97
--- /dev/null
+++ b/home/oam.asm
@@ -0,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
diff --git a/home/overworld.asm b/home/overworld.asm
index acc108c7..0408bf32 100644
--- a/home/overworld.asm
+++ b/home/overworld.asm
@@ -2421,3 +2421,54 @@ ForceBikeOrSurf::
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
diff --git a/home/palettes.asm b/home/palettes.asm
new file mode 100644
index 00000000..08dcdc85
--- /dev/null
+++ b/home/palettes.asm
@@ -0,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
diff --git a/home/pathfinding.asm b/home/pathfinding.asm
new file mode 100644
index 00000000..aca5a763
--- /dev/null
+++ b/home/pathfinding.asm
@@ -0,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
diff --git a/home/predef_text.asm b/home/predef_text.asm
new file mode 100644
index 00000000..b494a2c8
--- /dev/null
+++ b/home/predef_text.asm
@@ -0,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"
diff --git a/home/print_text.asm b/home/print_text.asm
new file mode 100644
index 00000000..049ddfb4
--- /dev/null
+++ b/home/print_text.asm
@@ -0,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
diff --git a/home/random.asm b/home/random.asm
new file mode 100644
index 00000000..33a24425
--- /dev/null
+++ b/home/random.asm
@@ -0,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
diff --git a/home/reload_sprites.asm b/home/reload_sprites.asm
new file mode 100644
index 00000000..8a08d64d
--- /dev/null
+++ b/home/reload_sprites.asm
@@ -0,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
diff --git a/home/reload_tiles.asm b/home/reload_tiles.asm
new file mode 100644
index 00000000..6228395c
--- /dev/null
+++ b/home/reload_tiles.asm
@@ -0,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
diff --git a/home/reset_player_sprite.asm b/home/reset_player_sprite.asm
new file mode 100644
index 00000000..72df31a1
--- /dev/null
+++ b/home/reset_player_sprite.asm
@@ -0,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
diff --git a/home/textbox.asm b/home/textbox.asm
new file mode 100644
index 00000000..5067b044
--- /dev/null
+++ b/home/textbox.asm
@@ -0,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
diff --git a/home/tilemap.asm b/home/tilemap.asm
new file mode 100644
index 00000000..afee7097
--- /dev/null
+++ b/home/tilemap.asm
@@ -0,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
diff --git a/home/trainers2.asm b/home/trainers2.asm
new file mode 100644
index 00000000..950eabb2
--- /dev/null
+++ b/home/trainers2.asm
@@ -0,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_
diff --git a/home/update_sprites.asm b/home/update_sprites.asm
new file mode 100644
index 00000000..80ea14d3
--- /dev/null
+++ b/home/update_sprites.asm
@@ -0,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
diff --git a/home/window.asm b/home/window.asm
new file mode 100644
index 00000000..e83f9585
--- /dev/null
+++ b/home/window.asm
@@ -0,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