aboutsummaryrefslogtreecommitdiffstats
path: root/engine/events
diff options
context:
space:
mode:
authordannye <33dannye@gmail.com>2020-11-04 00:06:44 -0600
committerdannye <33dannye@gmail.com>2020-11-04 00:06:44 -0600
commit5647ca687b92954dcf37a6ea6bfbc9a341c32de4 (patch)
treedde1937a1bfdb3a835f4155e1c2eb8f1aaf86f63 /engine/events
parentMerge pull request #55 from Deokishisu/patch-1 (diff)
downloadpokeyellow-5647ca687b92954dcf37a6ea6bfbc9a341c32de4.tar.gz
pokeyellow-5647ca687b92954dcf37a6ea6bfbc9a341c32de4.tar.xz
pokeyellow-5647ca687b92954dcf37a6ea6bfbc9a341c32de4.zip
Sync with pokered
Diffstat (limited to 'engine/events')
-rw-r--r--engine/events/black_out.asm48
-rwxr-xr-xengine/events/card_key.asm102
-rwxr-xr-xengine/events/cinnabar_lab.asm123
-rw-r--r--engine/events/diploma.asm17
-rw-r--r--engine/events/display_pokedex.asm19
-rwxr-xr-xengine/events/elevator.asm54
-rwxr-xr-xengine/events/give_pokemon.asm87
-rw-r--r--engine/events/heal_party.asm99
-rwxr-xr-xengine/events/hidden_items.asm172
-rw-r--r--engine/events/hidden_objects/bench_guys.asm98
-rw-r--r--engine/events/hidden_objects/bills_house_pc.asm131
-rw-r--r--engine/events/hidden_objects/blues_room.asm13
-rw-r--r--engine/events/hidden_objects/book_or_sculpture.asm21
-rw-r--r--engine/events/hidden_objects/bookshelves.asm39
-rw-r--r--engine/events/hidden_objects/cinnabar_gym_quiz.asm246
-rw-r--r--engine/events/hidden_objects/elevator.asm3
-rw-r--r--engine/events/hidden_objects/fanclub_pictures.asm23
-rw-r--r--engine/events/hidden_objects/fighting_dojo.asm23
-rw-r--r--engine/events/hidden_objects/gym_statues.asm39
-rw-r--r--engine/events/hidden_objects/indigo_plateau_hq.asm10
-rw-r--r--engine/events/hidden_objects/indigo_plateau_statues.asm24
-rw-r--r--engine/events/hidden_objects/magazines.asm8
-rw-r--r--engine/events/hidden_objects/museum_fossils.asm23
-rw-r--r--engine/events/hidden_objects/museum_fossils2.asm28
-rw-r--r--engine/events/hidden_objects/new_bike.asm7
-rw-r--r--engine/events/hidden_objects/oaks_lab_email.asm11
-rw-r--r--engine/events/hidden_objects/oaks_lab_posters.asm29
-rw-r--r--engine/events/hidden_objects/pokecenter_pc.asm11
-rw-r--r--engine/events/hidden_objects/pokemon_stuff.asm3
-rw-r--r--engine/events/hidden_objects/reds_room.asm14
-rw-r--r--engine/events/hidden_objects/route_15_binoculars.asm17
-rw-r--r--engine/events/hidden_objects/safari_game.asm78
-rw-r--r--engine/events/hidden_objects/school_blackboard.asm223
-rw-r--r--engine/events/hidden_objects/school_notebooks.asm65
-rw-r--r--engine/events/hidden_objects/town_map.asm22
-rw-r--r--engine/events/hidden_objects/vermilion_gym_trash.asm134
-rwxr-xr-xengine/events/in_game_trades.asm350
-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.asm151
-rwxr-xr-xengine/events/pokecenter.asm149
-rwxr-xr-xengine/events/pokedex_rating.asm138
-rwxr-xr-xengine/events/pokemart.asm272
-rwxr-xr-xengine/events/prize_menu.asm305
-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.asm132
49 files changed, 3837 insertions, 0 deletions
diff --git a/engine/events/black_out.asm b/engine/events/black_out.asm
new file mode 100644
index 00000000..6d3d91b8
--- /dev/null
+++ b/engine/events/black_out.asm
@@ -0,0 +1,48 @@
+ResetStatusAndHalveMoneyOnBlackout::
+; Reset player status on blackout.
+ xor a
+ ld [wd435], a
+ xor a ; gamefreak copypasting functions (double xor a)
+ ld [wBattleResult], a
+ ld [wWalkBikeSurfState], a
+ ld [wIsInBattle], a
+ ld [wMapPalOffset], a
+ ld [wNPCMovementScriptFunctionNum], a
+ ldh [hJoyHeld], a
+ ld [wNPCMovementScriptPointerTableNum], a
+ ld [wFlags_0xcd60], a
+
+ ldh [hMoney], a
+ ldh [hMoney + 1], a
+ ldh [hMoney + 2], a
+ call HasEnoughMoney
+ jr c, .lostmoney ; never happens
+
+ ; Halve the player's money.
+ ld a, [wPlayerMoney]
+ ldh [hMoney], a
+ ld a, [wPlayerMoney + 1]
+ ldh [hMoney + 1], a
+ ld a, [wPlayerMoney + 2]
+ ldh [hMoney + 2], a
+ xor a
+ ldh [hDivideBCDDivisor], a
+ ldh [hDivideBCDDivisor + 1], a
+ ld a, 2
+ ldh [hDivideBCDDivisor + 2], a
+ predef DivideBCDPredef3
+ ldh a, [hDivideBCDQuotient]
+ ld [wPlayerMoney], a
+ ldh a, [hDivideBCDQuotient + 1]
+ ld [wPlayerMoney + 1], a
+ ldh 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..de5f402e
--- /dev/null
+++ b/engine/events/card_key.asm
@@ -0,0 +1,102 @@
+PrintCardKeyText:
+ ld hl, SilphCoMapList
+ ld a, [wCurMap]
+ ld b, a
+.silphCoMapListLoop
+ ld a, [hli]
+ cp -1
+ ret z
+ cp b
+ jr nz, .silphCoMapListLoop
+; does not check for tile in front of player. This might be buggy
+ ;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
+ xor a
+ ld [wPlayerMovingDirection], a
+ tx_pre_id CardKeySuccessText
+ ldh [hSpriteIndexOrTextID], a
+ call PrintPredefTextID
+ call GetCoordsInFrontOfPlayer
+ 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
+ ldh [hSpriteIndexOrTextID], a
+ jp PrintPredefTextID
+
+INCLUDE "data/events/card_key_maps.asm"
+
+CardKeySuccessText::
+ text_far _CardKeySuccessText1
+ sound_get_item_1
+ text_far _CardKeySuccessText2
+ text_end
+
+CardKeyFailText::
+ text_far _CardKeyFailText
+ text_end
+
+; d = Y
+; e = X
+GetCoordsInFrontOfPlayer:
+ ld a, [wYCoord]
+ ld d, a
+ ld a, [wXCoord]
+ ld e, a
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ 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..bccc95d1
--- /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
+ hlcoord 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]
+ ldh [hItemToRemoveID], 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]
+ ldh [hItemToRemoveID], a
+ farcall 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:
+ text_far _Lab4Text_610ae
+ text_end
+
+LabFossil_610b3:
+ text_far _Lab4Text_610b3
+ text_end
+
+LabFossil_610b8:
+ text_far _Lab4Text_610b8
+ text_end
+
+LabFossil_610bd:
+ text_far _Lab4Text_610bd
+ text_end
+
+PrintFossilsInBag:
+; Prints each fossil in the player's bag on a separate line in the menu.
+ ld hl, wFilteredBagItems
+ xor a
+ ldh [hItemCounter], a
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ push hl
+ ld [wd11e], a
+ call GetItemName
+ hlcoord 2, 2
+ ldh 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 100644
index 00000000..a5a007fa
--- /dev/null
+++ b/engine/events/diploma.asm
@@ -0,0 +1,17 @@
+DisplayDiploma::
+ call SaveScreenTilesToBuffer2
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ld hl, wd730
+ set 6, [hl]
+ callfar _DisplayDiploma
+ call WaitForTextScrollButtonPress
+ ld hl, wd730
+ res 6, [hl]
+ call GBPalWhiteOutWithDelay3
+ call ReloadTilesetTilePatterns
+ call RestoreScreenTilesAndReloadTilePatterns
+ call Delay3
+ jp GBPalNormal
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..004893a0
--- /dev/null
+++ b/engine/events/elevator.asm
@@ -0,0 +1,54 @@
+DisplayElevatorFloorMenu:
+ ld hl, wd730
+ ld a, [hl]
+ push af
+ set 6, [hl]
+ ld hl, WhichFloorText
+ call PrintText
+ pop af
+ ld [wd730], a
+ 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:
+ text_far _WhichFloorText
+ text_end
diff --git a/engine/events/give_pokemon.asm b/engine/events/give_pokemon.asm
new file mode 100755
index 00000000..efc184f8
--- /dev/null
+++ b/engine/events/give_pokemon.asm
@@ -0,0 +1,87 @@
+_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
+ callfar LoadEnemyMonData
+ call SetPokedexOwnedFlag
+ callfar 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
+ ld hl, UnknownTerminator_f6794
+ call PrintText
+ 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
+
+UnknownTerminator_f6794:
+ text_end
+
+GotMonText:
+ text_far _GotMonText
+ sound_get_item_1
+ text_end
+
+SentToBoxText:
+ text_far _SentToBoxText
+ text_end
+
+BoxIsFullText:
+ text_far _BoxIsFullText
+ text_end
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..63b95bcf
--- /dev/null
+++ b/engine/events/hidden_items.asm
@@ -0,0 +1,172 @@
+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
+ jr nz, .itemAlreadyFound
+ call EnableAutoTextBoxDrawing
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument] ; item ID
+ ld [wd11e], a
+ call GetItemName
+ tx_pre_jump FoundHiddenItemText
+
+.itemAlreadyFound
+ ld a, $ff
+ ldh [hItemAlreadyFound], a
+ ret
+
+INCLUDE "data/events/hidden_item_coords.asm"
+
+FoundHiddenItemText::
+ text_far _FoundHiddenItemText
+ text_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::
+ text_far _HiddenItemBagFullText
+ text_end
+
+HiddenCoins:
+ ld b, COIN_CASE
+ predef GetQuantityOfItemInBag
+ ld a, b
+ and a
+ jr z, .doNotPickUpCoins
+ 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
+ jr nz, .doNotPickUpCoins
+ xor a
+ ldh [hUnusedCoinsByte], a
+ ldh [hCoins], a
+ ldh [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
+
+.doNotPickUpCoins
+ ld a, $ff
+ ldh [hItemAlreadyFound], a
+ ret
+
+.bcd10
+ ld a, $10
+ ldh [hCoins + 1], a
+ jr .bcdDone
+.bcd20
+ ld a, $20
+ ldh [hCoins + 1], a
+ jr .bcdDone
+.bcd40 ; due to a typo, this is never used
+ ld a, $40
+ ldh [hCoins + 1], a
+ jr .bcdDone
+.bcd100
+ ld a, $1
+ ldh [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/events/hidden_coins.asm"
+
+FoundHiddenCoinsText::
+ text_far _FoundHiddenCoinsText
+ sound_get_item_2
+ text_end
+
+DroppedHiddenCoinsText::
+ text_far _FoundHiddenCoins2Text
+ sound_get_item_2
+ text_far _DroppedHiddenCoinsText
+ text_end
+
+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 -1 ; 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_objects/bench_guys.asm b/engine/events/hidden_objects/bench_guys.asm
new file mode 100644
index 00000000..b41434ad
--- /dev/null
+++ b/engine/events/hidden_objects/bench_guys.asm
@@ -0,0 +1,98 @@
+PrintBenchGuyText:
+ call EnableAutoTextBoxDrawing
+ ld hl, BenchGuyTextPointers
+ ld a, [wCurMap]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp -1
+ ret z
+ cp b
+ jr z, .match
+ inc hl
+ inc hl
+ jr .loop
+.match
+ ld a, [hli]
+ ld b, a
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp b
+ jr nz, .loop ; player isn't facing the bench guy
+ ld a, [hl]
+ jp PrintPredefTextID
+
+INCLUDE "data/events/bench_guys.asm"
+
+ViridianCityPokecenterBenchGuyText::
+ text_far _ViridianCityPokecenterGuyText
+ text_end
+
+PewterCityPokecenterBenchGuyText::
+ text_far _PewterCityPokecenterGuyText
+ text_end
+
+CeruleanCityPokecenterBenchGuyText::
+ text_far _CeruleanPokecenterGuyText
+ text_end
+
+LavenderCityPokecenterBenchGuyText::
+ text_far _LavenderPokecenterGuyText
+ text_end
+
+MtMoonPokecenterBenchGuyText::
+ text_far _MtMoonPokecenterBenchGuyText
+ text_end
+
+RockTunnelPokecenterBenchGuyText::
+ text_far _RockTunnelPokecenterGuyText
+ text_end
+
+UnusedBenchGuyText1::
+ text_far _UnusedBenchGuyText1
+ text_end
+
+UnusedBenchGuyText2::
+ text_far _UnusedBenchGuyText2
+ text_end
+
+UnusedBenchGuyText3::
+ text_far _UnusedBenchGuyText3
+ text_end
+
+VermilionCityPokecenterBenchGuyText::
+ text_far _VermilionPokecenterGuyText
+ text_end
+
+CeladonCityPokecenterBenchGuyText::
+ text_far _CeladonCityPokecenterGuyText
+ text_end
+
+FuchsiaCityPokecenterBenchGuyText::
+ text_far _FuchsiaCityPokecenterGuyText
+ text_end
+
+CinnabarIslandPokecenterBenchGuyText::
+ text_far _CinnabarPokecenterGuyText
+ text_end
+
+SaffronCityPokecenterBenchGuyText::
+ text_asm
+ CheckEvent EVENT_BEAT_SILPH_CO_GIOVANNI
+ ld hl, SaffronCityPokecenterBenchGuyText2
+ jr nz, .asm_624f2
+ ld hl, SaffronCityPokecenterBenchGuyText1
+.asm_624f2
+ call PrintText
+ jp TextScriptEnd
+
+SaffronCityPokecenterBenchGuyText1:
+ text_far _SaffronCityPokecenterGuyText1
+ text_end
+
+SaffronCityPokecenterBenchGuyText2:
+ text_far _SaffronCityPokecenterGuyText2
+ text_end
+
+CeladonCityHotelText::
+ text_far _CeladonCityHotelText
+ text_end
diff --git a/engine/events/hidden_objects/bills_house_pc.asm b/engine/events/hidden_objects/bills_house_pc.asm
new file mode 100644
index 00000000..bdbaff7e
--- /dev/null
+++ b/engine/events/hidden_objects/bills_house_pc.asm
@@ -0,0 +1,131 @@
+BillsHousePC:
+ call EnableAutoTextBoxDrawing
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ 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::
+ text_far _BillsHouseMonitorText
+ text_end
+
+BillsHouseInitiatedText::
+ text_far _BillsHouseInitiatedText
+ text_promptbutton
+ text_asm
+ call StopAllMusic
+ ld c, 16
+ call DelayFrames
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 60
+ call DelayFrames
+ jp TextScriptEnd
+
+BillsHousePokemonList::
+ text_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]
+ hlcoord 0, 0
+ lb bc, 10, 9
+ call TextBoxBorder
+ hlcoord 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:
+ text_far _BillsHousePokemonListText1
+ text_end
+
+BillsMonListText:
+ db "EEVEE"
+ next "FLAREON"
+ next "JOLTEON"
+ next "VAPOREON"
+ next "CANCEL@"
+
+BillsHousePokemonListText2:
+ text_far _BillsHousePokemonListText2
+ text_end
diff --git a/engine/events/hidden_objects/blues_room.asm b/engine/events/hidden_objects/blues_room.asm
new file mode 100644
index 00000000..bcbad556
--- /dev/null
+++ b/engine/events/hidden_objects/blues_room.asm
@@ -0,0 +1,13 @@
+
+ ret ; unused
+
+UnusedPredefText::
+ db "@"
+
+PrintBookcaseText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump BookcaseText
+
+BookcaseText::
+ text_far _BookcaseText
+ text_end
diff --git a/engine/events/hidden_objects/book_or_sculpture.asm b/engine/events/hidden_objects/book_or_sculpture.asm
new file mode 100644
index 00000000..e04f4047
--- /dev/null
+++ b/engine/events/hidden_objects/book_or_sculpture.asm
@@ -0,0 +1,21 @@
+BookOrSculptureText::
+ text_asm
+ ld hl, PokemonBooksText
+ ld a, [wCurMapTileset]
+ cp MANSION ; Celadon Mansion tileset
+ jr nz, .ok
+ lda_coord 8, 6
+ cp $38
+ jr nz, .ok
+ ld hl, DiglettSculptureText
+.ok
+ call PrintText
+ jp TextScriptEnd
+
+PokemonBooksText:
+ text_far _PokemonBooksText
+ text_end
+
+DiglettSculptureText:
+ text_far _DiglettSculptureText
+ text_end
diff --git a/engine/events/hidden_objects/bookshelves.asm b/engine/events/hidden_objects/bookshelves.asm
new file mode 100644
index 00000000..b58444af
--- /dev/null
+++ b/engine/events/hidden_objects/bookshelves.asm
@@ -0,0 +1,39 @@
+; prints text for bookshelves in buildings without sign events
+PrintBookshelfText::
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ jr nz, .noMatch
+; facing up
+ ld a, [wCurMapTileset]
+ ld b, a
+ lda_coord 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
+ ldh [hFFDB], a
+ ret
+.nextBookshelfEntry1
+ inc hl
+.nextBookshelfEntry2
+ inc hl
+ jr .loop
+.noMatch
+ ld a, $ff
+ ldh [hFFDB], a
+ farjp PrintCardKeyText
+
+INCLUDE "data/tilesets/bookshelf_tile_ids.asm"
diff --git a/engine/events/hidden_objects/cinnabar_gym_quiz.asm b/engine/events/hidden_objects/cinnabar_gym_quiz.asm
new file mode 100644
index 00000000..da550c76
--- /dev/null
+++ b/engine/events/hidden_objects/cinnabar_gym_quiz.asm
@@ -0,0 +1,246 @@
+PrintCinnabarQuiz:
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump CinnabarGymQuiz
+
+CinnabarGymQuiz::
+ text_asm
+ xor a
+ ld [wOpponentAfterWrongAnswer], a
+ ld hl, wd475
+ res 7, [hl]
+ ld a, [wHiddenObjectFunctionArgument]
+ push af
+ and $f
+ ldh [hGymGateIndex], a
+ pop af
+ and $f0
+ swap a
+ ldh [hGymGateAnswer], a
+ ldh a, [hGymGateIndex]
+ ld hl, CinnabarGymQuizIntroText
+ cp 1
+ jr z, .onFirstQuestion
+ ld hl, CinnabarGymQuizShortIntroText
+.onFirstQuestion
+ call PrintText
+ ldh 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
+
+CinnabarGymQuizDummyIntroText:
+ text_far _CinnabarGymQuizDummyIntroText
+ text_end
+
+CinnabarGymQuizIntroText:
+ text_far _CinnabarGymQuizIntroText
+ text_end
+
+CinnabarGymQuizShortIntroText:
+ text_far _CinnabarGymQuizShortIntroText
+ text_end
+
+CinnabarQuizQuestions:
+ dw CinnabarQuizQuestionsText1
+ dw CinnabarQuizQuestionsText2
+ dw CinnabarQuizQuestionsText3
+ dw CinnabarQuizQuestionsText4
+ dw CinnabarQuizQuestionsText5
+ dw CinnabarQuizQuestionsText6
+
+CinnabarQuizQuestionsText1:
+ text_far _CinnabarQuizQuestionsText1
+ text_end
+
+CinnabarQuizQuestionsText2:
+ text_far _CinnabarQuizQuestionsText2
+ text_end
+
+CinnabarQuizQuestionsText3:
+ text_far _CinnabarQuizQuestionsText3
+ text_end
+
+CinnabarQuizQuestionsText4:
+ text_far _CinnabarQuizQuestionsText4
+ text_end
+
+CinnabarQuizQuestionsText5:
+ text_far _CinnabarQuizQuestionsText5
+ text_end
+
+CinnabarQuizQuestionsText6:
+ text_far _CinnabarQuizQuestionsText6
+ text_end
+
+CinnabarGymQuiz_1ea92:
+ call YesNoChoice
+ ldh a, [hGymGateAnswer]
+ ld c, a
+ ld a, [wCurrentMenuItem]
+ cp c
+ jr nz, .wrongAnswer
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+ ldh a, [hGymGateIndex]
+ ldh [hBackupGymGateIndex], a
+ ld hl, CinnabarGymQuizCorrectText
+ call PrintText
+ ldh a, [hBackupGymGateIndex]
+ 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
+ ldh 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
+ ldh a, [hGymGateIndex]
+ add $2
+ ld [wOpponentAfterWrongAnswer], a
+ ld hl, wd475
+ set 7, [hl]
+ ret
+
+CinnabarGymQuizCorrectText:
+ sound_get_item_1
+ text_far _CinnabarGymQuizCorrectText
+ text_promptbutton
+ text_asm
+
+ ldh a, [hBackupGymGateIndex]
+ 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:
+ text_far _CinnabarGymQuizIncorrectText
+ text_end
+
+CinnabarGymGateFlagAction:
+ EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
+ predef_jump FlagActionPredef
+
+UpdateCinnabarGymGateTileBlocks_::
+; Update the overworld map with open floor blocks or locked gate blocks
+; depending on event flags.
+ ld a, 6
+ ldh [hGymGateIndex], a
+.loop
+ ldh 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
+ ldh a, [hGymGateIndex]
+ ldh [hBackupGymGateIndex], 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
+ call CinnabarGym_ReplaceTileBlock
+ ld hl, hGymGateIndex
+ dec [hl]
+ jr nz, .loop
+ callfar RedrawMapView
+ ret
+
+gym_gate_coord: MACRO
+ db \1, \2, \3, 0
+ENDM
+
+HORIZONTAL_GATE_BLOCK EQU $54
+VERTICAL_GATE_BLOCK EQU $5f
+
+CinnabarGymGateCoords:
+ ; x coord, y coord, block id
+ gym_gate_coord 9, 3, HORIZONTAL_GATE_BLOCK
+ gym_gate_coord 6, 3, HORIZONTAL_GATE_BLOCK
+ gym_gate_coord 6, 6, HORIZONTAL_GATE_BLOCK
+ gym_gate_coord 3, 8, VERTICAL_GATE_BLOCK
+ gym_gate_coord 2, 6, HORIZONTAL_GATE_BLOCK
+ gym_gate_coord 2, 3, HORIZONTAL_GATE_BLOCK
+
+
+CinnabarGym_ReplaceTileBlock:
+; basically a copy of the first half of ReplaceTileBlock
+; before checking if it is necessary to redraw the map view
+ ld hl, wOverworldMap
+ ld a, [wCurMapWidth]
+ add $6
+ ld e, a
+ ld d, $0
+ add hl, de
+ add hl, de
+ add hl, de
+ ld e, $3
+ add hl, de
+ ld e, a
+ ld a, b
+ and a
+ jr z, .addX
+.addWidthYTimesLoop
+ add hl, de
+ dec b
+ jr nz, .addWidthYTimesLoop
+.addX
+ add hl, bc
+ ld a, [wNewTileBlockID]
+ ld [hl], a
+ ret
diff --git a/engine/events/hidden_objects/elevator.asm b/engine/events/hidden_objects/elevator.asm
new file mode 100644
index 00000000..ab0f731f
--- /dev/null
+++ b/engine/events/hidden_objects/elevator.asm
@@ -0,0 +1,3 @@
+ElevatorText::
+ text_far _ElevatorText
+ text_end
diff --git a/engine/events/hidden_objects/fanclub_pictures.asm b/engine/events/hidden_objects/fanclub_pictures.asm
new file mode 100644
index 00000000..30bc72c7
--- /dev/null
+++ b/engine/events/hidden_objects/fanclub_pictures.asm
@@ -0,0 +1,23 @@
+FanClubPicture1:
+ ld a, RAPIDASH
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre FanClubPicture1Text
+ ret
+
+FanClubPicture1Text::
+ text_far _FanClubPicture1Text
+ text_end
+
+FanClubPicture2:
+ ld a, FEAROW
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre FanClubPicture2Text
+ ret
+
+FanClubPicture2Text::
+ text_far _FanClubPicture2Text
+ text_end
diff --git a/engine/events/hidden_objects/fighting_dojo.asm b/engine/events/hidden_objects/fighting_dojo.asm
new file mode 100644
index 00000000..b4f89985
--- /dev/null
+++ b/engine/events/hidden_objects/fighting_dojo.asm
@@ -0,0 +1,23 @@
+PrintFightingDojoText2:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump EnemiesOnEverySideText
+
+EnemiesOnEverySideText::
+ text_far _EnemiesOnEverySideText
+ text_end
+
+PrintFightingDojoText3:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump WhatGoesAroundComesAroundText
+
+WhatGoesAroundComesAroundText::
+ text_far _WhatGoesAroundComesAroundText
+ text_end
+
+PrintFightingDojoText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump FightingDojoText
+
+FightingDojoText::
+ text_far _FightingDojoText
+ text_end
diff --git a/engine/events/hidden_objects/gym_statues.asm b/engine/events/hidden_objects/gym_statues.asm
new file mode 100644
index 00000000..1c7eb970
--- /dev/null
+++ b/engine/events/hidden_objects/gym_statues.asm
@@ -0,0 +1,39 @@
+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, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ ret nz
+ ld hl, MapBadgeFlags
+ 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
+
+INCLUDE "data/maps/badge_maps.asm"
+
+GymStatueText1::
+ text_far _GymStatueText1
+ text_end
+
+GymStatueText2::
+ text_far _GymStatueText2
+ text_end
diff --git a/engine/events/hidden_objects/indigo_plateau_hq.asm b/engine/events/hidden_objects/indigo_plateau_hq.asm
new file mode 100644
index 00000000..e8fd0220
--- /dev/null
+++ b/engine/events/hidden_objects/indigo_plateau_hq.asm
@@ -0,0 +1,10 @@
+PrintIndigoPlateauHQText:
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump IndigoPlateauHQText
+
+IndigoPlateauHQText::
+ text_far _IndigoPlateauHQText
+ text_end
diff --git a/engine/events/hidden_objects/indigo_plateau_statues.asm b/engine/events/hidden_objects/indigo_plateau_statues.asm
new file mode 100644
index 00000000..23e94fcf
--- /dev/null
+++ b/engine/events/hidden_objects/indigo_plateau_statues.asm
@@ -0,0 +1,24 @@
+IndigoPlateauStatues::
+ text_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:
+ text_far _IndigoPlateauStatuesText1
+ text_end
+
+IndigoPlateauStatuesText2:
+ text_far _IndigoPlateauStatuesText2
+ text_end
+
+IndigoPlateauStatuesText3:
+ text_far _IndigoPlateauStatuesText3
+ text_end
diff --git a/engine/events/hidden_objects/magazines.asm b/engine/events/hidden_objects/magazines.asm
new file mode 100644
index 00000000..b58636ff
--- /dev/null
+++ b/engine/events/hidden_objects/magazines.asm
@@ -0,0 +1,8 @@
+PrintMagazinesText:
+ call EnableAutoTextBoxDrawing
+ tx_pre MagazinesText
+ ret
+
+MagazinesText::
+ text_far _MagazinesText
+ text_end
diff --git a/engine/events/hidden_objects/museum_fossils.asm b/engine/events/hidden_objects/museum_fossils.asm
new file mode 100644
index 00000000..539f2c3f
--- /dev/null
+++ b/engine/events/hidden_objects/museum_fossils.asm
@@ -0,0 +1,23 @@
+AerodactylFossil:
+ ld a, FOSSIL_AERODACTYL
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre AerodactylFossilText
+ ret
+
+AerodactylFossilText::
+ text_far _AerodactylFossilText
+ text_end
+
+KabutopsFossil:
+ ld a, FOSSIL_KABUTOPS
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre KabutopsFossilText
+ ret
+
+KabutopsFossilText::
+ text_far _KabutopsFossilText
+ text_end
diff --git a/engine/events/hidden_objects/museum_fossils2.asm b/engine/events/hidden_objects/museum_fossils2.asm
new file mode 100644
index 00000000..fce0f03a
--- /dev/null
+++ b/engine/events/hidden_objects/museum_fossils2.asm
@@ -0,0 +1,28 @@
+DisplayMonFrontSpriteInBox:
+; Displays a pokemon's front sprite in a pop-up window.
+; [wcf91] = pokemon internal id number
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ xor a
+ ldh [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
+ ldh [hStartTileID], a
+ hlcoord 10, 11
+ predef AnimateSendingOutMon
+ call WaitForTextScrollButtonPress
+ call LoadScreenTilesFromBuffer1
+ call Delay3
+ ld a, $90
+ ldh [hWY], a
+ ret
diff --git a/engine/events/hidden_objects/new_bike.asm b/engine/events/hidden_objects/new_bike.asm
new file mode 100644
index 00000000..5bce5937
--- /dev/null
+++ b/engine/events/hidden_objects/new_bike.asm
@@ -0,0 +1,7 @@
+PrintNewBikeText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump NewBicycleText
+
+NewBicycleText::
+ text_far _NewBicycleText
+ text_end
diff --git a/engine/events/hidden_objects/oaks_lab_email.asm b/engine/events/hidden_objects/oaks_lab_email.asm
new file mode 100644
index 00000000..bd4c66d7
--- /dev/null
+++ b/engine/events/hidden_objects/oaks_lab_email.asm
@@ -0,0 +1,11 @@
+DisplayOakLabEmailText:
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre OakLabEmailText
+ ret
+
+OakLabEmailText::
+ text_far _OakLabEmailText
+ text_end
diff --git a/engine/events/hidden_objects/oaks_lab_posters.asm b/engine/events/hidden_objects/oaks_lab_posters.asm
new file mode 100644
index 00000000..502cf951
--- /dev/null
+++ b/engine/events/hidden_objects/oaks_lab_posters.asm
@@ -0,0 +1,29 @@
+DisplayOakLabLeftPoster:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump PushStartText
+
+PushStartText::
+ text_far _PushStartText
+ text_end
+
+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::
+ text_far _SaveOptionText
+ text_end
+
+StrengthsAndWeaknessesText::
+ text_far _StrengthsAndWeaknessesText
+ text_end
diff --git a/engine/events/hidden_objects/pokecenter_pc.asm b/engine/events/hidden_objects/pokecenter_pc.asm
new file mode 100644
index 00000000..f20f40ed
--- /dev/null
+++ b/engine/events/hidden_objects/pokecenter_pc.asm
@@ -0,0 +1,11 @@
+OpenPokemonCenterPC:
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ ld a, TRUE
+ ld [wAutoTextBoxDrawingControl], a
+ tx_pre_jump PokemonCenterPCText
+
+PokemonCenterPCText::
+ script_pokecenter_pc
diff --git a/engine/events/hidden_objects/pokemon_stuff.asm b/engine/events/hidden_objects/pokemon_stuff.asm
new file mode 100644
index 00000000..267a191a
--- /dev/null
+++ b/engine/events/hidden_objects/pokemon_stuff.asm
@@ -0,0 +1,3 @@
+PokemonStuffText::
+ text_far _PokemonStuffText
+ text_end
diff --git a/engine/events/hidden_objects/reds_room.asm b/engine/events/hidden_objects/reds_room.asm
new file mode 100644
index 00000000..7b8d51a0
--- /dev/null
+++ b/engine/events/hidden_objects/reds_room.asm
@@ -0,0 +1,14 @@
+PrintRedSNESText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump RedBedroomSNESText
+
+RedBedroomSNESText::
+ text_far _RedBedroomSNESText
+ text_end
+
+OpenRedsPC:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump RedBedroomPCText
+
+RedBedroomPCText::
+ script_players_pc
diff --git a/engine/events/hidden_objects/route_15_binoculars.asm b/engine/events/hidden_objects/route_15_binoculars.asm
new file mode 100644
index 00000000..9734e833
--- /dev/null
+++ b/engine/events/hidden_objects/route_15_binoculars.asm
@@ -0,0 +1,17 @@
+Route15GateLeftBinoculars:
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre Route15UpstairsBinocularsText
+ ld a, ARTICUNO
+ ld [wcf91], a
+ call PlayCry
+ call DisplayMonFrontSpriteInBox
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+Route15UpstairsBinocularsText::
+ text_far _Route15UpstairsBinocularsText
+ text_end
diff --git a/engine/events/hidden_objects/safari_game.asm b/engine/events/hidden_objects/safari_game.asm
new file mode 100644
index 00000000..5001a5d4
--- /dev/null
+++ b/engine/events/hidden_objects/safari_game.asm
@@ -0,0 +1,78 @@
+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
+ call StopAllMusic
+ 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
+ ldh [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ xor a
+ ld [wPlayerMovingDirection], a
+ ld a, SAFARI_ZONE_GATE
+ ldh [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:
+ text_asm
+ ld a, [wNumSafariBalls]
+ and a
+ jr z, .noMoreSafariBalls
+ ld hl, TimesUpText
+ call PrintText
+.noMoreSafariBalls
+ ld hl, GameOverText
+ call PrintText
+ jp TextScriptEnd
+
+TimesUpText:
+ text_far _TimesUpText
+ text_end
+
+GameOverText:
+ text_far _GameOverText
+ text_end
diff --git a/engine/events/hidden_objects/school_blackboard.asm b/engine/events/hidden_objects/school_blackboard.asm
new file mode 100644
index 00000000..eb927292
--- /dev/null
+++ b/engine/events/hidden_objects/school_blackboard.asm
@@ -0,0 +1,223 @@
+PrintBlackboardLinkCableText:
+ call EnableAutoTextBoxDrawing
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument]
+ call PrintPredefTextID
+ ret
+
+LinkCableHelp::
+ text_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]
+ hlcoord 0, 0
+ lb bc, 8, 13
+ call TextBoxBorder
+ hlcoord 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:
+ text_far _LinkCableHelpText1
+ text_end
+
+LinkCableHelpText2:
+ text_far _LinkCableHelpText2
+ text_end
+
+HowToLinkText:
+ db "HOW TO LINK"
+ next "COLOSSEUM"
+ next "TRADE CENTER"
+ next "STOP READING@"
+
+LinkCableInfoTexts:
+ dw LinkCableInfoText1
+ dw LinkCableInfoText2
+ dw LinkCableInfoText3
+
+LinkCableInfoText1:
+ text_far _LinkCableInfoText1
+ text_end
+
+LinkCableInfoText2:
+ text_far _LinkCableInfoText2
+ text_end
+
+LinkCableInfoText3:
+ text_far _LinkCableInfoText3
+ text_end
+
+ViridianSchoolBlackboard::
+ text_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]
+ hlcoord 0, 0
+ lb bc, 6, 10
+ call TextBoxBorder
+ hlcoord 1, 2
+ ld de, StatusAilmentText1
+ call PlaceString
+ hlcoord 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:
+ text_far _ViridianSchoolBlackboardText1
+ text_end
+
+ViridianSchoolBlackboardText2:
+ text_far _ViridianSchoolBlackboardText2
+ text_end
+
+StatusAilmentText1:
+ db " SLP"
+ next " PSN"
+ next " PAR@"
+
+StatusAilmentText2:
+ db " BRN"
+ next " FRZ"
+ next " QUIT@"
+
+ db "@" ; unused
+
+ViridianBlackboardStatusPointers:
+ dw ViridianBlackboardSleepText
+ dw ViridianBlackboardPoisonText
+ dw ViridianBlackboardPrlzText
+ dw ViridianBlackboardBurnText
+ dw ViridianBlackboardFrozenText
+
+ViridianBlackboardSleepText:
+ text_far _ViridianBlackboardSleepText
+ text_end
+
+ViridianBlackboardPoisonText:
+ text_far _ViridianBlackboardPoisonText
+ text_end
+
+ViridianBlackboardPrlzText:
+ text_far _ViridianBlackboardPrlzText
+ text_end
+
+ViridianBlackboardBurnText:
+ text_far _ViridianBlackboardBurnText
+ text_end
+
+ViridianBlackboardFrozenText:
+ text_far _ViridianBlackboardFrozenText
+ text_end
diff --git a/engine/events/hidden_objects/school_notebooks.asm b/engine/events/hidden_objects/school_notebooks.asm
new file mode 100644
index 00000000..96a44ab5
--- /dev/null
+++ b/engine/events/hidden_objects/school_notebooks.asm
@@ -0,0 +1,65 @@
+PrintNotebookText:
+ call EnableAutoTextBoxDrawing
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument]
+ jp PrintPredefTextID
+
+TMNotebook::
+ text_far TMNotebookText
+ text_waitbutton
+ text_end
+
+ViridianSchoolNotebook::
+ text_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:
+ text_far _TurnPageText
+ text_end
+
+ViridianSchoolNotebookText5:
+ text_far _ViridianSchoolNotebookText5
+ text_waitbutton
+ text_end
+
+ViridianSchoolNotebookText1:
+ text_far _ViridianSchoolNotebookText1
+ text_end
+
+ViridianSchoolNotebookText2:
+ text_far _ViridianSchoolNotebookText2
+ text_end
+
+ViridianSchoolNotebookText3:
+ text_far _ViridianSchoolNotebookText3
+ text_end
+
+ViridianSchoolNotebookText4:
+ text_far _ViridianSchoolNotebookText4
+ text_end
diff --git a/engine/events/hidden_objects/town_map.asm b/engine/events/hidden_objects/town_map.asm
new file mode 100644
index 00000000..4284214f
--- /dev/null
+++ b/engine/events/hidden_objects/town_map.asm
@@ -0,0 +1,22 @@
+TownMapText::
+ text_far _TownMapText
+ text_promptbutton
+ text_asm
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld hl, wd730
+ set 6, [hl]
+ call GBPalWhiteOutWithDelay3
+ xor a
+ ldh [hWY], a
+ inc a
+ ldh [hAutoBGTransferEnabled], a
+ call LoadFontTilePatterns
+ farcall DisplayTownMap
+ ld hl, wd730
+ res 6, [hl]
+ ld de, TextScriptEnd
+ push de
+ ldh a, [hLoadedROMBank]
+ push af
+ jp CloseTextDisplay
diff --git a/engine/events/hidden_objects/vermilion_gym_trash.asm b/engine/events/hidden_objects/vermilion_gym_trash.asm
new file mode 100644
index 00000000..21dd3ee0
--- /dev/null
+++ b/engine/events/hidden_objects/vermilion_gym_trash.asm
@@ -0,0 +1,134 @@
+PrintTrashText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump VermilionGymTrashText
+
+VermilionGymTrashText::
+ text_far _VermilionGymTrashText
+ text_end
+
+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
+ callfar Yellow_SampleSecondTrashCan
+ tx_pre_id VermilionGymTrashSuccessText1
+ jr .done
+
+.trySecondLock
+ ld a, [wGymTrashCanIndex]
+ ld b, a
+ ld a, [wSecondLockTrashCanIndex]
+ cp b
+ jr z, .openSecondLock
+ ld a, [wSecondLockTrashCanIndex + 1]
+ 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
+; Note that the mask is simply the number of valid trash can indices that
+; follow. The remaining bytes are filled with -1 to pad the length of each entry
+; to 5 bytes.
+; This is functionally replaced with GymTrashCans3a but was never removed from source.
+
+ db 2, 1, 3, -1, -1 ; 0
+ db 3, 0, 2, 4, -1 ; 1
+ db 2, 1, 5, -1, -1 ; 2
+ db 3, 0, 4, 6, -1 ; 3
+ db 4, 1, 3, 5, 7 ; 4
+ db 3, 2, 4, 8, -1 ; 5
+ db 3, 3, 7, 9, -1 ; 6
+ db 4, 4, 6, 8, 10 ; 7
+ db 3, 5, 7, 11, -1 ; 8
+ db 3, 6, 10, 12, -1 ; 9
+ db 4, 7, 9, 11, 13 ; 10
+ db 3, 8, 10, 14, -1 ; 11
+ db 2, 9, 13, -1, -1 ; 12
+ db 3, 10, 12, 14, -1 ; 13
+ db 2, 11, 13, -1, -1 ; 14
+
+VermilionGymTrashSuccessText1::
+ text_far _VermilionGymTrashSuccessText1
+ text_asm
+ call WaitForSoundToFinish
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+; unused
+VermilionGymTrashSuccessText2::
+ text_far _VermilionGymTrashSuccessText2
+ text_end
+
+; unused
+VermilionGymTrashSuccesPlaySfx:
+ text_asm
+ call WaitForSoundToFinish
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+VermilionGymTrashSuccessText3::
+ text_far _VermilionGymTrashSuccessText3
+ text_asm
+ call WaitForSoundToFinish
+ ld a, SFX_GO_INSIDE
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+VermilionGymTrashFailText::
+ text_far _VermilionGymTrashFailText
+ text_asm
+ call WaitForSoundToFinish
+ ld a, SFX_DENIED
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
diff --git a/engine/events/in_game_trades.asm b/engine/events/in_game_trades.asm
new file mode 100755
index 00000000..a0a23dfa
--- /dev/null
+++ b/engine/events/in_game_trades.asm
@@ -0,0 +1,350 @@
+DoInGameTradeDialogue:
+; trigger the trade offer/action specified by wWhichTrade
+ call SaveScreenTilesToBuffer2
+ ld hl, TradeMons
+ ld a, [wWhichTrade]
+ ld bc, $e
+ call AddNTimes
+ 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 a, $4
+ ld [wInGameTradeTextPointerTableIndex], a
+ ld b, FLAG_TEST
+ call InGameTrade_FlagActionPredef
+ ld a, c
+ and a
+ jr nz, .printText
+; if the trade hasn't been done yet
+ ld a, $0
+ 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/events/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 b, FLAG_SET
+ call InGameTrade_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
+ call InGameTrade_CheckForTradeEvo
+ call ClearScreen
+ call InGameTrade_RestoreScreen
+ farcall 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
+ farjp 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_FlagActionPredef:
+ ld hl, wCompletedInGameTradeFlags
+ ld a, [wWhichTrade]
+ ld c, a
+ predef_jump FlagActionPredef
+
+InGameTrade_CheckForTradeEvo:
+ ld a, [wInGameTradeReceiveMonSpecies]
+ cp KADABRA
+ jr z, .tradeEvo
+ cp GRAVELER
+ jr z, .tradeEvo
+ cp MACHOKE
+ jr z, .tradeEvo
+ cp HAUNTER
+ jr z, .tradeEvo
+ ret
+
+.tradeEvo
+ ld a, [wPartyCount]
+ dec a
+ ld [wWhichPokemon], a
+ ld a, $1
+ ld [wForceEvolution], a
+ ld a, LINK_STATE_TRADING
+ ld [wLinkState], a
+ callfar EvolveTradeMon
+ xor a ; LINK_STATE_NONE
+ ld [wLinkState], a
+ jp PlayDefaultMusic
+
+InGameTrade_TrainerString:
+ db "<TRAINER>@@@@@@@@@@"
+
+InGameTradeTextPointers:
+; entries correspond to TRADE_DIALOGSET_* constants
+ 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:
+ text_far _ConnectCableText
+ text_end
+
+TradedForText:
+ text_far _TradedForText
+ sound_get_key_item
+ text_pause
+ text_end
+
+WannaTrade1Text:
+ text_far _WannaTrade1Text
+ text_end
+
+NoTrade1Text:
+ text_far _NoTrade1Text
+ text_end
+
+WrongMon1Text:
+ text_far _WrongMon1Text
+ text_end
+
+Thanks1Text:
+ text_far _Thanks1Text
+ text_end
+
+AfterTrade1Text:
+ text_far _AfterTrade1Text
+ text_end
+
+WannaTrade2Text:
+ text_far _WannaTrade2Text
+ text_end
+
+NoTrade2Text:
+ text_far _NoTrade2Text
+ text_end
+
+WrongMon2Text:
+ text_far _WrongMon2Text
+ text_end
+
+Thanks2Text:
+ text_far _Thanks2Text
+ text_end
+
+AfterTrade2Text:
+ text_far _AfterTrade2Text
+ text_end
+
+WannaTrade3Text:
+ text_far _WannaTrade3Text
+ text_end
+
+NoTrade3Text:
+ text_far _NoTrade3Text
+ text_end
+
+WrongMon3Text:
+ text_far _WrongMon3Text
+ text_end
+
+Thanks3Text:
+ text_far _Thanks3Text
+ text_end
+
+AfterTrade3Text:
+ text_far _AfterTrade3Text
+ text_end
diff --git a/engine/events/oaks_aide.asm b/engine/events/oaks_aide.asm
new file mode 100755
index 00000000..f1801f5c
--- /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]
+ ldh [hOaksAideNumMonsOwned], a
+ ld b, a
+ ldh a, [hOaksAideRequirement]
+ cp b
+ jr z, .giveItem
+ jr nc, .notEnoughOwnedMons
+.giveItem
+ ld hl, OaksAideHereYouGoText
+ call PrintText
+ ldh a, [hOaksAideRewardItem]
+ ld b, a
+ ld c, 1
+ call GiveItem
+ jr nc, .bagFull
+ ld hl, OaksAideGotItemText
+ call PrintText
+ ld a, OAKS_AIDE_GOT_ITEM
+ jr .done
+.bagFull
+ ld hl, OaksAideNoRoomText
+ call PrintText
+ xor a ; OAKS_AIDE_BAG_FULL
+ jr .done
+.notEnoughOwnedMons
+ ld hl, OaksAideUhOhText
+ call PrintText
+ ld a, OAKS_AIDE_NOT_ENOUGH_MONS
+ jr .done
+.choseNo
+ ld hl, OaksAideComeBackText
+ call PrintText
+ ld a, OAKS_AIDE_REFUSED
+.done
+ ldh [hOaksAideResult], a
+ ret
+
+OaksAideHiText:
+ text_far _OaksAideHiText
+ text_end
+
+OaksAideUhOhText:
+ text_far _OaksAideUhOhText
+ text_end
+
+OaksAideComeBackText:
+ text_far _OaksAideComeBackText
+ text_end
+
+OaksAideHereYouGoText:
+ text_far _OaksAideHereYouGoText
+ text_end
+
+OaksAideGotItemText:
+ text_far _OaksAideGotItemText
+ sound_get_item_1
+ text_end
+
+OaksAideNoRoomText:
+ text_far _OaksAideNoRoomText
+ text_end
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..548db5be
--- /dev/null
+++ b/engine/events/pick_up_item.asm
@@ -0,0 +1,54 @@
+PickUpItem:
+ call EnableAutoTextBoxDrawing
+
+ ldh 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]
+ ldh [hMissableObjectIndex], a
+
+ ld hl, wMapSpriteExtraData
+ ldh 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
+
+ ldh a, [hMissableObjectIndex]
+ 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:
+ text_far _FoundItemText
+ sound_get_item_1
+ text_end
+
+NoMoreRoomForItemText:
+ text_far _NoMoreRoomForItemText
+ text_end
diff --git a/engine/events/poison.asm b/engine/events/poison.asm
new file mode 100644
index 00000000..9f3ad391
--- /dev/null
+++ b/engine/events/poison.asm
@@ -0,0 +1,151 @@
+ApplyOutOfBattlePoisonDamage:
+ ld a, [wd730]
+ add a
+ jp c, .noBlackOut ; no black out if joypad states are being simulated
+ ld a, [wd492]
+ bit 7, a
+ jp nz, .noBlackOut
+ ld a, [wd72e]
+ bit 6, a
+ jp nz, .noBlackOut
+ ld a, [wPartyCount]
+ and a
+ jp z, .noBlackOut
+ call IncrementDayCareMonExp
+ call Func_c4c7
+ ld a, [wStepCounter]
+ and $3 ; is the counter a multiple of 4?
+ jp nz, .skipPoisonEffectAndSound ; 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
+ ldh [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .curMonNotPlayerPikachu
+ ld e, $3
+ callfar PlayPikachuSoundClip
+ calladb_ModifyPikachuHappiness PIKAHAPPY_PSNFNT
+.curMonNotPlayerPikachu
+ 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
+ ldh [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ ld hl, wd72e
+ set 5, [hl]
+ ld a, $ff
+ jr .done
+.noBlackOut
+ xor a
+.done
+ ld [wOutOfBattleBlackout], a
+ ret
+
+Func_c4c7:
+ ld a, [wStepCounter]
+ and a
+ jr nz, .asm_c4de
+ call Random
+ and $1
+ jr z, .asm_c4de
+ calladb_ModifyPikachuHappiness $6
+.asm_c4de
+ ld hl, wPikachuMood
+ ld a, [hl]
+ cp $80
+ jr z, .asm_c4ef
+ jr c, .asm_c4ea
+ dec a
+ dec a
+.asm_c4ea
+ inc a
+ ld [hl], a
+ cp $80
+ ret nz
+.asm_c4ef
+ xor a
+ ld [wd49c], a
+ ret
diff --git a/engine/events/pokecenter.asm b/engine/events/pokecenter.asm
new file mode 100755
index 00000000..e007030a
--- /dev/null
+++ b/engine/events/pokecenter.asm
@@ -0,0 +1,149 @@
+DisplayPokemonCenterDialogue_::
+ ld a, [wCurMap]
+ cp PEWTER_POKECENTER
+ jr nz, .regularCenter
+ call CheckPikachuFollowingPlayer
+ jr z, .regularCenter
+ ld hl, LooksContentText ; if pikachu is sleeping, don't heal
+ call PrintText
+ ret
+.regularCenter
+ 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
+ call UpdateSprites
+ ld a, [wCurrentMenuItem]
+ and a
+ jp nz, .declinedHealing ; if the player chose No
+ call SetLastBlackoutMap
+ callfar IsStarterPikachuInOurParty
+ jr nc, .notHealingPlayerPikachu
+ call CheckPikachuFollowingPlayer
+ jr nz, .notHealingPlayerPikachu
+ call LoadCurrentMapView
+ call Delay3
+ call UpdateSprites
+ callfar PikachuWalksToNurseJoy ; todo
+.notHealingPlayerPikachu
+ ld hl, NeedYourPokemonText
+ call PrintText
+ ld c, 64
+ call DelayFrames
+ call CheckPikachuFollowingPlayer
+ jr nz, .playerPikachuNotOnScreen
+ call DisablePikachuOverworldSpriteDrawing
+ callfar IsStarterPikachuInOurParty
+ call c, Func_6eaa
+.playerPikachuNotOnScreen
+ lb bc, 1, 8
+ call Func_6ebb
+ ld c, 30
+ call DelayFrames
+ farcall AnimateHealingMachine ; do the healing machine animation
+ predef HealParty
+ xor a
+ ld [wAudioFadeOutControl], a
+ ld a, [wAudioSavedROMBank]
+ ld [wAudioROMBank], a
+ ld a, [wMapMusicSoundID]
+ ld [wLastMusicSoundID], a
+ ld [wNewSoundID], a
+ call PlaySound
+ call CheckPikachuFollowingPlayer
+ jr nz, .doNotReturnPikachu
+ callfar IsStarterPikachuInOurParty
+ call c, Func_6eaa
+ ld a, $5
+ ld [wPikachuSpawnState], a
+ call EnablePikachuOverworldSpriteDrawing
+.doNotReturnPikachu
+ lb bc, 1, 0
+ call Func_6ebb
+ ld hl, PokemonFightingFitText
+ call PrintText
+ callfar IsStarterPikachuInOurParty
+ jr nc, .notInParty
+ lb bc, 15, 0
+ call Func_6ebb
+.notInParty
+ call LoadCurrentMapView
+ call Delay3
+ call UpdateSprites
+ callfar ReloadWalkingTilePatterns
+ ld a, $1
+ ldh [hSpriteIndex], a
+ ld a, $1
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ld c, 40
+ call DelayFrames
+ call UpdateSprites
+ call LoadFontTilePatterns
+ jr .done
+.declinedHealing
+ call LoadScreenTilesFromBuffer1 ; restore screen
+.done
+ ld hl, PokemonCenterFarewellText
+ call PrintText
+ call UpdateSprites
+ ret
+
+Func_6eaa:
+ ld a, $1
+ ldh [hSpriteIndex], a
+ ld a, $4
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ld c, 64
+ call DelayFrames
+ ret
+
+Func_6ebb:
+ ld a, b
+ ldh [hSpriteIndex], a
+ ld a, c
+ ldh [hSpriteImageIndex], a
+ push bc
+ call SetSpriteFacingDirectionAndDelay
+ pop bc
+ ld a, b
+ ldh [hSpriteIndex], a
+ ld a, c
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ret
+
+PokemonCenterWelcomeText:
+ text_far _PokemonCenterWelcomeText
+ text_end
+
+ShallWeHealYourPokemonText:
+ text_pause
+ text_far _ShallWeHealYourPokemonText
+ text_end
+
+NeedYourPokemonText:
+ text_far _NeedYourPokemonText
+ text_end
+
+PokemonFightingFitText:
+ text_far _PokemonFightingFitText
+ text_end
+
+PokemonCenterFarewellText:
+ text_pause
+ text_far _PokemonCenterFarewellText
+ text_end
+
+LooksContentText:
+ text_far _LooksContentText
+ text_end
diff --git a/engine/events/pokedex_rating.asm b/engine/events/pokedex_rating.asm
new file mode 100755
index 00000000..1086257a
--- /dev/null
+++ b/engine/events/pokedex_rating.asm
@@ -0,0 +1,138 @@
+DisplayDexRating:
+ ld hl, wPokedexSeen
+ ld b, wPokedexSeenEnd - wPokedexSeen
+ call CountSetBits
+ ld a, [wNumSetBits]
+ ldh [hDexRatingNumMonsSeen], a
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ ld a, [wNumSetBits]
+ ldh [hDexRatingNumMonsOwned], a
+ ld hl, DexRatingsTable
+.findRating
+ ld a, [hli]
+ ld b, a
+ ldh 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, DexCompletionText
+ call PrintText
+ pop hl
+ call PrintText
+ farcall PlayPokedexRatingSfx
+ jp WaitForTextScrollButtonPress
+.hallOfFame
+ ld de, wDexRatingNumMonsSeen
+ ldh a, [hDexRatingNumMonsSeen]
+ ld [de], a
+ inc de
+ ldh 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
+
+DexCompletionText:
+ text_far _DexCompletionText
+ text_end
+
+DexRatingsTable:
+ dbw 10, DexRatingText_Own0To9
+ dbw 20, DexRatingText_Own10To19
+ dbw 30, DexRatingText_Own20To29
+ dbw 40, DexRatingText_Own30To39
+ dbw 50, DexRatingText_Own40To49
+ dbw 60, DexRatingText_Own50To59
+ dbw 70, DexRatingText_Own60To69
+ dbw 80, DexRatingText_Own70To79
+ dbw 90, DexRatingText_Own80To89
+ dbw 100, DexRatingText_Own90To99
+ dbw 110, DexRatingText_Own100To109
+ dbw 120, DexRatingText_Own110To119
+ dbw 130, DexRatingText_Own120To129
+ dbw 140, DexRatingText_Own130To139
+ dbw 150, DexRatingText_Own140To149
+ dbw NUM_POKEMON + 1, DexRatingText_Own150To151
+
+DexRatingText_Own0To9:
+ text_far _DexRatingText_Own0To9
+ text_end
+
+DexRatingText_Own10To19:
+ text_far _DexRatingText_Own10To19
+ text_end
+
+DexRatingText_Own20To29:
+ text_far _DexRatingText_Own20To29
+ text_end
+
+DexRatingText_Own30To39:
+ text_far _DexRatingText_Own30To39
+ text_end
+
+DexRatingText_Own40To49:
+ text_far _DexRatingText_Own40To49
+ text_end
+
+DexRatingText_Own50To59:
+ text_far _DexRatingText_Own50To59
+ text_end
+
+DexRatingText_Own60To69:
+ text_far _DexRatingText_Own60To69
+ text_end
+
+DexRatingText_Own70To79:
+ text_far _DexRatingText_Own70To79
+ text_end
+
+DexRatingText_Own80To89:
+ text_far _DexRatingText_Own80To89
+ text_end
+
+DexRatingText_Own90To99:
+ text_far _DexRatingText_Own90To99
+ text_end
+
+DexRatingText_Own100To109:
+ text_far _DexRatingText_Own100To109
+ text_end
+
+DexRatingText_Own110To119:
+ text_far _DexRatingText_Own110To119
+ text_end
+
+DexRatingText_Own120To129:
+ text_far _DexRatingText_Own120To129
+ text_end
+
+DexRatingText_Own130To139:
+ text_far _DexRatingText_Own130To139
+ text_end
+
+DexRatingText_Own140To149:
+ text_far _DexRatingText_Own140To149
+ text_end
+
+DexRatingText_Own150To151:
+ text_far _DexRatingText_Own150To151
+ text_end
diff --git a/engine/events/pokemart.asm b/engine/events/pokemart.asm
new file mode 100755
index 00000000..c7cb8115
--- /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
+ callfar 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
+ ldh [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
+ hlcoord 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
+ callfar 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
+ ldh [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
+ hlcoord 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:
+ text_far _PokemartBuyingGreetingText
+ text_end
+
+PokemartTellBuyPriceText:
+ text_far _PokemartTellBuyPriceText
+ text_end
+
+PokemartBoughtItemText:
+ text_far _PokemartBoughtItemText
+ text_end
+
+PokemartNotEnoughMoneyText:
+ text_far _PokemartNotEnoughMoneyText
+ text_end
+
+PokemartItemBagFullText:
+ text_far _PokemartItemBagFullText
+ text_end
+
+PokemonSellingGreetingText:
+ text_far _PokemonSellingGreetingText
+ text_end
+
+PokemartTellSellPriceText:
+ text_far _PokemartTellSellPriceText
+ text_end
+
+PokemartItemBagEmptyText:
+ text_far _PokemartItemBagEmptyText
+ text_end
+
+PokemartUnsellableItemText:
+ text_far _PokemartUnsellableItemText
+ text_end
+
+PokemartThankYouText:
+ text_far _PokemartThankYouText
+ text_end
+
+PokemartAnythingElseText:
+ text_far _PokemartAnythingElseText
+ text_end
diff --git a/engine/events/prize_menu.asm b/engine/events/prize_menu.asm
new file mode 100755
index 00000000..87244119
--- /dev/null
+++ b/engine/events/prize_menu.asm
@@ -0,0 +1,305 @@
+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
+ hlcoord 0, 2
+ lb bc, 8, 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:
+ text_far _RequireCoinCaseText
+ text_waitbutton
+ text_end
+
+ExchangeCoinsForPrizesTextPtr:
+ text_far _ExchangeCoinsForPrizesText
+ text_end
+
+WhichPrizeTextPtr:
+ text_far _WhichPrizeText
+ text_end
+
+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)
+ ldh 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
+ hlcoord 2, 4
+ call PlaceString
+ ld a, [wPrize2]
+ ld [wd11e], a
+ call GetItemName
+ hlcoord 2, 6
+ call PlaceString
+ ld a, [wPrize3]
+ ld [wd11e], a
+ call GetItemName
+ hlcoord 2, 8
+ call PlaceString
+ jr .putNoThanksText
+.putMonName
+ ld a, [wPrize1]
+ ld [wd11e], a
+ call GetMonName
+ hlcoord 2, 4
+ call PlaceString
+ ld a, [wPrize2]
+ ld [wd11e], a
+ call GetMonName
+ hlcoord 2, 6
+ call PlaceString
+ ld a, [wPrize3]
+ ld [wd11e], a
+ call GetMonName
+ hlcoord 2, 8
+ call PlaceString
+.putNoThanksText
+ hlcoord 2, 10
+ ld de, NoThanksText
+ call PlaceString
+; put prices on the right side of the textbox
+ ld de, wPrize1Price
+ hlcoord 13, 5
+; reg. c:
+; [low nybble] number of bytes
+; [bits 765 = %100] space-padding (not zero-padding)
+ ld c, (1 << 7 | 2)
+ call PrintBCDNumber
+ ld de, wPrize2Price
+ hlcoord 13, 7
+ ld c, (1 << 7 | 2)
+ call PrintBCDNumber
+ ld de, wPrize3Price
+ hlcoord 13, 9
+ ld c, (1 << 7 | 2)
+ jp PrintBCDNumber
+
+NoThanksText:
+ db "NO THANKS@"
+
+INCLUDE "data/events/prizes.asm"
+
+PrintPrizePrice:
+ hlcoord 11, 0
+ lb bc, 1, 7
+ call TextBoxBorder
+ call UpdateSprites
+ hlcoord 12, 0
+ ld de, .CoinString
+ call PlaceString
+ hlcoord 13, 1
+ ld de, .SixSpacesString
+ call PlaceString
+ hlcoord 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
+ ldh [hUnusedCoinsByte], a
+ ld a, [hli]
+ ldh [hCoins], a
+ ld a, [hl]
+ ldh [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:
+ text_far _HereYouGoText
+ text_waitbutton
+ text_end
+
+SoYouWantPrizeTextPtr:
+ text_far _SoYouWantPrizeText
+ text_end
+
+SorryNeedMoreCoinsText:
+ text_far _SorryNeedMoreCoinsText
+ text_waitbutton
+ text_end
+
+PrizeRoomBagIsFullTextPtr:
+ text_far _OopsYouDontHaveEnoughRoomText
+ text_waitbutton
+ text_end
+
+OhFineThenTextPtr:
+ text_far _OhFineThenText
+ text_waitbutton
+ text_end
+
+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/events/prize_mon_levels.asm"
diff --git a/engine/events/saffron_guards.asm b/engine/events/saffron_guards.asm
new file mode 100755
index 00000000..bf30b8c5
--- /dev/null
+++ b/engine/events/saffron_guards.asm
@@ -0,0 +1,15 @@
+RemoveGuardDrink::
+ ld hl, GuardDrinksList
+.drinkLoop
+ ld a, [hli]
+ ldh [hItemToRemoveID], a
+ and a
+ ret z
+ push hl
+ ld b, a
+ call IsItemInBag
+ pop hl
+ jr z, .drinkLoop
+ farjp RemoveItemByID
+
+INCLUDE "data/items/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..e8460240
--- /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/maps/rest_house_maps.asm"
diff --git a/engine/events/starter_dex.asm b/engine/events/starter_dex.asm
new file mode 100755
index 00000000..7cfe9af2
--- /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, 1 << (DEX_BULBASAUR - 1) | 1 << (DEX_IVYSAUR - 1) | 1 << (DEX_CHARMANDER - 1) | 1 << (DEX_SQUIRTLE - 1)
+ ld [wPokedexOwned], a
+ predef ShowPokedexData
+ xor a
+ ld [wPokedexOwned], a
+ ret
diff --git a/engine/events/vending_machine.asm b/engine/events/vending_machine.asm
new file mode 100755
index 00000000..6ff6a5e4
--- /dev/null
+++ b/engine/events/vending_machine.asm
@@ -0,0 +1,132 @@
+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]
+ hlcoord 0, 3
+ lb bc, 8, 12
+ call TextBoxBorder
+ call UpdateSprites
+ hlcoord 2, 5
+ ld de, DrinkText
+ call PlaceString
+ hlcoord 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
+ ldh [hMoney], a
+ ldh [hMoney + 2], a
+ ld a, $2
+ ldh [hMoney + 1], a
+ call HasEnoughMoney
+ jr nc, .enoughMoney
+ ld hl, VendingMachineText4
+ jp PrintText
+.enoughMoney
+ call LoadVendingMachineItem
+ ldh 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:
+ text_far _VendingMachineText1
+ text_end
+
+DrinkText:
+ db "FRESH WATER"
+ next "SODA POP"
+ next "LEMONADE"
+ next "CANCEL@"
+
+DrinkPriceText:
+ db "¥200"
+ next "¥300"
+ next "¥350"
+ next "@"
+
+VendingMachineText4:
+ text_far _VendingMachineText4
+ text_end
+
+VendingMachineText5:
+ text_far _VendingMachineText5
+ text_end
+
+VendingMachineText6:
+ text_far _VendingMachineText6
+ text_end
+
+VendingMachineText7:
+ text_far _VendingMachineText7
+ text_end
+
+LoadVendingMachineItem:
+ ld hl, VendingPrices
+ ld a, [wCurrentMenuItem]
+ add a
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ldh [hVendingMachineItem], a
+ ld a, [hli]
+ ldh [hVendingMachinePrice], a
+ ld a, [hli]
+ ldh [hVendingMachinePrice + 1], a
+ ld a, [hl]
+ ldh [hVendingMachinePrice + 2], a
+ ret
+
+INCLUDE "data/items/vending_prices.asm"