Files
gen1recomp/docs/gold-walkthrough/asm-walk/section-20-saffron-city-gym.md
T
bryanthaboi ae6cac89e1 G2 support
2026-08-11 11:53:30 -04:00

48 KiB

Section 20 - Saffron City Gym

Source: ../section-20-saffron-city-gym.txt (the FAQ numbers this chapter "26 > Saffron City Gym") Maps covered: MAP_ROUTE_6, MAP_ROUTE_6_UNDERGROUND_PATH_ENTRANCE, MAP_ROUTE_6_SAFFRON_GATE, MAP_SAFFRON_CITY, MAP_MR_PSYCHICS_HOUSE, MAP_SILPH_CO_1F, MAP_SAFFRON_MAGNET_TRAIN_STATION, MAP_SAFFRON_MART, MAP_FIGHTING_DOJO, MAP_SAFFRON_GYM, MAP_SAFFRON_POKECENTER_1F Badges / key milestones in this section: MARSHBADGE (ENGINE_MARSHBADGE), TM29 Psychic, Up-Grade, Focus Band, ENGINE_FLYPOINT_SAFFRON unlocked on first entry to Saffron City.

Map group / id pairs a bot needs (from constants/map_constants.asm):

Map constant group id
MAP_ROUTE_6 12 (VERMILION) 1
MAP_ROUTE_6_SAFFRON_GATE 12 12
MAP_ROUTE_6_UNDERGROUND_PATH_ENTRANCE 12 13
MAP_SAFFRON_CITY 25 (SAFFRON) 2
MAP_FIGHTING_DOJO 25 3
MAP_SAFFRON_GYM 25 4
MAP_SAFFRON_MART 25 5
MAP_SAFFRON_POKECENTER_1F 25 6
MAP_MR_PSYCHICS_HOUSE 25 8
MAP_SAFFRON_MAGNET_TRAIN_STATION 25 9
MAP_SILPH_CO_1F 25 10

1. Route order

# Map constant asm file Enter via Leaves via Why (walkthrough beat)
0 MAP_VERMILION_CITY maps/VermilionCity.asm (previous section) - north map connection "Heal at the Pokémon Center, then head north onto Route 6" - Vermilion belongs to the previous section
1 MAP_ROUTE_6 maps/Route6.asm south connection from Vermilion City warp 2 (6, 1) -> ROUTE_6_SAFFRON_GATE warp 3 "barren wasteland"; the Underground Path door is blocked
1a MAP_ROUTE_6_UNDERGROUND_PATH_ENTRANCE maps/Route6UndergroundPathEntrance.asm warp 1 (17, 3) on Route 6 - Walkthrough only notes it is blocked; do not enter this section
2 MAP_ROUTE_6_SAFFRON_GATE maps/Route6SaffronGate.asm warp 3/4 (4, 7) / (5, 7) warp 1/2 (4, 0) / (5, 0) -> SAFFRON_CITY warps 12 / 13 "make your way all the way up through the checkpoint house"
3 MAP_SAFFRON_CITY maps/SaffronCity.asm warp 12 (16, 33) / warp 13 (17, 33) see below Hub for the rest of the section; MAPCALLBACK_NEWMAP sets the fly point
4 MAP_MR_PSYCHICS_HOUSE maps/MrPsychicsHouse.asm Saffron warp 5 (27, 29) warp 1/2 (2, 7) / (3, 7) -> Saffron warp 5 "Mr. Psychic ... gets you TM29 Psychic"
5 MAP_SILPH_CO_1F maps/SilphCo1F.asm Saffron warp 7 (18, 21) warp 1/2 (2, 7) / (3, 7) -> Saffron warp 7 "Talk to the man blocking the pathway ... he'll give you Up-Grade"
6 MAP_SAFFRON_MAGNET_TRAIN_STATION maps/SaffronMagnetTrainStation.asm Saffron warp 6 (8, 3) warp 1/2 (8, 17) / (9, 17) -> Saffron warp 6 "On the northwest side of town is the Magnet Train ... currently closed"
7 MAP_SAFFRON_MART maps/SaffronMart.asm Saffron warp 3 (25, 11) warp 1/2 (2, 7) / (3, 7) -> Saffron warp 3 "There's a PokeMart if you want to buy or sell items"
8 MAP_FIGHTING_DOJO maps/FightingDojo.asm Saffron warp 1 (26, 3) warp 1/2 (4, 11) / (5, 11) -> Saffron warp 1 "The former fighting gym has a Focus Band you can pick up"
9 MAP_SAFFRON_GYM maps/SaffronGym.asm Saffron warp 2 (34, 3) warp 1/2 (8, 17) / (9, 17) -> Saffron warp 2 "head to the gym on the right ... Sabrina" -> MARSHBADGE
9a MAP_SAFFRON_POKECENTER_1F maps/SaffronPokecenter1F.asm Saffron warp 4 (9, 29) warp 1/2 (3, 7) / (4, 7) -> Saffron warp 4 Optional mid-gym heal trip described in the walkthrough

Spillover: the walkthrough's opening line ("Heal at the Pokémon Center") refers to Vermilion City, and its closing text ends inside the Saffron Gym exit - nothing past Saffron is described. MAP_COPYCATS_HOUSE_1F (Saffron warp 8, (9, 11)) exists on this map but the walkthrough never enters it in this section.

2. Maps

MAP_ROUTE_6

  • Script: maps/Route6.asm
  • Blocks: maps/Route6.blk (data/maps/blocks.asm:562 Route6_Blocks)
  • Header: data/maps/maps.asm:294 -> TILESET_KANTO, ROUTE, LANDMARK_ROUTE_6, MUSIC_ROUTE_3, phone FALSE, PALETTE_AUTO, FISHGROUP_POND
  • Dimensions: constants/map_constants.asm:271 map_const ROUTE_6, 10, 9 (10x9 blocks = 20x18 cells)
  • Connections: data/maps/attributes.asm:346-348 - north SaffronCity (offset -5), south VermilionCity (offset -5). No east/west.

Warps (def_warp_events)

idx x y destination map dest warp
1 17 3 ROUTE_6_UNDERGROUND_PATH_ENTRANCE 1
2 6 1 ROUTE_6_SAFFRON_GATE 3

Coord events (def_coord_events) - none.

BG events (def_bg_events)

x y type script/item
19 5 BGEVENT_READ Route6UndergroundPathSign (Route6UndergroundPathSignText)

Object events (def_object_events)

const sprite x y movement type script label event flag
ROUTE6_POKEFAN_M SPRITE_POKEFAN_M 17 4 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT (sight field 2, unused) Route6PokefanMScript (4f:581a) EVENT_ROUTE_5_6_POKEFAN_M_BLOCKS_UNDERGROUND_PATH

Scripts of interest

  • Route6PokefanMScript (maps/Route6.asm:9, sym 4f:581a): a bare jumptextfaceplayer Route6PokefanMText - "The road is closed until the problem at the POWER PLANT is solved." No flag reads. He stands at (17, 4), directly south of the Underground Path door at (17, 3), so his body is the block, not a script check.

Flags and events

constant defined in read/written by meaning for a bot
EVENT_ROUTE_5_6_POKEFAN_M_BLOCKS_UNDERGROUND_PATH constants/event_flags.asm:1299 set by maps/PowerPlant.asm:164; consumed as the object's event flag on maps/Route6.asm:43 and maps/Route5.asm:56 Flag set hides the object (CheckObjectFlag, engine/overworld/map_objects_2.asm:32). Clear (default) = the man is standing there = Underground Path shut

Items - none on this map.

Trainers - none on this map.

Wild encounters

data/wild/kanto_grass.asm:480 def_grass_wildmons ROUTE_6, encounter rates 10/10/10 percent (morn/day/nite). Gold block (IF DEF(_GOLD), lines 483-506):

slot morn day nite
1 L13 PIDGEY L13 PIDGEY L13 ODDISH
2 L13 BELLSPROUT L13 BELLSPROUT L14 ODDISH
3 L14 PIDGEY L14 PIDGEY L13 BELLSPROUT
4 L15 MAGNEMITE L15 MAGNEMITE L15 MAGNEMITE
5 L12 ABRA L12 ABRA L12 ABRA
6 L14 ABRA L14 ABRA L14 ABRA
7 L14 ABRA L14 ABRA L14 ABRA

Silver (ELIF DEF(_SILVER), lines 508-531) swaps the third slot for MEOWTH (L14) morn/day and slots 2/3 for MEOWTH/BELLSPROUT at nite.

Water: data/wild/kanto_water.asm:12 def_water_wildmons ROUTE_6, 2 percent - L10 PSYDUCK, L5 PSYDUCK, L10 GOLDUCK.

Fishing group is FISHGROUP_POND (data/maps/maps.asm:294).

MAP_ROUTE_6_UNDERGROUND_PATH_ENTRANCE

  • Script: maps/Route6UndergroundPathEntrance.asm
  • Blocks: shared maps/UndergroundPathEntrance.blk (data/maps/blocks.asm:466)
  • Header: data/maps/maps.asm:306 -> TILESET_GATE, GATE, LANDMARK_ROUTE_6, MUSIC_ROUTE_3, phone FALSE, PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:283 map_const ROUTE_6_UNDERGROUND_PATH_ENTRANCE, 4, 4
  • Connections: none (indoor)

Warps

idx x y destination map dest warp
1 3 7 ROUTE_6 1
2 4 7 ROUTE_6 1
3 4 3 UNDERGROUND_PATH 2

No coord events, no bg events, no object events. Nothing gates warp 3 from the inside - the only block is the NPC body on Route 6.

MAP_ROUTE_6_SAFFRON_GATE

  • Script: maps/Route6SaffronGate.asm
  • Blocks: shared maps/NorthSouthGate.blk (data/maps/blocks.asm:210,215)
  • Header: data/maps/maps.asm:305 -> TILESET_GATE, GATE, LANDMARK_ROUTE_6, MUSIC_ROUTE_3, phone FALSE, PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:282 map_const ROUTE_6_SAFFRON_GATE, 5, 4
  • Scene scripts: one entry, scene_script Route6SaffronGateNoopScene with no scene-id argument (maps/Route6SaffronGate.asm:6), so no SCENE_* constant is generated and the scene is a bare end.

Warps

idx x y destination map dest warp
1 4 0 SAFFRON_CITY 12
2 5 0 SAFFRON_CITY 13
3 4 7 ROUTE_6 2
4 5 7 ROUTE_6 2

Coord events - none. BG events - none.

Object events

const sprite x y movement type script label event flag
ROUTE6SAFFRONGATE_OFFICER SPRITE_OFFICER 0 4 SPRITEMOVEDATA_STANDING_RIGHT OBJECTTYPE_SCRIPT Route6SaffronGuardScript (59:523c) -1 (always)

Scripts of interest

  • Route6SaffronGuardScript (maps/Route6SaffronGate.asm:13, sym 59:523c): faceplayer / opentext / checkevent EVENT_RETURNED_MACHINE_PART / iftrue .ReturnedPart. Before the Power Plant is fixed he explains the Magnet Train is dead; after, a one-liner. He stands at (0, 4), off the walking lane - he never blocks passage.

MAP_SAFFRON_CITY

  • Script: maps/SaffronCity.asm
  • Blocks: maps/SaffronCity.blk (data/maps/blocks.asm:24)
  • Header: data/maps/maps.asm:490 -> TILESET_KANTO, TOWN, LANDMARK_SAFFRON_CITY, MUSIC_VIRIDIAN_CITY, phone FALSE, PALETTE_AUTO, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:454 map_const SAFFRON_CITY, 20, 18 (40x36 cells)
  • Connections: data/maps/attributes.asm:350-354 - north Route5 (+5), south Route6 (+5), west Route7 (+9), east Route8 (+9)
  • Spawn / fly: data/maps/spawn_points.asm:21 spawn SAFFRON_CITY, 9, 30; data/maps/flypoints.asm:26 db LANDMARK_SAFFRON_CITY, SPAWN_SAFFRON

Warps (def_warp_events)

idx x y destination map dest warp
1 26 3 FIGHTING_DOJO 1
2 34 3 SAFFRON_GYM 1
3 25 11 SAFFRON_MART 2
4 9 29 SAFFRON_POKECENTER_1F 1
5 27 29 MR_PSYCHICS_HOUSE 1
6 8 3 SAFFRON_MAGNET_TRAIN_STATION 2
7 18 21 SILPH_CO_1F 1
8 9 11 COPYCATS_HOUSE_1F 1
9 18 3 ROUTE_5_SAFFRON_GATE 3
10 0 24 ROUTE_7_SAFFRON_GATE 3
11 0 25 ROUTE_7_SAFFRON_GATE 4
12 16 33 ROUTE_6_SAFFRON_GATE 1
13 17 33 ROUTE_6_SAFFRON_GATE 2
14 39 22 ROUTE_8_SAFFRON_GATE 1
15 39 23 ROUTE_8_SAFFRON_GATE 2

Coord events - none.

BG events

x y type script/item
21 5 BGEVENT_READ SaffronCitySign
33 5 BGEVENT_READ SaffronGymSign
25 5 BGEVENT_READ FightingDojoSign
15 21 BGEVENT_READ SilphCoSign
25 29 BGEVENT_READ MrPsychicsHouseSign
11 5 BGEVENT_READ SaffronCityMagnetTrainStationSign
10 29 BGEVENT_READ SaffronCityPokecenterSign (jumpstd PokecenterSignScript)
26 11 BGEVENT_READ SaffronCityMartSign (jumpstd MartSignScript)

No hidden items on this map.

Object events

const sprite x y movement type script label event flag
SAFFRONCITY_LASS1 SPRITE_LASS 7 14 SPRITEMOVEDATA_WALK_LEFT_RIGHT (rx 2) OBJECTTYPE_SCRIPT SaffronCityLass1Script -1
SAFFRONCITY_POKEFAN_M SPRITE_POKEFAN_M 19 30 SPRITEMOVEDATA_WALK_LEFT_RIGHT (rx 2) OBJECTTYPE_SCRIPT SaffronCityPokefanMScript -1
SAFFRONCITY_COOLTRAINER_M SPRITE_COOLTRAINER_M 32 7 SPRITEMOVEDATA_WALK_LEFT_RIGHT (rx 1) OBJECTTYPE_SCRIPT SaffronCityCooltrainerMScript -1
SAFFRONCITY_COOLTRAINER_F SPRITE_COOLTRAINER_F 20 24 SPRITEMOVEDATA_WALK_LEFT_RIGHT (rx 2) OBJECTTYPE_SCRIPT SaffronCityCooltrainerFScript -1
SAFFRONCITY_FISHER SPRITE_FISHER 27 12 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT SaffronCityFisherScript -1
SAFFRONCITY_YOUNGSTER1 SPRITE_YOUNGSTER 15 19 SPRITEMOVEDATA_WALK_UP_DOWN (ry 1) OBJECTTYPE_SCRIPT SaffronCityYoungster1Script -1
SAFFRONCITY_YOUNGSTER2 SPRITE_YOUNGSTER 35 22 SPRITEMOVEDATA_WANDER (rx 1, ry 1) OBJECTTYPE_SCRIPT SaffronCityYoungster2Script -1
SAFFRONCITY_LASS2 SPRITE_LASS 19 8 SPRITEMOVEDATA_SPINRANDOM_SLOW OBJECTTYPE_SCRIPT SaffronCityLass2Script -1

Every Saffron City NPC is OBJECTTYPE_SCRIPT; none of them blocks a warp tile.

Scripts of interest

  • SaffronCityFlypointCallback (maps/SaffronCity.asm:17), registered as callback MAPCALLBACK_NEWMAP: setflag ENGINE_FLYPOINT_SAFFRON / endcallback. Walking in from the Route 6 gate is what unlocks Fly to Saffron - there is no NPC or item involved.
  • SaffronCityLass1Script, SaffronCityPokefanMScript, SaffronCityFisherScript all branch on checkevent EVENT_RETURNED_MACHINE_PART. Purely dialogue; useful only as a state probe.

Flags and events

constant defined in read/written by meaning for a bot
ENGINE_FLYPOINT_SAFFRON constants/engine_flags.asm:74 set by SaffronCityFlypointCallback Fly destination unlocked; also the SPAWN_SAFFRON blackout target once the player has been here
EVENT_RETURNED_MACHINE_PART constants/event_flags.asm:200 set in maps/PowerPlant.asm:161; read by four Saffron scripts and Route6SaffronGuardScript Not set in this section. Its absence is what keeps the Magnet Train shut

Items - none directly on the city map.

Trainers - none.

Wild encounters - none. SAFFRON_CITY has no entry in data/wild/kanto_grass.asm, kanto_water.asm, fish.asm or treemons.asm (grep over data/wild/ for SAFFRON returns nothing).

MAP_MR_PSYCHICS_HOUSE

  • Script: maps/MrPsychicsHouse.asm
  • Blocks: shared maps/House1.blk (data/maps/blocks.asm:195,201)
  • Header: data/maps/maps.asm:496 -> TILESET_HOUSE, INDOOR, LANDMARK_SAFFRON_CITY, MUSIC_VIRIDIAN_CITY, phone FALSE, PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:460 map_const MR_PSYCHICS_HOUSE, 4, 4

Warps

idx x y destination map dest warp
1 2 7 SAFFRON_CITY 5
2 3 7 SAFFRON_CITY 5

Coord events - none.

BG events

x y type script/item
0 1 BGEVENT_READ MrPsychicsHouseBookshelf (jumpstd DifficultBookshelfScript)
1 1 BGEVENT_READ MrPsychicsHouseBookshelf

Object events

const sprite x y movement type script label event flag
MRPSYCHICSHOUSE_FISHING_GURU SPRITE_FISHING_GURU 5 3 SPRITEMOVEDATA_STANDING_LEFT OBJECTTYPE_SCRIPT MrPsychic (61:4b15) -1

Scripts of interest

  • MrPsychic (maps/MrPsychicsHouse.asm:9, sym 61:4b15): faceplayer / opentext / checkevent EVENT_GOT_TM29_PSYCHIC / iftrue .AlreadyGotItem / writetext MrPsychicText1 / promptbutton / verbosegiveitem TM_PSYCHIC_M / iffalse .Done / setevent EVENT_GOT_TM29_PSYCHIC / .AlreadyGotItem: writetext MrPsychicText2 / waitbutton / .Done: closetext / end. One verbosegiveitem; a full bag drops through .Done without setting the flag, so a bot must re-talk after making room.

Flags and events

constant defined in read/written by meaning for a bot
EVENT_GOT_TM29_PSYCHIC constants/event_flags.asm:226 read+set by MrPsychic One-shot guard on TM29

Items

item how obtained source (label / bg_event / hidden) one-time flag
TM_PSYCHIC_M (TM29, constants/item_constants.asm:250 add_tm PSYCHIC_M ; dd) talk to MRPSYCHICSHOUSE_FISHING_GURU at (5, 3) MrPsychic, verbosegiveitem EVENT_GOT_TM29_PSYCHIC

MAP_SILPH_CO_1F

  • Script: maps/SilphCo1F.asm
  • Blocks: maps/SilphCo1F.blk (data/maps/blocks.asm:874)
  • Header: data/maps/maps.asm:498 -> TILESET_FACILITY, INDOOR, LANDMARK_SAFFRON_CITY, MUSIC_VIRIDIAN_CITY, phone FALSE, PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:462 map_const SILPH_CO_1F, 8, 4

Warps

idx x y destination map dest warp
1 2 7 SAFFRON_CITY 7
2 3 7 SAFFRON_CITY 7

Coord events - none. BG events - none.

Object events

const sprite x y movement type script label event flag
SILPHCO1F_RECEPTIONIST SPRITE_RECEPTIONIST 4 2 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT SilphCoReceptionistScript -1
SILPHCO1F_OFFICER SPRITE_OFFICER 13 1 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT SilphCoOfficerScript (61:4f81) -1

Scripts of interest

  • SilphCoOfficerScript (maps/SilphCo1F.asm:13, sym 61:4f81): faceplayer / opentext / checkevent EVENT_GOT_UP_GRADE / iftrue .GotUpGrade / writetext SilphCoOfficerText / promptbutton / verbosegiveitem UP_GRADE / iffalse .NoRoom / setevent EVENT_GOT_UP_GRADE / .GotUpGrade: writetext ... / waitbutton / .NoRoom: closetext / end. Same full-bag shape as Mr. Psychic. There is no upstairs on this map at all - the "man blocking the stairway" is (13, 1), standing on the only path north; nothing scripted opens it.

Flags and events

constant defined in read/written by meaning for a bot
EVENT_GOT_UP_GRADE constants/event_flags.asm:221 read+set by SilphCoOfficerScript One-shot guard on Up-Grade

Items

item how obtained source (label / bg_event / hidden) one-time flag
UP_GRADE (constants/item_constants.asm:180, $ac) talk to SILPHCO1F_OFFICER at (13, 1) SilphCoOfficerScript, verbosegiveitem EVENT_GOT_UP_GRADE

MAP_SAFFRON_MAGNET_TRAIN_STATION

  • Script: maps/SaffronMagnetTrainStation.asm
  • Blocks: maps/SaffronMagnetTrainStation.blk
  • Header: data/maps/maps.asm:497 -> TILESET_TRAIN_STATION, INDOOR, LANDMARK_SAFFRON_CITY, MUSIC_VIRIDIAN_CITY, phone FALSE, PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:461 map_const SAFFRON_MAGNET_TRAIN_STATION, 10, 9
  • Scene variable: data/maps/scenes.asm:17 scene_var SAFFRON_MAGNET_TRAIN_STATION, wSaffronMagnetTrainStationSceneID

Warps

idx x y destination map dest warp
1 8 17 SAFFRON_CITY 6
2 9 17 SAFFRON_CITY 6
3 6 5 GOLDENROD_MAGNET_TRAIN_STATION 4
4 11 5 GOLDENROD_MAGNET_TRAIN_STATION 3

Coord events

scene x y script label effect
SCENE_SAFFRONMAGNETTRAINSTATION_ARRIVE_FROM_GOLDENROD (= 0, generated by the scene_script macro at maps/SaffronMagnetTrainStation.asm:9) 11 6 Script_ArriveFromGoldenrod Arrival cutscene when riding in from Goldenrod; not reachable in this section

BG events - none.

Object events

const sprite x y movement type script label event flag
SAFFRONMAGNETTRAINSTATION_OFFICER SPRITE_OFFICER 9 9 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT SaffronMagnetTrainStationOfficerScript (61:4bc2) -1
SAFFRONMAGNETTRAINSTATION_GYM_GUIDE SPRITE_GYM_GUIDE 10 14 SPRITEMOVEDATA_WANDER (1,1) OBJECTTYPE_SCRIPT SaffronMagnetTrainStationGymGuideScript -1
SAFFRONMAGNETTRAINSTATION_TEACHER SPRITE_TEACHER 6 11 SPRITEMOVEDATA_STANDING_RIGHT OBJECTTYPE_SCRIPT SaffronMagnetTrainStationTeacherScript EVENT_SAFFRON_TRAIN_STATION_POPULATION
SAFFRONMAGNETTRAINSTATION_LASS SPRITE_LASS 6 10 SPRITEMOVEDATA_STANDING_UP OBJECTTYPE_SCRIPT SaffronMagnetTrainStationLassScript EVENT_SAFFRON_TRAIN_STATION_POPULATION

Scripts of interest

  • SaffronMagnetTrainStationOfficerScript (maps/SaffronMagnetTrainStation.asm:16, sym 61:4bc2): checkevent EVENT_RESTORED_POWER_TO_KANTO / iftrue .MagnetTrainToGoldenrod, else "the MAGNET TRAIN isn't operating now" and end. The ride arm additionally runs yesorno, checkitem PASS, two applymovements, setval TRUE / special MagnetTrain / warpcheck / newloadmap MAPSETUP_TRAIN. In this section both EVENT_RESTORED_POWER_TO_KANTO and PASS are missing, so the officer is a dead end.

Flags and events

constant defined in read/written by meaning for a bot
EVENT_RESTORED_POWER_TO_KANTO constants/event_flags.asm:204 set at maps/PowerPlant.asm:165; read by the officer script Gate on the Magnet Train being operable at all
EVENT_SAFFRON_TRAIN_STATION_POPULATION constants/event_flags.asm:1300 cleared at maps/PowerPlant.asm:160 While set (the state in this section) the Teacher and Lass are hidden - the station looks empty on purpose

MAP_SAFFRON_MART

  • Script: maps/SaffronMart.asm
  • Blocks: shared maps/Mart.blk (data/maps/blocks.asm:333,335)
  • Header: data/maps/maps.asm:493 -> TILESET_MART, INDOOR, LANDMARK_SAFFRON_CITY, MUSIC_VIRIDIAN_CITY, phone FALSE, PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:457 map_const SAFFRON_MART, 6, 4

Warps

idx x y destination map dest warp
1 2 7 SAFFRON_CITY 3
2 3 7 SAFFRON_CITY 3

Coord events - none. BG events - none.

Object events

const sprite x y movement type script label event flag
SAFFRONMART_CLERK SPRITE_CLERK 1 3 SPRITEMOVEDATA_STANDING_RIGHT OBJECTTYPE_SCRIPT SaffronMartClerkScript -1
SAFFRONMART_COOLTRAINER_M SPRITE_COOLTRAINER_M 7 2 SPRITEMOVEDATA_SPINRANDOM_SLOW OBJECTTYPE_SCRIPT SaffronMartCooltrainerMScript -1
SAFFRONMART_COOLTRAINER_F SPRITE_COOLTRAINER_F 7 6 SPRITEMOVEDATA_WALK_LEFT_RIGHT (rx 1) OBJECTTYPE_SCRIPT SaffronMartCooltrainerFScript -1

Scripts of interest

  • SaffronMartClerkScript: opentext / pokemart MARTTYPE_STANDARD, MART_SAFFRON / closetext / end.

Items - shop stock, data/items/marts.asm:362 MartSaffron: GREAT_BALL, ULTRA_BALL, HYPER_POTION, MAX_POTION, FULL_HEAL, X_ATTACK, X_DEFEND, FLOWER_MAIL.

MAP_FIGHTING_DOJO

  • Script: maps/FightingDojo.asm
  • Blocks: maps/FightingDojo.blk (data/maps/blocks.asm:871)
  • Header: data/maps/maps.asm:491 -> TILESET_TRAIN_STATION, INDOOR, LANDMARK_SAFFRON_CITY, MUSIC_VIRIDIAN_CITY, phone FALSE, PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:455 map_const FIGHTING_DOJO, 5, 6

Warps

idx x y destination map dest warp
1 4 11 SAFFRON_CITY 1
2 5 11 SAFFRON_CITY 1

Coord events - none.

BG events

x y type script/item
4 0 BGEVENT_READ FightingDojoSign1
5 0 BGEVENT_READ FightingDojoSign2

Object events

const sprite x y movement type script label event flag
FIGHTINGDOJO_BLACK_BELT SPRITE_BLACK_BELT 4 4 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT FightingDojoBlackBelt -1
FIGHTINGDOJO_POKE_BALL SPRITE_POKE_BALL 3 1 SPRITEMOVEDATA_STILL OBJECTTYPE_ITEMBALL FightingDojoFocusBand (61:400b) EVENT_PICKED_UP_FOCUS_BAND

Scripts of interest

  • FightingDojoFocusBand (maps/FightingDojo.asm:19, sym 61:400b): the two-byte itemball FOCUS_BAND struct (macro at macros/scripts/maps.asm:154, quantity defaults to 1), not a script. The engine's own item-ball path runs it.
  • There are no trainers in the Fighting Dojo in Gen 2. FightingDojoBlackBeltText explains the Karate King is away in a Johto cave (Rock Tunnel-era content elsewhere), so nothing here fights back.

Items

item how obtained source (label / bg_event / hidden) one-time flag
FOCUS_BAND (constants/item_constants.asm:127, $77) walk onto / press A at (3, 1) FightingDojoFocusBand (OBJECTTYPE_ITEMBALL) EVENT_PICKED_UP_FOCUS_BAND (constants/event_flags.asm:1312) - once set the ball object is masked

MAP_SAFFRON_GYM

  • Script: maps/SaffronGym.asm
  • Blocks: maps/SaffronGym.blk (data/maps/blocks.asm:861)
  • Header: data/maps/maps.asm:492 -> TILESET_UNDERGROUND, INDOOR, LANDMARK_SAFFRON_CITY, MUSIC_GYM, phone TRUE (phone calls suppressed), PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:456 map_const SAFFRON_GYM, 10, 9 (20x18 cells)
  • Connections: none

Warps (def_warp_events, maps/SaffronGym.asm:294-326) - warps 1-2 are the street doors; warps 3-32 are the 30 teleport pads. Every pad's destination is SAFFRON_GYM and the player lands on the destination warp's own tile.

idx x y destination map dest warp
1 8 17 SAFFRON_CITY 2
2 9 17 SAFFRON_CITY 2
3 11 15 SAFFRON_GYM 18
4 19 15 SAFFRON_GYM 19
5 19 11 SAFFRON_GYM 20
6 1 11 SAFFRON_GYM 21
7 5 3 SAFFRON_GYM 22
8 11 5 SAFFRON_GYM 23
9 1 15 SAFFRON_GYM 24
10 19 3 SAFFRON_GYM 25
11 15 17 SAFFRON_GYM 26
12 5 17 SAFFRON_GYM 27
13 5 9 SAFFRON_GYM 28
14 9 3 SAFFRON_GYM 29
15 15 9 SAFFRON_GYM 30
16 15 5 SAFFRON_GYM 31
17 1 5 SAFFRON_GYM 32
18 19 17 SAFFRON_GYM 3
19 19 9 SAFFRON_GYM 4
20 1 9 SAFFRON_GYM 5
21 5 5 SAFFRON_GYM 6
22 11 3 SAFFRON_GYM 7
23 1 17 SAFFRON_GYM 8
24 19 5 SAFFRON_GYM 9
25 15 15 SAFFRON_GYM 10
26 5 15 SAFFRON_GYM 11
27 5 11 SAFFRON_GYM 12
28 9 5 SAFFRON_GYM 13
29 15 11 SAFFRON_GYM 14
30 15 3 SAFFRON_GYM 15
31 1 3 SAFFRON_GYM 16
32 11 9 SAFFRON_GYM 17

Teleporter graph, resolved to landing coordinates. Every pair is mutual, so the graph is 15 undirected edges. Room labels are derived from the pad clusters and the object coordinates; they are a reading aid, the coordinates are the ground truth.

room (occupant) pads (x, y)
ENTRANCE (doors (8,17)/(9,17), guide (9,14), statue (8,15)) (11,15)
BL (Psychic Franklin (3,16)) (1,15) (5,15) (1,17) (5,17)
BR (Medium Rebecca (17,16)) (15,15) (19,15) (15,17) (19,17)
ML (1,9) (5,9) (1,11) (5,11)
CENTER (Sabrina (9,8)) (11,9)
MR (15,9) (19,9) (15,11) (19,11)
TL (Medium Doris (3,4)) (1,3) (5,3) (1,5) (5,5)
TC (9,3) (11,3) (9,5) (11,5)
TR (Psychic Jared (17,4)) (15,3) (19,3) (15,5) (19,5)
step on pad warp idx lands at room reached
(11,15) ENTRANCE 3 (19,17) BR
(19,17) BR 18 (11,15) ENTRANCE
(19,15) BR 4 (19,9) MR
(19,9) MR 19 (19,15) BR
(15,17) BR 11 (5,15) BL
(5,15) BL 26 (15,17) BR
(15,15) BR 25 (19,3) TR
(19,3) TR 10 (15,15) BR
(1,15) BL 9 (19,5) TR
(19,5) TR 24 (1,15) BL
(1,17) BL 23 (11,5) TC
(11,5) TC 8 (1,17) BL
(5,17) BL 12 (5,11) ML
(5,11) ML 27 (5,17) BL
(1,9) ML 20 (19,11) MR
(19,11) MR 5 (1,9) ML
(5,9) ML 13 (9,5) TC
(9,5) TC 28 (5,9) ML
(1,11) ML 6 (5,5) TL
(5,5) TL 21 (1,11) ML
(15,9) MR 15 (15,3) TR
(15,3) TR 30 (15,9) MR
(15,11) MR 29 (9,3) TC
(9,3) TC 14 (15,11) MR
(5,3) TL 7 (11,3) TC
(11,3) TC 22 (5,3) TL
(1,3) TL 31 (15,5) TR
(15,5) TR 16 (1,3) TL
(1,5) TL 17 (11,9) CENTER (Sabrina)
(11,9) CENTER 32 (1,5) TL

(1,5) in the top-left room is the only pad that reaches Sabrina, and (11,9) is the only way out of her chamber. This matches the walkthrough's "go to the bottom left teleporter and you'll go straight to the gym leader".

Coord events - none. The gym has no trip-wires; every transition is a warp tile.

BG events

x y type script/item
8 15 BGEVENT_READ SaffronGymStatue (61:4170)

Object events

const sprite x y movement type sight script label event flag
SAFFRONGYM_SABRINA SPRITE_SABRINA 9 8 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT 0 SaffronGymSabrinaScript (61:40cf) -1
SAFFRONGYM_GRANNY1 SPRITE_GRANNY 17 16 SPRITEMOVEDATA_SPINRANDOM_FAST OBJECTTYPE_TRAINER 3 TrainerMediumRebecca (61:410c) -1
SAFFRONGYM_YOUNGSTER1 SPRITE_YOUNGSTER 3 16 SPRITEMOVEDATA_SPINRANDOM_FAST OBJECTTYPE_TRAINER 3 TrainerPsychicFranklin (61:4120) -1
SAFFRONGYM_GRANNY2 SPRITE_GRANNY 3 4 SPRITEMOVEDATA_SPINRANDOM_FAST OBJECTTYPE_TRAINER 2 TrainerMediumDoris (61:4134) -1
SAFFRONGYM_YOUNGSTER2 SPRITE_YOUNGSTER 17 4 SPRITEMOVEDATA_SPINRANDOM_FAST OBJECTTYPE_TRAINER 2 TrainerPsychicJared (61:4148) -1
SAFFRONGYM_GYM_GUIDE SPRITE_GYM_GUIDE 9 14 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT 0 SaffronGymGuideScript -1

All four trainers spin (SPINRANDOM_FAST), so their line of sight rotates - a bot cannot assume a fixed approach lane; walking into the room will trigger them.

Scripts of interest

  • SaffronGymSabrinaScript (maps/SaffronGym.asm:14, sym 61:40cf): faceplayer / opentext / checkflag ENGINE_MARSHBADGE / iftrue .FightDone / writetext SabrinaIntroText / waitbutton / closetext / winlosstext SabrinaWinLossText, 0 / loadtrainer SABRINA, SABRINA1 / startbattle / reloadmapafterbattle / then a burst of five setevents: EVENT_BEAT_SABRINA, EVENT_BEAT_MEDIUM_REBECCA, EVENT_BEAT_MEDIUM_DORIS, EVENT_BEAT_PSYCHIC_FRANKLIN, EVENT_BEAT_PSYCHIC_JARED / opentext / writetext ReceivedMarshBadgeText / playsound SFX_GET_BADGE / waitsfx / setflag ENGINE_MARSHBADGE / writetext SabrinaMarshBadgeText / waitbutton / closetext / end. Two consequences a bot should exploit: the four gym trainers are auto-cleared when Sabrina falls, so they are entirely skippable; and the badge is a setflag on ENGINE_MARSHBADGE, which is also the re-entry guard (.FightDone).
  • TrainerMediumRebecca / TrainerPsychicFranklin / TrainerMediumDoris / TrainerPsychicJared (maps/SaffronGym.asm:47,58,69,80): each is a trainer CLASS, ID, EVENT_BEAT_*, SeenText, BeatenText, 0, .Script struct (macros/scripts/maps.asm:142; field order is group, id, flag, seen, win, loss, after) followed by an endifjustbattled / opentext / writetext ...AfterBattleText / waitbutton / closetext / end after-battle script.
  • SaffronGymStatue (maps/SaffronGym.asm:107, sym 61:4170): checkflag ENGINE_MARSHBADGE / iftrue .Beaten / jumpstd GymStatue1Script; the beaten arm does gettrainername STRING_BUFFER_4, SABRINA, SABRINA1 then jumpstd GymStatue2Script. Handy as a cheap post-badge assertion.
  • SaffronGymGuideScript (maps/SaffronGym.asm:91): branches on checkevent EVENT_BEAT_SABRINA; no items, no flags written.

Flags and events

constant defined in read/written by meaning for a bot
ENGINE_MARSHBADGE constants/engine_flags.asm:52 (bit 5 of wKantoBadges; Kanto order is Boulder, Cascade, Thunder, Rainbow, Soul, Marsh, Volcano, Earth) checkflag in SaffronGymSabrinaScript and SaffronGymStatue; setflag after the win The section's terminal postcondition
EVENT_BEAT_SABRINA constants/event_flags.asm:720 set by SaffronGymSabrinaScript; read by SaffronGymGuideScript Leader defeated
EVENT_BEAT_MEDIUM_REBECCA constants/event_flags.asm:935 trainer struct flag; also force-set by the Sabrina script Rebecca cleared
EVENT_BEAT_MEDIUM_DORIS constants/event_flags.asm:936 as above Doris cleared
EVENT_BEAT_PSYCHIC_FRANKLIN constants/event_flags.asm:564 as above Franklin cleared
EVENT_BEAT_PSYCHIC_JARED constants/event_flags.asm:573 as above Jared cleared

Items - none in the gym.

Trainers

const class id party (data/trainers/parties.asm label) script label rematch/phone
SABRINA / SABRINA1 SABRINA (constants/trainer_constants.asm:309, class 23) 1 SabrinaGroup ; SABRINA (1) (data/trainers/parties.asm:1400-1406), TRAINERTYPE_MOVES: L46 ESPEON (Sand-Attack, Quick Attack, Swift, Psychic), L46 MR__MIME (Barrier, Reflect, Baton Pass, Psychic), L48 ALAKAZAM (Recover, Future Sight, Psychic, Reflect) SaffronGymSabrinaScript none; leader (data/trainers/leaders.asm:29)
MEDIUM / REBECCA MEDIUM 6 (constants/trainer_constants.asm:590) MediumGroup ; MEDIUM (6): L35 DROWZEE, L35 HYPNO TrainerMediumRebecca none
PSYCHIC_T / FRANKLIN PSYCHIC_T (class 34) 2 (constants/trainer_constants.asm:513) PsychicGroup ; PSYCHIC_T (2) (data/trainers/parties.asm:2516): L37 KADABRA TrainerPsychicFranklin none
MEDIUM / DORIS MEDIUM 7 (constants/trainer_constants.asm:591) MediumGroup ; MEDIUM (7): L34 SLOWPOKE, L36 SLOWBRO TrainerMediumDoris none
PSYCHIC_T / JARED PSYCHIC_T 11 (constants/trainer_constants.asm:522) PsychicGroup ; PSYCHIC_T (11) (data/trainers/parties.asm:2569): L32 MR__MIME, L32 EXEGGCUTE, L35 EXEGGCUTE TrainerPsychicJared none

Prize money: ComputeTrainerReward (engine/battle/read_trainer_party.asm:300) is base reward x last mon's level, and engine/battle/core.asm:2344-2358 pays that quarter out four times, so the visible payout is 4 x base x level. Base rewards: Sabrina 25 (data/trainers/attributes.asm:211), Medium 10 (:343), Psychic T 8 (:313). That reproduces the walkthrough's 4800G / 1400G / 1440G / 1184G / 1120G exactly. Sabrina also carries a HYPER_POTION as an AI item (data/trainers/attributes.asm:210).

Wild encounters - none (indoor gym).

MAP_SAFFRON_POKECENTER_1F

  • Script: maps/SaffronPokecenter1F.asm
  • Blocks: shared maps/Pokecenter1F.blk (data/maps/blocks.asm:362,364)
  • Header: data/maps/maps.asm:494 -> TILESET_POKECENTER, INDOOR, LANDMARK_SAFFRON_CITY, MUSIC_POKEMON_CENTER, phone FALSE, PALETTE_DAY, FISHGROUP_SHORE
  • Dimensions: constants/map_constants.asm:458 map_const SAFFRON_POKECENTER_1F, 5, 4

Warps

idx x y destination map dest warp
1 3 7 SAFFRON_CITY 4
2 4 7 SAFFRON_CITY 4
3 0 7 POKECENTER_2F 1

Object events (nurse only listed; the rest are flavour)

const sprite x y movement type script label event flag
SAFFRONPOKECENTER1F_NURSE SPRITE_NURSE 3 1 SPRITEMOVEDATA_STANDING_DOWN OBJECTTYPE_SCRIPT SaffronPokecenter1FNurseScript (jumpstd PokecenterNurseScript) -1
SAFFRONPOKECENTER1F_TEACHER SPRITE_TEACHER 7 2 SPRITEMOVEDATA_WANDER (1,1) OBJECTTYPE_SCRIPT SaffronPokecenter1FTeacherScript -1
SAFFRONPOKECENTER1F_FISHER SPRITE_FISHER 8 6 SPRITEMOVEDATA_STANDING_LEFT OBJECTTYPE_SCRIPT SaffronPokecenter1FFisherScript -1
SAFFRONPOKECENTER1F_YOUNGSTER SPRITE_YOUNGSTER 1 4 SPRITEMOVEDATA_SPINRANDOM_SLOW OBJECTTYPE_SCRIPT SaffronPokecenter1FYoungsterScript -1

3. Blockers and gates

Gate Enforced by (file:label) Requirement Unlock condition
Underground Path (Route 6 warp 1 at (17, 3)) maps/Route6.asm:43 - ROUTE6_POKEFAN_M object standing at (17, 4) with event flag EVENT_ROUTE_5_6_POKEFAN_M_BLOCKS_UNDERGROUND_PATH; visibility decided by CheckObjectFlag, engine/overworld/map_objects_2.asm:32 Nothing the player can do in this section maps/PowerPlant.asm:164 setevent EVENT_ROUTE_5_6_POKEFAN_M_BLOCKS_UNDERGROUND_PATH (flag set = object masked), which is part of returning the MACHINE_PART
Magnet Train Saffron -> Goldenrod maps/SaffronMagnetTrainStation.asm:19 checkevent EVENT_RESTORED_POWER_TO_KANTO, then checkitem PASS at :30 EVENT_RESTORED_POWER_TO_KANTO and PASS in bag maps/PowerPlant.asm:165 sets the event; the PASS comes from elsewhere. Both false here, so the officer only prints "isn't operating now"
Silph Co. upper floors maps/SilphCo1F.asm:69 - SILPHCO1F_OFFICER object at (13, 1) with event flag -1 (never hides). No stairs warp exists on SilphCo1F at all Permanently blocked in Gen 2 Never; this is not a gate that opens
Saffron Gym maze The 30 pad warps at maps/SaffronGym.asm:296-326. Pads are teleport panels (COLL_WARP_PANEL-class tiles), so they fire on landing, not on a directional press Navigation only - no badge, item or flag check anywhere in SaffronGym.asm n/a. The single route to Sabrina is (11,15) -> (19,17) -> ... -> (1,5) -> (11,9); see the pad table
MARSHBADGE re-fight guard maps/SaffronGym.asm:17 checkflag ENGINE_MARSHBADGE / iftrue .FightDone Badge not yet held Beating Sabrina once; afterwards she only talks
Gym trainers Each trainer struct's EVENT_BEAT_* flag; the trainer only challenges while its flag is clear Walking into their sight cone (sight 3 for Rebecca/Franklin, 2 for Doris/Jared) Beating them, or beating Sabrina, which sets all four flags at maps/SaffronGym.asm:27-30

No HM field move is required anywhere in this section - no engine/overworld/cut.asm, surf.asm, strength.asm or whirlpool.asm check is reachable from these maps. The Bicycle the walkthrough recommends is convenience only.

4. Bot checklist

Coordinates are asm cell coordinates on the named map. "Warp N" means the def_warp_events index in that map's table.

  1. MAP_ROUTE_6 - walk north along the route to warp 2 at (6, 1). Precondition: none. Postcondition: on MAP_ROUTE_6_SAFFRON_GATE warp 3 (4, 7).
    • Optional: read the sign at (19, 5). Do not try warp 1 at (17, 3); ROUTE6_POKEFAN_M occupies (17, 4) while EVENT_ROUTE_5_6_POKEFAN_M_BLOCKS_UNDERGROUND_PATH is clear.
  2. MAP_ROUTE_6_SAFFRON_GATE - walk from (4, 7) to warp 1 at (4, 0). Postcondition: on MAP_SAFFRON_CITY warp 12 (16, 33); MAPCALLBACK_NEWMAP fires and ENGINE_FLYPOINT_SAFFRON becomes set.
  3. MAP_SAFFRON_CITY - walk to warp 5 at (27, 29). Enter MAP_MR_PSYCHICS_HOUSE.
  4. MAP_MR_PSYCHICS_HOUSE - talk to MRPSYCHICSHOUSE_FISHING_GURU at (5, 3) (approach from (4, 3) facing right, he faces left). Precondition: EVENT_GOT_TM29_PSYCHIC clear and TM pocket has room. Postcondition: TM_PSYCHIC_M in bag, EVENT_GOT_TM29_PSYCHIC set. Exit warp 1 (2, 7).
  5. MAP_SAFFRON_CITY - walk to warp 7 at (18, 21). Enter MAP_SILPH_CO_1F.
  6. MAP_SILPH_CO_1F - talk to SILPHCO1F_OFFICER at (13, 1). Precondition: EVENT_GOT_UP_GRADE clear, item pocket has room. Postcondition: UP_GRADE in bag, EVENT_GOT_UP_GRADE set. Exit warp 1 (2, 7).
  7. (Optional, dialogue only) MAP_SAFFRON_CITY warp 6 at (8, 3) -> MAP_SAFFRON_MAGNET_TRAIN_STATION; talk to SAFFRONMAGNETTRAINSTATION_OFFICER at (9, 9). Expect the "isn't operating now" arm because EVENT_RESTORED_POWER_TO_KANTO is clear. Exit warp 1 (8, 17).
  8. (Optional) MAP_SAFFRON_CITY warp 3 at (25, 11) -> MAP_SAFFRON_MART; talk to SAFFRONMART_CLERK at (1, 3) for MART_SAFFRON. Exit warp 1 (2, 7).
  9. MAP_SAFFRON_CITY - warp 1 at (26, 3) -> MAP_FIGHTING_DOJO. Walk onto / face FIGHTINGDOJO_POKE_BALL at (3, 1). Precondition: EVENT_PICKED_UP_FOCUS_BAND clear. Postcondition: FOCUS_BAND in bag, EVENT_PICKED_UP_FOCUS_BAND set (ball object masked from then on). Exit warp 1 (4, 11).
  10. (Optional heal) MAP_SAFFRON_CITY warp 4 at (9, 29) -> MAP_SAFFRON_POKECENTER_1F; talk to nurse at (3, 1). Exit warp 1 (3, 7).
  11. MAP_SAFFRON_CITY - warp 2 at (34, 3) -> MAP_SAFFRON_GYM, landing on warp 1 (8, 17).
  12. MAP_SAFFRON_GYM - walk to the pad at (11, 15). Warps to (19, 17).
  13. MAP_SAFFRON_GYM BR room - battle SAFFRONGYM_GRANNY1 (Medium Rebecca) at (17, 16), sight 3. Precondition: EVENT_BEAT_MEDIUM_REBECCA clear. Postcondition: that flag set. (Skippable: her flag is force-set by the Sabrina script.)
  14. MAP_SAFFRON_GYM - step on pad (15, 17). Warps to (5, 15).
  15. MAP_SAFFRON_GYM BL room - battle SAFFRONGYM_YOUNGSTER1 (Psychic Franklin) at (3, 16), sight 3. Postcondition: EVENT_BEAT_PSYCHIC_FRANKLIN set.
  16. MAP_SAFFRON_GYM - step on pad (1, 15). Warps to (19, 5).
  17. MAP_SAFFRON_GYM TR room - battle SAFFRONGYM_YOUNGSTER2 (Psychic Jared) at (17, 4), sight 2. Postcondition: EVENT_BEAT_PSYCHIC_JARED set.
  18. MAP_SAFFRON_GYM - step on pad (15, 5). Warps to (1, 3).
  19. MAP_SAFFRON_GYM TL room - battle SAFFRONGYM_GRANNY2 (Medium Doris) at (3, 4), sight 2. Postcondition: EVENT_BEAT_MEDIUM_DORIS set.
  20. MAP_SAFFRON_GYM - step on pad (1, 5). Warps to (11, 9), Sabrina's chamber.
  21. MAP_SAFFRON_GYM - talk to SAFFRONGYM_SABRINA at (9, 8) (stand at (9, 9) facing up, or (10, 8) facing left). Precondition: ENGINE_MARSHBADGE clear. Battle SABRINA/SABRINA1. Postcondition: EVENT_BEAT_SABRINA, the four trainer flags, and ENGINE_MARSHBADGE all set; +4800G.
  22. MAP_SAFFRON_GYM exit - (11, 9) -> (1, 5); walk right to (5, 5) -> (1, 11); walk right to (5, 11) -> (5, 17); walk up to (5, 15) -> (15, 17); walk right to (19, 17) -> (11, 15); walk down to warp 1/2 at (8, 17)/(9, 17) -> MAP_SAFFRON_CITY warp 2 (34, 3).
  23. Mid-gym heal-and-return (if step 21 needs a fresh party): exit via step 22, heal at MAP_SAFFRON_POKECENTER_1F, re-enter, then (11,15) -> (19,17), up to (19,15) -> (19,9), left to (15,9) -> (15,3), down to (15,5) -> (1,3), down to (1,5) -> (11,9). This is the walkthrough's "1st teleporter, then up, left, down, down" and it checks out against the pad table.

5. Port coverage

Beat Port file Status
Map load, block grid, COLL_* collision, connections src/world/gen2/Map.lua, src/world/gen2/Permissions.lua, src/world/gen2/World.lua Implemented (generic; Gold maps come from src/import/RomExtractorGen2.lua, not hand-ported)
Warp panels / teleport pads (the whole gym maze) src/world/gen2/Permissions.lua:195 COLL_WARP_PANEL = 0x7c in WARP_FACING_DOWN, Permissions.warpFacesDown; warp taking in src/world/gen2/World.lua:1566 World:warpTo Implemented (panels warp on landing, which is what all 30 gym pads are)
Map-to-self warps (every gym pad targets SAFFRON_GYM) src/world/gen2/World.lua warp handling Implemented, but untested for this map - no driver exercises a same-map warp chain
MAPCALLBACK_NEWMAP -> setflag ENGINE_FLYPOINT_SAFFRON src/world/gen2/World.lua:5659 self:runMapCallback("MAPCALLBACK_NEWMAP"); fly-point row at src/world/gen2/FieldMoves.lua:365 (LANDMARK_SAFFRON_CITY / SPAWN_SAFFRON / flag 59) Implemented
Script opcodes used by every script in this section (checkevent, iftrue, iffalse, setevent, checkflag, setflag, verbosegiveitem, promptbutton, writetext, waitbutton, jumptext, jumptextfaceplayer, jumpstd, gettrainername, pokemart, yesorno, checkitem, applymovement, special, warpcheck, newloadmap, loadtrainer, startbattle, reloadmapafterbattle, winlosstext, endifjustbattled, playsound, waitsfx) src/script/gen2/Opcodes.lua, src/script/gen2/Vm.lua (checkflag :195, verbosegiveitem :490, pokemart :597, jumpstd :742, loadtrainer :806, startbattle :817, winlosstext :918) Implemented
Object visibility from event flags (the Route 6 blocker, the station's hidden Teacher/Lass, the picked-up Focus Band ball) src/world/gen2/Events.lua:1-2 documents and implements "flag SET -> object hidden", matching CheckObjectFlag Implemented
Overworld trainer sight + battle handoff (Rebecca, Franklin, Doris, Jared) src/world/gen2/Trainers.lua (eyesight from home/trainers.asm, party build) Implemented
Gym leader battle, badge grant, prize money x4 src/battle/gen2/Battle.lua; src/battle/gen2/Prize.lua:82 Prize.reward(baseMoney, level) and :181 local quarter = ... (the four-way payout) Implemented
Item ball pickup (FOCUS_BAND in the Fighting Dojo) Extracted at src/import/RomExtractorGen2.lua:2968-2969 into obj.itemball, but nothing reads obj.itemball at runtime (grep for .itemball in src/ hits only the extractor). src/script/gen2/CallAsm.lua:551 explicitly stubs TryReceiveItem Missing - the ball object will exist and be masked correctly by its flag, but stepping on it grants nothing
Magnet Train ride (special MagnetTrain) src/core/gen2/MagnetTrain.lua, src/ui/gen2/MagnetTrainRide.lua Implemented (not exercised in this section - the officer's gate is false here)
Mart (pokemart MARTTYPE_STANDARD, MART_SAFFRON) src/ui/gen2/MartMenu.lua, Vm.lua:597 Implemented
Pokecenter heal (jumpstd PokecenterNurseScript) std scripts extracted (src/import/RomExtractorGen2.lua:2901), heal hook src/script/gen2/Specials.lua:451 Implemented
Bicycle src/world/gen2/Bike.lua Implemented
Any Saffron-specific hand-ported content none Missing by design - the Gen 2 port is data-driven off the ROM; there are no SAFFRON symbols anywhere under src/ except Gen 1 save-conversion tables (src/save_convert/), which are unrelated
Driver coverage for this section tests/drivers/gold_*.lua (25 drivers: boot, walk, warp, trainer, battle, map callbacks, ...) Missing - no driver reaches Kanto or Saffron; gold_warp_scene.lua / gold_walk_smoke.lua are Johto-early smoke tests

6. Unresolved / verify by hand

  • Psychic Jared's third Pokemon. The walkthrough lists "Level 32 Exeggcute (672 EXP)" twice. data/trainers/parties.asm:2569-2574 gives PSYCHIC_T (11) JARED as L32 MR__MIME, L32 EXEGGCUTE, L35 EXEGGCUTE. The asm wins; the walkthrough's second Exeggcute level and its EXP figure are both wrong.
  • EXP values. None of the per-Pokemon EXP numbers in the walkthrough (765, 1237, 1149, 735, 672, 720, 1264, 1941, 1339, 1912) were checked against data/pokemon/base_stats/ - they are outside what a bot needs and were not verified.
  • "PokeMart ... upper-right corner of Saffron City". The mart door is warp 3 at (25, 11) on a 40x36-cell map, i.e. north-of-centre and east of the middle, not the corner. The two gyms it says are "further north" are at (26, 3) and (34, 3), which is correct.
  • "Silph Co ... the multi-story building above the Pokémon Center". Silph is warp 7 at (18, 21); the Pokecenter is warp 4 at (9, 29). Silph is north-east of it, and SilphCo1F has no stairs warp - only the two street doors. There is no upper floor in Gen 2.
  • "You now have 10 badges!" ENGINE_MARSHBADGE is bit 5 of wKantoBadges (constants/engine_flags.asm:52), so it is the 6th Kanto badge in flag order, not the 10th badge overall. The count of 10 only holds for a player who took Vermilion before Saffron, as this FAQ's chapter order does. Nothing in the asm enforces that order.
  • The walkthrough's mid-maze "left/right (whichever way works) till you find that one trainer again (Franklin)" heal route is deliberately vague in the source text and was not reduced to a single pad sequence. The precise post-heal route it gives afterwards ("1st teleporter, then up, left, down, down") does resolve cleanly and is recorded in bot checklist step 23.
  • The "large man who blocks the entire entrance to the Underground Path" is described as taunting the player about moving boulders. Route6PokefanMText (maps/Route6.asm:15) contains only the Power Plant line; no boulder or strength text exists on this map. Treat the boulder remark as FAQ colour.