summaryrefslogtreecommitdiff
path: root/engine/events
diff options
context:
space:
mode:
Diffstat (limited to 'engine/events')
-rw-r--r--engine/events/black_out.asm46
-rwxr-xr-xengine/events/card_key.asm112
-rwxr-xr-xengine/events/cinnabar_lab.asm123
-rwxr-xr-xengine/events/diploma.asm113
-rw-r--r--engine/events/display_pokedex.asm19
-rwxr-xr-xengine/events/elevator.asm48
-rwxr-xr-xengine/events/evolve_trade.asm44
-rwxr-xr-xengine/events/give_pokemon.asm82
-rw-r--r--engine/events/heal_party.asm99
-rwxr-xr-xengine/events/hidden_items.asm161
-rwxr-xr-xengine/events/hidden_object_functions14.asm100
-rwxr-xr-xengine/events/hidden_object_functions17.asm475
-rwxr-xr-xengine/events/hidden_object_functions18.asm198
-rwxr-xr-xengine/events/hidden_object_functions3.asm117
-rwxr-xr-xengine/events/hidden_object_functions7.asm467
-rwxr-xr-xengine/events/in_game_trades.asm330
-rwxr-xr-xengine/events/oaks_aide.asm71
-rwxr-xr-xengine/events/pewter_guys.asm102
-rw-r--r--engine/events/pick_up_item.asm54
-rw-r--r--engine/events/poison.asm112
-rwxr-xr-xengine/events/pokecenter.asm68
-rwxr-xr-xengine/events/pokedex_rating.asm154
-rwxr-xr-xengine/events/pokemart.asm272
-rwxr-xr-xengine/events/prize_menu.asm306
-rwxr-xr-xengine/events/saffron_guards.asm15
-rw-r--r--engine/events/set_blackout_map.asm25
-rwxr-xr-xengine/events/starter_dex.asm9
-rwxr-xr-xengine/events/vending_machine.asm133
28 files changed, 3855 insertions, 0 deletions
diff --git a/engine/events/black_out.asm b/engine/events/black_out.asm
new file mode 100644
index 00000000..6c358ce3
--- /dev/null
+++ b/engine/events/black_out.asm
@@ -0,0 +1,46 @@
+ResetStatusAndHalveMoneyOnBlackout::
+; Reset player status on blackout.
+ xor a
+ ld [wBattleResult], a
+ ld [wWalkBikeSurfState], a
+ ld [wIsInBattle], a
+ ld [wMapPalOffset], a
+ ld [wNPCMovementScriptFunctionNum], a
+ ld [hJoyHeld], a
+ ld [wNPCMovementScriptPointerTableNum], a
+ ld [wFlags_0xcd60], a
+
+ ld [hMoney], a
+ ld [hMoney + 1], a
+ ld [hMoney + 2], a
+ call HasEnoughMoney
+ jr c, .lostmoney ; never happens
+
+ ; Halve the player's money.
+ ld a, [wPlayerMoney]
+ ld [hMoney], a
+ ld a, [wPlayerMoney + 1]
+ ld [hMoney + 1], a
+ ld a, [wPlayerMoney + 2]
+ ld [hMoney + 2], a
+ xor a
+ ld [hDivideBCDDivisor], a
+ ld [hDivideBCDDivisor + 1], a
+ ld a, 2
+ ld [hDivideBCDDivisor + 2], a
+ predef DivideBCDPredef3
+ ld a, [hDivideBCDQuotient]
+ ld [wPlayerMoney], a
+ ld a, [hDivideBCDQuotient + 1]
+ ld [wPlayerMoney + 1], a
+ ld a, [hDivideBCDQuotient + 2]
+ ld [wPlayerMoney + 2], a
+
+.lostmoney
+ ld hl, wd732
+ set 2, [hl]
+ res 3, [hl]
+ set 6, [hl]
+ ld a, %11111111
+ ld [wJoyIgnore], a
+ predef_jump HealParty
diff --git a/engine/events/card_key.asm b/engine/events/card_key.asm
new file mode 100755
index 00000000..c77d5fcd
--- /dev/null
+++ b/engine/events/card_key.asm
@@ -0,0 +1,112 @@
+PrintCardKeyText:
+ ld hl, SilphCoMapList
+ ld a, [wCurMap]
+ ld b, a
+.silphCoMapListLoop
+ ld a, [hli]
+ cp $ff
+ ret z
+ cp b
+ jr nz, .silphCoMapListLoop
+ predef GetTileAndCoordsInFrontOfPlayer
+ ld a, [wTileInFrontOfPlayer]
+ cp $18
+ jr z, .cardKeyDoorInFrontOfPlayer
+ cp $24
+ jr z, .cardKeyDoorInFrontOfPlayer
+ ld b, a
+ ld a, [wCurMap]
+ cp SILPH_CO_11F
+ ret nz
+ ld a, b
+ cp $5e
+ ret nz
+.cardKeyDoorInFrontOfPlayer
+ ld b, CARD_KEY
+ call IsItemInBag
+ jr z, .noCardKey
+ call GetCoordsInFrontOfPlayer
+ push de
+ tx_pre_id CardKeySuccessText
+ ld [hSpriteIndexOrTextID], a
+ call PrintPredefTextID
+ pop de
+ srl d
+ ld a, d
+ ld b, a
+ ld [wCardKeyDoorY], a
+ srl e
+ ld a, e
+ ld c, a
+ ld [wCardKeyDoorX], a
+ ld a, [wCurMap]
+ cp SILPH_CO_11F
+ jr nz, .notSilphCo11F
+ ld a, $3
+ jr .replaceCardKeyDoorTileBlock
+.notSilphCo11F
+ ld a, $e
+.replaceCardKeyDoorTileBlock
+ ld [wNewTileBlockID], a
+ predef ReplaceTileBlock
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+ ld a, SFX_GO_INSIDE
+ jp PlaySound
+.noCardKey
+ tx_pre_id CardKeyFailText
+ ld [hSpriteIndexOrTextID], a
+ jp PrintPredefTextID
+
+SilphCoMapList:
+ db SILPH_CO_2F
+ db SILPH_CO_3F
+ db SILPH_CO_4F
+ db SILPH_CO_5F
+ db SILPH_CO_6F
+ db SILPH_CO_7F
+ db SILPH_CO_8F
+ db SILPH_CO_9F
+ db SILPH_CO_10F
+ db SILPH_CO_11F
+ db $FF
+
+CardKeySuccessText::
+ TX_FAR _CardKeySuccessText1
+ TX_SFX_ITEM_1
+ TX_FAR _CardKeySuccessText2
+ db "@"
+
+CardKeyFailText::
+ TX_FAR _CardKeyFailText
+ db "@"
+
+; d = Y
+; e = X
+GetCoordsInFrontOfPlayer:
+ ld a, [wYCoord]
+ ld d, a
+ ld a, [wXCoord]
+ ld e, a
+ ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ and a
+ jr nz, .notFacingDown
+; facing down
+ inc d
+ ret
+.notFacingDown
+ cp SPRITE_FACING_UP
+ jr nz, .notFacingUp
+; facing up
+ dec d
+ ret
+.notFacingUp
+ cp SPRITE_FACING_LEFT
+ jr nz, .notFacingLeft
+; facing left
+ dec e
+ ret
+.notFacingLeft
+; facing right
+ inc e
+ ret
diff --git a/engine/events/cinnabar_lab.asm b/engine/events/cinnabar_lab.asm
new file mode 100755
index 00000000..e642840d
--- /dev/null
+++ b/engine/events/cinnabar_lab.asm
@@ -0,0 +1,123 @@
+GiveFossilToCinnabarLab::
+ ld hl, wd730
+ set 6, [hl]
+ xor a
+ ld [wCurrentMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, [wFilteredBagItemsCount]
+ dec a
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ ld a, [wFilteredBagItemsCount]
+ dec a
+ ld bc, 2
+ ld hl, 3
+ call AddNTimes
+ dec l
+ ld b, l
+ ld c, $d
+ coord hl, 0, 0
+ call TextBoxBorder
+ call UpdateSprites
+ call PrintFossilsInBag
+ ld hl, wd730
+ res 6, [hl]
+ call HandleMenuInput
+ bit 1, a ; pressed B?
+ jr nz, .cancelledGivingFossil
+ ld hl, wFilteredBagItems
+ ld a, [wCurrentMenuItem]
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ ld [$ffdb], a
+ cp DOME_FOSSIL
+ jr z, .choseDomeFossil
+ cp HELIX_FOSSIL
+ jr z, .choseHelixFossil
+ ld b, AERODACTYL
+ jr .fossilSelected
+.choseHelixFossil
+ ld b, OMANYTE
+ jr .fossilSelected
+.choseDomeFossil
+ ld b, KABUTO
+.fossilSelected
+ ld [wFossilItem], a
+ ld a, b
+ ld [wFossilMon], a
+ call LoadFossilItemAndMonName
+ ld hl, LabFossil_610ae
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .cancelledGivingFossil
+ ld hl, LabFossil_610b3
+ call PrintText
+ ld a, [wFossilItem]
+ ld [hItemToRemoveID], a
+ callba RemoveItemByID
+ ld hl, LabFossil_610b8
+ call PrintText
+ SetEvents EVENT_GAVE_FOSSIL_TO_LAB, EVENT_LAB_STILL_REVIVING_FOSSIL
+ ret
+.cancelledGivingFossil
+ ld hl, LabFossil_610bd
+ call PrintText
+ ret
+
+LabFossil_610ae:
+ TX_FAR _Lab4Text_610ae
+ db "@"
+
+LabFossil_610b3:
+ TX_FAR _Lab4Text_610b3
+ db "@"
+
+LabFossil_610b8:
+ TX_FAR _Lab4Text_610b8
+ db "@"
+
+LabFossil_610bd:
+ TX_FAR _Lab4Text_610bd
+ db "@"
+
+PrintFossilsInBag:
+; Prints each fossil in the player's bag on a separate line in the menu.
+ ld hl, wFilteredBagItems
+ xor a
+ ld [hItemCounter], a
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ push hl
+ ld [wd11e], a
+ call GetItemName
+ coord hl, 2, 2
+ ld a, [hItemCounter]
+ ld bc, SCREEN_WIDTH * 2
+ call AddNTimes
+ ld de, wcd6d
+ call PlaceString
+ ld hl, hItemCounter
+ inc [hl]
+ pop hl
+ jr .loop
+
+; loads the names of the fossil item and the resulting mon
+LoadFossilItemAndMonName::
+ ld a, [wFossilMon]
+ ld [wd11e], a
+ call GetMonName
+ call CopyStringToCF4B
+ ld a, [wFossilItem]
+ ld [wd11e], a
+ call GetItemName
+ ret
diff --git a/engine/events/diploma.asm b/engine/events/diploma.asm
new file mode 100755
index 00000000..e53ef58f
--- /dev/null
+++ b/engine/events/diploma.asm
@@ -0,0 +1,113 @@
+DisplayDiploma::
+ call SaveScreenTilesToBuffer2
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ld hl, wd730
+ set 6, [hl]
+ call DisableLCD
+ ld hl, CircleTile
+ ld de, vChars2 + $700
+ ld bc, $0010
+ ld a, BANK(CircleTile)
+ call FarCopyData2
+ coord hl, 0, 0
+ lb bc, 16, 18
+ predef Diploma_TextBoxBorder
+ ld hl, DiplomaTextPointersAndCoords
+ ld c, $5
+.asm_56715
+ push bc
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ push hl
+ ld h, [hl]
+ ld l, a
+ call PlaceString
+ pop hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .asm_56715
+ coord hl, 10, 4
+ ld de, wPlayerName
+ call PlaceString
+ callba DrawPlayerCharacter
+
+; Move the player 33 pixels right and set the priority bit so he appears
+; behind the background layer.
+ ld hl, wOAMBuffer + $01
+ lb bc, $80, $28
+.adjustPlayerGfxLoop
+ ld a, [hl] ; X
+ add 33
+ ld [hli], a
+ inc hl
+ ld a, b
+ ld [hli], a ; attributes
+ inc hl
+ dec c
+ jr nz, .adjustPlayerGfxLoop
+
+ call EnableLCD
+ callba LoadTrainerInfoTextBoxTiles
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ call Delay3
+ call GBPalNormal
+ ld a, $90
+ ld [rOBP0], a
+ call WaitForTextScrollButtonPress
+ ld hl, wd730
+ res 6, [hl]
+ call GBPalWhiteOutWithDelay3
+ call RestoreScreenTilesAndReloadTilePatterns
+ call Delay3
+ jp GBPalNormal
+
+UnusedPlayerNameLengthFunc:
+; Unused function that does a calculation involving the length of the player's
+; name.
+ ld hl, wPlayerName
+ ld bc, $ff00
+.loop
+ ld a, [hli]
+ cp "@"
+ ret z
+ dec c
+ jr .loop
+
+DiplomaTextPointersAndCoords:
+ dw DiplomaText
+ dwCoord 5, 2
+ dw DiplomaPlayer
+ dwCoord 3, 4
+ dw DiplomaEmptyText
+ dwCoord 15, 4
+ dw DiplomaCongrats
+ dwCoord 2, 6
+ dw DiplomaGameFreak
+ dwCoord 9, 16
+
+DiplomaText:
+ db $70,"Diploma",$70,"@"
+
+DiplomaPlayer:
+ db "Player@"
+
+DiplomaEmptyText:
+ db "@"
+
+DiplomaCongrats:
+ db "Congrats! This"
+ next "diploma certifies"
+ next "that you have"
+ next "completed your"
+ next "#DEX.@"
+
+DiplomaGameFreak:
+ db "GAME FREAK@"
diff --git a/engine/events/display_pokedex.asm b/engine/events/display_pokedex.asm
new file mode 100644
index 00000000..d657ea85
--- /dev/null
+++ b/engine/events/display_pokedex.asm
@@ -0,0 +1,19 @@
+_DisplayPokedex::
+ ld hl, wd730
+ set 6, [hl]
+ predef ShowPokedexData
+ ld hl, wd730
+ res 6, [hl]
+ call ReloadMapData
+ ld c, 10
+ call DelayFrames
+ predef IndexToPokedex
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_SET
+ ld hl, wPokedexSeen
+ predef FlagActionPredef
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ret
diff --git a/engine/events/elevator.asm b/engine/events/elevator.asm
new file mode 100755
index 00000000..752bdd1a
--- /dev/null
+++ b/engine/events/elevator.asm
@@ -0,0 +1,48 @@
+DisplayElevatorFloorMenu:
+ ld hl, WhichFloorText
+ call PrintText
+ ld hl, wItemList
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ ld a, [wListScrollOffset]
+ push af
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wListScrollOffset], a
+ ld [wPrintItemPrices], a
+ ld a, SPECIALLISTMENU
+ ld [wListMenuID], a
+ call DisplayListMenuID
+ pop bc
+ ld a, b
+ ld [wListScrollOffset], a
+ ret c
+ ld hl, wCurrentMapScriptFlags
+ set 7, [hl]
+ ld hl, wElevatorWarpMaps
+ ld a, [wWhichPokemon]
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ ld c, a
+ ld hl, wWarpEntries
+ call .UpdateWarp
+
+.UpdateWarp
+ inc hl
+ inc hl
+ ld a, b
+ ld [hli], a ; destination warp ID
+ ld a, c
+ ld [hli], a ; destination map ID
+ ret
+
+WhichFloorText:
+ TX_FAR _WhichFloorText
+ db "@"
diff --git a/engine/events/evolve_trade.asm b/engine/events/evolve_trade.asm
new file mode 100755
index 00000000..e17fc05c
--- /dev/null
+++ b/engine/events/evolve_trade.asm
@@ -0,0 +1,44 @@
+EvolveTradeMon:
+; Verify the TradeMon's species name before
+; attempting to initiate a trade evolution.
+
+; The names of the trade evolutions in Blue (JP)
+; are checked. In that version, TradeMons that
+; can evolve are Graveler and Haunter.
+
+; In localization, this check was translated
+; before monster names were finalized.
+; Then, Haunter's name was "Spectre".
+; Since its name no longer starts with
+; "SP", it is prevented from evolving.
+
+; This may have been why Red/Green's trades
+; were used instead, where none can evolve.
+
+; This was fixed in Yellow.
+
+ ld a, [wInGameTradeReceiveMonName]
+
+ ; GRAVELER
+ cp "G"
+ jr z, .ok
+
+ ; "SPECTRE" (HAUNTER)
+ cp "S"
+ ret nz
+ ld a, [wInGameTradeReceiveMonName + 1]
+ cp "P"
+ ret nz
+
+.ok
+ ld a, [wPartyCount]
+ dec a
+ ld [wWhichPokemon], a
+ ld a, $1
+ ld [wForceEvolution], a
+ ld a, LINK_STATE_TRADING
+ ld [wLinkState], a
+ callab TryEvolvingMon
+ xor a ; LINK_STATE_NONE
+ ld [wLinkState], a
+ jp PlayDefaultMusic
diff --git a/engine/events/give_pokemon.asm b/engine/events/give_pokemon.asm
new file mode 100755
index 00000000..03177e60
--- /dev/null
+++ b/engine/events/give_pokemon.asm
@@ -0,0 +1,82 @@
+_GivePokemon::
+; returns success in carry
+; and whether the mon was added to the party in [wAddedToParty]
+ call EnableAutoTextBoxDrawing
+ xor a
+ ld [wAddedToParty], a
+ ld a, [wPartyCount]
+ cp PARTY_LENGTH
+ jr c, .addToParty
+ ld a, [wNumInBox]
+ cp MONS_PER_BOX
+ jr nc, .boxFull
+; add to box
+ xor a
+ ld [wEnemyBattleStatus3], a
+ ld a, [wcf91]
+ ld [wEnemyMonSpecies2], a
+ callab LoadEnemyMonData
+ call SetPokedexOwnedFlag
+ callab SendNewMonToBox
+ ld hl, wcf4b
+ ld a, [wCurrentBoxNum]
+ and $7f
+ cp 9
+ jr c, .singleDigitBoxNum
+ sub 9
+ ld [hl], "1"
+ inc hl
+ add "0"
+ jr .next
+.singleDigitBoxNum
+ add "1"
+.next
+ ld [hli], a
+ ld [hl], "@"
+ ld hl, SentToBoxText
+ call PrintText
+ scf
+ ret
+.boxFull
+ ld hl, BoxIsFullText
+ call PrintText
+ and a
+ ret
+.addToParty
+ call SetPokedexOwnedFlag
+ call AddPartyMon
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld [wAddedToParty], a
+ scf
+ ret
+
+SetPokedexOwnedFlag:
+ ld a, [wcf91]
+ push af
+ ld [wd11e], a
+ predef IndexToPokedex
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld hl, wPokedexOwned
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ pop af
+ ld [wd11e], a
+ call GetMonName
+ ld hl, GotMonText
+ jp PrintText
+
+GotMonText:
+ TX_FAR _GotMonText
+ TX_SFX_ITEM_1
+ db "@"
+
+SentToBoxText:
+ TX_FAR _SentToBoxText
+ db "@"
+
+BoxIsFullText:
+ TX_FAR _BoxIsFullText
+ db "@"
diff --git a/engine/events/heal_party.asm b/engine/events/heal_party.asm
new file mode 100644
index 00000000..7aaa1bd1
--- /dev/null
+++ b/engine/events/heal_party.asm
@@ -0,0 +1,99 @@
+HealParty:
+; Restore HP and PP.
+
+ ld hl, wPartySpecies
+ ld de, wPartyMon1HP
+.healmon
+ ld a, [hli]
+ cp $ff
+ jr z, .done
+
+ push hl
+ push de
+
+ ld hl, wPartyMon1Status - wPartyMon1HP
+ add hl, de
+ xor a
+ ld [hl], a
+
+ push de
+ ld b, NUM_MOVES ; A Pokémon has 4 moves
+.pp
+ ld hl, wPartyMon1Moves - wPartyMon1HP
+ add hl, de
+
+ ld a, [hl]
+ and a
+ jr z, .nextmove
+
+ dec a
+ ld hl, wPartyMon1PP - wPartyMon1HP
+ add hl, de
+
+ push hl
+ push de
+ push bc
+
+ ld hl, Moves
+ ld bc, MoveEnd - Moves
+ call AddNTimes
+ ld de, wcd6d
+ ld a, BANK(Moves)
+ call FarCopyData
+ ld a, [wcd6d + 5] ; PP is byte 5 of move data
+
+ pop bc
+ pop de
+ pop hl
+
+ inc de
+ push bc
+ ld b, a
+ ld a, [hl]
+ and $c0
+ add b
+ ld [hl], a
+ pop bc
+
+.nextmove
+ dec b
+ jr nz, .pp
+ pop de
+
+ ld hl, wPartyMon1MaxHP - wPartyMon1HP
+ add hl, de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+
+ pop de
+ pop hl
+
+ push hl
+ ld bc, wPartyMon2 - wPartyMon1
+ ld h, d
+ ld l, e
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ jr .healmon
+
+.done
+ xor a
+ ld [wWhichPokemon], a
+ ld [wd11e], a
+
+ ld a, [wPartyCount]
+ ld b, a
+.ppup
+ push bc
+ call RestoreBonusPP
+ pop bc
+ ld hl, wWhichPokemon
+ inc [hl]
+ dec b
+ jr nz, .ppup
+ ret
diff --git a/engine/events/hidden_items.asm b/engine/events/hidden_items.asm
new file mode 100755
index 00000000..e40b0ac7
--- /dev/null
+++ b/engine/events/hidden_items.asm
@@ -0,0 +1,161 @@
+HiddenItems:
+ ld hl, HiddenItemCoords
+ call FindHiddenItemOrCoinsIndex
+ ld [wHiddenItemOrCoinsIndex], a
+ ld hl, wObtainedHiddenItemsFlags
+ ld a, [wHiddenItemOrCoinsIndex]
+ ld c, a
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ret nz
+ call EnableAutoTextBoxDrawing
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument] ; item ID
+ ld [wd11e], a
+ call GetItemName
+ tx_pre_jump FoundHiddenItemText
+
+INCLUDE "data/hidden_item_coords.asm"
+
+FoundHiddenItemText::
+ TX_FAR _FoundHiddenItemText
+ TX_ASM
+ ld a, [wHiddenObjectFunctionArgument] ; item ID
+ ld b, a
+ ld c, 1
+ call GiveItem
+ jr nc, .bagFull
+ ld hl, wObtainedHiddenItemsFlags
+ ld a, [wHiddenItemOrCoinsIndex]
+ ld c, a
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ ld a, SFX_GET_ITEM_2
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+.bagFull
+ call WaitForTextScrollButtonPress ; wait for button press
+ xor a
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld hl, HiddenItemBagFullText
+ call PrintText
+ jp TextScriptEnd
+
+HiddenItemBagFullText::
+ TX_FAR _HiddenItemBagFullText
+ db "@"
+
+HiddenCoins:
+ ld b, COIN_CASE
+ predef GetQuantityOfItemInBag
+ ld a, b
+ and a
+ ret z
+ ld hl, HiddenCoinCoords
+ call FindHiddenItemOrCoinsIndex
+ ld [wHiddenItemOrCoinsIndex], a
+ ld hl, wObtainedHiddenCoinsFlags
+ ld a, [wHiddenItemOrCoinsIndex]
+ ld c, a
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ret nz
+ xor a
+ ld [hUnusedCoinsByte], a
+ ld [hCoins], a
+ ld [hCoins + 1], a
+ ld a, [wHiddenObjectFunctionArgument]
+ sub COIN
+ cp 10
+ jr z, .bcd10
+ cp 20
+ jr z, .bcd20
+ cp 40
+ jr z, .bcd20 ; should be bcd40
+ jr .bcd100
+.bcd10
+ ld a, $10
+ ld [hCoins + 1], a
+ jr .bcdDone
+.bcd20
+ ld a, $20
+ ld [hCoins + 1], a
+ jr .bcdDone
+.bcd40 ; due to a typo, this is never used
+ ld a, $40
+ ld [hCoins + 1], a
+ jr .bcdDone
+.bcd100
+ ld a, $1
+ ld [hCoins], a
+.bcdDone
+ ld de, wPlayerCoins + 1
+ ld hl, hCoins + 1
+ ld c, $2
+ predef AddBCDPredef
+ ld hl, wObtainedHiddenCoinsFlags
+ ld a, [wHiddenItemOrCoinsIndex]
+ ld c, a
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ call EnableAutoTextBoxDrawing
+ ld a, [wPlayerCoins]
+ cp $99
+ jr nz, .roomInCoinCase
+ ld a, [wPlayerCoins + 1]
+ cp $99
+ jr nz, .roomInCoinCase
+ tx_pre_id DroppedHiddenCoinsText
+ jr .done
+.roomInCoinCase
+ tx_pre_id FoundHiddenCoinsText
+.done
+ jp PrintPredefTextID
+
+INCLUDE "data/hidden_coins.asm"
+
+FoundHiddenCoinsText::
+ TX_FAR _FoundHiddenCoinsText
+ TX_SFX_ITEM_2
+ db "@"
+
+DroppedHiddenCoinsText::
+ TX_FAR _FoundHiddenCoins2Text
+ TX_SFX_ITEM_2
+ TX_FAR _DroppedHiddenCoinsText
+ db "@"
+
+FindHiddenItemOrCoinsIndex:
+ ld a, [wHiddenObjectY]
+ ld d, a
+ ld a, [wHiddenObjectX]
+ ld e, a
+ ld a, [wCurMap]
+ ld b, a
+ ld c, -1
+.loop
+ inc c
+ ld a, [hli]
+ cp $ff ; end of the list?
+ ret z ; if so, we're done here
+ cp b
+ jr nz, .next1
+ ld a, [hli]
+ cp d
+ jr nz, .next2
+ ld a, [hli]
+ cp e
+ jr nz, .loop
+ ld a, c
+ ret
+.next1
+ inc hl
+.next2
+ inc hl
+ jr .loop
diff --git a/engine/events/hidden_object_functions14.asm b/engine/events/hidden_object_functions14.asm
new file mode 100755
index 00000000..9e14c6a7
--- /dev/null
+++ b/engine/events/hidden_object_functions14.asm
@@ -0,0 +1,100 @@
+PrintNotebookText:
+ call EnableAutoTextBoxDrawing
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument]
+ jp PrintPredefTextID
+
+TMNotebook::
+ TX_FAR TMNotebookText
+ TX_WAIT
+ db "@"
+
+ViridianSchoolNotebook::
+ TX_ASM
+ ld hl, ViridianSchoolNotebookText1
+ call PrintText
+ call TurnPageSchoolNotebook
+ jr nz, .doneReading
+ ld hl, ViridianSchoolNotebookText2
+ call PrintText
+ call TurnPageSchoolNotebook
+ jr nz, .doneReading
+ ld hl, ViridianSchoolNotebookText3
+ call PrintText
+ call TurnPageSchoolNotebook
+ jr nz, .doneReading
+ ld hl, ViridianSchoolNotebookText4
+ call PrintText
+ ld hl, ViridianSchoolNotebookText5
+ call PrintText
+.doneReading
+ jp TextScriptEnd
+
+TurnPageSchoolNotebook:
+ ld hl, TurnPageText
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ ret
+
+TurnPageText:
+ TX_FAR _TurnPageText
+ db "@"
+
+ViridianSchoolNotebookText5:
+ TX_FAR _ViridianSchoolNotebookText5
+ TX_WAIT
+ db "@"
+
+ViridianSchoolNotebookText1:
+ TX_FAR _ViridianSchoolNotebookText1
+ db "@"
+
+ViridianSchoolNotebookText2:
+ TX_FAR _ViridianSchoolNotebookText2
+ db "@"
+
+ViridianSchoolNotebookText3:
+ TX_FAR _ViridianSchoolNotebookText3
+ db "@"
+
+ViridianSchoolNotebookText4:
+ TX_FAR _ViridianSchoolNotebookText4
+ db "@"
+
+PrintFightingDojoText2:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump EnemiesOnEverySideText
+
+EnemiesOnEverySideText::
+ TX_FAR _EnemiesOnEverySideText
+ db "@"
+
+PrintFightingDojoText3:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump WhatGoesAroundComesAroundText
+
+WhatGoesAroundComesAroundText::
+ TX_FAR _WhatGoesAroundComesAroundText
+ db "@"
+
+PrintFightingDojoText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump FightingDojoText
+
+FightingDojoText::
+ TX_FAR _FightingDojoText
+ db "@"
+
+PrintIndigoPlateauHQText:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump IndigoPlateauHQText
+
+IndigoPlateauHQText::
+ TX_FAR _IndigoPlateauHQText
+ db "@"
diff --git a/engine/events/hidden_object_functions17.asm b/engine/events/hidden_object_functions17.asm
new file mode 100755
index 00000000..bb2a358c
--- /dev/null
+++ b/engine/events/hidden_object_functions17.asm
@@ -0,0 +1,475 @@
+PrintRedSNESText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump RedBedroomSNESText
+
+RedBedroomSNESText::
+ TX_FAR _RedBedroomSNESText
+ db "@"
+
+OpenRedsPC:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump RedBedroomPCText
+
+RedBedroomPCText::
+ TX_PLAYERS_PC
+
+Route15GateLeftBinoculars:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre Route15UpstairsBinocularsText
+ ld a, ARTICUNO
+ ld [wcf91], a
+ call PlayCry
+ jp DisplayMonFrontSpriteInBox
+
+Route15UpstairsBinocularsText::
+ TX_FAR _Route15UpstairsBinocularsText
+ db "@"
+
+AerodactylFossil:
+ ld a, FOSSIL_AERODACTYL
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre AerodactylFossilText
+ ret
+
+AerodactylFossilText::
+ TX_FAR _AerodactylFossilText
+ db "@"
+
+KabutopsFossil:
+ ld a, FOSSIL_KABUTOPS
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre KabutopsFossilText
+ ret
+
+KabutopsFossilText::
+ TX_FAR _KabutopsFossilText
+ db "@"
+
+DisplayMonFrontSpriteInBox:
+; Displays a pokemon's front sprite in a pop-up window.
+; [wcf91] = pokemon internal id number
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ xor a
+ ld [hWY], a
+ call SaveScreenTilesToBuffer1
+ ld a, MON_SPRITE_POPUP
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ call UpdateSprites
+ ld a, [wcf91]
+ ld [wd0b5], a
+ call GetMonHeader
+ ld de, vChars1 + $310
+ call LoadMonFrontSprite
+ ld a, $80
+ ld [hStartTileID], a
+ coord hl, 10, 11
+ predef AnimateSendingOutMon
+ call WaitForTextScrollButtonPress
+ call LoadScreenTilesFromBuffer1
+ call Delay3
+ ld a, $90
+ ld [hWY], a
+ ret
+
+PrintBlackboardLinkCableText:
+ call EnableAutoTextBoxDrawing
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument]
+ call PrintPredefTextID
+ ret
+
+LinkCableHelp::
+ TX_ASM
+ call SaveScreenTilesToBuffer1
+ ld hl, LinkCableHelpText1
+ call PrintText
+ xor a
+ ld [wMenuItemOffset], a ; not used
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 3
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+.linkHelpLoop
+ ld hl, wd730
+ set 6, [hl]
+ coord hl, 0, 0
+ ld b, 8
+ ld c, 13
+ call TextBoxBorder
+ coord hl, 2, 2
+ ld de, HowToLinkText
+ call PlaceString
+ ld hl, LinkCableHelpText2
+ call PrintText
+ call HandleMenuInput
+ bit 1, a ; pressed b
+ jr nz, .exit
+ ld a, [wCurrentMenuItem]
+ cp 3 ; pressed a on "STOP READING"
+ jr z, .exit
+ ld hl, wd730
+ res 6, [hl]
+ ld hl, LinkCableInfoTexts
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+ jp .linkHelpLoop
+.exit
+ ld hl, wd730
+ res 6, [hl]
+ call LoadScreenTilesFromBuffer1
+ jp TextScriptEnd
+
+LinkCableHelpText1:
+ TX_FAR _LinkCableHelpText1
+ db "@"
+
+LinkCableHelpText2:
+ TX_FAR _LinkCableHelpText2
+ db "@"
+
+HowToLinkText:
+ db "HOW TO LINK"
+ next "COLOSSEUM"
+ next "TRADE CENTER"
+ next "STOP READING@"
+
+LinkCableInfoTexts:
+ dw LinkCableInfoText1
+ dw LinkCableInfoText2
+ dw LinkCableInfoText3
+
+LinkCableInfoText1:
+ TX_FAR _LinkCableInfoText1
+ db "@"
+
+LinkCableInfoText2:
+ TX_FAR _LinkCableInfoText2
+ db "@"
+
+LinkCableInfoText3:
+ TX_FAR _LinkCableInfoText3
+ db "@"
+
+ViridianSchoolBlackboard::
+ TX_ASM
+ call SaveScreenTilesToBuffer1
+ ld hl, ViridianSchoolBlackboardText1
+ call PrintText
+ xor a
+ ld [wMenuItemOffset], a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 2
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+.blackboardLoop
+ ld hl, wd730
+ set 6, [hl]
+ coord hl, 0, 0
+ lb bc, 6, 10
+ call TextBoxBorder
+ coord hl, 1, 2
+ ld de, StatusAilmentText1
+ call PlaceString
+ coord hl, 6, 2
+ ld de, StatusAilmentText2
+ call PlaceString
+ ld hl, ViridianSchoolBlackboardText2
+ call PrintText
+ call HandleMenuInput ; pressing up and down is handled in here
+ bit 1, a ; pressed b
+ jr nz, .exitBlackboard
+ bit 4, a ; pressed right
+ jr z, .didNotPressRight
+ ; move cursor to right column
+ ld a, 2
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 6
+ ld [wTopMenuItemX], a
+ ld a, 3 ; in the the right column, use an offset to prevent overlap
+ ld [wMenuItemOffset], a
+ jr .blackboardLoop
+.didNotPressRight
+ bit 5, a ; pressed left
+ jr z, .didNotPressLeftOrRight
+ ; move cursor to left column
+ ld a, 2
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ xor a
+ ld [wMenuItemOffset], a
+ jr .blackboardLoop
+.didNotPressLeftOrRight
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, [wMenuItemOffset]
+ add b
+ cp 5 ; cursor is pointing to "QUIT"
+ jr z, .exitBlackboard
+ ; we must have pressed a on a status condition
+ ; so print the text
+ ld hl, wd730
+ res 6, [hl]
+ ld hl, ViridianBlackboardStatusPointers
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+ jp .blackboardLoop
+.exitBlackboard
+ ld hl, wd730
+ res 6, [hl]
+ call LoadScreenTilesFromBuffer1
+ jp TextScriptEnd
+
+ViridianSchoolBlackboardText1:
+ TX_FAR _ViridianSchoolBlackboardText1
+ db "@"
+
+ViridianSchoolBlackboardText2:
+ TX_FAR _ViridianSchoolBlackboardText2
+ db "@"
+
+StatusAilmentText1:
+ db " SLP"
+ next " PSN"
+ next " PAR@"
+
+StatusAilmentText2:
+ db " BRN"
+ next " FRZ"
+ next " QUIT@@"
+
+ViridianBlackboardStatusPointers:
+ dw ViridianBlackboardSleepText
+ dw ViridianBlackboardPoisonText
+ dw ViridianBlackboardPrlzText
+ dw ViridianBlackboardBurnText
+ dw ViridianBlackboardFrozenText
+
+ViridianBlackboardSleepText:
+ TX_FAR _ViridianBlackboardSleepText
+ db "@"
+
+ViridianBlackboardPoisonText:
+ TX_FAR _ViridianBlackboardPoisonText
+ db "@"
+
+ViridianBlackboardPrlzText:
+ TX_FAR _ViridianBlackboardPrlzText
+ db "@"
+
+ViridianBlackboardBurnText:
+ TX_FAR _ViridianBlackboardBurnText
+ db "@"
+
+ViridianBlackboardFrozenText:
+ TX_FAR _ViridianBlackboardFrozenText
+ db "@"
+
+PrintTrashText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump VermilionGymTrashText
+
+VermilionGymTrashText::
+ TX_FAR _VermilionGymTrashText
+ db "@"
+
+GymTrashScript:
+ call EnableAutoTextBoxDrawing
+ ld a, [wHiddenObjectFunctionArgument]
+ ld [wGymTrashCanIndex], a
+
+; Don't do the trash can puzzle if it's already been done.
+ CheckEvent EVENT_2ND_LOCK_OPENED
+ jr z, .ok
+
+ tx_pre_jump VermilionGymTrashText
+
+.ok
+ CheckEventReuseA EVENT_1ST_LOCK_OPENED
+ jr nz, .trySecondLock
+
+ ld a, [wFirstLockTrashCanIndex]
+ ld b, a
+ ld a, [wGymTrashCanIndex]
+ cp b
+ jr z, .openFirstLock
+
+ tx_pre_id VermilionGymTrashText
+ jr .done
+
+.openFirstLock
+; Next can is trying for the second switch.
+ SetEvent EVENT_1ST_LOCK_OPENED
+
+ ld hl, GymTrashCans
+ ld a, [wGymTrashCanIndex]
+ ; * 5
+ ld b, a
+ add a
+ add a
+ add b
+
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+
+; There is a bug in this code. It should calculate a value in the range [0, 3]
+; but if the mask and random number don't have any 1 bits in common, then
+; the result of the AND will be 0. When 1 is subtracted from that, the value
+; will become $ff. This will result in 255 being added to hl, which will cause
+; hl to point to one of the zero bytes that pad the end of the ROM bank.
+; Trash can 0 was intended to be able to have the second lock only when the
+; first lock was in trash can 1 or 3. However, due to this bug, trash can 0 can
+; have the second lock regardless of which trash can had the first lock.
+
+ ld [hGymTrashCanRandNumMask], a
+ push hl
+ call Random
+ swap a
+ ld b, a
+ ld a, [hGymTrashCanRandNumMask]
+ and b
+ dec a
+ pop hl
+
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ and $f
+ ld [wSecondLockTrashCanIndex], a
+
+ tx_pre_id VermilionGymTrashSuccessText1
+ jr .done
+
+.trySecondLock
+ ld a, [wSecondLockTrashCanIndex]
+ ld b, a
+ ld a, [wGymTrashCanIndex]
+ cp b
+ jr z, .openSecondLock
+
+; Reset the cans.
+ ResetEvent EVENT_1ST_LOCK_OPENED
+ call Random
+
+ and $e
+ ld [wFirstLockTrashCanIndex], a
+
+ tx_pre_id VermilionGymTrashFailText
+ jr .done
+
+.openSecondLock
+; Completed the trash can puzzle.
+ SetEvent EVENT_2ND_LOCK_OPENED
+ ld hl, wCurrentMapScriptFlags
+ set 6, [hl]
+
+ tx_pre_id VermilionGymTrashSuccessText3
+
+.done
+ jp PrintPredefTextID
+
+GymTrashCans:
+; byte 0: mask for random number
+; bytes 1-4: indices of the trash cans that can have the second lock
+; (but see the comment above explaining a bug regarding this)
+; Note that the mask is simply the number of valid trash can indices that
+; follow. The remaining bytes are filled with 0 to pad the length of each entry
+; to 5 bytes.
+ db 2, 1, 3, 0, 0 ; 0
+ db 3, 0, 2, 4, 0 ; 1
+ db 2, 1, 5, 0, 0 ; 2
+ db 3, 0, 4, 6, 0 ; 3
+ db 4, 1, 3, 5, 7 ; 4
+ db 3, 2, 4, 8, 0 ; 5
+ db 3, 3, 7, 9, 0 ; 6
+ db 4, 4, 6, 8, 10 ; 7
+ db 3, 5, 7, 11, 0 ; 8
+ db 3, 6, 10, 12, 0 ; 9
+ db 4, 7, 9, 11, 13 ; 10
+ db 3, 8, 10, 14, 0 ; 11
+ db 2, 9, 13, 0, 0 ; 12
+ db 3, 10, 12, 14, 0 ; 13
+ db 2, 11, 13, 0, 0 ; 14
+
+VermilionGymTrashSuccessText1::
+ TX_FAR _VermilionGymTrashSuccessText1
+ TX_ASM
+ call WaitForSoundToFinish
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+; unused
+VermilionGymTrashSuccessText2::
+ TX_FAR _VermilionGymTrashSuccessText2
+ db "@"
+
+; unused
+VermilionGymTrashSuccesPlaySfx:
+ TX_ASM
+ call WaitForSoundToFinish
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+VermilionGymTrashSuccessText3::
+ TX_FAR _VermilionGymTrashSuccessText3
+ TX_ASM
+ call WaitForSoundToFinish
+ ld a, SFX_GO_INSIDE
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+VermilionGymTrashFailText::
+ TX_FAR _VermilionGymTrashFailText
+ TX_ASM
+ call WaitForSoundToFinish
+ ld a, SFX_DENIED
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
diff --git a/engine/events/hidden_object_functions18.asm b/engine/events/hidden_object_functions18.asm
new file mode 100755
index 00000000..c0e5aa34
--- /dev/null
+++ b/engine/events/hidden_object_functions18.asm
@@ -0,0 +1,198 @@
+GymStatues:
+; if in a gym and have the corresponding badge, a = GymStatueText2_id and jp PrintPredefTextID
+; if in a gym and don’t have the corresponding badge, a = GymStatueText1_id and jp PrintPredefTextID
+; else ret
+ call EnableAutoTextBoxDrawing
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ ld hl, .BadgeFlags
+ ld a, [wCurMap]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ cp b
+ jr z, .match
+ inc hl
+ jr .loop
+.match
+ ld b, [hl]
+ ld a, [wBeatGymFlags]
+ and b
+ cp b
+ tx_pre_id GymStatueText2
+ jr z, .haveBadge
+ tx_pre_id GymStatueText1
+.haveBadge
+ jp PrintPredefTextID
+
+.BadgeFlags:
+ db PEWTER_GYM, %00000001
+ db CERULEAN_GYM, %00000010
+ db VERMILION_GYM,%00000100
+ db CELADON_GYM, %00001000
+ db FUCHSIA_GYM, %00010000
+ db SAFFRON_GYM, %00100000
+ db CINNABAR_GYM, %01000000
+ db VIRIDIAN_GYM, %10000000
+ db $ff
+
+GymStatueText1::
+ TX_FAR _GymStatueText1
+ db "@"
+
+GymStatueText2::
+ TX_FAR _GymStatueText2
+ db "@"
+
+PrintBenchGuyText:
+ call EnableAutoTextBoxDrawing
+ ld hl, BenchGuyTextPointers
+ ld a, [wCurMap]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ cp b
+ jr z, .match
+ inc hl
+ inc hl
+ jr .loop
+.match
+ ld a, [hli]
+ ld b, a
+ ld a, [wSpriteStateData1 + 9]
+ cp b
+ jr nz, .loop ; player isn't facing left at the bench guy
+ ld a, [hl]
+ jp PrintPredefTextID
+
+; format: db map id, player sprite facing direction, text id of PredefTextIDPointerTable
+BenchGuyTextPointers:
+ db VIRIDIAN_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre ViridianCityPokecenterBenchGuyText
+ db PEWTER_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre PewterCityPokecenterBenchGuyText
+ db CERULEAN_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre CeruleanCityPokecenterBenchGuyText
+ db LAVENDER_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre LavenderCityPokecenterBenchGuyText
+ db VERMILION_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre VermilionCityPokecenterBenchGuyText
+ db CELADON_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre CeladonCityPokecenterBenchGuyText
+ db CELADON_HOTEL, SPRITE_FACING_LEFT
+ db_tx_pre CeladonCityHotelText
+ db FUCHSIA_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre FuchsiaCityPokecenterBenchGuyText
+ db CINNABAR_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre CinnabarIslandPokecenterBenchGuyText
+ db SAFFRON_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre SaffronCityPokecenterBenchGuyText
+ db MT_MOON_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre MtMoonPokecenterBenchGuyText
+ db ROCK_TUNNEL_POKECENTER,SPRITE_FACING_LEFT
+ db_tx_pre RockTunnelPokecenterBenchGuyText
+ db $FF
+
+ViridianCityPokecenterBenchGuyText::
+ TX_FAR _ViridianCityPokecenterGuyText
+ db "@"
+
+PewterCityPokecenterBenchGuyText::
+ TX_FAR _PewterCityPokecenterGuyText
+ db "@"
+
+CeruleanCityPokecenterBenchGuyText::
+ TX_FAR _CeruleanPokecenterGuyText
+ db "@"
+
+LavenderCityPokecenterBenchGuyText::
+ TX_FAR _LavenderPokecenterGuyText
+ db "@"
+
+MtMoonPokecenterBenchGuyText::
+ TX_FAR _MtMoonPokecenterBenchGuyText
+ db "@"
+
+RockTunnelPokecenterBenchGuyText::
+ TX_FAR _RockTunnelPokecenterGuyText
+ db "@"
+
+UnusedBenchGuyText1::
+ TX_FAR _UnusedBenchGuyText1
+ db "@"
+
+UnusedBenchGuyText2::
+ TX_FAR _UnusedBenchGuyText2
+ db "@"
+
+UnusedBenchGuyText3::
+ TX_FAR _UnusedBenchGuyText3
+ db "@"
+
+VermilionCityPokecenterBenchGuyText::
+ TX_FAR _VermilionPokecenterGuyText
+ db "@"
+
+CeladonCityPokecenterBenchGuyText::
+ TX_FAR _CeladonCityPokecenterGuyText
+ db "@"
+
+FuchsiaCityPokecenterBenchGuyText::
+ TX_FAR _FuchsiaCityPokecenterGuyText
+ db "@"
+
+CinnabarIslandPokecenterBenchGuyText::
+ TX_FAR _CinnabarPokecenterGuyText
+ db "@"
+
+SaffronCityPokecenterBenchGuyText::
+ TX_ASM
+ CheckEvent EVENT_BEAT_SILPH_CO_GIOVANNI
+ ld hl, SaffronCityPokecenterBenchGuyText2
+ jr nz, .asm_624f2
+ ld hl, SaffronCityPokecenterBenchGuyText1
+.asm_624f2
+ call PrintText
+ jp TextScriptEnd
+
+SaffronCityPokecenterBenchGuyText1:
+ TX_FAR _SaffronCityPokecenterGuyText1
+ db "@"
+
+SaffronCityPokecenterBenchGuyText2:
+ TX_FAR _SaffronCityPokecenterGuyText2
+ db "@"
+
+CeladonCityHotelText::
+ TX_FAR _CeladonCityHotelText
+ db "@"
+
+ ret
+
+UnusedPredefText::
+ db "@"
+
+PrintBookcaseText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump BookcaseText
+
+BookcaseText::
+ TX_FAR _BookcaseText
+ db "@"
+
+OpenPokemonCenterPC:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP ; check to see if player is facing up
+ ret nz
+ call EnableAutoTextBoxDrawing
+ ld a, $1
+ ld [wAutoTextBoxDrawingControl], a
+ tx_pre_jump PokemonCenterPCText
+
+PokemonCenterPCText::
+ TX_POKECENTER_PC
diff --git a/engine/events/hidden_object_functions3.asm b/engine/events/hidden_object_functions3.asm
new file mode 100755
index 00000000..1237e960
--- /dev/null
+++ b/engine/events/hidden_object_functions3.asm
@@ -0,0 +1,117 @@
+; prints text for bookshelves in buildings without sign events
+PrintBookshelfText::
+ ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ cp SPRITE_FACING_UP
+ jr nz, .noMatch
+; facing up
+ ld a, [wCurMapTileset]
+ ld b, a
+ aCoord 8, 7
+ ld c, a
+ ld hl, BookshelfTileIDs
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .noMatch
+ cp b
+ jr nz, .nextBookshelfEntry1
+ ld a, [hli]
+ cp c
+ jr nz, .nextBookshelfEntry2
+ ld a, [hl]
+ push af
+ call EnableAutoTextBoxDrawing
+ pop af
+ call PrintPredefTextID
+ xor a
+ ld [$ffdb], a
+ ret
+.nextBookshelfEntry1
+ inc hl
+.nextBookshelfEntry2
+ inc hl
+ jr .loop
+.noMatch
+ ld a, $ff
+ ld [$ffdb], a
+ jpba PrintCardKeyText
+
+INCLUDE "data/bookshelf_tile_ids.asm"
+
+IndigoPlateauStatues::
+ TX_ASM
+ ld hl, IndigoPlateauStatuesText1
+ call PrintText
+ ld a, [wXCoord]
+ bit 0, a
+ ld hl, IndigoPlateauStatuesText2
+ jr nz, .ok
+ ld hl, IndigoPlateauStatuesText3
+.ok
+ call PrintText
+ jp TextScriptEnd
+
+IndigoPlateauStatuesText1:
+ TX_FAR _IndigoPlateauStatuesText1
+ db "@"
+
+IndigoPlateauStatuesText2:
+ TX_FAR _IndigoPlateauStatuesText2
+ db "@"
+
+IndigoPlateauStatuesText3:
+ TX_FAR _IndigoPlateauStatuesText3
+ db "@"
+
+BookOrSculptureText::
+ TX_ASM
+ ld hl, PokemonBooksText
+ ld a, [wCurMapTileset]
+ cp MANSION ; Celadon Mansion tileset
+ jr nz, .ok
+ aCoord 8, 6
+ cp $38
+ jr nz, .ok
+ ld hl, DiglettSculptureText
+.ok
+ call PrintText
+ jp TextScriptEnd
+
+PokemonBooksText:
+ TX_FAR _PokemonBooksText
+ db "@"
+
+DiglettSculptureText:
+ TX_FAR _DiglettSculptureText
+ db "@"
+
+ElevatorText::
+ TX_FAR _ElevatorText
+ db "@"
+
+TownMapText::
+ TX_FAR _TownMapText
+ TX_BLINK
+ TX_ASM
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld hl, wd730
+ set 6, [hl]
+ call GBPalWhiteOutWithDelay3
+ xor a
+ ld [hWY], a
+ inc a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call LoadFontTilePatterns
+ callba DisplayTownMap
+ ld hl, wd730
+ res 6, [hl]
+ ld de, TextScriptEnd
+ push de
+ ld a, [H_LOADEDROMBANK]
+ push af
+ jp CloseTextDisplay
+
+PokemonStuffText::
+ TX_FAR _PokemonStuffText
+ db "@"
diff --git a/engine/events/hidden_object_functions7.asm b/engine/events/hidden_object_functions7.asm
new file mode 100755
index 00000000..e18b9570
--- /dev/null
+++ b/engine/events/hidden_object_functions7.asm
@@ -0,0 +1,467 @@
+PrintNewBikeText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump NewBicycleText
+
+NewBicycleText::
+ TX_FAR _NewBicycleText
+ db "@"
+
+DisplayOakLabLeftPoster:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump PushStartText
+
+PushStartText::
+ TX_FAR _PushStartText
+ db "@"
+
+DisplayOakLabRightPoster:
+ call EnableAutoTextBoxDrawing
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ ld a, [wNumSetBits]
+ cp 2
+ tx_pre_id SaveOptionText
+ jr c, .ownLessThanTwo
+ ; own two or more mon
+ tx_pre_id StrengthsAndWeaknessesText
+.ownLessThanTwo
+ jp PrintPredefTextID
+
+SaveOptionText::
+ TX_FAR _SaveOptionText
+ db "@"
+
+StrengthsAndWeaknessesText::
+ TX_FAR _StrengthsAndWeaknessesText
+ db "@"
+
+SafariZoneCheck::
+ CheckEventHL EVENT_IN_SAFARI_ZONE ; if we are not in the Safari Zone,
+ jr z, SafariZoneGameStillGoing ; don't bother printing game over text
+ ld a, [wNumSafariBalls]
+ and a
+ jr z, SafariZoneGameOver
+ jr SafariZoneGameStillGoing
+
+SafariZoneCheckSteps::
+ ld a, [wSafariSteps]
+ ld b, a
+ ld a, [wSafariSteps + 1]
+ ld c, a
+ or b
+ jr z, SafariZoneGameOver
+ dec bc
+ ld a, b
+ ld [wSafariSteps], a
+ ld a, c
+ ld [wSafariSteps + 1], a
+SafariZoneGameStillGoing:
+ xor a
+ ld [wSafariZoneGameOver], a
+ ret
+
+SafariZoneGameOver:
+ call EnableAutoTextBoxDrawing
+ xor a
+ ld [wAudioFadeOutControl], a
+ dec a
+ call PlaySound
+ ld c, BANK(SFX_Safari_Zone_PA)
+ ld a, SFX_SAFARI_ZONE_PA
+ call PlayMusic
+.waitForMusicToPlay
+ ld a, [wChannelSoundIDs + Ch5]
+ cp SFX_SAFARI_ZONE_PA
+ jr nz, .waitForMusicToPlay
+ ld a, TEXT_SAFARI_GAME_OVER
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ xor a
+ ld [wPlayerMovingDirection], a
+ ld a, SAFARI_ZONE_GATE
+ ld [hWarpDestinationMap], a
+ ld a, $3
+ ld [wDestinationWarpID], a
+ ld a, $5
+ ld [wSafariZoneGateCurScript], a
+ SetEvent EVENT_SAFARI_GAME_OVER
+ ld a, 1
+ ld [wSafariZoneGameOver], a
+ ret
+
+PrintSafariGameOverText::
+ xor a
+ ld [wJoyIgnore], a
+ ld hl, SafariGameOverText
+ jp PrintText
+
+SafariGameOverText:
+ TX_ASM
+ ld a, [wNumSafariBalls]
+ and a
+ jr z, .noMoreSafariBalls
+ ld hl, TimesUpText
+ call PrintText
+.noMoreSafariBalls
+ ld hl, GameOverText
+ call PrintText
+ jp TextScriptEnd
+
+TimesUpText:
+ TX_FAR _TimesUpText
+ db "@"
+
+GameOverText:
+ TX_FAR _GameOverText
+ db "@"
+
+PrintCinnabarQuiz:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump CinnabarGymQuiz
+
+CinnabarGymQuiz::
+ TX_ASM
+ xor a
+ ld [wOpponentAfterWrongAnswer], a
+ ld a, [wHiddenObjectFunctionArgument]
+ push af
+ and $f
+ ld [hGymGateIndex], a
+ pop af
+ and $f0
+ swap a
+ ld [$ffdc], a
+ ld hl, CinnabarGymQuizIntroText
+ call PrintText
+ ld a, [hGymGateIndex]
+ dec a
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, CinnabarQuizQuestions
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ call CinnabarGymQuiz_1ea92
+ jp TextScriptEnd
+
+CinnabarGymQuizIntroText:
+ TX_FAR _CinnabarGymQuizIntroText
+ db "@"
+
+CinnabarQuizQuestions:
+ dw CinnabarQuizQuestionsText1
+ dw CinnabarQuizQuestionsText2
+ dw CinnabarQuizQuestionsText3
+ dw CinnabarQuizQuestionsText4
+ dw CinnabarQuizQuestionsText5
+ dw CinnabarQuizQuestionsText6
+
+CinnabarQuizQuestionsText1:
+ TX_FAR _CinnabarQuizQuestionsText1
+ db "@"
+
+CinnabarQuizQuestionsText2:
+ TX_FAR _CinnabarQuizQuestionsText2
+ db "@"
+
+CinnabarQuizQuestionsText3:
+ TX_FAR _CinnabarQuizQuestionsText3
+ db "@"
+
+CinnabarQuizQuestionsText4:
+ TX_FAR _CinnabarQuizQuestionsText4
+ db "@"
+
+CinnabarQuizQuestionsText5:
+ TX_FAR _CinnabarQuizQuestionsText5
+ db "@"
+
+CinnabarQuizQuestionsText6:
+ TX_FAR _CinnabarQuizQuestionsText6
+ db "@"
+
+CinnabarGymGateFlagAction:
+ EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
+ predef_jump FlagActionPredef
+
+CinnabarGymQuiz_1ea92:
+ call YesNoChoice
+ ld a, [$ffdc]
+ ld c, a
+ ld a, [wCurrentMenuItem]
+ cp c
+ jr nz, .wrongAnswer
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+ ld a, [hGymGateIndex]
+ ld [$ffe0], a
+ ld hl, CinnabarGymQuizCorrectText
+ call PrintText
+ ld a, [$ffe0]
+ AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
+ ld c, a
+ ld b, FLAG_SET
+ call CinnabarGymGateFlagAction
+ jp UpdateCinnabarGymGateTileBlocks_
+.wrongAnswer
+ call WaitForSoundToFinish
+ ld a, SFX_DENIED
+ call PlaySound
+ call WaitForSoundToFinish
+ ld hl, CinnabarGymQuizIncorrectText
+ call PrintText
+ ld a, [hGymGateIndex]
+ add $2
+ AdjustEventBit EVENT_BEAT_CINNABAR_GYM_TRAINER_0, 2
+ ld c, a
+ ld b, FLAG_TEST
+ EventFlagAddress hl, EVENT_BEAT_CINNABAR_GYM_TRAINER_0
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ret nz
+ ld a, [hGymGateIndex]
+ add $2
+ ld [wOpponentAfterWrongAnswer], a
+ ret
+
+CinnabarGymQuizCorrectText:
+ TX_SFX_ITEM_1
+ TX_FAR _CinnabarGymQuizCorrectText
+ TX_BLINK
+ TX_ASM
+
+ ld a, [$ffe0]
+ AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
+ ld c, a
+ ld b, FLAG_TEST
+ call CinnabarGymGateFlagAction
+ ld a, c
+ and a
+ jp nz, TextScriptEnd
+ call WaitForSoundToFinish
+ ld a, SFX_GO_INSIDE
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+CinnabarGymQuizIncorrectText:
+ TX_FAR _CinnabarGymQuizIncorrectText
+ db "@"
+
+UpdateCinnabarGymGateTileBlocks_::
+; Update the overworld map with open floor blocks or locked gate blocks
+; depending on event flags.
+ ld a, 6
+ ld [hGymGateIndex], a
+.loop
+ ld a, [hGymGateIndex]
+ dec a
+ add a
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, CinnabarGymGateCoords
+ add hl, de
+ ld a, [hli]
+ ld b, [hl]
+ ld c, a
+ inc hl
+ ld a, [hl]
+ ld [wGymGateTileBlock], a
+ push bc
+ ld a, [hGymGateIndex]
+ ld [$ffe0], a
+ AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
+ ld c, a
+ ld b, FLAG_TEST
+ call CinnabarGymGateFlagAction
+ ld a, c
+ and a
+ jr nz, .unlocked
+ ld a, [wGymGateTileBlock]
+ jr .next
+.unlocked
+ ld a, $e
+.next
+ pop bc
+ ld [wNewTileBlockID], a
+ predef ReplaceTileBlock
+ ld hl, hGymGateIndex
+ dec [hl]
+ jr nz, .loop
+ ret
+
+CinnabarGymGateCoords:
+ ; format: x-coord, y-coord, direction, padding
+ ; direction: $54 = horizontal gate, $5f = vertical gate
+ db $09,$03,$54,$00
+ db $06,$03,$54,$00
+ db $06,$06,$54,$00
+ db $03,$08,$5f,$00
+ db $02,$06,$54,$00
+ db $02,$03,$54,$00
+
+PrintMagazinesText:
+ call EnableAutoTextBoxDrawing
+ tx_pre MagazinesText
+ ret
+
+MagazinesText::
+ TX_FAR _MagazinesText
+ db "@"
+
+BillsHousePC:
+ call EnableAutoTextBoxDrawing
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ CheckEvent EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING
+ jr nz, .displayBillsHousePokemonList
+ CheckEventReuseA EVENT_USED_CELL_SEPARATOR_ON_BILL
+ jr nz, .displayBillsHouseMonitorText
+ CheckEventReuseA EVENT_BILL_SAID_USE_CELL_SEPARATOR
+ jr nz, .doCellSeparator
+.displayBillsHouseMonitorText
+ tx_pre_jump BillsHouseMonitorText
+.doCellSeparator
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ tx_pre BillsHouseInitiatedText
+ ld c, 32
+ call DelayFrames
+ ld a, SFX_TINK
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 80
+ call DelayFrames
+ ld a, SFX_SHRINK
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 48
+ call DelayFrames
+ ld a, SFX_TINK
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 32
+ call DelayFrames
+ ld a, SFX_GET_ITEM_1
+ call PlaySound
+ call WaitForSoundToFinish
+ call PlayDefaultMusic
+ SetEvent EVENT_USED_CELL_SEPARATOR_ON_BILL
+ ret
+.displayBillsHousePokemonList
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ tx_pre BillsHousePokemonList
+ ret
+
+BillsHouseMonitorText::
+ TX_FAR _BillsHouseMonitorText
+ db "@"
+
+BillsHouseInitiatedText::
+ TX_FAR _BillsHouseInitiatedText
+ TX_BLINK
+ TX_ASM
+ ld a, $ff
+ ld [wNewSoundID], a
+ call PlaySound
+ ld c, 16
+ call DelayFrames
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 60
+ call DelayFrames
+ jp TextScriptEnd
+
+BillsHousePokemonList::
+ TX_ASM
+ call SaveScreenTilesToBuffer1
+ ld hl, BillsHousePokemonListText1
+ call PrintText
+ xor a
+ ld [wMenuItemOffset], a ; not used
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 4
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+.billsPokemonLoop
+ ld hl, wd730
+ set 6, [hl]
+ coord hl, 0, 0
+ ld b, 10
+ ld c, 9
+ call TextBoxBorder
+ coord hl, 2, 2
+ ld de, BillsMonListText
+ call PlaceString
+ ld hl, BillsHousePokemonListText2
+ call PrintText
+ call SaveScreenTilesToBuffer2
+ call HandleMenuInput
+ bit 1, a ; pressed b
+ jr nz, .cancel
+ ld a, [wCurrentMenuItem]
+ add EEVEE
+ cp EEVEE
+ jr z, .displayPokedex
+ cp FLAREON
+ jr z, .displayPokedex
+ cp JOLTEON
+ jr z, .displayPokedex
+ cp VAPOREON
+ jr z, .displayPokedex
+ jr .cancel
+.displayPokedex
+ call DisplayPokedex
+ call LoadScreenTilesFromBuffer2
+ jr .billsPokemonLoop
+.cancel
+ ld hl, wd730
+ res 6, [hl]
+ call LoadScreenTilesFromBuffer2
+ jp TextScriptEnd
+
+BillsHousePokemonListText1:
+ TX_FAR _BillsHousePokemonListText1
+ db "@"
+
+BillsMonListText:
+ db "EEVEE"
+ next "FLAREON"
+ next "JOLTEON"
+ next "VAPOREON"
+ next "CANCEL@"
+
+BillsHousePokemonListText2:
+ TX_FAR _BillsHousePokemonListText2
+ db "@"
+
+DisplayOakLabEmailText:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump OakLabEmailText
+
+OakLabEmailText::
+ TX_FAR _OakLabEmailText
+ db "@"
diff --git a/engine/events/in_game_trades.asm b/engine/events/in_game_trades.asm
new file mode 100755
index 00000000..c01bc3c3
--- /dev/null
+++ b/engine/events/in_game_trades.asm
@@ -0,0 +1,330 @@
+DoInGameTradeDialogue:
+; trigger the trade offer/action specified by wWhichTrade
+ call SaveScreenTilesToBuffer2
+ ld hl, TradeMons
+ ld a, [wWhichTrade]
+ ld b, a
+ swap a
+ sub b
+ sub b
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld [wInGameTradeGiveMonSpecies], a
+ ld a, [hli]
+ ld [wInGameTradeReceiveMonSpecies], a
+ ld a, [hli]
+ push af
+ ld de, wInGameTradeMonNick
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop af
+ ld l, a
+ ld h, 0
+ ld de, InGameTradeTextPointers
+ add hl, hl
+ add hl, de
+ ld a, [hli]
+ ld [wInGameTradeTextPointerTablePointer], a
+ ld a, [hl]
+ ld [wInGameTradeTextPointerTablePointer + 1], a
+ ld a, [wInGameTradeGiveMonSpecies]
+ ld de, wInGameTradeGiveMonName
+ call InGameTrade_GetMonName
+ ld a, [wInGameTradeReceiveMonSpecies]
+ ld de, wInGameTradeReceiveMonName
+ call InGameTrade_GetMonName
+ ld hl, wCompletedInGameTradeFlags
+ ld a, [wWhichTrade]
+ ld c, a
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ld a, $4
+ ld [wInGameTradeTextPointerTableIndex], a
+ jr nz, .printText
+; if the trade hasn't been done yet
+ xor a
+ ld [wInGameTradeTextPointerTableIndex], a
+ call .printText
+ ld a, $1
+ ld [wInGameTradeTextPointerTableIndex], a
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .printText
+ call InGameTrade_DoTrade
+ jr c, .printText
+ ld hl, TradedForText
+ call PrintText
+.printText
+ ld hl, wInGameTradeTextPointerTableIndex
+ ld a, [hld] ; wInGameTradeTextPointerTableIndex
+ ld e, a
+ ld d, 0
+ ld a, [hld] ; wInGameTradeTextPointerTablePointer + 1
+ ld l, [hl] ; wInGameTradeTextPointerTablePointer
+ ld h, a
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp PrintText
+
+; copies name of species a to hl
+InGameTrade_GetMonName:
+ push de
+ ld [wd11e], a
+ call GetMonName
+ ld hl, wcd6d
+ pop de
+ ld bc, NAME_LENGTH
+ jp CopyData
+
+INCLUDE "data/trades.asm"
+
+InGameTrade_DoTrade:
+ xor a ; NORMAL_PARTY_MENU
+ ld [wPartyMenuTypeOrMessageID], a
+ dec a
+ ld [wUpdateSpritesEnabled], a
+ call DisplayPartyMenu
+ push af
+ call InGameTrade_RestoreScreen
+ pop af
+ ld a, $1
+ jp c, .tradeFailed ; jump if the player didn't select a pokemon
+ ld a, [wInGameTradeGiveMonSpecies]
+ ld b, a
+ ld a, [wcf91]
+ cp b
+ ld a, $2
+ jr nz, .tradeFailed ; jump if the selected mon's species is not the required one
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMon1Level
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld a, [hl]
+ ld [wCurEnemyLVL], a
+ ld hl, wCompletedInGameTradeFlags
+ ld a, [wWhichTrade]
+ ld c, a
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ ld hl, ConnectCableText
+ call PrintText
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wCurEnemyLVL]
+ push af
+ call LoadHpBarAndStatusTilePatterns
+ call InGameTrade_PrepareTradeData
+ predef InternalClockTradeAnim
+ pop af
+ ld [wCurEnemyLVL], a
+ pop af
+ ld [wWhichPokemon], a
+ ld a, [wInGameTradeReceiveMonSpecies]
+ ld [wcf91], a
+ xor a
+ ld [wMonDataLocation], a ; not used
+ ld [wRemoveMonFromBox], a
+ call RemovePokemon
+ ld a, $80 ; prevent the player from naming the mon
+ ld [wMonDataLocation], a
+ call AddPartyMon
+ call InGameTrade_CopyDataToReceivedMon
+ callab EvolveTradeMon
+ call ClearScreen
+ call InGameTrade_RestoreScreen
+ callba RedrawMapView
+ and a
+ ld a, $3
+ jr .tradeSucceeded
+.tradeFailed
+ scf
+.tradeSucceeded
+ ld [wInGameTradeTextPointerTableIndex], a
+ ret
+
+InGameTrade_RestoreScreen:
+ call GBPalWhiteOutWithDelay3
+ call RestoreScreenTilesAndReloadTilePatterns
+ call ReloadTilesetTilePatterns
+ call LoadScreenTilesFromBuffer2
+ call Delay3
+ call LoadGBPal
+ ld c, 10
+ call DelayFrames
+ jpba LoadWildData
+
+InGameTrade_PrepareTradeData:
+ ld hl, wTradedPlayerMonSpecies
+ ld a, [wInGameTradeGiveMonSpecies]
+ ld [hli], a ; wTradedPlayerMonSpecies
+ ld a, [wInGameTradeReceiveMonSpecies]
+ ld [hl], a ; wTradedEnemyMonSpecies
+ ld hl, wPartyMonOT
+ ld bc, NAME_LENGTH
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld de, wTradedPlayerMonOT
+ ld bc, NAME_LENGTH
+ call InGameTrade_CopyData
+ ld hl, InGameTrade_TrainerString
+ ld de, wTradedEnemyMonOT
+ call InGameTrade_CopyData
+ ld de, wLinkEnemyTrainerName
+ call InGameTrade_CopyData
+ ld hl, wPartyMon1OTID
+ ld bc, wPartyMon2 - wPartyMon1
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld de, wTradedPlayerMonOTID
+ ld bc, $2
+ call InGameTrade_CopyData
+ call Random
+ ld hl, hRandomAdd
+ ld de, wTradedEnemyMonOTID
+ jp CopyData
+
+InGameTrade_CopyData:
+ push hl
+ push bc
+ call CopyData
+ pop bc
+ pop hl
+ ret
+
+InGameTrade_CopyDataToReceivedMon:
+ ld hl, wPartyMonNicks
+ ld bc, NAME_LENGTH
+ call InGameTrade_GetReceivedMonPointer
+ ld hl, wInGameTradeMonNick
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wPartyMonOT
+ ld bc, NAME_LENGTH
+ call InGameTrade_GetReceivedMonPointer
+ ld hl, InGameTrade_TrainerString
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wPartyMon1OTID
+ ld bc, wPartyMon2 - wPartyMon1
+ call InGameTrade_GetReceivedMonPointer
+ ld hl, wTradedEnemyMonOTID
+ ld bc, $2
+ jp CopyData
+
+; the received mon's index is (partyCount - 1),
+; so this adds bc to hl (partyCount - 1) times and moves the result to de
+InGameTrade_GetReceivedMonPointer:
+ ld a, [wPartyCount]
+ dec a
+ call AddNTimes
+ ld e, l
+ ld d, h
+ ret
+
+InGameTrade_TrainerString:
+ ; "TRAINER@@@@@@@@@@"
+ db $5d, "@@@@@@@@@@"
+
+InGameTradeTextPointers:
+ dw TradeTextPointers1
+ dw TradeTextPointers2
+ dw TradeTextPointers3
+
+TradeTextPointers1:
+ dw WannaTrade1Text
+ dw NoTrade1Text
+ dw WrongMon1Text
+ dw Thanks1Text
+ dw AfterTrade1Text
+
+TradeTextPointers2:
+ dw WannaTrade2Text
+ dw NoTrade2Text
+ dw WrongMon2Text
+ dw Thanks2Text
+ dw AfterTrade2Text
+
+TradeTextPointers3:
+ dw WannaTrade3Text
+ dw NoTrade3Text
+ dw WrongMon3Text
+ dw Thanks3Text
+ dw AfterTrade3Text
+
+ConnectCableText:
+ TX_FAR _ConnectCableText
+ db "@"
+
+TradedForText:
+ TX_FAR _TradedForText
+ TX_SFX_KEY_ITEM
+ TX_DELAY
+ db "@"
+
+WannaTrade1Text:
+ TX_FAR _WannaTrade1Text
+ db "@"
+
+NoTrade1Text:
+ TX_FAR _NoTrade1Text
+ db "@"
+
+WrongMon1Text:
+ TX_FAR _WrongMon1Text
+ db "@"
+
+Thanks1Text:
+ TX_FAR _Thanks1Text
+ db "@"
+
+AfterTrade1Text:
+ TX_FAR _AfterTrade1Text
+ db "@"
+
+WannaTrade2Text:
+ TX_FAR _WannaTrade2Text
+ db "@"
+
+NoTrade2Text:
+ TX_FAR _NoTrade2Text
+ db "@"
+
+WrongMon2Text:
+ TX_FAR _WrongMon2Text
+ db "@"
+
+Thanks2Text:
+ TX_FAR _Thanks2Text
+ db "@"
+
+AfterTrade2Text:
+ TX_FAR _AfterTrade2Text
+ db "@"
+
+WannaTrade3Text:
+ TX_FAR _WannaTrade3Text
+ db "@"
+
+NoTrade3Text:
+ TX_FAR _NoTrade3Text
+ db "@"
+
+WrongMon3Text:
+ TX_FAR _WrongMon3Text
+ db "@"
+
+Thanks3Text:
+ TX_FAR _Thanks3Text
+ db "@"
+
+AfterTrade3Text:
+ TX_FAR _AfterTrade3Text
+ db "@"
diff --git a/engine/events/oaks_aide.asm b/engine/events/oaks_aide.asm
new file mode 100755
index 00000000..f5068fda
--- /dev/null
+++ b/engine/events/oaks_aide.asm
@@ -0,0 +1,71 @@
+OaksAideScript:
+ ld hl, OaksAideHiText
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .choseNo
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ ld a, [wNumSetBits]
+ ld [hOaksAideNumMonsOwned], a
+ ld b, a
+ ld a, [hOaksAideRequirement]
+ cp b
+ jr z, .giveItem
+ jr nc, .notEnoughOwnedMons
+.giveItem
+ ld hl, OaksAideHereYouGoText
+ call PrintText
+ ld a, [hOaksAideRewardItem]
+ ld b, a
+ ld c, 1
+ call GiveItem
+ jr nc, .bagFull
+ ld hl, OaksAideGotItemText
+ call PrintText
+ ld a, $1
+ jr .done
+.bagFull
+ ld hl, OaksAideNoRoomText
+ call PrintText
+ xor a
+ jr .done
+.notEnoughOwnedMons
+ ld hl, OaksAideUhOhText
+ call PrintText
+ ld a, $80
+ jr .done
+.choseNo
+ ld hl, OaksAideComeBackText
+ call PrintText
+ ld a, $ff
+.done
+ ld [hOaksAideResult], a
+ ret
+
+OaksAideHiText:
+ TX_FAR _OaksAideHiText
+ db "@"
+
+OaksAideUhOhText:
+ TX_FAR _OaksAideUhOhText
+ db "@"
+
+OaksAideComeBackText:
+ TX_FAR _OaksAideComeBackText
+ db "@"
+
+OaksAideHereYouGoText:
+ TX_FAR _OaksAideHereYouGoText
+ db "@"
+
+OaksAideGotItemText:
+ TX_FAR _OaksAideGotItemText
+ TX_SFX_ITEM_1
+ db "@"
+
+OaksAideNoRoomText:
+ TX_FAR _OaksAideNoRoomText
+ db "@"
diff --git a/engine/events/pewter_guys.asm b/engine/events/pewter_guys.asm
new file mode 100755
index 00000000..532fa4bf
--- /dev/null
+++ b/engine/events/pewter_guys.asm
@@ -0,0 +1,102 @@
+PewterGuys:
+ ld hl, wSimulatedJoypadStatesEnd
+ ld a, [wSimulatedJoypadStatesIndex]
+ dec a ; this decrement causes it to overwrite the last byte before $FF in the list
+ ld [wSimulatedJoypadStatesIndex], a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld d, h
+ ld e, l
+ ld hl, PointerTable_37ce6
+ ld a, [wWhichPewterGuy]
+ add a
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wYCoord]
+ ld b, a
+ ld a, [wXCoord]
+ ld c, a
+.findMatchingCoordsLoop
+ ld a, [hli]
+ cp b
+ jr nz, .nextEntry1
+ ld a, [hli]
+ cp c
+ jr nz, .nextEntry2
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.copyMovementDataLoop
+ ld a, [hli]
+ cp $ff
+ ret z
+ ld [de], a
+ inc de
+ ld a, [wSimulatedJoypadStatesIndex]
+ inc a
+ ld [wSimulatedJoypadStatesIndex], a
+ jr .copyMovementDataLoop
+.nextEntry1
+ inc hl
+.nextEntry2
+ inc hl
+ inc hl
+ jr .findMatchingCoordsLoop
+
+PointerTable_37ce6:
+ dw PewterMuseumGuyCoords
+ dw PewterGymGuyCoords
+
+; these are the four coordinates of the spaces below, above, to the left and
+; to the right of the museum guy, and pointers to different movements for
+; the player to make to get positioned before the main movement.
+PewterMuseumGuyCoords:
+ db 18, 27
+ dw .down
+ db 16, 27
+ dw .up
+ db 17, 26
+ dw .left
+ db 17, 28
+ dw .right
+
+.down
+ db D_UP, D_UP, $ff
+.up
+ db D_RIGHT, D_LEFT, $ff
+.left
+ db D_UP, D_RIGHT, $ff
+.right
+ db D_UP, D_LEFT, $ff
+
+; these are the five coordinates which trigger the gym guy and pointers to
+; different movements for the player to make to get positioned before the
+; main movement
+; $00 is a pause
+PewterGymGuyCoords:
+ db 16, 34
+ dw .one
+ db 17, 35
+ dw .two
+ db 18, 37
+ dw .three
+ db 19, 37
+ dw .four
+ db 17, 36
+ dw .five
+
+.one
+ db D_LEFT, D_DOWN, D_DOWN, D_RIGHT, $ff
+.two
+ db D_LEFT, D_DOWN, D_RIGHT, D_LEFT, $ff
+.three
+ db D_LEFT, D_LEFT, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff
+.four
+ db D_LEFT, D_LEFT, D_UP, D_LEFT, $ff
+.five
+ db D_LEFT, D_DOWN, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff
diff --git a/engine/events/pick_up_item.asm b/engine/events/pick_up_item.asm
new file mode 100644
index 00000000..9f19100a
--- /dev/null
+++ b/engine/events/pick_up_item.asm
@@ -0,0 +1,54 @@
+PickUpItem:
+ call EnableAutoTextBoxDrawing
+
+ ld a, [hSpriteIndexOrTextID]
+ ld b, a
+ ld hl, wMissableObjectList
+.missableObjectsListLoop
+ ld a, [hli]
+ cp $ff
+ ret z
+ cp b
+ jr z, .isMissable
+ inc hl
+ jr .missableObjectsListLoop
+
+.isMissable
+ ld a, [hl]
+ ld [$ffdb], a
+
+ ld hl, wMapSpriteExtraData
+ ld a, [hSpriteIndexOrTextID]
+ dec a
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ ld b, a ; item
+ ld c, 1 ; quantity
+ call GiveItem
+ jr nc, .BagFull
+
+ ld a, [$ffdb]
+ ld [wMissableObjectIndex], a
+ predef HideObject
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld hl, FoundItemText
+ jr .print
+
+.BagFull
+ ld hl, NoMoreRoomForItemText
+.print
+ call PrintText
+ ret
+
+FoundItemText:
+ TX_FAR _FoundItemText
+ TX_SFX_ITEM_1
+ db "@"
+
+NoMoreRoomForItemText:
+ TX_FAR _NoMoreRoomForItemText
+ db "@"
diff --git a/engine/events/poison.asm b/engine/events/poison.asm
new file mode 100644
index 00000000..5d8eb9fd
--- /dev/null
+++ b/engine/events/poison.asm
@@ -0,0 +1,112 @@
+ApplyOutOfBattlePoisonDamage:
+ ld a, [wd730]
+ add a
+ jp c, .noBlackOut ; no black out if joypad states are being simulated
+ ld a, [wPartyCount]
+ and a
+ jp z, .noBlackOut
+ call IncrementDayCareMonExp
+ ld a, [wStepCounter]
+ and $3 ; is the counter a multiple of 4?
+ jp nz, .noBlackOut ; only apply poison damage every fourth step
+ ld [wWhichPokemon], a
+ ld hl, wPartyMon1Status
+ ld de, wPartySpecies
+.applyDamageLoop
+ ld a, [hl]
+ and (1 << PSN)
+ jr z, .nextMon2 ; not poisoned
+ dec hl
+ dec hl
+ ld a, [hld]
+ ld b, a
+ ld a, [hli]
+ or b
+ jr z, .nextMon ; already fainted
+; subtract 1 from HP
+ ld a, [hl]
+ dec a
+ ld [hld], a
+ inc a
+ jr nz, .noBorrow
+; borrow 1 from upper byte of HP
+ dec [hl]
+ inc hl
+ jr .nextMon
+.noBorrow
+ ld a, [hli]
+ or [hl]
+ jr nz, .nextMon ; didn't faint from damage
+; the mon fainted from the damage
+ push hl
+ inc hl
+ inc hl
+ ld [hl], a
+ ld a, [de]
+ ld [wd11e], a
+ push de
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ xor a
+ ld [wJoyIgnore], a
+ call EnableAutoTextBoxDrawing
+ ld a, TEXT_MON_FAINTED
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ pop de
+ pop hl
+.nextMon
+ inc hl
+ inc hl
+.nextMon2
+ inc de
+ ld a, [de]
+ inc a
+ jr z, .applyDamageLoopDone
+ ld bc, wPartyMon2 - wPartyMon1
+ add hl, bc
+ push hl
+ ld hl, wWhichPokemon
+ inc [hl]
+ pop hl
+ jr .applyDamageLoop
+.applyDamageLoopDone
+ ld hl, wPartyMon1Status
+ ld a, [wPartyCount]
+ ld d, a
+ ld e, 0
+.countPoisonedLoop
+ ld a, [hl]
+ and (1 << PSN)
+ or e
+ ld e, a
+ ld bc, wPartyMon2 - wPartyMon1
+ add hl, bc
+ dec d
+ jr nz, .countPoisonedLoop
+ ld a, e
+ and a ; are any party members poisoned?
+ jr z, .skipPoisonEffectAndSound
+ ld b, $2
+ predef ChangeBGPalColor0_4Frames ; change BG white to dark grey for 4 frames
+ ld a, SFX_POISONED
+ call PlaySound
+.skipPoisonEffectAndSound
+ predef AnyPartyAlive
+ ld a, d
+ and a
+ jr nz, .noBlackOut
+ call EnableAutoTextBoxDrawing
+ ld a, TEXT_BLACKED_OUT
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ ld hl, wd72e
+ set 5, [hl]
+ ld a, $ff
+ jr .done
+.noBlackOut
+ xor a
+.done
+ ld [wOutOfBattleBlackout], a
+ ret
diff --git a/engine/events/pokecenter.asm b/engine/events/pokecenter.asm
new file mode 100755
index 00000000..f340e06d
--- /dev/null
+++ b/engine/events/pokecenter.asm
@@ -0,0 +1,68 @@
+DisplayPokemonCenterDialogue_::
+ call SaveScreenTilesToBuffer1 ; save screen
+ ld hl, PokemonCenterWelcomeText
+ call PrintText
+ ld hl, wd72e
+ bit 2, [hl]
+ set 1, [hl]
+ set 2, [hl]
+ jr nz, .skipShallWeHealYourPokemon
+ ld hl, ShallWeHealYourPokemonText
+ call PrintText
+.skipShallWeHealYourPokemon
+ call YesNoChoicePokeCenter ; yes/no menu
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .declinedHealing ; if the player chose No
+ call SetLastBlackoutMap
+ call LoadScreenTilesFromBuffer1 ; restore screen
+ ld hl, NeedYourPokemonText
+ call PrintText
+ ld a, $18
+ ld [wSpriteStateData1 + $12], a ; make the nurse turn to face the machine
+ call Delay3
+ predef HealParty
+ callba AnimateHealingMachine ; do the healing machine animation
+ xor a
+ ld [wAudioFadeOutControl], a
+ ld a, [wAudioSavedROMBank]
+ ld [wAudioROMBank], a
+ ld a, [wMapMusicSoundID]
+ ld [wLastMusicSoundID], a
+ ld [wNewSoundID], a
+ call PlaySound
+ ld hl, PokemonFightingFitText
+ call PrintText
+ ld a, $14
+ ld [wSpriteStateData1 + $12], a ; make the nurse bow
+ ld c, a
+ call DelayFrames
+ jr .done
+.declinedHealing
+ call LoadScreenTilesFromBuffer1 ; restore screen
+.done
+ ld hl, PokemonCenterFarewellText
+ call PrintText
+ jp UpdateSprites
+
+PokemonCenterWelcomeText:
+ TX_FAR _PokemonCenterWelcomeText
+ db "@"
+
+ShallWeHealYourPokemonText:
+ TX_DELAY
+ TX_FAR _ShallWeHealYourPokemonText
+ db "@"
+
+NeedYourPokemonText:
+ TX_FAR _NeedYourPokemonText
+ db "@"
+
+PokemonFightingFitText:
+ TX_FAR _PokemonFightingFitText
+ db "@"
+
+PokemonCenterFarewellText:
+ TX_DELAY
+ TX_FAR _PokemonCenterFarewellText
+ db "@"
diff --git a/engine/events/pokedex_rating.asm b/engine/events/pokedex_rating.asm
new file mode 100755
index 00000000..f1aaf618
--- /dev/null
+++ b/engine/events/pokedex_rating.asm
@@ -0,0 +1,154 @@
+DisplayDexRating:
+ ld hl, wPokedexSeen
+ ld b, wPokedexSeenEnd - wPokedexSeen
+ call CountSetBits
+ ld a, [wNumSetBits]
+ ld [hDexRatingNumMonsSeen], a
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ ld a, [wNumSetBits]
+ ld [hDexRatingNumMonsOwned], a
+ ld hl, DexRatingsTable
+.findRating
+ ld a, [hli]
+ ld b, a
+ ld a, [hDexRatingNumMonsOwned]
+ cp b
+ jr c, .foundRating
+ inc hl
+ inc hl
+ jr .findRating
+.foundRating
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; load text pointer into hl
+ CheckAndResetEventA EVENT_HALL_OF_FAME_DEX_RATING
+ jr nz, .hallOfFame
+ push hl
+ ld hl, PokedexRatingText_441cc
+ call PrintText
+ pop hl
+ call PrintText
+ callba PlayPokedexRatingSfx
+ jp WaitForTextScrollButtonPress
+.hallOfFame
+ ld de, wDexRatingNumMonsSeen
+ ld a, [hDexRatingNumMonsSeen]
+ ld [de], a
+ inc de
+ ld a, [hDexRatingNumMonsOwned]
+ ld [de], a
+ inc de
+.copyRatingTextLoop
+ ld a, [hli]
+ cp "@"
+ jr z, .doneCopying
+ ld [de], a
+ inc de
+ jr .copyRatingTextLoop
+.doneCopying
+ ld [de], a
+ ret
+
+PokedexRatingText_441cc:
+ TX_FAR _OaksLabText_441cc
+ db "@"
+
+DexRatingsTable:
+ db 10
+ dw PokedexRatingText_44201
+ db 20
+ dw PokedexRatingText_44206
+ db 30
+ dw PokedexRatingText_4420b
+ db 40
+ dw PokedexRatingText_44210
+ db 50
+ dw PokedexRatingText_44215
+ db 60
+ dw PokedexRatingText_4421a
+ db 70
+ dw PokedexRatingText_4421f
+ db 80
+ dw PokedexRatingText_44224
+ db 90
+ dw PokedexRatingText_44229
+ db 100
+ dw PokedexRatingText_4422e
+ db 110
+ dw PokedexRatingText_44233
+ db 120
+ dw PokedexRatingText_44238
+ db 130
+ dw PokedexRatingText_4423d
+ db 140
+ dw PokedexRatingText_44242
+ db 150
+ dw PokedexRatingText_44247
+ db NUM_POKEMON + 1
+ dw PokedexRatingText_4424c
+
+PokedexRatingText_44201:
+ TX_FAR _OaksLabText_44201
+ db "@"
+
+PokedexRatingText_44206:
+ TX_FAR _OaksLabText_44206
+ db "@"
+
+PokedexRatingText_4420b:
+ TX_FAR _OaksLabText_4420b
+ db "@"
+
+PokedexRatingText_44210:
+ TX_FAR _OaksLabText_44210
+ db "@"
+
+PokedexRatingText_44215:
+ TX_FAR _OaksLabText_44215
+ db "@"
+
+PokedexRatingText_4421a:
+ TX_FAR _OaksLabText_4421a
+ db "@"
+
+PokedexRatingText_4421f:
+ TX_FAR _OaksLabText_4421f
+ db "@"
+
+PokedexRatingText_44224:
+ TX_FAR _OaksLabText_44224
+ db "@"
+
+PokedexRatingText_44229:
+ TX_FAR _OaksLabText_44229
+ db "@"
+
+PokedexRatingText_4422e:
+ TX_FAR _OaksLabText_4422e
+ db "@"
+
+PokedexRatingText_44233:
+ TX_FAR _OaksLabText_44233
+ db "@"
+
+PokedexRatingText_44238:
+ TX_FAR _OaksLabText_44238
+ db "@"
+
+PokedexRatingText_4423d:
+ TX_FAR _OaksLabText_4423d
+ db "@"
+
+PokedexRatingText_44242:
+ TX_FAR _OaksLabText_44242
+ db "@"
+
+PokedexRatingText_44247:
+ TX_FAR _OaksLabText_44247
+ db "@"
+
+PokedexRatingText_4424c:
+ TX_FAR _OaksLabText_4424c
+ db "@"
diff --git a/engine/events/pokemart.asm b/engine/events/pokemart.asm
new file mode 100755
index 00000000..177e8a09
--- /dev/null
+++ b/engine/events/pokemart.asm
@@ -0,0 +1,272 @@
+DisplayPokemartDialogue_::
+ ld a, [wListScrollOffset]
+ ld [wSavedListScrollOffset], a
+ call UpdateSprites
+ xor a
+ ld [wBoughtOrSoldItemInMart], a
+.loop
+ xor a
+ ld [wListScrollOffset], a
+ ld [wCurrentMenuItem], a
+ ld [wPlayerMonNumber], a
+ inc a
+ ld [wPrintItemPrices], a
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld a, BUY_SELL_QUIT_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+
+; This code is useless. It copies the address of the pokemart's inventory to hl,
+; but the address is never used.
+ ld hl, wItemListPointer
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+
+ ld a, [wMenuExitMethod]
+ cp CANCELLED_MENU
+ jp z, .done
+ ld a, [wChosenMenuItem]
+ and a ; buying?
+ jp z, .buyMenu
+ dec a ; selling?
+ jp z, .sellMenu
+ dec a ; quitting?
+ jp z, .done
+.sellMenu
+
+; the same variables are set again below, so this code has no effect
+ xor a
+ ld [wPrintItemPrices], a
+ ld a, INIT_BAG_ITEM_LIST
+ ld [wInitListType], a
+ callab InitList
+
+ ld a, [wNumBagItems]
+ and a
+ jp z, .bagEmpty
+ ld hl, PokemonSellingGreetingText
+ call PrintText
+ call SaveScreenTilesToBuffer1 ; save screen
+.sellMenuLoop
+ call LoadScreenTilesFromBuffer1 ; restore saved screen
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; draw money text box
+ ld hl, wNumBagItems
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ xor a
+ ld [wPrintItemPrices], a
+ ld [wCurrentMenuItem], a
+ ld a, ITEMLISTMENU
+ ld [wListMenuID], a
+ call DisplayListMenuID
+ jp c, .returnToMainPokemartMenu ; if the player closed the menu
+.confirmItemSale ; if the player is trying to sell a specific item
+ call IsKeyItem
+ ld a, [wIsKeyItem]
+ and a
+ jr nz, .unsellableItem
+ ld a, [wcf91]
+ call IsItemHM
+ jr c, .unsellableItem
+ ld a, PRICEDITEMLISTMENU
+ ld [wListMenuID], a
+ ld [hHalveItemPrices], a ; halve prices when selling
+ call DisplayChooseQuantityMenu
+ inc a
+ jr z, .sellMenuLoop ; if the player closed the choose quantity menu with the B button
+ ld hl, PokemartTellSellPriceText
+ lb bc, 14, 1 ; location that PrintText always prints to, this is useless
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ ld a, [wMenuExitMethod]
+ cp CHOSE_SECOND_ITEM
+ jr z, .sellMenuLoop ; if the player chose No or pressed the B button
+
+; The following code is supposed to check if the player chose No, but the above
+; check already catches it.
+ ld a, [wChosenMenuItem]
+ dec a
+ jr z, .sellMenuLoop
+
+.sellItem
+ ld a, [wBoughtOrSoldItemInMart]
+ and a
+ jr nz, .skipSettingFlag1
+ inc a
+ ld [wBoughtOrSoldItemInMart], a
+.skipSettingFlag1
+ call AddAmountSoldToMoney
+ ld hl, wNumBagItems
+ call RemoveItemFromInventory
+ jp .sellMenuLoop
+.unsellableItem
+ ld hl, PokemartUnsellableItemText
+ call PrintText
+ jp .returnToMainPokemartMenu
+.bagEmpty
+ ld hl, PokemartItemBagEmptyText
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ jp .returnToMainPokemartMenu
+.buyMenu
+
+; the same variables are set again below, so this code has no effect
+ ld a, 1
+ ld [wPrintItemPrices], a
+ ld a, INIT_OTHER_ITEM_LIST
+ ld [wInitListType], a
+ callab InitList
+
+ ld hl, PokemartBuyingGreetingText
+ call PrintText
+ call SaveScreenTilesToBuffer1
+.buyMenuLoop
+ call LoadScreenTilesFromBuffer1
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld hl, wItemList
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ xor a
+ ld [wCurrentMenuItem], a
+ inc a
+ ld [wPrintItemPrices], a
+ inc a ; a = 2 (PRICEDITEMLISTMENU)
+ ld [wListMenuID], a
+ call DisplayListMenuID
+ jr c, .returnToMainPokemartMenu ; if the player closed the menu
+ ld a, 99
+ ld [wMaxItemQuantity], a
+ xor a
+ ld [hHalveItemPrices], a ; don't halve item prices when buying
+ call DisplayChooseQuantityMenu
+ inc a
+ jr z, .buyMenuLoop ; if the player closed the choose quantity menu with the B button
+ ld a, [wcf91] ; item ID
+ ld [wd11e], a ; store item ID for GetItemName
+ call GetItemName
+ call CopyStringToCF4B ; copy name to wcf4b
+ ld hl, PokemartTellBuyPriceText
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ ld a, [wMenuExitMethod]
+ cp CHOSE_SECOND_ITEM
+ jp z, .buyMenuLoop ; if the player chose No or pressed the B button
+
+; The following code is supposed to check if the player chose No, but the above
+; check already catches it.
+ ld a, [wChosenMenuItem]
+ dec a
+ jr z, .buyMenuLoop
+
+.buyItem
+ call .isThereEnoughMoney
+ jr c, .notEnoughMoney
+ ld hl, wNumBagItems
+ call AddItemToInventory
+ jr nc, .bagFull
+ call SubtractAmountPaidFromMoney
+ ld a, [wBoughtOrSoldItemInMart]
+ and a
+ jr nz, .skipSettingFlag2
+ ld a, 1
+ ld [wBoughtOrSoldItemInMart], a
+.skipSettingFlag2
+ ld a, SFX_PURCHASE
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ ld hl, PokemartBoughtItemText
+ call PrintText
+ jp .buyMenuLoop
+.returnToMainPokemartMenu
+ call LoadScreenTilesFromBuffer1
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld hl, PokemartAnythingElseText
+ call PrintText
+ jp .loop
+.isThereEnoughMoney
+ ld de, wPlayerMoney
+ ld hl, hMoney
+ ld c, 3 ; length of money in bytes
+ jp StringCmp
+.notEnoughMoney
+ ld hl, PokemartNotEnoughMoneyText
+ call PrintText
+ jr .returnToMainPokemartMenu
+.bagFull
+ ld hl, PokemartItemBagFullText
+ call PrintText
+ jr .returnToMainPokemartMenu
+.done
+ ld hl, PokemartThankYouText
+ call PrintText
+ ld a, 1
+ ld [wUpdateSpritesEnabled], a
+ call UpdateSprites
+ ld a, [wSavedListScrollOffset]
+ ld [wListScrollOffset], a
+ ret
+
+PokemartBuyingGreetingText:
+ TX_FAR _PokemartBuyingGreetingText
+ db "@"
+
+PokemartTellBuyPriceText:
+ TX_FAR _PokemartTellBuyPriceText
+ db "@"
+
+PokemartBoughtItemText:
+ TX_FAR _PokemartBoughtItemText
+ db "@"
+
+PokemartNotEnoughMoneyText:
+ TX_FAR _PokemartNotEnoughMoneyText
+ db "@"
+
+PokemartItemBagFullText:
+ TX_FAR _PokemartItemBagFullText
+ db "@"
+
+PokemonSellingGreetingText:
+ TX_FAR _PokemonSellingGreetingText
+ db "@"
+
+PokemartTellSellPriceText:
+ TX_FAR _PokemartTellSellPriceText
+ db "@"
+
+PokemartItemBagEmptyText:
+ TX_FAR _PokemartItemBagEmptyText
+ db "@"
+
+PokemartUnsellableItemText:
+ TX_FAR _PokemartUnsellableItemText
+ db "@"
+
+PokemartThankYouText:
+ TX_FAR _PokemartThankYouText
+ db "@"
+
+PokemartAnythingElseText:
+ TX_FAR _PokemartAnythingElseText
+ db "@"
diff --git a/engine/events/prize_menu.asm b/engine/events/prize_menu.asm
new file mode 100755
index 00000000..5e08bb8f
--- /dev/null
+++ b/engine/events/prize_menu.asm
@@ -0,0 +1,306 @@
+CeladonPrizeMenu::
+ ld b, COIN_CASE
+ call IsItemInBag
+ jr nz, .havingCoinCase
+ ld hl, RequireCoinCaseTextPtr
+ jp PrintText
+.havingCoinCase
+ ld hl, wd730
+ set 6, [hl] ; disable letter-printing delay
+ ld hl, ExchangeCoinsForPrizesTextPtr
+ call PrintText
+; the following are the menu settings
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, $03
+ ld [wMaxMenuItem], a
+ ld a, $04
+ ld [wTopMenuItemY], a
+ ld a, $01
+ ld [wTopMenuItemX], a
+ call PrintPrizePrice
+ coord hl, 0, 2
+ ld b, 8
+ ld c, 16
+ call TextBoxBorder
+ call GetPrizeMenuId
+ call UpdateSprites
+ ld hl, WhichPrizeTextPtr
+ call PrintText
+ call HandleMenuInput ; menu choice handler
+ bit 1, a ; keypress = B (Cancel)
+ jr nz, .noChoice
+ ld a, [wCurrentMenuItem]
+ cp 3 ; "NO,THANKS" choice
+ jr z, .noChoice
+ call HandlePrizeChoice
+.noChoice
+ ld hl, wd730
+ res 6, [hl]
+ ret
+
+RequireCoinCaseTextPtr:
+ TX_FAR _RequireCoinCaseText
+ TX_WAIT
+ db "@"
+
+ExchangeCoinsForPrizesTextPtr:
+ TX_FAR _ExchangeCoinsForPrizesText
+ db "@"
+
+WhichPrizeTextPtr:
+ TX_FAR _WhichPrizeText
+ db "@"
+
+GetPrizeMenuId:
+; determine which one among the three
+; prize-texts has been selected
+; using the text ID (stored in [hSpriteIndexOrTextID])
+; load the three prizes at wd13d-wd13f
+; load the three prices at wd141-wd146
+; display the three prizes' names
+; (distinguishing between Pokemon names
+; and Items (specifically TMs) names)
+ ld a, [hSpriteIndexOrTextID]
+ sub 3 ; prize-texts' id are 3, 4 and 5
+ ld [wWhichPrizeWindow], a ; prize-texts' id (relative, i.e. 0, 1 or 2)
+ add a
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, PrizeDifferentMenuPtrs
+ add hl, de
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ inc hl
+ push hl
+ ld hl, wPrize1
+ call CopyString
+ pop hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wPrize1Price
+ ld bc, 6
+ call CopyData
+ ld a, [wWhichPrizeWindow]
+ cp 2 ;is TM_menu?
+ jr nz, .putMonName
+ ld a, [wPrize1]
+ ld [wd11e], a
+ call GetItemName
+ coord hl, 2, 4
+ call PlaceString
+ ld a, [wPrize2]
+ ld [wd11e], a
+ call GetItemName
+ coord hl, 2, 6
+ call PlaceString
+ ld a, [wPrize3]
+ ld [wd11e], a
+ call GetItemName
+ coord hl, 2, 8
+ call PlaceString
+ jr .putNoThanksText
+.putMonName
+ ld a, [wPrize1]
+ ld [wd11e], a
+ call GetMonName
+ coord hl, 2, 4
+ call PlaceString
+ ld a, [wPrize2]
+ ld [wd11e], a
+ call GetMonName
+ coord hl, 2, 6
+ call PlaceString
+ ld a, [wPrize3]
+ ld [wd11e], a
+ call GetMonName
+ coord hl, 2, 8
+ call PlaceString
+.putNoThanksText
+ coord hl, 2, 10
+ ld de, NoThanksText
+ call PlaceString
+; put prices on the right side of the textbox
+ ld de, wPrize1Price
+ coord hl, 13, 5
+; reg. c:
+; [low nybble] number of bytes
+; [bit 765 = %100] space-padding (not zero-padding)
+ ld c, (1 << 7 | 2)
+; Function $15CD displays BCD value (same routine
+; used by text-command $02)
+ call PrintBCDNumber
+ ld de, wPrize2Price
+ coord hl, 13, 7
+ ld c, (1 << 7 | 2)
+ call PrintBCDNumber
+ ld de, wPrize3Price
+ coord hl, 13, 9
+ ld c, (1 << 7 | 2)
+ jp PrintBCDNumber
+
+INCLUDE "data/prizes.asm"
+
+PrintPrizePrice:
+ coord hl, 11, 0
+ ld b, 1
+ ld c, 7
+ call TextBoxBorder
+ call UpdateSprites
+ coord hl, 12, 0
+ ld de, .CoinString
+ call PlaceString
+ coord hl, 13, 1
+ ld de, .SixSpacesString
+ call PlaceString
+ coord hl, 13, 1
+ ld de, wPlayerCoins
+ ld c, %10000010
+ call PrintBCDNumber
+ ret
+
+.CoinString:
+ db "COIN@"
+
+.SixSpacesString:
+ db " @"
+
+LoadCoinsToSubtract:
+ ld a, [wWhichPrize]
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, wPrize1Price
+ add hl, de ; get selected prize's price
+ xor a
+ ld [hUnusedCoinsByte], a
+ ld a, [hli]
+ ld [hCoins], a
+ ld a, [hl]
+ ld [hCoins + 1], a
+ ret
+
+HandlePrizeChoice:
+ ld a, [wCurrentMenuItem]
+ ld [wWhichPrize], a
+ ld d, 0
+ ld e, a
+ ld hl, wPrize1
+ add hl, de
+ ld a, [hl]
+ ld [wd11e], a
+ ld a, [wWhichPrizeWindow]
+ cp 2 ; is prize a TM?
+ jr nz, .getMonName
+ call GetItemName
+ jr .givePrize
+.getMonName
+ call GetMonName
+.givePrize
+ ld hl, SoYouWantPrizeTextPtr
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem] ; yes/no answer (Y=0, N=1)
+ and a
+ jr nz, .printOhFineThen
+ call LoadCoinsToSubtract
+ call HasEnoughCoins
+ jr c, .notEnoughCoins
+ ld a, [wWhichPrizeWindow]
+ cp $02
+ jr nz, .giveMon
+ ld a, [wd11e]
+ ld b, a
+ ld a, 1
+ ld c, a
+ call GiveItem
+ jr nc, .bagFull
+ jr .subtractCoins
+.giveMon
+ ld a, [wd11e]
+ ld [wcf91], a
+ push af
+ call GetPrizeMonLevel
+ ld c, a
+ pop af
+ ld b, a
+ call GivePokemon
+
+; If either the party or box was full, wait after displaying message.
+ push af
+ ld a, [wAddedToParty]
+ and a
+ call z, WaitForTextScrollButtonPress
+ pop af
+
+; If the mon couldn't be given to the player (because both the party and box
+; were full), return without subtracting coins.
+ ret nc
+
+.subtractCoins
+ call LoadCoinsToSubtract
+ ld hl, hCoins + 1
+ ld de, wPlayerCoins + 1
+ ld c, $02 ; how many bytes
+ predef SubBCDPredef
+ jp PrintPrizePrice
+.bagFull
+ ld hl, PrizeRoomBagIsFullTextPtr
+ jp PrintText
+.notEnoughCoins
+ ld hl, SorryNeedMoreCoinsText
+ jp PrintText
+.printOhFineThen
+ ld hl, OhFineThenTextPtr
+ jp PrintText
+
+UnknownPrizeData:
+; XXX what's this?
+ db $00,$01,$00,$01,$00,$01,$00,$00,$01
+
+HereYouGoTextPtr:
+ TX_FAR _HereYouGoText
+ TX_WAIT
+ db "@"
+
+SoYouWantPrizeTextPtr:
+ TX_FAR _SoYouWantPrizeText
+ db "@"
+
+SorryNeedMoreCoinsText:
+ TX_FAR _SorryNeedMoreCoinsText
+ TX_WAIT
+ db "@"
+
+PrizeRoomBagIsFullTextPtr:
+ TX_FAR _OopsYouDontHaveEnoughRoomText
+ TX_WAIT
+ db "@"
+
+OhFineThenTextPtr:
+ TX_FAR _OhFineThenText
+ TX_WAIT
+ db "@"
+
+GetPrizeMonLevel:
+ ld a, [wcf91]
+ ld b, a
+ ld hl, PrizeMonLevelDictionary
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .matchFound
+ inc hl
+ jr .loop
+.matchFound
+ ld a, [hl]
+ ld [wCurEnemyLVL], a
+ ret
+
+INCLUDE "data/prize_mon_levels.asm"
diff --git a/engine/events/saffron_guards.asm b/engine/events/saffron_guards.asm
new file mode 100755
index 00000000..091cfa1a
--- /dev/null
+++ b/engine/events/saffron_guards.asm
@@ -0,0 +1,15 @@
+RemoveGuardDrink::
+ ld hl, GuardDrinksList
+.drinkLoop
+ ld a, [hli]
+ ld [$ffdb], a
+ and a
+ ret z
+ push hl
+ ld b, a
+ call IsItemInBag
+ pop hl
+ jr z, .drinkLoop
+ jpba RemoveItemByID
+
+INCLUDE "data/guard_drink_items.asm"
diff --git a/engine/events/set_blackout_map.asm b/engine/events/set_blackout_map.asm
new file mode 100644
index 00000000..14f0ba28
--- /dev/null
+++ b/engine/events/set_blackout_map.asm
@@ -0,0 +1,25 @@
+SetLastBlackoutMap:
+; Set the map to return to when
+; blacking out or using Teleport or Dig.
+; Safari rest houses don't count.
+
+ push hl
+ ld hl, SafariZoneRestHouses
+ ld a, [wCurMap]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .notresthouse
+ cp b
+ jr nz, .loop
+ jr .done
+
+.notresthouse
+ ld a, [wLastMap]
+ ld [wLastBlackoutMap], a
+.done
+ pop hl
+ ret
+
+INCLUDE "data/rest_house_maps.asm"
diff --git a/engine/events/starter_dex.asm b/engine/events/starter_dex.asm
new file mode 100755
index 00000000..21289c6a
--- /dev/null
+++ b/engine/events/starter_dex.asm
@@ -0,0 +1,9 @@
+; this function temporarily makes the starters (and Ivysaur) seen
+; so that the full Pokedex information gets displayed in Oak's lab
+StarterDex:
+ ld a, %01001011 ; set starter flags
+ ld [wPokedexOwned], a
+ predef ShowPokedexData
+ xor a ; unset starter flags
+ ld [wPokedexOwned], a
+ ret
diff --git a/engine/events/vending_machine.asm b/engine/events/vending_machine.asm
new file mode 100755
index 00000000..554c5d4f
--- /dev/null
+++ b/engine/events/vending_machine.asm
@@ -0,0 +1,133 @@
+VendingMachineMenu::
+ ld hl, VendingMachineText1
+ call PrintText
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 3
+ ld [wMaxMenuItem], a
+ ld a, 5
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ ld hl, wd730
+ set 6, [hl]
+ coord hl, 0, 3
+ ld b, 8
+ ld c, 12
+ call TextBoxBorder
+ call UpdateSprites
+ coord hl, 2, 5
+ ld de, DrinkText
+ call PlaceString
+ coord hl, 9, 6
+ ld de, DrinkPriceText
+ call PlaceString
+ ld hl, wd730
+ res 6, [hl]
+ call HandleMenuInput
+ bit 1, a ; pressed B?
+ jr nz, .notThirsty
+ ld a, [wCurrentMenuItem]
+ cp 3 ; chose Cancel?
+ jr z, .notThirsty
+ xor a
+ ld [hMoney], a
+ ld [hMoney + 2], a
+ ld a, $2
+ ld [hMoney + 1], a
+ call HasEnoughMoney
+ jr nc, .enoughMoney
+ ld hl, VendingMachineText4
+ jp PrintText
+.enoughMoney
+ call LoadVendingMachineItem
+ ld a, [hVendingMachineItem]
+ ld b, a
+ ld c, 1
+ call GiveItem
+ jr nc, .BagFull
+
+ ld b, 60 ; number of times to play the "brrrrr" sound
+.playDeliverySound
+ ld c, 2
+ call DelayFrames
+ push bc
+ ld a, SFX_PUSH_BOULDER
+ call PlaySound
+ pop bc
+ dec b
+ jr nz, .playDeliverySound
+
+ ld hl, VendingMachineText5
+ call PrintText
+ ld hl, hVendingMachinePrice + 2
+ ld de, wPlayerMoney + 2
+ ld c, $3
+ predef SubBCDPredef
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ jp DisplayTextBoxID
+.BagFull
+ ld hl, VendingMachineText6
+ jp PrintText
+.notThirsty
+ ld hl, VendingMachineText7
+ jp PrintText
+
+VendingMachineText1:
+ TX_FAR _VendingMachineText1
+ db "@"
+
+DrinkText:
+ db "FRESH WATER"
+ next "SODA POP"
+ next "LEMONADE"
+ next "CANCEL@"
+
+DrinkPriceText:
+ db "¥200"
+ next "¥300"
+ next "¥350"
+ next "@"
+
+VendingMachineText4:
+ TX_FAR _VendingMachineText4
+ db "@"
+
+VendingMachineText5:
+ TX_FAR _VendingMachineText5
+ db "@"
+
+VendingMachineText6:
+ TX_FAR _VendingMachineText6
+ db "@"
+
+VendingMachineText7:
+ TX_FAR _VendingMachineText7
+ db "@"
+
+LoadVendingMachineItem:
+ ld hl, VendingPrices
+ ld a, [wCurrentMenuItem]
+ add a
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld [hVendingMachineItem], a
+ ld a, [hli]
+ ld [hVendingMachinePrice], a
+ ld a, [hli]
+ ld [hVendingMachinePrice + 1], a
+ ld a, [hl]
+ ld [hVendingMachinePrice + 2], a
+ ret
+
+INCLUDE "data/vending_prices.asm"