# Section 03 - Ruins of Alph and Union Cave Source: `../section-03-ruins-of-alph-and-union-cave.txt` Maps covered: `MAP_VIOLET_POKECENTER_1F`, `MAP_ROUTE_36_RUINS_OF_ALPH_GATE`, `MAP_RUINS_OF_ALPH_OUTSIDE`, `MAP_RUINS_OF_ALPH_KABUTO_CHAMBER`, `MAP_RUINS_OF_ALPH_INNER_CHAMBER`, `MAP_RUINS_OF_ALPH_RESEARCH_CENTER`, `MAP_RUINS_OF_ALPH_AERODACTYL_CHAMBER` (Surf-gated), `MAP_ROUTE_32_RUINS_OF_ALPH_GATE`, `MAP_ROUTE_32`, `MAP_ROUTE_32_POKECENTER_1F`, `MAP_UNION_CAVE_1F`, `MAP_UNION_CAVE_B1F`, `MAP_UNION_CAVE_B2F` (Strength/Surf-gated), `MAP_ROUTE_33` Badges / key milestones in this section: - Togepi EGG from Elm's Aide (`EVENT_GOT_TOGEPI_EGG_FROM_ELMS_AIDE`) - this is the real unlock for the section: it flips Route 32's scene off the blocking one. - First Unown puzzle solved (`EVENT_SOLVED_KABUTO_PUZZLE`, `ENGINE_UNLOCKED_UNOWNS_A_TO_K`) - makes Unown spawnable at all. - UNOWN #DEX mode (`ENGINE_UNOWN_DEX`) from the Research Center. - MIRACLE_SEED, TM05 ROAR, OLD_ROD, POISON_BARB (Friday), TM39 SWIFT. - No badge is earned in this stretch. The section ends walking west out of Route 33 into Azalea Town. --- ## 1. Route order | # | Map constant | asm file | Enter via | Leaves via | Why (walkthrough beat) | |---|---|---|---|---|---| | 1 | `MAP_VIOLET_CITY` | `maps/VioletCity.asm` | leaving Violet Gym (warp 2 at 18,17) | warp 5 at `31, 25` -> `VIOLET_POKECENTER_1F` 1 | Elm phones about "something important at the Pokemon Center" | | 2 | `MAP_VIOLET_POKECENTER_1F` | `maps/VioletPokecenter1F.asm` | warp 1/2 at `3, 7` / `4, 7` | same warps back to `VIOLET_CITY` 5 | take the Togepi EGG from Elm's Aide | | 3 | `MAP_VIOLET_CITY` | `maps/VioletCity.asm` | back out of the Center | **west connection** -> `Route36` (offset 0) | "head west ... until you enter Route 36" | | 4 | `MAP_ROUTE_36` | `maps/Route36.asm` | Violet City west connection | warp 3/4 at `47, 13` / `48, 13` -> `ROUTE_36_RUINS_OF_ALPH_GATE` 1/2 | pass through; the Sudowoodo tree at `35, 9` is a later section | | 5 | `MAP_ROUTE_36_RUINS_OF_ALPH_GATE` | `maps/Route36RuinsOfAlphGate.asm` | warp 1/2 at `4, 0` / `5, 0` | warp 3/4 at `4, 7` / `5, 7` -> `RUINS_OF_ALPH_OUTSIDE` 9 | "the route-changing station" | | 6 | `MAP_RUINS_OF_ALPH_OUTSIDE` | `maps/RuinsOfAlphOutside.asm` | warp 9 at `7, 5` | warp 2 at `14, 7` -> `RUINS_OF_ALPH_KABUTO_CHAMBER` 1 | "enter the first cave on the right" | | 7 | `MAP_RUINS_OF_ALPH_KABUTO_CHAMBER` | `maps/RuinsOfAlphKabutoChamber.asm` | warp 1/2 at `3, 9` / `4, 9` | warp 3/4 at `3, 3` / `4, 3` -> `RUINS_OF_ALPH_INNER_CHAMBER` 4/5 (the floor holes) | solve the Kabuto puzzle, fall through | | 8 | `MAP_RUINS_OF_ALPH_INNER_CHAMBER` | `maps/RuinsOfAlphInnerChamber.asm` | warps 4/5 at `15, 3` / `16, 3` | warp 1 at `10, 13` -> `RUINS_OF_ALPH_OUTSIDE` 5 | catch Unown; "the lower passageway eventually leads up to a ladder" | | 9 | `MAP_RUINS_OF_ALPH_OUTSIDE` | `maps/RuinsOfAlphOutside.asm` | warp 5 at `10, 13` | coord_event at `11, 14` or `10, 15` -> scientist cutscene -> warp 6 at `17, 11` | 3+ Unown letters caught -> assistant walks you to the lab | | 10 | `MAP_RUINS_OF_ALPH_RESEARCH_CENTER` | `maps/RuinsOfAlphResearchCenter.asm` | warp 1/2 at `2, 7` / `3, 7` | same warps -> `RUINS_OF_ALPH_OUTSIDE` 6 | UNOWN #DEX upgrade (`ENGINE_UNOWN_DEX`) | | 11 | `MAP_RUINS_OF_ALPH_OUTSIDE` | `maps/RuinsOfAlphOutside.asm` | warp 6 at `17, 11` | warp 10/11 at `13, 20` / `13, 21` -> `ROUTE_32_RUINS_OF_ALPH_GATE` 1/2 | "go south, and then east ... another route changing house" | | 12 | `MAP_ROUTE_32_RUINS_OF_ALPH_GATE` | `maps/Route32RuinsOfAlphGate.asm` | warp 1/2 at `0, 4` / `0, 5` | warp 3/4 at `9, 4` / `9, 5` -> `ROUTE_32` 2/3 | "Welcome to Route 32" | | 13 | `MAP_ROUTE_32` | `maps/Route32.asm` | warp 2/3 at `4, 2` / `4, 3` | warp 4 at `6, 79` -> `UNION_CAVE_1F` 4 | the whole trainer gauntlet; detours north into Violet City (connection) for the PRZCureBerry tree and to warp 1 at `11, 73` for the Pokemon Center | | 14 | `MAP_ROUTE_32_POKECENTER_1F` | `maps/Route32Pokecenter1F.asm` | warp 1/2 at `3, 7` / `4, 7` | same warps -> `ROUTE_32` 1 | heal; Fishing Guru hands over the OLD_ROD | | 15 | `MAP_UNION_CAVE_1F` | `maps/UnionCave1F.asm` | warp 4 at `17, 3` | warp 1 at `5, 19` -> `UNION_CAVE_B1F` 3 | "go up and down the ladder" | | 16 | `MAP_UNION_CAVE_B1F` | `maps/UnionCaveB1F.asm` | warp 3 at `7, 19` | warp 4 at `3, 33` -> `UNION_CAVE_1F` 2 | TM39 SWIFT at `2, 16`, X DEFEND at `17, 23` | | 17 | `MAP_UNION_CAVE_1F` | `maps/UnionCave1F.asm` | warp 2 at `3, 33` | warp 3 at `17, 31` -> `ROUTE_33` 1 | Awakening at `12, 33`, Firebreather Ray at `16, 31`, out the east door | | 18 | `MAP_ROUTE_33` | `maps/Route33.asm` | warp 1 at `11, 9` | **west connection** -> `AzaleaTown` (offset 0) | PSNCureBerry tree, Hiker Anthony, then into Azalea Town | Deferred re-visits the walkthrough flags but does not do yet: - `RUINS_OF_ALPH_AERODACTYL_CHAMBER` (outside warp 4 at `16, 33`) needs Surf across the outside water. - `UNION_CAVE_B2F` (B1F warp 5 at `17, 31`) needs the Strength boulder at B1F `7, 10` and gives the Friday-only Lapras. - `UNION_CAVE_B1F` warps 1/2 at `3, 3` / `3, 11` lead back out to `RUINS_OF_ALPH_OUTSIDE` warps 7/8 (`6, 19`, `6, 27`) - "the entrance to more of the Ruins of Alph" the walkthrough mentions. Spill into the next section: Route 33's west connection lands in Azalea Town; stop there. --- ## 2. Maps ### MAP_VIOLET_POKECENTER_1F Only the EGG beat is in scope here; Violet City itself belongs to section 02. - Script: `maps/VioletPokecenter1F.asm` - Header: `data/maps/maps.asm:256` -> `TILESET_POKECENTER, INDOOR, LANDMARK_VIOLET_CITY, MUSIC_POKEMON_CENTER, FALSE, PALETTE_DAY, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm` group `VIOLET` (10), id 6, `5, 4` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 3 | 7 | `VIOLET_CITY` | 5 | | 2 | 4 | 7 | `VIOLET_CITY` | 5 | | 3 | 0 | 7 | `POKECENTER_2F` | 1 | **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `VIOLETPOKECENTER1F_NURSE` | `SPRITE_NURSE` | 3 | 1 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `VioletPokecenterNurse` | -1 | | `VIOLETPOKECENTER1F_SUPER_NERD` | `SPRITE_SUPER_NERD` | 7 | 6 | `WALK_LEFT_RIGHT` | `OBJECTTYPE_SCRIPT` | `VioletPokecenter1FSuperNerdScript` | -1 | | `VIOLETPOKECENTER1F_GENTLEMAN` | `SPRITE_GENTLEMAN` | 1 | 4 | `SPINRANDOM_SLOW` | `OBJECTTYPE_SCRIPT` | `VioletPokecenter1FGentlemanScript` | -1 | | `VIOLETPOKECENTER1F_YOUNGSTER` | `SPRITE_YOUNGSTER` | 8 | 1 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `VioletPokecenter1FYoungsterScript` | -1 | | `VIOLETPOKECENTER1F_ELMS_AIDE` | `SPRITE_SCIENTIST` | 4 | 3 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `VioletPokecenter1F_ElmsAideScript` | `EVENT_ELMS_AIDE_IN_VIOLET_POKEMON_CENTER` | **Scripts of interest** - `VioletPokecenter1F_ElmsAideScript` - `faceplayer` / `opentext`; if `EVENT_REFUSED_TO_TAKE_EGG_FROM_ELMS_AIDE` it re-asks with a different text. `yesorno`; on yes it reads `VAR_PARTYCOUNT` and bails to `.PartyFull` at `PARTY_LENGTH`, otherwise `giveegg TOGEPI, EGG_LEVEL`, then `setevent EVENT_GOT_TOGEPI_EGG_FROM_ELMS_AIDE`, `clearevent EVENT_ELMS_AIDE_IN_LAB`, `clearevent EVENT_TOGEPI_HATCHED`, and crucially `setmapscene ROUTE_32, SCENE_ROUTE32_OFFER_SLOWPOKETAIL`. It then branches on `VAR_FACING` (`UP` -> walk around the player) and `disappear`s. - The aide only exists because `engine/phone/scripts/elm.asm:84` (`ElmPhoneCallerScript` `.assistant`) does `clearevent EVENT_ELMS_AIDE_IN_VIOLET_POKEMON_CENTER` / `setevent EVENT_ELMS_AIDE_IN_LAB`. That call is armed by `maps/VioletGym.asm:38` `specialphonecall SPECIALCALL_ASSISTANT` after Falkner. `engine/events/std_scripts.asm:468` sets `EVENT_ELMS_AIDE_IN_VIOLET_POKEMON_CENTER` at new game, and a set object event flag means the object is hidden (`Script_appear` clears, `Script_disappear` sets - `engine/overworld/scripting.asm:879-898`). **Flags and events** | constant | defined in | read/written by | meaning for a bot | |---|---|---|---| | `EVENT_ELMS_AIDE_IN_VIOLET_POKEMON_CENTER` | `constants/event_flags.asm:1186` | set by `InitializeEventsScript`, cleared by Elm's `.assistant` phone call | aide object visible only while CLEAR | | `EVENT_REFUSED_TO_TAKE_EGG_FROM_ELMS_AIDE` | `constants/event_flags.asm:53` | `VioletPokecenter1F_ElmsAideScript` | second-ask text | | `EVENT_GOT_TOGEPI_EGG_FROM_ELMS_AIDE` | `constants/event_flags.asm:54` | set here; read by `Route32CooltrainerMScript` | precondition for the Miracle Seed | | `EVENT_TOGEPI_HATCHED` | `constants/event_flags.asm:93` | cleared here | egg-hatch bookkeeping | | `SPECIALCALL_ASSISTANT` | `constants/phone_constants.asm:47` | `maps/VioletGym.asm:38` | the phone call that spawns the aide | --- ### MAP_ROUTE_36_RUINS_OF_ALPH_GATE - Script: `maps/Route36RuinsOfAlphGate.asm` - Header: `data/maps/maps.asm:262` -> `TILESET_GATE, GATE, LANDMARK_ROUTE_36, MUSIC_ROUTE_36, FALSE, PALETTE_DAY, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm` group `VIOLET` (10), id 16, `5, 4` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 4 | 0 | `ROUTE_36` | 3 | | 2 | 5 | 0 | `ROUTE_36` | 4 | | 3 | 4 | 7 | `RUINS_OF_ALPH_OUTSIDE` | 9 | | 4 | 5 | 7 | `RUINS_OF_ALPH_OUTSIDE` | 9 | **BG events**: none. **Coord events**: none. **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `ROUTE36RUINSOFALPHGATE_OFFICER` | `SPRITE_OFFICER` | 0 | 4 | `STANDING_RIGHT` | `OBJECTTYPE_SCRIPT` | `Route36RuinsOfAlphGateOfficerScript` | -1 | | `ROUTE36RUINSOFALPHGATE_GRAMPS` | `SPRITE_GRAMPS` | 7 | 5 | `WANDER` (r 1,2) | `OBJECTTYPE_SCRIPT` | `Route36RuinsOfAlphGateGrampsScript` | -1 | Both are `jumptextfaceplayer` only - no flags, no gate. The gate is walk-through. --- ### MAP_RUINS_OF_ALPH_OUTSIDE - Script: `maps/RuinsOfAlphOutside.asm` - Blocks: `maps/RuinsOfAlphOutside.blk` - Header: `data/maps/maps.asm:100` -> `TILESET_JOHTO, ROUTE, LANDMARK_RUINS_OF_ALPH, MUSIC_UNION_CAVE, FALSE, PALETTE_AUTO, FISHGROUP_POND` - Dimensions: `constants/map_constants.asm:87` group `DUNGEONS` (3), id 22, `map_const RUINS_OF_ALPH_OUTSIDE, 10, 18` (10x18 blocks = 20x36 cells) - Connections: none (`data/maps/attributes.asm` `map_attributes RuinsOfAlphOutside, RUINS_OF_ALPH_OUTSIDE, $05` has no `connection` rows). Every exit is a warp. **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 2 | 17 | `RUINS_OF_ALPH_HO_OH_CHAMBER` | 1 | | 2 | 14 | 7 | `RUINS_OF_ALPH_KABUTO_CHAMBER` | 1 | | 3 | 2 | 29 | `RUINS_OF_ALPH_OMANYTE_CHAMBER` | 1 | | 4 | 16 | 33 | `RUINS_OF_ALPH_AERODACTYL_CHAMBER` | 1 | | 5 | 10 | 13 | `RUINS_OF_ALPH_INNER_CHAMBER` | 1 | | 6 | 17 | 11 | `RUINS_OF_ALPH_RESEARCH_CENTER` | 1 | | 7 | 6 | 19 | `UNION_CAVE_B1F` | 1 | | 8 | 6 | 27 | `UNION_CAVE_B1F` | 2 | | 9 | 7 | 5 | `ROUTE_36_RUINS_OF_ALPH_GATE` | 3 | | 10 | 13 | 20 | `ROUTE_32_RUINS_OF_ALPH_GATE` | 1 | | 11 | 13 | 21 | `ROUTE_32_RUINS_OF_ALPH_GATE` | 2 | **Coord events** (`def_coord_events`) | scene | x | y | script label | effect | |---|---|---|---|---| | `SCENE_RUINSOFALPHOUTSIDE_GET_UNOWN_DEX` (1) | 11 | 14 | `RuinsOfAlphOutsideScientistScene1` | scientist turns UP, player DOWN, then the shared cutscene | | `SCENE_RUINSOFALPHOUTSIDE_GET_UNOWN_DEX` (1) | 10 | 15 | `RuinsOfAlphOutsideScientistScene2` | scientist turns LEFT, player RIGHT, then the shared cutscene | Scene ids are declared inline by `scene_script` (see `macros/scripts/maps.asm:12-33`): `SCENE_RUINSOFALPHOUTSIDE_NOOP` = 0, `SCENE_RUINSOFALPHOUTSIDE_GET_UNOWN_DEX` = 1. **BG events** (`def_bg_events`) | x | y | type | script/item | |---|---|---|---| | 16 | 8 | `BGEVENT_READ` | `RuinsOfAlphOutsideMysteryChamberSign` | | 12 | 16 | `BGEVENT_READ` | `RuinsOfAlphSign` | | 18 | 12 | `BGEVENT_READ` | `RuinsOfAlphResearchCenterSign` | **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `RUINSOFALPHOUTSIDE_YOUNGSTER1` | `SPRITE_YOUNGSTER` | 4 | 20 | `STANDING_DOWN` | `OBJECTTYPE_TRAINER` (sight 1) | `TrainerPsychicNathan` | -1 | | `RUINSOFALPHOUTSIDE_SCIENTIST` | `SPRITE_SCIENTIST` | 11 | 15 | `STANDING_UP` | `OBJECTTYPE_SCRIPT` | `RuinsOfAlphOutsideScientistScript` | `EVENT_RUINS_OF_ALPH_OUTSIDE_SCIENTIST` | Note: the `object_const_def` block declares five consts (`YOUNGSTER1`, `SCIENTIST`, `FISHER`, `YOUNGSTER2`, `YOUNGSTER3`) but only two `object_event` rows exist. The last three consts are dead in Gold. **Scripts of interest** - `RuinsOfAlphOutsideScientistCallback` (`callback MAPCALLBACK_OBJECTS`) - the whole gate for the #DEX upgrade: `checkflag ENGINE_UNOWN_DEX` -> if true, `.NoScientist`; `checkevent EVENT_MADE_UNOWN_APPEAR_IN_RUINS` -> if false, `.NoScientist`; otherwise `readvar VAR_UNOWNCOUNT` / `ifgreater 2, .YesScientist`. `.YesScientist` does `appear RUINSOFALPHOUTSIDE_SCIENTIST` + `setscene SCENE_RUINSOFALPHOUTSIDE_GET_UNOWN_DEX`; `.NoScientist` does `disappear` + `setscene SCENE_RUINSOFALPHOUTSIDE_NOOP`. **"At least three different Unown" in the walkthrough is exactly `ifgreater 2`.** - `RuinsOfAlphOutsideScientistSceneContinue` - text, `playmusic MUSIC_SHOW_ME_AROUND`, `follow RUINSOFALPHOUTSIDE_SCIENTIST, PLAYER`, `applymovement` along `RuinsOfAlphOutsideScientistWalkToLabMovement` (`RIGHT RIGHT RIGHT RIGHT UP UP RIGHT RIGHT UP UP`), `disappear`, `stopfollow`, `applymovement PLAYER, RuinsOfAlphOutsidePlayerEnterLabMovement` (`UP`), `setmapscene RUINS_OF_ALPH_RESEARCH_CENTER, SCENE_RUINSOFALPHRESEARCHCENTER_GET_UNOWN_DEX`, `warpcheck`. The player is walked into warp 6 by the script; a bot does not need to drive that step itself. **Flags and events** | constant | defined in | read/written by | meaning for a bot | |---|---|---|---| | `EVENT_RUINS_OF_ALPH_OUTSIDE_SCIENTIST` | `constants/event_flags.asm:1189` | set by `InitializeEventsScript` (`engine/events/std_scripts.asm:470`), toggled by the map callback | scientist hidden while SET | | `EVENT_MADE_UNOWN_APPEAR_IN_RUINS` | `constants/event_flags.asm:55` | set by `RuinsOfAlphInnerChamberStrangePresenceScript` | precondition for the scientist | | `ENGINE_UNOWN_DEX` | `constants/engine_flags.asm:21` | set by `RuinsOfAlphResearchCenterGetUnownDexScript` | once set the scientist never reappears | | `VAR_UNOWNCOUNT` | `constants/script_constants.asm:62` (`0e`) | read here and in the Research Center | distinct Unown forms recorded | | `SCENE_RUINSOFALPHOUTSIDE_*` | inline `scene_script` rows | callback / coord events | 0 = noop, 1 = run the scientist scene | **Wild encounters** `data/wild/johto_grass.asm:388` `def_grass_wildmons RUINS_OF_ALPH_OUTSIDE`, rate `4 percent` for all three windows; morn/day/nite are identical: `20 NATU, 22 NATU, 18 NATU, 24 NATU, 20 SMEARGLE, 22 SMEARGLE, 22 SMEARGLE`. `data/wild/johto_water.asm:5` `def_water_wildmons RUINS_OF_ALPH_OUTSIDE`, rate `2 percent`: `15 WOOPER, 20 QUAGSIRE, 15 QUAGSIRE`. This is the Wooper the walkthrough points at, and it needs Surf. Fishing group is `FISHGROUP_POND` (`data/wild/fish.asm:15` -> `.Pond_Old`: `MAGIKARP 10, MAGIKARP 10, POLIWAG 10`). **Trainers** | const | class | id | party (`data/trainers/parties.asm`) | script label | rematch/phone | |---|---|---|---|---|---| | `NATHAN` | `PSYCHIC_T` | 1 | `PsychicGroup` `; PSYCHIC_T (1)` (line 2512): `26 GIRAFARIG` | `TrainerPsychicNathan` (`EVENT_BEAT_PSYCHIC_NATHAN`) | none | Level 26 at this point in the game - the walkthrough silently skips him, and a bot routed through `4, 20` will get pulled into a very lopsided fight. Sight range is 1. `TrainerSuperNerdEricUnused` is present in the file but marked `; unreferenced`. --- ### MAP_RUINS_OF_ALPH_KABUTO_CHAMBER - Script: `maps/RuinsOfAlphKabutoChamber.asm` - Blocks: `maps/RuinsOfAlphPuzzleChamber.blk` (shared by all four chambers) - Header: `data/maps/maps.asm:102` -> `TILESET_RUINS_OF_ALPH, DUNGEON, LANDMARK_RUINS_OF_ALPH, MUSIC_UNION_CAVE, TRUE, PALETTE_DAY, FISHGROUP_SHORE` (phone service flag TRUE = phone calls suppressed) - Dimensions: `constants/map_constants.asm:89` group `DUNGEONS` (3), id 24, `4, 5` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 3 | 9 | `RUINS_OF_ALPH_OUTSIDE` | 2 | | 2 | 4 | 9 | `RUINS_OF_ALPH_OUTSIDE` | 2 | | 3 | 3 | 3 | `RUINS_OF_ALPH_INNER_CHAMBER` | 4 | | 4 | 4 | 3 | `RUINS_OF_ALPH_INNER_CHAMBER` | 5 | Warps 3/4 are the holes in the floor; they are only reachable after the puzzle. **Coord events**: none. **BG events** (`def_bg_events`) | x | y | type | script/item | |---|---|---|---| | 2 | 3 | `BGEVENT_READ` | `RuinsOfAlphKabutoChamberAncientReplica` | | 5 | 3 | `BGEVENT_READ` | `RuinsOfAlphKabutoChamberAncientReplica` | | 3 | 2 | `BGEVENT_UP` | `RuinsOfAlphKabutoChamberPuzzle` | | 4 | 2 | `BGEVENT_UP` | `RuinsOfAlphKabutoChamberDescriptionSign` | `BGEVENT_UP` means the player must be standing below the tile and facing UP. The puzzle panel is the LEFT of the two (`3, 2`) - the walkthrough's "go up to the left panel" is literal. **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `RUINSOFALPHKABUTOCHAMBER_RECEPTIONIST` | `SPRITE_RECEPTIONIST` | 5 | 5 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `RuinsOfAlphKabutoChamberReceptionistScript` | `EVENT_RUINS_OF_ALPH_KABUTO_CHAMBER_RECEPTIONIST` | Only ONE NPC is defined here. The walkthrough says "talk to the two people inside"; the asm has a single receptionist. **Scripts of interest** - `RuinsOfAlphKabutoChamberHiddenDoorsCallback` (`callback MAPCALLBACK_TILES`) - `checkevent EVENT_SOLVED_KABUTO_PUZZLE`; if false it patches the floor closed with `changeblock 2, 2, $01` (left floor) and `changeblock 4, 2, $02` (right floor). The `.blk` itself already contains the holes. - `RuinsOfAlphKabutoChamberPuzzle` - `reanchormap`, `setval UNOWNPUZZLE_KABUTO`, `special UnownPuzzle`, `closetext`, `iftrue .PuzzleComplete`. `.PuzzleComplete` runs, in order: `setevent EVENT_RUINS_OF_ALPH_INNER_CHAMBER_TOURISTS` (this HIDES the three tourists - a set object flag means hidden), `setevent EVENT_SOLVED_KABUTO_PUZZLE`, `setflag ENGINE_UNLOCKED_UNOWNS_A_TO_K`, `setevent EVENT_RUINS_OF_ALPH_KABUTO_CHAMBER_RECEPTIONIST` (hides the receptionist), `setmapscene RUINS_OF_ALPH_INNER_CHAMBER, SCENE_RUINSOFALPHINNERCHAMBER_STRANGE_PRESENCE`, `earthquake 30`, `showemote EMOTE_SHOCK, PLAYER, 15`, `changeblock 2, 2, $18` / `changeblock 4, 2, $19` (the holes), `refreshmap`, `playsound SFX_STRENGTH`, `earthquake 80`, `warpcheck`. `warpcheck` is what drops the player through - no manual walk needed. **Flags and events** | constant | defined in | read/written by | meaning for a bot | |---|---|---|---| | `EVENT_SOLVED_KABUTO_PUZZLE` | `constants/event_flags.asm:334` | this script / the tiles callback | floor stays open once set | | `ENGINE_UNLOCKED_UNOWNS_A_TO_K` | `constants/engine_flags.asm:56` | this script; read by `CheckUnownLetter` (`engine/battle/core.asm:6219`) and `ChooseWildEncounter` (`engine/overworld/wildmons.asm:341`) | letters A-K become catchable (`data/wild/unlocked_unowns.asm` `.Set_A_K`) | | `EVENT_RUINS_OF_ALPH_KABUTO_CHAMBER_RECEPTIONIST` | `constants/event_flags.asm:1264` | this script | receptionist hidden once SET | | `EVENT_RUINS_OF_ALPH_INNER_CHAMBER_TOURISTS` | `constants/event_flags.asm:1191` | this script | the three Inner Chamber NPCs hidden once SET | Sibling puzzles, for completeness (same shape, different flags): | chamber | asm | puzzle const | sets | unlocks | |---|---|---|---|---| | Ho-Oh | `maps/RuinsOfAlphHoOhChamber.asm` | `UNOWNPUZZLE_HO_OH` | `EVENT_SOLVED_HO_OH_PUZZLE` | `ENGINE_UNLOCKED_UNOWNS_X_TO_Z` | | Omanyte | `maps/RuinsOfAlphOmanyteChamber.asm` | `UNOWNPUZZLE_OMANYTE` | `EVENT_SOLVED_OMANYTE_PUZZLE` | `ENGINE_UNLOCKED_UNOWNS_L_TO_R` | | Aerodactyl | `maps/RuinsOfAlphAerodactylChamber.asm` | `UNOWNPUZZLE_AERODACTYL` | `EVENT_SOLVED_AERODACTYL_PUZZLE` (`constants/event_flags.asm:336`) | `ENGINE_UNLOCKED_UNOWNS_S_TO_W` | --- ### MAP_RUINS_OF_ALPH_AERODACTYL_CHAMBER The Surf-gated puzzle the walkthrough defers. Included because it is the one place the section names a field-move requirement. - Script: `maps/RuinsOfAlphAerodactylChamber.asm` - Header: `data/maps/maps.asm:104` -> `TILESET_RUINS_OF_ALPH, DUNGEON, LANDMARK_RUINS_OF_ALPH, MUSIC_UNION_CAVE, TRUE, PALETTE_DAY, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm:91` group `DUNGEONS` (3), id 26, `4, 5` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 3 | 9 | `RUINS_OF_ALPH_OUTSIDE` | 4 | | 2 | 4 | 9 | `RUINS_OF_ALPH_OUTSIDE` | 4 | | 3 | 3 | 3 | `RUINS_OF_ALPH_INNER_CHAMBER` | 8 | | 4 | 4 | 3 | `RUINS_OF_ALPH_INNER_CHAMBER` | 9 | **BG events** (`def_bg_events`) | x | y | type | script/item | |---|---|---|---| | 2 | 3 | `BGEVENT_READ` | `RuinsOfAlphAerodactylChamberAncientReplica` | | 5 | 3 | `BGEVENT_READ` | `RuinsOfAlphAerodactylChamberAncientReplica` | | 3 | 2 | `BGEVENT_UP` | `RuinsOfAlphAerodactylChamberPuzzle` | | 4 | 2 | `BGEVENT_UP` | `RuinsOfAlphAerodactylChamberDescriptionSign` | **Object events**: `def_object_events` is empty. No receptionist here. --- ### MAP_RUINS_OF_ALPH_INNER_CHAMBER - Script: `maps/RuinsOfAlphInnerChamber.asm` - Blocks: `maps/RuinsOfAlphInnerChamber.blk` - Header: `data/maps/maps.asm:105` -> `TILESET_RUINS_OF_ALPH, DUNGEON, LANDMARK_RUINS_OF_ALPH, MUSIC_RUINS_OF_ALPH_INTERIOR, TRUE, PALETTE_DAY, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm:92` group `DUNGEONS` (3), id 27, `10, 14` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 10 | 13 | `RUINS_OF_ALPH_OUTSIDE` | 5 | | 2 | 3 | 15 | `RUINS_OF_ALPH_HO_OH_CHAMBER` | 3 | | 3 | 4 | 15 | `RUINS_OF_ALPH_HO_OH_CHAMBER` | 4 | | 4 | 15 | 3 | `RUINS_OF_ALPH_KABUTO_CHAMBER` | 3 | | 5 | 16 | 3 | `RUINS_OF_ALPH_KABUTO_CHAMBER` | 4 | | 6 | 3 | 21 | `RUINS_OF_ALPH_OMANYTE_CHAMBER` | 3 | | 7 | 4 | 21 | `RUINS_OF_ALPH_OMANYTE_CHAMBER` | 4 | | 8 | 15 | 24 | `RUINS_OF_ALPH_AERODACTYL_CHAMBER` | 3 | | 9 | 16 | 24 | `RUINS_OF_ALPH_AERODACTYL_CHAMBER` | 4 | Falling through the Kabuto holes lands you at `15, 3` / `16, 3`; the ladder out is warp 1 at `10, 13`. **Coord events**: none. The "strange presence" fires from the scene script, not a coord event. **BG events** (`def_bg_events`) - 26 identical `BGEVENT_READ, RuinsOfAlphInnerChamberStatue` rows at: `(2,3) (5,3) (8,3) (11,3) (14,3) (17,3) (2,8) (5,8) (8,8) (11,8) (14,8) (17,8) (2,13) (17,13) (2,18) (5,18) (8,18) (11,18) (14,18) (17,18) (2,24) (5,24) (8,24) (11,24) (14,24) (17,24)`. All flavour text; none are items. **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `RUINSOFALPHINNERCHAMBER_FISHER` | `SPRITE_FISHER` | 3 | 7 | `SPINRANDOM_SLOW` | `OBJECTTYPE_SCRIPT` | `RuinsOfAlphInnerChamberFisherScript` | `EVENT_RUINS_OF_ALPH_INNER_CHAMBER_TOURISTS` | | `RUINSOFALPHINNERCHAMBER_TEACHER` | `SPRITE_TEACHER` | 14 | 13 | `WANDER` (r 1,1) | `OBJECTTYPE_SCRIPT` | `RuinsOfAlphInnerChamberTeacherScript` | `EVENT_RUINS_OF_ALPH_INNER_CHAMBER_TOURISTS` | | `RUINSOFALPHINNERCHAMBER_GRAMPS` | `SPRITE_GRAMPS` | 11 | 19 | `STANDING_UP` | `OBJECTTYPE_SCRIPT` | `RuinsOfAlphInnerChamberGrampsScript` | `EVENT_RUINS_OF_ALPH_INNER_CHAMBER_TOURISTS` | All three share one flag, so they are all present before any puzzle is solved and all vanish the moment one is. **Scripts of interest** - `RuinsOfAlphInnerChamberStrangePresenceScene` - `sdefer RuinsOfAlphInnerChamberStrangePresenceScript`. The deferred script prints "There is a strange presence here...", then `setscene SCENE_RUINSOFALPHINNERCHAMBER_NOOP` and `setevent EVENT_MADE_UNOWN_APPEAR_IN_RUINS`. Scene ids: `NOOP` = 0, `STRANGE_PRESENCE` = 1. **Wild encounters** `data/wild/johto_grass.asm:416` `def_grass_wildmons RUINS_OF_ALPH_INNER_CHAMBER`, rate `6 percent` all windows, all 21 slots `db 5, UNOWN`. The level is always 5, identical morn/day/nite. Two gates sit on top of that table: - `ChooseWildEncounter` (`engine/overworld/wildmons.asm:337-347`): after the species is picked, `cp UNOWN` / `ld a, [wUnlockedUnowns]` / `and a` / `jr z, .nowildbattle` - with no puzzle solved, `wUnlockedUnowns` is 0 and Unown encounters are silently cancelled, so the Inner Chamber has zero encounters before a puzzle. - `CheckUnownLetter` (`engine/battle/core.asm:6219`) re-rolls the form against `UnlockedUnownLetterSets` (`data/wild/unlocked_unowns.asm`), so with only the Kabuto puzzle solved you can only ever meet A-K (11 letters), which is more than the 3 the scientist needs. `NUM_UNOWN EQU 26` (`constants/pokemon_constants.asm:308`) - see "Unresolved" for the walkthrough's "28 forms" claim. --- ### MAP_RUINS_OF_ALPH_RESEARCH_CENTER - Script: `maps/RuinsOfAlphResearchCenter.asm` - Blocks: `maps/RuinsOfAlphResearchCenter.blk` - Header: `data/maps/maps.asm:106` -> `TILESET_FACILITY, INDOOR, LANDMARK_RUINS_OF_ALPH, MUSIC_UNION_CAVE, FALSE, PALETTE_DAY, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm:93` group `DUNGEONS` (3), id 28, `4, 4` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 2 | 7 | `RUINS_OF_ALPH_OUTSIDE` | 6 | | 2 | 3 | 7 | `RUINS_OF_ALPH_OUTSIDE` | 6 | **Coord events**: none (the cutscene is a `scene_script` + `sdefer`). **BG events** (`def_bg_events`) | x | y | type | script/item | |---|---|---|---| | 6 | 5 | `BGEVENT_READ` | `RuinsOfAlphResearchCenterBookshelf` | | 3 | 4 | `BGEVENT_READ` | `RuinsOfAlphResearchCenterComputer` | | 7 | 1 | `BGEVENT_READ` | `RuinsOfAlphResearchCenterPrinter` | **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `RUINSOFALPHRESEARCHCENTER_SCIENTIST1` | `SPRITE_SCIENTIST` | 4 | 5 | `STANDING_UP` | `OBJECTTYPE_SCRIPT` | `RuinsOfAlphResearchCenterScientist1Script` | -1 | | `RUINSOFALPHRESEARCHCENTER_SCIENTIST2` | `SPRITE_SCIENTIST` | 5 | 2 | `WANDER` (r 2,1) | `OBJECTTYPE_SCRIPT` | `RuinsOfAlphResearchCenterScientist2Script` | -1 | | `RUINSOFALPHRESEARCHCENTER_SCIENTIST3` | `SPRITE_SCIENTIST` | 2 | 5 | `STANDING_UP` | `OBJECTTYPE_SCRIPT` | `RuinsOfAlphResearchCenterScientist3Script` | `EVENT_RUINS_OF_ALPH_RESEARCH_CENTER_SCIENTIST` | **Scripts of interest** - `RuinsOfAlphResearchCenterScientistCallback` (`callback MAPCALLBACK_OBJECTS`) - `checkscene` / `ifequal SCENE_RUINSOFALPHRESEARCHCENTER_GET_UNOWN_DEX, .ShowScientist`; `.ShowScientist` does `moveobject RUINSOFALPHRESEARCHCENTER_SCIENTIST3, 3, 7` (onto the doorway) and `appear`. So scientist 3 is teleported onto the entrance tile for the cutscene, not spawned at his listed `2, 5`. - `RuinsOfAlphResearchCenterGetUnownDexScript` (`sdefer` from the scene) - `applymovement` to the computer (`UP UP LEFT`, `turn_head UP`), a run of `playsound`/`pause` beats, text, then `setflag ENGINE_UNOWN_DEX`, more text, `applymovement` away, `setscene SCENE_RUINSOFALPHRESEARCHCENTER_NOOP`, `special RestartMapMusic`. **No item is added to the bag** - the "Unown Pokedex" the walkthrough lists is an engine flag, not an inventory item. - `RuinsOfAlphResearchCenterPrinter` / `...Computer` / `...Scientist3Script` - all gate their good branch on `readvar VAR_UNOWNCOUNT` / `ifequal NUM_UNOWN`, i.e. all 26 forms. `EVENT_RUINS_OF_ALPH_RESEARCH_CENTER_SCIENTIST` short-circuits the check (`.SkipChecking`) while scientist 3 is still hidden. - `RuinsOfAlphResearchCenterScientist1Script` / `...Scientist2Script` - pure text, branching on `ENGINE_UNOWN_DEX` and `EVENT_MADE_UNOWN_APPEAR_IN_RUINS`. **Flags and events** | constant | defined in | read/written by | meaning for a bot | |---|---|---|---| | `ENGINE_UNOWN_DEX` | `constants/engine_flags.asm:21` | set here; read by the outside callback and the Pokedex | the section's "Unown Pokedex" reward | | `EVENT_RUINS_OF_ALPH_RESEARCH_CENTER_SCIENTIST` | `constants/event_flags.asm:1190` | set by `InitializeEventsScript` (`engine/events/std_scripts.asm:471`), cleared by `appear` in the callback | scientist 3 hidden while SET | | `SCENE_RUINSOFALPHRESEARCHCENTER_GET_UNOWN_DEX` | inline `scene_script` (= 1) | set remotely by `RuinsOfAlphOutsideScientistSceneContinue` | arms the cutscene on entry | --- ### MAP_ROUTE_32_RUINS_OF_ALPH_GATE - Script: `maps/Route32RuinsOfAlphGate.asm` - Header: `data/maps/maps.asm:258` -> `TILESET_GATE, GATE, LANDMARK_ROUTE_32, MUSIC_ROUTE_30, FALSE, PALETTE_DAY, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm:237` group `VIOLET` (10), id 12, `5, 4` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 0 | 4 | `RUINS_OF_ALPH_OUTSIDE` | 10 | | 2 | 0 | 5 | `RUINS_OF_ALPH_OUTSIDE` | 11 | | 3 | 9 | 4 | `ROUTE_32` | 2 | | 4 | 9 | 5 | `ROUTE_32` | 3 | **Coord events / BG events**: none. **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `ROUTE32RUINSOFALPHGATE_OFFICER` | `SPRITE_OFFICER` | 5 | 2 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `Route32RuinsOfAlphGateOfficerScript` | -1 | | `ROUTE32RUINSOFALPHGATE_POKEFAN_M` | `SPRITE_POKEFAN_M` | 8 | 2 | `WALK_UP_DOWN` (r 0,1) | `OBJECTTYPE_SCRIPT` | `Route32RuinsOfAlphGatePokefanMScript` | -1 | | `ROUTE32RUINSOFALPHGATE_YOUNGSTER` | `SPRITE_YOUNGSTER` | 1 | 6 | `STANDING_UP` | `OBJECTTYPE_SCRIPT` | `Route32RuinsOfAlphGateYoungsterScript` | -1 | All `jumptextfaceplayer`. No gate. --- ### MAP_ROUTE_32 - Script: `maps/Route32.asm` - Blocks: `maps/Route32.blk` - Header: `data/maps/maps.asm:247` -> `TILESET_JOHTO, ROUTE, LANDMARK_ROUTE_32, MUSIC_ROUTE_30, FALSE, PALETTE_AUTO, FISHGROUP_QWILFISH` - Dimensions: `constants/map_constants.asm:226` group `VIOLET` (10), id 1, `map_const ROUTE_32, 10, 45` (10x45 blocks = 20x90 cells - by far the longest map in this section) - Connections (`data/maps/attributes.asm`): `connection north, VioletCity, VIOLET_CITY, 0` and `connection south, Route33, ROUTE_33, 0` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 11 | 73 | `ROUTE_32_POKECENTER_1F` | 1 | | 2 | 4 | 2 | `ROUTE_32_RUINS_OF_ALPH_GATE` | 3 | | 3 | 4 | 3 | `ROUTE_32_RUINS_OF_ALPH_GATE` | 4 | | 4 | 6 | 79 | `UNION_CAVE_1F` | 4 | **Coord events** (`def_coord_events`) | scene | x | y | script label | effect | |---|---|---|---|---| | `SCENE_ROUTE32_COOLTRAINER_M_BLOCKS` (0) | 18 | 8 | `Route32CooltrainerMStopsYouScene` | turns both parties, text, `follow PLAYER, ROUTE32_COOLTRAINER_M`, `applymovement PLAYER, Movement_Route32CooltrainerMPushesYouBackToViolet` (`UP UP`), `stopfollow`, `turnobject PLAYER, DOWN`, `scall Route32CooltrainerMContinueScene`, then resets him with `DOWN` then `RIGHT` | | `SCENE_ROUTE32_OFFER_SLOWPOKETAIL` (1) | 7 | 71 | `Route32WannaBuyASlowpokeTailScript` | `turnobject ROUTE32_FISHER4, DOWN` / `turnobject PLAYER, UP` then falls into `_OfferToSellSlowpokeTail` | Scene ids from the inline `scene_script` rows: `SCENE_ROUTE32_COOLTRAINER_M_BLOCKS` = 0 (the default, since scene bytes start at 0), `SCENE_ROUTE32_OFFER_SLOWPOKETAIL` = 1, `SCENE_ROUTE32_NOOP` = 2. **BG events** (`def_bg_events`) | x | y | type | script/item | |---|---|---|---| | 13 | 5 | `BGEVENT_READ` | `Route32Sign` | | 9 | 1 | `BGEVENT_READ` | `Route32RuinsSign` | | 10 | 84 | `BGEVENT_READ` | `Route32UnionCaveSign` | | 12 | 73 | `BGEVENT_READ` | `Route32PokecenterSign` (`jumpstd PokecenterSignScript`) | | 12 | 67 | `BGEVENT_ITEM` | `Route32HiddenGreatBall` -> `hiddenitem GREAT_BALL, EVENT_ROUTE_32_HIDDEN_GREAT_BALL` | | 11 | 40 | `BGEVENT_ITEM` | `Route32HiddenSuperPotion` -> `hiddenitem SUPER_POTION, EVENT_ROUTE_32_HIDDEN_SUPER_POTION` | **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `ROUTE32_FISHER1` | `SPRITE_FISHER` | 8 | 49 | `STANDING_DOWN` | `OBJECTTYPE_TRAINER` (sight 1) | `TrainerFisherJustin` | -1 | | `ROUTE32_FISHER2` | `SPRITE_FISHER` | 12 | 56 | `STANDING_UP` | `OBJECTTYPE_TRAINER` (sight 3) | `TrainerFisherRalph1` | -1 | | `ROUTE32_FISHER3` | `SPRITE_FISHER` | 6 | 48 | `STANDING_LEFT` | `OBJECTTYPE_TRAINER` (sight 1) | `TrainerFisherHenry` | -1 | | `ROUTE32_YOUNGSTER1` | `SPRITE_YOUNGSTER` | 13 | 23 | `STANDING_UP` | `OBJECTTYPE_TRAINER` (sight 3) | `TrainerYoungsterAlbert` | -1 | | `ROUTE32_YOUNGSTER2` | `SPRITE_YOUNGSTER` | 4 | 65 | `SPINCLOCKWISE` | `OBJECTTYPE_TRAINER` (sight 3) | `TrainerYoungsterGordon` | -1 | | `ROUTE32_YOUNGSTER3` | `SPRITE_YOUNGSTER` | 1 | 56 | `STANDING_UP` | `OBJECTTYPE_TRAINER` (sight 4) | `TrainerCamperRoland` | -1 | | `ROUTE32_LASS1` | `SPRITE_LASS` | 10 | 30 | `STANDING_LEFT` | `OBJECTTYPE_TRAINER` (sight 1) | `TrainerPicnickerLiz1` | -1 | | `ROUTE32_COOLTRAINER_M` | `SPRITE_COOLTRAINER_M` | 19 | 8 | `STANDING_LEFT` | `OBJECTTYPE_SCRIPT` | `Route32CooltrainerMScript` | -1 | | `ROUTE32_YOUNGSTER4` | `SPRITE_YOUNGSTER` | 11 | 82 | `STANDING_UP` | `OBJECTTYPE_TRAINER` (sight 3) | `TrainerBirdKeeperPeter` | -1 | | `ROUTE32_FISHER4` | `SPRITE_FISHER` | 7 | 70 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `SlowpokeTailSalesmanScript` | `EVENT_SLOWPOKE_WELL_ROCKETS` | | `ROUTE32_POKE_BALL1` | `SPRITE_POKE_BALL` | 6 | 53 | `STILL` | `OBJECTTYPE_ITEMBALL` | `Route32GreatBall` (`itemball GREAT_BALL`) | `EVENT_ROUTE_32_GREAT_BALL` | | `ROUTE32_FISHER5` | `SPRITE_FISHER` | 15 | 13 | `STANDING_RIGHT` | `OBJECTTYPE_SCRIPT` | `Route32RoarTMGuyScript` | -1 | | `ROUTE32_FRIEDA` | `SPRITE_LASS` | 12 | 67 | `STANDING_LEFT` | `OBJECTTYPE_SCRIPT` | `FriedaScript` | `EVENT_ROUTE_32_FRIEDA_OF_FRIDAY` | | `ROUTE32_POKE_BALL2` | `SPRITE_POKE_BALL` | 3 | 30 | `STILL` | `OBJECTTYPE_ITEMBALL` | `Route32Potion` (`itemball POTION`) | `EVENT_ROUTE_32_POTION` | **Scripts of interest** - `Route32FriedaCallback` (`callback MAPCALLBACK_OBJECTS`) - `readvar VAR_WEEKDAY` / `ifequal FRIDAY, .FriedaAppears`; otherwise `disappear ROUTE32_FRIEDA`. She is a hard weekday gate, and she stands on the same cell (`12, 67`) as the hidden Great Ball. - `FriedaScript` - if `EVENT_GOT_POISON_BARB_FROM_FRIEDA` -> Friday chat; else `readvar VAR_WEEKDAY` / `ifnotequal FRIDAY, .NotFriday`; else `setevent EVENT_MET_FRIEDA_OF_FRIDAY`, `verbosegiveitem POISON_BARB`, `iffalse .Done` (bag full), `setevent EVENT_GOT_POISON_BARB_FROM_FRIEDA`. - `Route32CooltrainerMScript` / `Route32CooltrainerMContinueScene` - the Miracle Seed decision tree, in asm order: `checkevent EVENT_GOT_MIRACLE_SEED_IN_ROUTE_32` -> `.GotMiracleSeed` (thanks text); `checkflag ENGINE_ZEPHYRBADGE` -> if false `.DontHaveZephyrBadge` ("have you gone to the GYM"); `checkevent EVENT_GOT_TOGEPI_EGG_FROM_ELMS_AIDE` -> if true `.GiveMiracleSeed`, else "the aide is waiting at the #MON CENTER". `.GiveMiracleSeed` -> `verbosegiveitem MIRACLE_SEED`, `iffalse .BagFull`, `setevent EVENT_GOT_MIRACLE_SEED_IN_ROUTE_32`. So the Miracle Seed needs BOTH `ENGINE_ZEPHYRBADGE` and the Togepi egg. - `Route32RoarTMGuyScript` - `checkevent EVENT_GOT_TM05_ROAR`, `verbosegiveitem TM_ROAR`, `setevent EVENT_GOT_TM05_ROAR`. Unconditional otherwise. - `SlowpokeTailSalesmanScript` / `_OfferToSellSlowpokeTail` - first thing it does is `setscene SCENE_ROUTE32_NOOP`, so the `7, 71` trip-wire fires exactly once. `yesorno`: "yes" gives the mocking `Text_ThoughtKidsWereLoaded`, nothing is bought or given either way. There is no purchase path in the asm. - `TrainerFisherRalph1` / `TrainerPicnickerLiz1` - both are phone-number trainers. After the battle: `checkevent EVENT_*_READY_FOR_REMATCH` -> `.Rematch`; `checkcellnum PHONE_FISHER_RALPH` / `PHONE_PICNICKER_LIZ` -> already registered; `checkevent EVENT_*_ASKED_FOR_PHONE_NUMBER` -> ask again; otherwise `setevent EVENT_*_ASKED_FOR_PHONE_NUMBER` then `askforphonenumber PHONE_FISHER_RALPH` with `PHONE_CONTACTS_FULL` / `PHONE_CONTACT_REFUSED` branches. **You must talk to them a second time after the battle** to get the number, exactly as the walkthrough says. Rematch parties escalate: Ralph -> `RALPH2` after `ENGINE_FLYPOINT_ECRUTEAK`, `RALPH3` after `ENGINE_FLYPOINT_LAKE_OF_RAGE`; Liz -> `LIZ2` after `ENGINE_FLYPOINT_ECRUTEAK`, `LIZ3` after `EVENT_CLEARED_ROCKET_HIDEOUT`. **Flags and events** | constant | defined in | read/written by | meaning for a bot | |---|---|---|---| | `EVENT_GOT_MIRACLE_SEED_IN_ROUTE_32` | `constants/event_flags.asm:102` | `Route32CooltrainerMScript` | one-time | | `ENGINE_ZEPHYRBADGE` | `constants/engine_flags.asm:38` | read by the same script | Miracle Seed precondition | | `EVENT_GOT_TM05_ROAR` | `constants/event_flags.asm:87` | `Route32RoarTMGuyScript` | one-time | | `EVENT_MET_FRIEDA_OF_FRIDAY` | `constants/event_flags.asm:107` | `FriedaScript` | intro-text-only | | `EVENT_GOT_POISON_BARB_FROM_FRIEDA` | `constants/event_flags.asm:108` | `FriedaScript` | one-time | | `EVENT_ROUTE_32_FRIEDA_OF_FRIDAY` | `constants/event_flags.asm:1274` | `Route32FriedaCallback` | object hidden while SET (non-Friday) | | `EVENT_ROUTE_32_GREAT_BALL` | `constants/event_flags.asm:1105` | itemball at `6, 53` | one-time | | `EVENT_ROUTE_32_POTION` | `constants/event_flags.asm:1106` | itemball at `3, 30` | one-time | | `EVENT_ROUTE_32_HIDDEN_GREAT_BALL` | `constants/event_flags.asm:175` | hidden item at `12, 67` | one-time | | `EVENT_ROUTE_32_HIDDEN_SUPER_POTION` | `constants/event_flags.asm:176` | hidden item at `11, 40` | one-time | | `EVENT_SLOWPOKE_WELL_ROCKETS` | `constants/event_flags.asm:1182` | gates `ROUTE32_FISHER4` | salesman disappears once Slowpoke Well is cleared | | `PHONE_FISHER_RALPH` / `PHONE_PICNICKER_LIZ` | `constants/phone_constants.asm:20-21` | `askforphonenumber` | contact slots 17 / 18 | | `VAR_WEEKDAY` | `constants/script_constants.asm:59` (`0b`) | Frieda callback and script | `FRIDAY` | **Items** | item | how obtained | source (label / bg_event / hidden) | one-time flag | |---|---|---|---| | `MIRACLE_SEED` | talk to `ROUTE32_COOLTRAINER_M` at `19, 8` | `Route32CooltrainerMScript` `.GiveMiracleSeed` | `EVENT_GOT_MIRACLE_SEED_IN_ROUTE_32` | | `TM_ROAR` (TM05) | talk to `ROUTE32_FISHER5` at `15, 13` | `Route32RoarTMGuyScript` | `EVENT_GOT_TM05_ROAR` | | `POISON_BARB` | talk to Frieda at `12, 67` on a Friday | `FriedaScript` | `EVENT_GOT_POISON_BARB_FROM_FRIEDA` | | `GREAT_BALL` | itemball at `6, 53` | `Route32GreatBall` | `EVENT_ROUTE_32_GREAT_BALL` | | `POTION` | itemball at `3, 30` | `Route32Potion` | `EVENT_ROUTE_32_POTION` | | `GREAT_BALL` (hidden) | hidden at `12, 67` | `Route32HiddenGreatBall` | `EVENT_ROUTE_32_HIDDEN_GREAT_BALL` | | `SUPER_POTION` (hidden) | hidden at `11, 40` | `Route32HiddenSuperPotion` | `EVENT_ROUTE_32_HIDDEN_SUPER_POTION` | | `OLD_ROD` | `ROUTE_32_POKECENTER_1F`, see below | `Route32Pokecenter1FFishingGuruScript` | `EVENT_GOT_OLD_ROD` | **Trainers** | const | class | id | party (`data/trainers/parties.asm`) | script label | rematch/phone | |---|---|---|---|---|---| | `ALBERT` | `YOUNGSTER` | 3 | `YoungsterGroup` `; YOUNGSTER (3)` line 351: `6 RATTATA`, `8 ZUBAT` | `TrainerYoungsterAlbert` (`EVENT_BEAT_YOUNGSTER_ALBERT`) | none | | `LIZ1` | `PICNICKER` | 1 | `PicnickerGroup` `; PICNICKER (1)` line 2584: `9 NIDORAN_F` | `TrainerPicnickerLiz1` (`EVENT_BEAT_PICNICKER_LIZ`) | `PHONE_PICNICKER_LIZ`; `LIZ2` `15 WEEPINBELL / 15 NIDORINA`, `LIZ3` `19 WEEPINBELL / 19 NIDORINO / 21 NIDOQUEEN` | | `JUSTIN` | `FISHER` | 1 | `FisherGroup` `; FISHER (1)` line 1498: `5 MAGIKARP`, `5 MAGIKARP`, `15 MAGIKARP`, `5 MAGIKARP` | `TrainerFisherJustin` (`EVENT_BEAT_FISHER_JUSTIN`) | none | | `HENRY` | `FISHER` | 5 | `FisherGroup` `; FISHER (5)` line 1523: `8 POLIWAG`, `8 POLIWAG` | `TrainerFisherHenry` (`EVENT_BEAT_FISHER_HENRY`) | none | | `RALPH1` | `FISHER` | 2 | `FisherGroup` `; FISHER (2)` line 1506: `10 GOLDEEN` | `TrainerFisherRalph1` (`EVENT_BEAT_FISHER_RALPH`) | `PHONE_FISHER_RALPH`; `RALPH2` `17 GOLDEEN`, `RALPH3` `17 QWILFISH / 19 GOLDEEN` | | `ROLAND` | `CAMPER` | 1 | `CamperGroup` `; CAMPER (1)` line 2705: `9 NIDORAN_M` | `TrainerCamperRoland` (`EVENT_BEAT_CAMPER_ROLAND`) | none | | `GORDON` | `YOUNGSTER` | 4 | `YoungsterGroup` `; YOUNGSTER (4)` line 357: `10 WOOPER` | `TrainerYoungsterGordon` (`EVENT_BEAT_YOUNGSTER_GORDON`) | none | | `PETER` | `BIRD_KEEPER` | 13 | `BirdKeeperGroup` `; BIRD_KEEPER (13)` line 598: `6 PIDGEY`, `6 PIDGEY`, `8 SPEAROW` | `TrainerBirdKeeperPeter` (`EVENT_BEAT_BIRD_KEEPER_PETER`) | none | All eight parties are `TRAINERTYPE_NORMAL` (level + species only, no custom moves or held items). **Wild encounters** `data/wild/johto_grass.asm:1711` `def_grass_wildmons ROUTE_32`, rate `10 percent` all windows. **Gold** branch (`IF DEF(_GOLD)`): - morn: `6 BELLSPROUT, 4 RATTATA, 6 MAREEP, 6 HOPPIP, 6 RATTATA, 4 WOOPER, 4 ZUBAT` - day: `6 BELLSPROUT, 4 RATTATA, 6 MAREEP, 6 HOPPIP, 6 RATTATA, 8 RATTATA, 8 RATTATA` - nite: `6 WOOPER, 4 RATTATA, 6 BELLSPROUT, 6 MAREEP, 8 WOOPER, 8 ZUBAT, 8 ZUBAT` Silver swaps the `RATTATA` in slot 2 for `EKANS`. **Wooper is a morn-or-nite mon in Gold** - it does not appear in the day table at all, which is why the walkthrough says "Wooper will be a bit harder to find than Bellsprout". `data/wild/johto_water.asm:142` `def_water_wildmons ROUTE_32`, rate `6 percent`: `15 TENTACOOL, 20 QUAGSIRE, 20 TENTACRUEL` (Surf only). Fishing group `FISHGROUP_QWILFISH` (`data/wild/fish.asm:22`); `.Qwilfish_Old` (line 178) is `MAGIKARP 10, MAGIKARP 10, TENTACOOL 10` - the Old Rod here gives no Qwilfish. --- ### MAP_ROUTE_32_POKECENTER_1F - Script: `maps/Route32Pokecenter1F.asm` - Header: `data/maps/maps.asm:259` -> `TILESET_POKECENTER, INDOOR, LANDMARK_ROUTE_32, MUSIC_POKEMON_CENTER, FALSE, PALETTE_DAY, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm:238` group `VIOLET` (10), id 13, `5, 4` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 3 | 7 | `ROUTE_32` | 1 | | 2 | 4 | 7 | `ROUTE_32` | 1 | | 3 | 0 | 7 | `POKECENTER_2F` | 1 | **Coord events / BG events**: none. **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `ROUTE32POKECENTER1F_NURSE` | `SPRITE_NURSE` | 3 | 1 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `Route32Pokecenter1FNurseScript` (`jumpstd PokecenterNurseScript`) | -1 | | `ROUTE32POKECENTER1F_FISHING_GURU` | `SPRITE_FISHING_GURU` | 1 | 4 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `Route32Pokecenter1FFishingGuruScript` | -1 | | `ROUTE32POKECENTER1F_COOLTRAINER_F` | `SPRITE_COOLTRAINER_F` | 6 | 2 | `STANDING_DOWN` | `OBJECTTYPE_SCRIPT` | `Route32Pokecenter1FCooltrainerFScript` | -1 | **Scripts of interest** - `Route32Pokecenter1FFishingGuruScript` - `checkevent EVENT_GOT_OLD_ROD` -> `.GotOldRod`; else text, `yesorno`, `iffalse .Refused`, then `verbosegiveitem OLD_ROD`, text, `setevent EVENT_GOT_OLD_ROD`. Note: unlike most gift NPCs there is **no `iffalse` bag-full guard after the `verbosegiveitem`** - the flag is set unconditionally on the yes path. Answering "no" is recoverable (`.Refused` sets nothing). **Items** | item | how obtained | source (label / bg_event / hidden) | one-time flag | |---|---|---|---| | `OLD_ROD` | talk to the Fishing Guru at `1, 4`, answer YES | `Route32Pokecenter1FFishingGuruScript` | `EVENT_GOT_OLD_ROD` (`constants/event_flags.asm:31`) | --- ### MAP_UNION_CAVE_1F - Script: `maps/UnionCave1F.asm` - Blocks: `maps/UnionCave1F.blk` - Header: `data/maps/maps.asm:107` -> `TILESET_CAVE, CAVE, LANDMARK_UNION_CAVE, MUSIC_UNION_CAVE, TRUE, PALETTE_NITE, FISHGROUP_LAKE` The palette is `PALETTE_NITE`, not `PALETTE_DARK` - **Union Cave is not a dark cave and never needs FLASH**, despite Firebreather Ray's "if it's light, a cave isn't scary" line. - Dimensions: `constants/map_constants.asm:94` group `DUNGEONS` (3), id 29, `10, 18` - Connections: none (`map_attributes UnionCave1F, UNION_CAVE_1F, $09`) **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 5 | 19 | `UNION_CAVE_B1F` | 3 | | 2 | 3 | 33 | `UNION_CAVE_B1F` | 4 | | 3 | 17 | 31 | `ROUTE_33` | 1 | | 4 | 17 | 3 | `ROUTE_32` | 4 | **Coord events**: none. **BG events**: none (`UnionCave1FUnusedSign` exists in the file but is marked `; unreferenced`). **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `UNIONCAVE1F_POKEFAN_M1` | `SPRITE_POKEFAN_M` | 4 | 4 | `SPINRANDOM_FAST` | `OBJECTTYPE_TRAINER` (sight 1) | `TrainerHikerDaniel` | -1 | | `UNIONCAVE1F_SUPER_NERD` | `SPRITE_SUPER_NERD` | 4 | 21 | `STANDING_DOWN` | `OBJECTTYPE_TRAINER` (sight 2) | `TrainerPokemaniacLarry` | -1 | | `UNIONCAVE1F_POKEFAN_M2` | `SPRITE_POKEFAN_M` | 15 | 8 | `STANDING_LEFT` | `OBJECTTYPE_TRAINER` (sight 3) | `TrainerHikerRussell` | -1 | | `UNIONCAVE1F_FISHER1` | `SPRITE_FISHER` | 16 | 31 | `STANDING_UP` | `OBJECTTYPE_TRAINER` (sight 4) | `TrainerFirebreatherRay` | -1 | | `UNIONCAVE1F_FISHER2` | `SPRITE_FISHER` | 15 | 15 | `SPINRANDOM_FAST` | `OBJECTTYPE_TRAINER` (sight 2) | `TrainerFirebreatherBill` | -1 | | `UNIONCAVE1F_POKE_BALL1` | `SPRITE_POKE_BALL` | 17 | 21 | `STILL` | `OBJECTTYPE_ITEMBALL` | `UnionCave1FGreatBall` (`itemball GREAT_BALL`) | `EVENT_UNION_CAVE_1F_GREAT_BALL` | | `UNIONCAVE1F_POKE_BALL2` | `SPRITE_POKE_BALL` | 4 | 2 | `STILL` | `OBJECTTYPE_ITEMBALL` | `UnionCave1FPotion` (`itemball POTION`) | `EVENT_UNION_CAVE_1F_POTION` | | `UNIONCAVE1F_POKE_BALL3` | `SPRITE_POKE_BALL` | 4 | 17 | `STILL` | `OBJECTTYPE_ITEMBALL` | `UnionCave1FXAttack` (`itemball X_ATTACK`) | `EVENT_UNION_CAVE_1F_X_ATTACK` | | `UNIONCAVE1F_POKE_BALL4` | `SPRITE_POKE_BALL` | 12 | 33 | `STILL` | `OBJECTTYPE_ITEMBALL` | `UnionCave1FAwakening` (`itemball AWAKENING`) | `EVENT_UNION_CAVE_1F_AWAKENING` | **Scripts of interest** Every trainer script here is the plain `endifjustbattled / opentext / writetext / waitbutton / closetext / end` shape. No flags beyond the `EVENT_BEAT_*` in the `trainer` macro, no items, no rematch. **Items** | item | how obtained | source (label / bg_event / hidden) | one-time flag | |---|---|---|---| | `GREAT_BALL` | itemball at `17, 21` | `UnionCave1FGreatBall` | `EVENT_UNION_CAVE_1F_GREAT_BALL` (`constants/event_flags.asm:1019`) | | `POTION` | itemball at `4, 2` | `UnionCave1FPotion` | `EVENT_UNION_CAVE_1F_POTION` (:1020) | | `X_ATTACK` | itemball at `4, 17` | `UnionCave1FXAttack` | `EVENT_UNION_CAVE_1F_X_ATTACK` (:1021) | | `AWAKENING` | itemball at `12, 33` | `UnionCave1FAwakening` | `EVENT_UNION_CAVE_1F_AWAKENING` (:1022) | **Trainers** | const | class | id | party (`data/trainers/parties.asm`) | script label | rematch/phone | |---|---|---|---|---|---| | `DANIEL` | `HIKER` | 18 | `HikerGroup` `; HIKER (18)` line 2229: `11 ONIX` | `TrainerHikerDaniel` (`EVENT_BEAT_HIKER_DANIEL`) | none | | `RUSSELL` | `HIKER` | 2 | `HikerGroup` `; HIKER (2)` line 2123: `4 GEODUDE`, `6 GEODUDE`, `8 GEODUDE` | `TrainerHikerRussell` (`EVENT_BEAT_HIKER_RUSSELL`) | none | | `BILL` | `FIREBREATHER` | 5 | `FirebreatherGroup` `; FIREBREATHER (5)` line 2359: `6 KOFFING`, `6 KOFFING` | `TrainerFirebreatherBill` (`EVENT_BEAT_FIREBREATHER_BILL`) | none | | `LARRY` | `POKEMANIAC` | 1 | `PokemaniacGroup` `; POKEMANIAC (1)` line 1081: `10 SLOWPOKE` | `TrainerPokemaniacLarry` (`EVENT_BEAT_POKEMANIAC_LARRY`) | none | | `RAY` | `FIREBREATHER` | 7 | `FirebreatherGroup` `; FIREBREATHER (7)` line 2371: `9 VULPIX` | `TrainerFirebreatherRay` (`EVENT_BEAT_FIREBREATHER_RAY`) | none | **Wild encounters** `data/wild/johto_grass.asm:444` `def_grass_wildmons UNION_CAVE_1F`, rate `6 percent` all windows. **Gold** branch, identical morn/day/nite: `6 GEODUDE, 6 SANDSHREW, 5 ZUBAT, 4 RATTATA, 7 ZUBAT, 6 ONIX, 6 ONIX`. (Silver replaces `SANDSHREW` with a second `RATTATA`.) Note `SANDSHREW` and `ONIX` are in the table but not in the walkthrough's list. `data/wild/johto_water.asm:12` `def_water_wildmons UNION_CAVE_1F`, rate `2 percent`: `15 WOOPER, 20 QUAGSIRE, 15 QUAGSIRE`. Fishing group `FISHGROUP_LAKE` (`data/wild/fish.asm:14`); `.Lake_Old` (line 57) `MAGIKARP 10, MAGIKARP 10, GOLDEEN 10`. --- ### MAP_UNION_CAVE_B1F - Script: `maps/UnionCaveB1F.asm` - Blocks: `maps/UnionCaveB1F.blk` - Header: `data/maps/maps.asm:108` -> `TILESET_CAVE, CAVE, LANDMARK_UNION_CAVE, MUSIC_UNION_CAVE, TRUE, PALETTE_NITE, FISHGROUP_LAKE` - Dimensions: `constants/map_constants.asm:95` group `DUNGEONS` (3), id 30, `10, 18` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 3 | 3 | `RUINS_OF_ALPH_OUTSIDE` | 7 | | 2 | 3 | 11 | `RUINS_OF_ALPH_OUTSIDE` | 8 | | 3 | 7 | 19 | `UNION_CAVE_1F` | 1 | | 4 | 3 | 33 | `UNION_CAVE_1F` | 2 | | 5 | 17 | 31 | `UNION_CAVE_B2F` | 1 | **Coord events / BG events**: none. **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `UNIONCAVEB1F_POKEFAN_M1` | `SPRITE_POKEFAN_M` | 10 | 4 | `SPINRANDOM_FAST` | `OBJECTTYPE_TRAINER` (sight 1) | `TrainerHikerPhillip` | -1 | | `UNIONCAVEB1F_POKEFAN_M2` | `SPRITE_POKEFAN_M` | 17 | 10 | `STANDING_DOWN` | `OBJECTTYPE_TRAINER` (sight 3) | `TrainerHikerLeonard` | -1 | | `UNIONCAVEB1F_SUPER_NERD1` | `SPRITE_SUPER_NERD` | 5 | 32 | `STANDING_LEFT` | `OBJECTTYPE_TRAINER` (sight 3) | `TrainerPokemaniacAndrew` | -1 | | `UNIONCAVEB1F_SUPER_NERD2` | `SPRITE_SUPER_NERD` | 17 | 30 | `STANDING_LEFT` | `OBJECTTYPE_TRAINER` (sight 3) | `TrainerPokemaniacCalvin` | -1 | | `UNIONCAVEB1F_POKE_BALL1` | `SPRITE_POKE_BALL` | 2 | 16 | `STILL` | `OBJECTTYPE_ITEMBALL` | `UnionCaveB1FTMSwift` (`itemball TM_SWIFT`) | `EVENT_UNION_CAVE_B1F_TM_SWIFT` | | `UNIONCAVEB1F_BOULDER` | `SPRITE_BOULDER` | 7 | 10 | `STRENGTH_BOULDER` | `OBJECTTYPE_SCRIPT` | `UnionCaveB1FBoulder` (`jumpstd StrengthBoulderScript`) | -1 | | `UNIONCAVEB1F_POKE_BALL2` | `SPRITE_POKE_BALL` | 17 | 23 | `STILL` | `OBJECTTYPE_ITEMBALL` | `UnionCaveB1FXDefend` (`itemball X_DEFEND`) | `EVENT_UNION_CAVE_B1F_X_DEFEND` | **Items** | item | how obtained | source (label / bg_event / hidden) | one-time flag | |---|---|---|---| | `TM_SWIFT` (TM39) | itemball at `2, 16` | `UnionCaveB1FTMSwift` | `EVENT_UNION_CAVE_B1F_TM_SWIFT` (`constants/event_flags.asm:1023`) | | `X_DEFEND` | itemball at `17, 23` | `UnionCaveB1FXDefend` | `EVENT_UNION_CAVE_B1F_X_DEFEND` (:1024) | **Trainers** (all beyond the walkthrough's current route; they sit on the B2F path) | const | class | id | party (`data/trainers/parties.asm`) | script label | rematch/phone | |---|---|---|---|---|---| | `PHILLIP` | `HIKER` | 3 | `; HIKER (3)` line 2130: `23 GEODUDE`, `23 GEODUDE`, `23 GRAVELER` | `TrainerHikerPhillip` | none | | `LEONARD` | `HIKER` | 4 | `; HIKER (4)` line 2137: `23 GEODUDE`, `25 MACHOP` | `TrainerHikerLeonard` | none | | `ANDREW` | `POKEMANIAC` | 2 | `; POKEMANIAC (2)` line 1086: `24 MAROWAK`, `24 MAROWAK` | `TrainerPokemaniacAndrew` | none | | `CALVIN` | `POKEMANIAC` | 3 | `; POKEMANIAC (3)` line 1092: `26 KANGASKHAN` | `TrainerPokemaniacCalvin` | none | Level 23-26 - a bot at the walkthrough's level 15-17 must NOT wander into these. The TM Swift / X Defend route (`7, 19` -> `2, 16` -> `17, 23` -> `3, 33`) keeps clear of Phillip (`10, 4`) and Leonard (`17, 10`) but passes near Calvin (`17, 30`, sight 3) on the way to X Defend at `17, 23`. **Wild encounters** `data/wild/johto_grass.asm:499` `def_grass_wildmons UNION_CAVE_B1F`, rate `6 percent`. Gold branch, identical morn/day/nite: `8 GEODUDE, 8 SANDSHREW, 7 ZUBAT, 8 ONIX, 9 ZUBAT, 6 RATTATA, 6 RATTATA`. `data/wild/johto_water.asm:19`, rate `2 percent`: `15 WOOPER, 20 QUAGSIRE, 15 QUAGSIRE`. --- ### MAP_UNION_CAVE_B2F Out of the walkthrough's current route (needs Strength for the B1F boulder), but it is the map the section explicitly says to come back to. - Script: `maps/UnionCaveB2F.asm` - Blocks: `maps/UnionCaveB2F.blk` - Header: `data/maps/maps.asm:109` -> `TILESET_CAVE, CAVE, LANDMARK_UNION_CAVE, MUSIC_UNION_CAVE, TRUE, PALETTE_NITE, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm:96` group `DUNGEONS` (3), id 31, `10, 18` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 5 | 3 | `UNION_CAVE_B1F` | 5 | **Coord events / BG events**: none. **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `UNIONCAVEB2F_ROCKER` | `SPRITE_ROCKER` | 17 | 23 | `STANDING_LEFT` | `OBJECTTYPE_TRAINER` (sight 5) | `TrainerCooltrainermNick` | -1 | | `UNIONCAVEB2F_COOLTRAINER_F1` | `SPRITE_COOLTRAINER_F` | 5 | 13 | `SPINRANDOM_FAST` | `OBJECTTYPE_TRAINER` (sight 1) | `TrainerCooltrainerfGwen` | -1 | | `UNIONCAVEB2F_COOLTRAINER_F2` | `SPRITE_COOLTRAINER_F` | 3 | 28 | `STANDING_DOWN` | `OBJECTTYPE_TRAINER` (sight 2) | `TrainerCooltrainerfEmma` | -1 | | `UNIONCAVEB2F_POKE_BALL1` | `SPRITE_POKE_BALL` | 16 | 2 | `STILL` | `OBJECTTYPE_ITEMBALL` | `UnionCaveB2FElixer` | `EVENT_UNION_CAVE_B2F_ELIXER` | | `UNIONCAVEB2F_POKE_BALL2` | `SPRITE_POKE_BALL` | 12 | 19 | `STILL` | `OBJECTTYPE_ITEMBALL` | `UnionCaveB2FHyperPotion` | `EVENT_UNION_CAVE_B2F_HYPER_POTION` | | `UNIONCAVEB2F_LAPRAS` | `SPRITE_SURF` | 11 | 31 | `SWIM_WANDER` (r 1,1) | `OBJECTTYPE_SCRIPT` | `UnionCaveLapras` | `EVENT_UNION_CAVE_B2F_LAPRAS` | **Scripts of interest** - `UnionCaveB2FLaprasCallback` (`callback MAPCALLBACK_OBJECTS`) - `checkflag ENGINE_UNION_CAVE_LAPRAS` -> if true `.NoAppear`; `readvar VAR_WEEKDAY` / `ifequal FRIDAY, .Appear`; else `disappear`. - `UnionCaveLapras` - `faceplayer`, `cry LAPRAS`, `loadwildmon LAPRAS, 20`, `startbattle`, `disappear`, `setflag ENGINE_UNION_CAVE_LAPRAS`, `reloadmapafterbattle`. **Level 20, once per week only if you fail to catch it - no, once ever**: `ENGINE_UNION_CAVE_LAPRAS` (`constants/engine_flags.asm:107`) is set unconditionally after the battle. The Lapras is on water, so Surf is needed to reach `11, 31`. **Trainers** | const | class | id | party | script label | |---|---|---|---|---| | `NICK` | `COOLTRAINERM` | 1 | `CooltrainerMGroup` `; COOLTRAINERM (1)` line 740, `TRAINERTYPE_MOVES`: `26 CHARMANDER` (EMBER/SMOKESCREEN/RAGE/SCARY_FACE), `26 SQUIRTLE` (WITHDRAW/WATER_GUN/BITE/CURSE), `26 BULBASAUR` (LEECH_SEED/POISONPOWDER/SLEEP_POWDER/RAZOR_LEAF) | `TrainerCooltrainermNick` | | `GWEN` | `COOLTRAINERF` | 1 | `CooltrainerFGroup` `; COOLTRAINERF (1)` line 865: `26 EEVEE`, `22 FLAREON`, `22 VAPOREON`, `22 JOLTEON` | `TrainerCooltrainerfGwen` | | `EMMA` | `COOLTRAINERF` | 15 | line 954: `28 POLIWHIRL` | `TrainerCooltrainerfEmma` | **Wild encounters** `data/wild/johto_grass.asm:554`, rate `4 percent`, identical morn/day/nite: `22 ZUBAT, 22 RATICATE, 22 GOLBAT, 21 GEODUDE, 20 RATTATA, 23 ONIX, 23 ONIX`. `data/wild/johto_water.asm:26`, rate `4 percent`: `15 TENTACOOL, 20 QUAGSIRE, 20 TENTACRUEL`. --- ### MAP_ROUTE_33 - Script: `maps/Route33.asm` - Blocks: `maps/Route33.blk` - Header: `data/maps/maps.asm:231` -> `TILESET_JOHTO_MODERN, ROUTE, LANDMARK_ROUTE_33, MUSIC_ROUTE_30, FALSE, PALETTE_AUTO, FISHGROUP_SHORE` - Dimensions: `constants/map_constants.asm:212` group `AZALEA` (8), id 6, `10, 9` - Connections (`data/maps/attributes.asm`): `connection north, Route32, ROUTE_32, 0` and `connection west, AzaleaTown, AZALEA_TOWN, 0` **Warps** (`def_warp_events`) | idx | x | y | destination map | dest warp | |---|---|---|---|---| | 1 | 11 | 9 | `UNION_CAVE_1F` | 3 | **Coord events**: none. **BG events** (`def_bg_events`) | x | y | type | script/item | |---|---|---|---| | 11 | 11 | `BGEVENT_READ` | `Route33Sign` | **Object events** (`def_object_events`) | const | sprite | x | y | movement | type | script label | event flag | |---|---|---|---|---|---|---|---| | `ROUTE33_POKEFAN_M` | `SPRITE_POKEFAN_M` | 6 | 13 | `SPINRANDOM_FAST` | `OBJECTTYPE_TRAINER` (sight 2) | `TrainerHikerAnthony` | -1 | | `ROUTE33_FRUIT_TREE` | `SPRITE_FRUIT_TREE` | 14 | 16 | `STILL` | `OBJECTTYPE_SCRIPT` | `Route33FruitTree` (`fruittree FRUITTREE_ROUTE_33`) | -1 | **Scripts of interest** - `TrainerHikerAnthony` - same phone shape as Ralph/Liz: `EVENT_ANTHONY_READY_FOR_REMATCH` -> `.Rematch`; `checkcellnum PHONE_HIKER_ANTHONY`; `EVENT_ANTHONY_ASKED_FOR_PHONE_NUMBER`; `askforphonenumber PHONE_HIKER_ANTHONY`. Rematch escalates to `ANTHONY1` after `ENGINE_FLYPOINT_OLIVINE` and `ANTHONY3` after `EVENT_CLEARED_RADIO_TOWER`. - `Route33FruitTree` - `fruittree FRUITTREE_ROUTE_33` (`constants/script_constants.asm:212`, index `06`); `data/items/fruit_trees.asm` row 6 is `db PSNCUREBERRY ; ROUTE_33`. **Items** | item | how obtained | source (label / bg_event / hidden) | one-time flag | |---|---|---|---| | `PSNCUREBERRY` | headbutt-style fruit tree object at `14, 16` | `Route33FruitTree` / `data/items/fruit_trees.asm` `; ROUTE_33` | none - fruit trees respawn on a timer, tracked in `wFruitTreeFlags`, not an `EVENT_*` | **Trainers** | const | class | id | party (`data/trainers/parties.asm`) | script label | rematch/phone | |---|---|---|---|---|---| | `ANTHONY2` | `HIKER` | 5 | `HikerGroup` `; HIKER (5)` line 2143: `11 GEODUDE`, `11 MACHOP` | `TrainerHikerAnthony` (`EVENT_BEAT_HIKER_ANTHONY`) | `PHONE_HIKER_ANTHONY` (slot 19); `ANTHONY1` `16 GEODUDE / 18 MACHAMP`, `ANTHONY3` `25 GRAVELER / 27 GRAVELER / 29 MACHOKE` | **Wild encounters** `data/wild/johto_grass.asm:1766` `def_grass_wildmons ROUTE_33`, rate `10 percent`. **Gold** branch: - morn: `6 HOPPIP, 7 RATTATA, 6 SPEAROW, 6 RATTATA, 8 HOPPIP, 4 ZUBAT, 4 ZUBAT` - day: `6 HOPPIP, 7 RATTATA, 6 SPEAROW, 6 RATTATA, 8 HOPPIP, 8 RATTATA, 8 RATTATA` - nite: `6 ZUBAT, 7 RATTATA, 6 RATTATA, 6 RATTATA, 8 ZUBAT, 8 ZUBAT, 8 ZUBAT` Silver replaces the slot-2 `RATTATA` with `EKANS`. No water table. --- ## 3. Blockers and gates | Gate | Enforced by (file:label) | Requirement | Unlock condition | |---|---|---|---| | Route 32 south is soft-blocked at the top | `maps/Route32.asm` `coord_event 18, 8, SCENE_ROUTE32_COOLTRAINER_M_BLOCKS, Route32CooltrainerMStopsYouScene` | scene byte for `ROUTE_32` must not be 0 | `maps/VioletPokecenter1F.asm` `setmapscene ROUTE_32, SCENE_ROUTE32_OFFER_SLOWPOKETAIL` when you take the Togepi EGG. Until then the coord event fires every time and `applymovement PLAYER, Movement_Route32CooltrainerMPushesYouBackToViolet` (`UP UP`) shoves you back toward Violet | | Elm's Aide does not exist yet | `engine/events/std_scripts.asm:468` sets `EVENT_ELMS_AIDE_IN_VIOLET_POKEMON_CENTER`; `engine/phone/scripts/elm.asm:84` clears it | Falkner must be beaten so `maps/VioletGym.asm:38` `specialphonecall SPECIALCALL_ASSISTANT` arms the call, then the call must actually land | after the phone call, `VIOLETPOKECENTER1F_ELMS_AIDE` appears at `4, 3` | | Miracle Seed | `maps/Route32.asm` `Route32CooltrainerMScript` | `ENGINE_ZEPHYRBADGE` AND `EVENT_GOT_TOGEPI_EGG_FROM_ELMS_AIDE` | both true -> `.GiveMiracleSeed` | | Kabuto chamber floor | `maps/RuinsOfAlphKabutoChamber.asm` `RuinsOfAlphKabutoChamberHiddenDoorsCallback` (`MAPCALLBACK_TILES`) | `EVENT_SOLVED_KABUTO_PUZZLE` | solve `special UnownPuzzle` with `setval UNOWNPUZZLE_KABUTO` from the `BGEVENT_UP` at `3, 2` | | Unown do not spawn at all | `engine/overworld/wildmons.asm:341-347` `cp UNOWN` / `ld a, [wUnlockedUnowns]` / `and a` / `jr z, .nowildbattle` | at least one `ENGINE_UNLOCKED_UNOWNS_*` bit set | solve any chamber puzzle | | Only some Unown letters spawn | `engine/battle/core.asm:6219` `CheckUnownLetter` vs `data/wild/unlocked_unowns.asm` | the letter must be in an unlocked set | Kabuto -> A-K, Omanyte -> L-R, Aerodactyl -> S-W, Ho-Oh -> X-Z | | Unown #DEX scientist | `maps/RuinsOfAlphOutside.asm` `RuinsOfAlphOutsideScientistCallback` | `ENGINE_UNOWN_DEX` clear AND `EVENT_MADE_UNOWN_APPEAR_IN_RUINS` set AND `VAR_UNOWNCOUNT > 2` | catch three distinct Unown forms, then walk onto `11, 14` or `10, 15` | | Aerodactyl chamber | reachable only across the Ruins Outside water; `engine/events/overworld.asm:490` `ld de, ENGINE_FOGBADGE` / `call CheckEngineFlag`, then `ld d, SURF` / `call CheckPartyMove` | FOGBADGE + a party member knowing SURF | Chuck's badge, later game | | Union Cave B1F boulder at `7, 10` | `maps/UnionCaveB1F.asm` `UnionCaveB1FBoulder` -> `jumpstd StrengthBoulderScript` -> `engine/events/std_scripts.asm:197` `farsjump AskStrengthScript` -> `engine/events/overworld.asm:1033` `TryStrengthOW`: `ld d, STRENGTH` / `CheckPartyMove`, then `ld de, ENGINE_PLAINBADGE` / `CheckEngineFlag` | PLAINBADGE + STRENGTH in the party | Whitney's badge + HM04 | | Union Cave Lapras | `maps/UnionCaveB2F.asm` `UnionCaveB2FLaprasCallback` | `VAR_WEEKDAY == FRIDAY` and `ENGINE_UNION_CAVE_LAPRAS` clear | real-world Friday, once ever | | Frieda / POISON_BARB | `maps/Route32.asm` `Route32FriedaCallback` + `FriedaScript` | `VAR_WEEKDAY == FRIDAY` | real-world Friday | | Route 36 Sudowoodo | `maps/Route36.asm` `object_event 35, 9, SPRITE_WEIRD_TREE, ... SudowoodoScript, EVENT_ROUTE_36_SUDOWOODO` | out of scope for this section - the walkthrough says "ignore that for now" | next section | | FLASH | **not required** - `data/maps/maps.asm:107-109` give all three Union Cave floors `PALETTE_NITE`, not `PALETTE_DARK` | none | n/a | --- ## 4. Bot checklist Coordinates are `x, y` in the map's own cell space, as written in the asm. 1. `VIOLET_CITY` -> step onto warp 5 at `31, 25`. pre: `EVENT_ELMS_AIDE_IN_VIOLET_POKEMON_CENTER` CLEAR (Elm's call landed). post: on `VIOLET_POKECENTER_1F`. 2. `VIOLET_POKECENTER_1F` -> talk to `VIOLETPOKECENTER1F_ELMS_AIDE` at `4, 3`, answer YES. pre: `VAR_PARTYCOUNT < PARTY_LENGTH`. post: `EVENT_GOT_TOGEPI_EGG_FROM_ELMS_AIDE` set; `ROUTE_32` scene = `SCENE_ROUTE32_OFFER_SLOWPOKETAIL`. 3. `VIOLET_POKECENTER_1F` -> heal at `VIOLETPOKECENTER1F_NURSE` (`3, 1`), buy balls at `VIOLET_MART` (Violet City warp 1 at `9, 17`). Then exit west out of Violet City on the map connection into `ROUTE_36`. 4. `ROUTE_36` -> walk to warp 3/4 at `47, 13` / `48, 13`. avoid: `object_event 35, 9` Sudowoodo, and trainers at `20, 12` / `31, 14`. post: `ROUTE_36_RUINS_OF_ALPH_GATE`. 5. `ROUTE_36_RUINS_OF_ALPH_GATE` -> warp 3/4 at `4, 7` / `5, 7`. post: `RUINS_OF_ALPH_OUTSIDE` at warp 9 (`7, 5`). 6. `RUINS_OF_ALPH_OUTSIDE` -> walk to warp 2 at `14, 7`. avoid: `TrainerPsychicNathan` at `4, 20` (L26 Girafarig, sight 1) - it is far south of this path, so no detour is needed. post: `RUINS_OF_ALPH_KABUTO_CHAMBER`. 7. `RUINS_OF_ALPH_KABUTO_CHAMBER` -> stand at `3, 3` facing UP, press A on the `BGEVENT_UP` at `3, 2`. Solve the sliding puzzle (`special UnownPuzzle`, `setval UNOWNPUZZLE_KABUTO`). post: `EVENT_SOLVED_KABUTO_PUZZLE`, `ENGINE_UNLOCKED_UNOWNS_A_TO_K`, `EVENT_RUINS_OF_ALPH_INNER_CHAMBER_TOURISTS`, `EVENT_RUINS_OF_ALPH_KABUTO_CHAMBER_RECEPTIONIST`, `RUINS_OF_ALPH_INNER_CHAMBER` scene = `SCENE_RUINSOFALPHINNERCHAMBER_STRANGE_PRESENCE`; `warpcheck` drops you through warp 3/4 into the Inner Chamber at `15, 3` / `16, 3`. 8. `RUINS_OF_ALPH_INNER_CHAMBER` -> the deferred scene prints "strange presence". post: `EVENT_MADE_UNOWN_APPEAR_IN_RUINS`; scene reset to `SCENE_RUINSOFALPHINNERCHAMBER_NOOP`. 9. `RUINS_OF_ALPH_INNER_CHAMBER` -> grind grass encounters (rate `6 percent`, always `5 UNOWN`, letters A-K) and CATCH three distinct letters. post: `VAR_UNOWNCOUNT >= 3`. 10. `RUINS_OF_ALPH_INNER_CHAMBER` -> warp 1 at `10, 13`. post: `RUINS_OF_ALPH_OUTSIDE` at `10, 13`; `RuinsOfAlphOutsideScientistCallback` runs on load and `appear`s the scientist + sets the scene. 11. `RUINS_OF_ALPH_OUTSIDE` -> step to `10, 15` (or `11, 14`). pre: `VAR_UNOWNCOUNT > 2`, `ENGINE_UNOWN_DEX` clear. post: cutscene runs; the script `applymovement`s you into the Research Center. Do not drive movement during this - it uses `follow` / `stopfollow` / `warpcheck`. 12. `RUINS_OF_ALPH_RESEARCH_CENTER` -> the scene fires on entry; press through. post: `ENGINE_UNOWN_DEX` set; scene reset to `SCENE_RUINSOFALPHRESEARCHCENTER_NOOP`. 13. `RUINS_OF_ALPH_RESEARCH_CENTER` -> warp 1/2 at `2, 7` / `3, 7` back outside, then walk south-east to warp 10/11 at `13, 20` / `13, 21`. post: `ROUTE_32_RUINS_OF_ALPH_GATE`. 14. `ROUTE_32_RUINS_OF_ALPH_GATE` -> warp 3/4 at `9, 4` / `9, 5`. post: `ROUTE_32` at `4, 2` / `4, 3`. 15. `ROUTE_32` -> optional: north connection into Violet City for the `VioletCityFruitTree` at Violet City `14, 29` (PRZCUREBERRY, `data/items/fruit_trees.asm` `; VIOLET_CITY`). 16. `ROUTE_32` -> talk to `ROUTE32_COOLTRAINER_M` at `19, 8`. pre: `ENGINE_ZEPHYRBADGE` set AND `EVENT_GOT_TOGEPI_EGG_FROM_ELMS_AIDE` set. post: `MIRACLE_SEED` in bag, `EVENT_GOT_MIRACLE_SEED_IN_ROUTE_32`. 17. `ROUTE_32` -> talk to `ROUTE32_FISHER5` at `15, 13`. post: `TM_ROAR`, `EVENT_GOT_TM05_ROAR`. 18. `ROUTE_32` -> battle `TrainerYoungsterAlbert` (object at `13, 23`, sight 3). post: `EVENT_BEAT_YOUNGSTER_ALBERT`. 19. `ROUTE_32` -> pick up the `POTION` itemball at `3, 30`. post: `EVENT_ROUTE_32_POTION`. 20. `ROUTE_32` -> battle `TrainerPicnickerLiz1` (object at `10, 30`, sight 1), then TALK TO HER AGAIN. post: `EVENT_BEAT_PICNICKER_LIZ`, `EVENT_LIZ_ASKED_FOR_PHONE_NUMBER`, then `PHONE_PICNICKER_LIZ` registered via `askforphonenumber`. 21. `ROUTE_32` -> hidden `SUPER_POTION` at `11, 40` (`BGEVENT_ITEM`, needs the ITEMFINDER-style bump or a direct A press on the tile). post: `EVENT_ROUTE_32_HIDDEN_SUPER_POTION`. 22. `ROUTE_32` -> battle `TrainerFisherJustin` (`8, 49`, sight 1), then `TrainerFisherHenry` (`6, 48`, sight 1), then `TrainerFisherRalph1` (`12, 56`, sight 3) and talk to Ralph again for `PHONE_FISHER_RALPH`. 23. `ROUTE_32` -> battle `TrainerCamperRoland` (`1, 56`, sight 4). 24. `ROUTE_32` -> pick up the `GREAT_BALL` itemball at `6, 53`. post: `EVENT_ROUTE_32_GREAT_BALL`. 25. `ROUTE_32` -> battle `TrainerYoungsterGordon` (`4, 65`, `SPINCLOCKWISE`, sight 3). 26. `ROUTE_32` -> hidden `GREAT_BALL` at `12, 67`; on a Friday `ROUTE32_FRIEDA` stands there, talk to her for `POISON_BARB`. post: `EVENT_ROUTE_32_HIDDEN_GREAT_BALL`; optionally `EVENT_GOT_POISON_BARB_FROM_FRIEDA`. 27. `ROUTE_32` -> step onto `7, 71` to fire `Route32WannaBuyASlowpokeTailScript` (pre: scene == `SCENE_ROUTE32_OFFER_SLOWPOKETAIL`); answer either way. post: scene = `SCENE_ROUTE32_NOOP`, one-shot done. 28. `ROUTE_32` -> warp 1 at `11, 73` into `ROUTE_32_POKECENTER_1F`; heal at `3, 1`; talk to the Fishing Guru at `1, 4` and answer YES. post: `OLD_ROD`, `EVENT_GOT_OLD_ROD`. 29. `ROUTE_32` -> battle `TrainerBirdKeeperPeter` (`11, 82`, sight 3), then warp 4 at `6, 79`. post: `UNION_CAVE_1F` at `17, 3`. 30. `UNION_CAVE_1F` -> `POTION` itemball at `4, 2`; battle `TrainerHikerDaniel` (`4, 4`, `SPINRANDOM_FAST`, sight 1). post: `EVENT_UNION_CAVE_1F_POTION`, `EVENT_BEAT_HIKER_DANIEL`. 31. `UNION_CAVE_1F` -> battle `TrainerHikerRussell` (`15, 8`, sight 3) and `TrainerFirebreatherBill` (`15, 15`, sight 2). 32. `UNION_CAVE_1F` -> `X_ATTACK` itemball at `4, 17`; `GREAT_BALL` itemball at `17, 21`; battle `TrainerPokemaniacLarry` (`4, 21`, sight 2). post: `EVENT_UNION_CAVE_1F_X_ATTACK`, `EVENT_UNION_CAVE_1F_GREAT_BALL`, `EVENT_BEAT_POKEMANIAC_LARRY`. 33. `UNION_CAVE_1F` -> warp 1 at `5, 19`. post: `UNION_CAVE_B1F` at `7, 19`. 34. `UNION_CAVE_B1F` -> `TM_SWIFT` itemball at `2, 16`, then `X_DEFEND` itemball at `17, 23`. avoid: `TrainerHikerPhillip` `10, 4`, `TrainerHikerLeonard` `17, 10`, `TrainerPokemaniacCalvin` `17, 30` (sight 3), `TrainerPokemaniacAndrew` `5, 32` - all L23-26. post: `EVENT_UNION_CAVE_B1F_TM_SWIFT`, `EVENT_UNION_CAVE_B1F_X_DEFEND`. 35. `UNION_CAVE_B1F` -> warp 4 at `3, 33`. post: `UNION_CAVE_1F` at `3, 33`. 36. `UNION_CAVE_1F` -> `AWAKENING` itemball at `12, 33`; battle `TrainerFirebreatherRay` (`16, 31`, sight 4); warp 3 at `17, 31`. post: `EVENT_UNION_CAVE_1F_AWAKENING`, `EVENT_BEAT_FIREBREATHER_RAY`, on `ROUTE_33` at `11, 9`. 37. `ROUTE_33` -> `Route33FruitTree` at `14, 16` for `PSNCUREBERRY`. 38. `ROUTE_33` -> battle `TrainerHikerAnthony` (`6, 13`, `SPINRANDOM_FAST`, sight 2), then talk again for `PHONE_HIKER_ANTHONY`. post: `EVENT_BEAT_HIKER_ANTHONY`, `EVENT_ANTHONY_ASKED_FOR_PHONE_NUMBER`. 39. `ROUTE_33` -> walk west across the map connection into `AZALEA_TOWN`. Section ends here. Deferred steps (record as TODO, do not attempt this pass): - `RUINS_OF_ALPH_OUTSIDE` warp 4 at `16, 33` (Aerodactyl puzzle) - needs SURF + `ENGINE_FOGBADGE`. - `UNION_CAVE_B1F` boulder at `7, 10` -> `UNION_CAVE_B2F` - needs STRENGTH + `ENGINE_PLAINBADGE`; then the Friday Lapras at B2F `11, 31` (needs SURF). --- ## 5. Port coverage | Beat | Port file | Status | |---|---|---| | Map data (warps / coord / bg / object events) for every map in this section | `src/import/RomExtractorGen2.lua` (`MapGroupPointers` walk, per-map `def_*` header parse around lines 878-987), consumed by `src/world/gen2/Map.lua` and `src/world/gen2/World.lua` | implemented - maps are extracted generically from the ROM, so nothing here is hand-authored per map | | Warps / map connections | `src/world/gen2/World.lua`, `src/world/gen2/BorderFill.lua` | implemented | | Coord-event trip-wires and `scene` bytes | `src/world/gen2/World.lua:5013` (coord event scan), `src/script/gen2/Vm.lua:274-296` (`setscene`, `checkscene`, `setmapscene`, `checkmapscene`) | implemented | | Map callbacks (`MAPCALLBACK_OBJECTS` / `MAPCALLBACK_TILES`) - Frieda, Lapras, Ruins scientist, Kabuto floor | `src/world/gen2/World.lua:5659-5700` (`runMapCallback`, documented ordering at 5980-5984), `src/script/gen2/Vm.lua:1002` (`changeblock`) | implemented; driver `tests/drivers/gold_map_callbacks.lua` exercises callbacks generally, but not these maps specifically | | `verbosegiveitem` / `giveitem` (Miracle Seed, TM05, Poison Barb, Old Rod) | `src/script/gen2/Vm.lua:490-498` | implemented | | Itemballs (`OBJECTTYPE_ITEMBALL`) | `src/world/gen2/World.lua` object handling | implemented | | Hidden items (`BGEVENT_ITEM` / `hiddenitem`) | `src/world/gen2/HiddenItems.lua`, `src/import/RomExtractorGen2.lua` | implemented | | `giveegg` (Togepi EGG) + hatching | `src/script/gen2/Vm.lua:453`, `src/core/gen2/Breeding.lua`; driver `tests/drivers/gold_egg_hatch.lua` | implemented | | Phone: `askforphonenumber` / `checkcellnum`, Ralph/Liz/Anthony contacts | `src/script/gen2/Vm.lua` (op present), `src/core/gen2/Phone.lua:172-179` has `[17] FISHER/RALPH1 ROUTE_32`, `[18] PICNICKER/LIZ1 ROUTE_32`, `[19] HIKER/ANTHONY2 ROUTE_33` | implemented | | Elm's `SPECIALCALL_ASSISTANT` call that spawns the aide | `src/core/gen2/Phone.lua` | partial - the contact table is present; I did not find a `SPECIALCALL_*` special-call scheduler, so verify by hand that the aide actually appears | | Unown puzzle (`special UnownPuzzle`, `setval UNOWNPUZZLE_*`) | `src/script/gen2/Specials.lua:919` (`H.UnownPuzzle`), UI in `src/ui/gen2/UnownPuzzle.lua` | implemented | | Unown letter unlock sets / `wUnlockedUnowns` / letter-from-DVs | `src/core/gen2/Unown.lua` (ports `GetUnownLetter`, `CheckUnownLetter`, `UnlockedUnownLetterSets`, `NUM_UNOWN = 26`, `ENGINE_UNOWN_DEX = 12`) | implemented | | `ChooseWildEncounter` cancelling Unown when `wUnlockedUnowns == 0` | `src/battle/gen2/Encounter.lua` | partial - `Encounter.lua` handles grass/water/fish tables; I did not verify the Unown short-circuit lives there. Verify by hand | | Unown #DEX mode / Unown printer | `src/ui/gen2/PokedexMenu.lua`, `src/ui/gen2/UnownPrinter.lua` | implemented | | Wild encounters, morn/day/nite split, encounter rates | `src/battle/gen2/Encounter.lua` | implemented | | Fishing (Old Rod, fish groups) | `src/battle/gen2/Encounter.lua:79-111` (`Encounter.fish`, `Encounter.fishSlot`, map `fishGroup`) | implemented | | Fruit trees (`fruittree FRUITTREE_ROUTE_33` -> PSNCUREBERRY) | `src/script/gen2/Vm.lua` (`fruittree` op), `src/core/gen2/Apricorns.lua:360` (`"PSNCUREBERRY", -- 06 FRUITTREE_ROUTE_33`) | implemented | | Strength boulder (`jumpstd StrengthBoulderScript` -> `TryStrengthOW`) | `src/world/gen2/FieldMoves.lua:684-689` (documents the 0/1/2 `wScriptVar` result), badge map at :104-110 (`STRENGTH = "PLAIN"`) | implemented; driver `tests/drivers/gold_icepath_boulder.lua` covers a different map | | Surf / FOGBADGE gate for the Aerodactyl chamber | `src/world/gen2/FieldMoves.lua:106` (`SURF = "FOG"`) | implemented | | `ENGINE_UNION_CAVE_LAPRAS` flag id | `src/core/gen2/Apricorns.lua:84` (`{ id = 88, name = "ENGINE_UNION_CAVE_LAPRAS" }`) | implemented | | `VAR_WEEKDAY` gating (Frieda, Lapras) | `src/script/gen2/Specials.lua`, `src/world/gen2/World.lua` | implemented | | Ruins of Alph radio station (213.5) | `src/ui/gen2/Pokegear.lua:85, 799-802` (`UNOWN_RADIO`, landmark-gated to `LANDMARK_RUINS_OF_ALPH`) | implemented | | Mom's shopping (Super Potion / Repel) | `src/core/gen2/MomShopping.lua`; asm table `data/items/mom_phone.asm` | implemented | | End-to-end driver for this section | none | **missing** - `tests/drivers/gold_*.lua` has no Ruins of Alph, Route 32, Union Cave or Route 33 driver. The nearest are `gold_walk_smoke.lua` and `gold_trainer_smoke.lua` | --- ## 6. Unresolved / verify by hand 1. **"Repel" on Route 32.** The walkthrough lists Repel among Route 32 items and says "Take the left path and get the Repel". `maps/Route32.asm` has no `REPEL` anywhere. The only pickups on that fork are the `POTION` itemball at `3, 30` and the hidden `SUPER_POTION` at `11, 40`. The Repel the player actually ends up with almost certainly comes from `data/items/mom_phone.asm` `MomItems_2` (`momitem 4000, 270, MOM_ITEM, REPEL`), which fits the walkthrough's own "Mom will buy something once your savings reach certain thresholds" paragraph. Treat the Route 32 Repel as a walkthrough error. 2. **Ekans on Routes 32 and 33.** The walkthrough lists `#023 Ekans` for both routes. `data/wild/johto_grass.asm` puts `EKANS` only in the `ELIF DEF(_SILVER)` branches; the `IF DEF(_GOLD)` branches have `RATTATA` in that slot. This section's encounter list is Silver's, not Gold's. 3. **"Unown in its 28 forms ... plus two punctuation marks (? and !)."** `constants/pokemon_constants.asm:308` is `DEF NUM_UNOWN EQU const_value - 1 ; 26`, and the form constants stop at `UNOWN_Z`. The `?` and `!` forms are a Gen 3 addition. The Research Center printer/computer both check `ifequal NUM_UNOWN`, so the completion target in Gold is 26. 4. **"Talk to the two people inside" the Kabuto chamber.** `maps/RuinsOfAlphKabutoChamber.asm` defines exactly one `object_event` (`RUINSOFALPHKABUTOCHAMBER_RECEPTIONIST` at `5, 5`). There is no second NPC. 5. **`RuinsOfAlphOutside` declares five object consts but only two objects.** `RUINSOFALPHOUTSIDE_FISHER`, `_YOUNGSTER2` and `_YOUNGSTER3` have no `object_event` row. Either dead constants or a Crystal-era leftover; a port that indexes objects by const must not assume the list is dense. 6. **Route 32 grass Pokemon the walkthrough omits.** It lists Rattata, Ekans, Zubat, Bellsprout, Mareep, Hoppip, Wooper. The Gold table also never yields Ekans (see 2), and Wooper is morn/nite only - the day table has no Wooper at all. Similarly Union Cave 1F/B1F contain `SANDSHREW` and `ONIX` in Gold, neither of which the walkthrough's Union Cave list mentions. 7. **"Some rando fisher will give you an Old Rod" - order.** The walkthrough puts the Old Rod after Frieda and the Slowpoke-tail salesman. The Fishing Guru is inside `ROUTE_32_POKECENTER_1F` (`1, 4`), reached by warp 1 at Route 32 `11, 73`, which is south of Frieda (`12, 67`) and the salesman coord event (`7, 71`). Order is consistent, but the guru is indoors, not "on the route". 8. **"X Attack below Bill" / "the item to the far left ... a Potion".** Firebreather Bill is at `15, 15`; the X Attack is at `4, 17` and the Potion at `4, 2`. Both are far to the WEST, not directly below/left of Bill. The prose directions are loose; use the coordinates. 9. **`SPECIALCALL_*` scheduling in the port.** I could not find the mechanism that arms and delivers `SPECIALCALL_ASSISTANT` (`maps/VioletGym.asm:38` -> `engine/phone/scripts/elm.asm` `.assistant`) in this repo. `src/core/gen2/Phone.lua` has the contact table but the special-call queue was not located. Without it, `EVENT_ELMS_AIDE_IN_VIOLET_POKEMON_CENTER` never clears, the aide never appears, and Route 32 stays permanently blocked by the `18, 8` coord event - the single hardest failure mode for a bot in this section. 10. **The Unown short-circuit in `ChooseWildEncounter`.** `engine/overworld/wildmons.asm:341-347` cancels the encounter entirely when `wUnlockedUnowns == 0`. I confirmed `src/core/gen2/Unown.lua` ports the letter sets and `CheckUnownLetter`, but did not confirm `src/battle/gen2/Encounter.lua` reproduces the "no puzzle solved -> no encounter at all" branch. If it does not, a bot could meet Unown in the Inner Chamber before solving any puzzle. 11. **`Route32Pokecenter1FFishingGuruScript` has no bag-full guard.** Unlike `Route32CooltrainerMScript` and `FriedaScript`, it does not `iffalse` after `verbosegiveitem OLD_ROD` before `setevent EVENT_GOT_OLD_ROD`. If the KEY ITEMS pocket were full the flag would be set without the rod. This is asm behaviour, not a port bug - flagged so nobody "fixes" it. 12. **Union Cave Lapras is once-ever, not once-weekly.** `UnionCaveLapras` sets `ENGINE_UNION_CAVE_LAPRAS` after `startbattle` regardless of outcome, and `UnionCaveB2FLaprasCallback` checks that flag before the weekday check. The walkthrough's "only appears on Friday" is right about the weekday but does not mention that fleeing or fainting loses it permanently.