From ef520096f4ee9aef93a027f6a823702d7858b987 Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 11:12:22 -0800 Subject: [PATCH 01/13] BDSP AutoStory: 00.02 on the shared steps The Starly battle is a BATTLE step, variant "starter" (fight_starly(): no talk first, no Poke Balls, and the scene goes on either way), and the walk out of the lake after it a MASH scene that ends on the Lakefront's quiet overworld, instead of Butters' fixed 60 s of B. Stays named: starter_briefcase (B until an image match of the open briefcase) and choose_starter (the briefcase's cursor from the program's starter option): menus only BDSP has. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../PokemonBDSP_AutoStory_Events_Lake.cpp | 15 ++++----------- .../PokemonBDSP_AutoStory_StoryExecutor.cpp | 7 +++++++ .../PokemonBDSP_AutoStory_StoryTable.cpp | 8 +++++--- .../PokemonBDSP_AutoStory_StoryTable_Tests.cpp | 2 +- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp index 80b271cd1e..f0343fff40 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp @@ -5,9 +5,9 @@ * Adapted from PokemonAutomation/Arduino-Source#1717 by Developer-Butters. * * The scenes of the story's start that need scripted input: the briefcase - * at Lake Verity, the starter, the Starly battle and the scene after it, - * the Pokedex in Rowan's lab, Mom's and Barry's mother's lines, and Dawn's - * catching tutorial. The button sequences are Butters' (#1717); they ran on + * at Lake Verity, the starter, the Pokedex in Rowan's lab, Mom's and Barry's + * mother's lines, and Dawn's catching tutorial. The button sequences are + * Butters' (#1717); they ran on * the console in his recordings, but not yet from the planned walks around * them. * @@ -116,12 +116,6 @@ void azure_flute_if_there(VideoStream& stream, ProControllerContext& context){ } } -// 00.02: after the Starly battle, Rowan's lines and the walk out of the -// lake, B for a minute. -void after_starly(VideoStream&, ProControllerContext& context){ - pbf_mash_button(context, BUTTON_B, 60000ms); - context.wait_for_all_requests(); -} // 00.03: Dawn walks us into Rowan's lab: his lines, "give a nickname?" // (B: No), and the Pokedex, taken with A. @@ -151,8 +145,7 @@ void add_lake_events(StoryEvents& events){ events.emplace("azure_flute_if_there", console_event(azure_flute_if_there)); events.emplace("starter_briefcase", console_event(starter_briefcase)); events.emplace("choose_starter", choose_starter); - events.emplace("fight_starly", console_event(fight_starly)); - events.emplace("after_starly", console_event(after_starly)); + events.emplace("rowan_gives_pokedex", console_event(rowan_gives_pokedex)); events.emplace("catch_tutorial", console_event(catch_tutorial)); events.emplace("catch_pokemon", console_event(catch_1_pokemon)); diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp index c7a5c8a090..aab4658b3d 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp @@ -501,6 +501,13 @@ Outcome StoryExecutor::mash(RunState& state, const StoryStep& step){ } Outcome StoryExecutor::battle(RunState&, const StoryStep& step){ + // "starter": the Starly battle at the lake (00.02). It opens on its own, + // with no talk, and the starter has no Poke Balls to throw; the scene + // goes on whoever wins. + if (step.variant == "starter"){ + fight_starly(stream(), context()); + return Pokemon::outcome_ok(); + } // A loss sends us to a Pokemon Center, so ending on its floor means a // loss - unless the floor check already passed where the battle began: // Jubilife's yellow plaza reads as Center floor (63 %, r79 won Rowan's diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 021fb6d3c5..1b50e75a73 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -301,11 +301,13 @@ std::vector lake_and_pokedex(){ step_into("lake_entrance", NORTH, "the trigger (16..17, 12): Barry hears Rowan and the two walk in"), event("starter_briefcase", "the lake's scene, to the open briefcase"), event("choose_starter", "the starter from the program's option"), - event("fight_starly", "the Starly battle"), + battle("starly", true, "the Starly battle, with the starter alone", "starter"), // The game walks us out of the lake, then the Lakefront's scene walks us 3 // south: (17, 14) facing south, or a tile below (decomp; timeline 00.02 #5). - event("after_starly", "Rowan's lines and the walk out of the lake", - at_or_next_to(LAKEFRONT, "below_lake_entrance", SOUTH)), + // Butters' sequence was B for a fixed 60 s; the scene rule ends it on + // the quiet overworld instead (unchecked on the console). + scene("after_starly", at_or_next_to(LAKEFRONT, "below_lake_entrance", SOUTH), + "Rowan's lines and the walk out of the lake"), }), row("00.03", "Back to Sandgem: Rowan, Dawn and the Pokedex", at_or_next_to(LAKEFRONT, "below_lake_entrance", SOUTH), { route("short_of_rowan", at(ROUTE_201, 4, 14, EAST), "back east onto Route 201's lower level"), diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable_Tests.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable_Tests.cpp index 1debf3d6bc..43d2818e0b 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable_Tests.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable_Tests.cpp @@ -41,7 +41,7 @@ const std::map>& built_in_variants(){ {StoryStepKind::LEGS, {"", "one_short_ok", "to_wall", "to_dialogue", "to_map"}}, {StoryStepKind::STEP, {"", "to_banner"}}, {StoryStepKind::MASH, {"", "a"}}, - {StoryStepKind::BATTLE, {"", "doubles"}}, + {StoryStepKind::BATTLE, {"", "doubles", "starter"}}, }; return variants; } From 2452838752d6b0bc7c7035f6e8449a6c8b7dc3c0 Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 11:13:10 -0800 Subject: [PATCH 02/13] BDSP AutoStory: 00.03 on the shared steps Rowan's Pokedex is a MASH scene ending at Rowan in the lab, through the fade into it. Butters' sequence pressed B through Dawn's and Rowan's lines and the nickname question, then A for the Pokedex; the scene's B answers the question No too, and closes an item's lines as it closed Barry's parcel in 00.04 (r45). Stays named: nothing in 00.03. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../AutoStory/PokemonBDSP_AutoStory_Events.h | 4 ++-- .../PokemonBDSP_AutoStory_Events_Lake.cpp | 17 +++-------------- .../PokemonBDSP_AutoStory_StoryTable.cpp | 8 ++++++-- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h index 388b396eae..49bbc296c7 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h @@ -4,8 +4,8 @@ * * The story's steps that only BDSP has, by name: a step of the table whose * variant names one of these runs it (StoryExecutor::run()). Some are the - * scripted scenes (the intro's briefcase, the starter, the Starly battle, - * the Pokedex); most are segment 01's walks, which were measured on the + * scripted scenes (the lake's briefcase, the starter, Dawn's catching + * tutorial); most are segment 01's walks, which were measured on the * console as holds, taps and walks until stopped rather than planned, and * are kept as they ran there. Each fails by throwing, with a screenshot; * the executor turns that into a failed step. diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp index f0343fff40..0ecd9e3f77 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp @@ -5,8 +5,8 @@ * Adapted from PokemonAutomation/Arduino-Source#1717 by Developer-Butters. * * The scenes of the story's start that need scripted input: the briefcase - * at Lake Verity, the starter, the Pokedex in Rowan's lab, Mom's and Barry's - * mother's lines, and Dawn's catching tutorial. The button sequences are + * at Lake Verity, the starter, Mom's and Barry's mother's lines, and Dawn's + * catching tutorial. The button sequences are * Butters' (#1717); they ran on * the console in his recordings, but not yet from the planned walks around * them. @@ -117,17 +117,6 @@ void azure_flute_if_there(VideoStream& stream, ProControllerContext& context){ } -// 00.03: Dawn walks us into Rowan's lab: his lines, "give a nickname?" -// (B: No), and the Pokedex, taken with A. -void rowan_gives_pokedex(VideoStream& stream, ProControllerContext& context){ - wait_for_dialogue(stream, context, "Dawn at Sandgem's entrance"); - pbf_mash_button(context, BUTTON_B, 50000ms); - wait_for_dialogue(stream, context, "Nickname: no"); - pbf_mash_button(context, BUTTON_B, 40000ms); - wait_for_dialogue(stream, context, "The Pokedex"); - pbf_mash_button(context, BUTTON_A, 40000ms); - context.wait_for_all_requests(); -} // 00.04: Dawn's catching tutorial on Route 202: her lines and her demo // battle, B for 70 s. @@ -146,7 +135,7 @@ void add_lake_events(StoryEvents& events){ events.emplace("starter_briefcase", console_event(starter_briefcase)); events.emplace("choose_starter", choose_starter); - events.emplace("rowan_gives_pokedex", console_event(rowan_gives_pokedex)); + events.emplace("catch_tutorial", console_event(catch_tutorial)); events.emplace("catch_pokemon", console_event(catch_1_pokemon)); } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 1b50e75a73..2637eae876 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -330,8 +330,12 @@ std::vector lake_and_pokedex(){ // Dawn's scene starts as we come into Sandgem (trigger (4, 10..15)); // walk until it does rather than to a tile (r35, r36). legs("into_sandgem", {{.direction = EAST, .tiles = 8}}, "east into Sandgem until Dawn's scene starts", "to_dialogue"), - event("rowan_gives_pokedex", "Dawn walks us to the lab: Rowan, no nickname, the Pokedex", - at(LAB, "rowan_talk", NORTH)), + // Butters' sequence pressed B through Dawn's and Rowan's lines and + // the nickname question (No), then A for the Pokedex. The scene's + // B answers No too, and closes an item's lines as it did Barry's + // parcel (r45). Into the lab is a fade. + scene("rowan_gives_pokedex", at(LAB, "rowan_talk", NORTH), + "Dawn walks us to the lab: Rowan, no nickname, the Pokedex"), }), }; } From d9040cb194f66b6498ae3c9c5ecdae81898a31fd Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 11:13:49 -0800 Subject: [PATCH 03/13] BDSP AutoStory: 00.05 on the shared steps Barry's Town Map is a TALK west from beside him at the School's back wall (the walk there now says it ends facing him) and a MASH scene with A to "You obtained a Town Map!". The event's second try, north to the wall again when he did not answer, is not kept: the walk north already ends on the wall. Stays named: up_the_steps. It taps a tile west and two north from 00.05's save below Jubilife's steps, and that save's tile is not known (the map has only where the taps end, "up_the_steps", column 46 or 47 a few rows up), so the row has no start pose for a LEGS step to walk from. It needs the save's tile measured on the console, as a point on JubilifeCity's map. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../PokemonBDSP_AutoStory_Events_Jubilife.cpp | 16 +--------------- .../PokemonBDSP_AutoStory_StoryTable.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp index c1dc95e0dd..04c36c9aa1 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp @@ -51,20 +51,6 @@ void up_the_steps(VideoStream& stream, ProControllerContext& context){ } } -// 00.05: Barry stands at the blackboard a tile west of the door's column, -// and that column is clear to the back wall: north to it, face west, his -// scene to "You obtained a Town Map!" (A closes it). A tile west by a hold -// went two in r149a and the boy at the table stopped us. -void barry_town_map(VideoStream& stream, ProControllerContext& context){ - for (size_t attempt = 0; attempt < 2; attempt++){ - const DialogueRead read = talk_facing(stream, context, Direction::WEST, BUTTON_A, "Barry"); - if (read.opened && read.closed){ - return; - } - walk_until_stopped(stream, context, Direction::NORTH, 4, "North to the back wall"); - } - fail_step(stream, "Trainers' School: Barry did not answer from beside the back wall."); -} // 00.05b: a talk to someone who wanders a tile either side of home along a // row (the clowns by the Mart and the Poketch Company, WANDER_AROUND with @@ -214,7 +200,7 @@ void east_to_barry(VideoStream& stream, ProControllerContext& context){ void add_jubilife_events(StoryEvents& events){ events.emplace("up_the_steps", console_event(up_the_steps)); - events.emplace("barry_town_map", console_event(barry_town_map)); + events.emplace("talk_to_wanderer", talk_to_wanderer); events.emplace("jubilife_center_to_street", console_event(jubilife_center_to_street)); events.emplace("east_to_barry", console_event(east_to_barry)); diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 2637eae876..9d913d9c95 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -462,8 +462,15 @@ StoryCheckpoint the_town_map(){ route("to_the_school", next_to(JUBILIFE, "trainers_school_door", SOUTH, NORTH), "below the School's door (40, 40)", "town"), step_into("into_the_school", NORTH, "the School's door", inside(TRAINERS_SCHOOL)), - to_walls("up_to_barry", {{.direction = NORTH, .tiles = 10}}, "the door's column to the back wall, beside Barry"), - event("barry_town_map", "Barry gives the Town Map", inside(TRAINERS_SCHOOL)), + // Barry stands at the blackboard a tile west of the door's column, + // which is clear to the back wall: beside him there, face west and + // talk. A tile west by a hold went two in r149a, and the boy at the + // table stopped us. (The event walked to the wall again once when he + // did not answer.) + anchored(to_walls("up_to_barry", {{.direction = NORTH, .tiles = 10}}, "the door's column to the back wall, beside Barry"), + Pokemon::tile_pose(TRAINERS_SCHOOL, {}, WEST)), + talk("barry", "Barry, west of us at the blackboard"), + scene("barry_town_map", inside(TRAINERS_SCHOOL), "his lines to \"You obtained a Town Map!\", closed with A", "a"), // Barry stands beside the door's column, which is clear down to the door. step_into("out_of_the_school", SOUTH, "straight down the door's column and out", below_the_school()), }); From de371f7b7e96816261d9ded5dcc1acedb697d04d Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 11:15:20 -0800 Subject: [PATCH 04/13] BDSP AutoStory: 01.01 on the shared steps 01.01 starts where 00.05c ends, (58, 22) on Jubilife's street east to Route 203, and is planned on the joined Route 203 and Jubilife: a route to (4, 18) on Route 203, a step east onto Barry's coord event (column 5, rows 17 to 20, VAR_ROUTE_203_RIVAL_STATE 0, Diamond's zone event narc_0329), then his battle, which leaves us on the trigger (assumed). Dropped with jubilife_center_to_street: its start from a save at the Jubilife Center's PC (two tiles south, three west, the nurse, then stick holds to the street). A save there no longer starts 01.01; the row's save is made on the street. Dropped with east_to_barry: its walk east row by row past walls, which the plan replaces. Stays named: nothing in 01.01. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../PokemonBDSP_AutoStory_Events_Jubilife.cpp | 105 +----------------- .../PokemonBDSP_AutoStory_StoryTable.cpp | 16 ++- 2 files changed, 15 insertions(+), 106 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp index 04c36c9aa1..9919b71635 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp @@ -1,14 +1,12 @@ -/* BDSP AutoStory - Events: Jubilife City (00.05, 01.01) +/* BDSP AutoStory - Events: Jubilife City (00.05) * * From: https://github.com/PokemonAutomation/ * - * The Jubilife beats of 00.05 the story table cannot plan (up the steps, - * Barry's Town Map, the talk to a wandering clown), and segment 01's walk - * out of the Center to Barry. + * The Jubilife beats of 00.05 the story table cannot plan: up the steps, + * and the talk to a wandering clown. * */ -#include #include #include #include "CommonFramework/ImageTools/ImageBoxes.h" @@ -16,10 +14,8 @@ #include "CommonTools/Async/InferenceRoutines.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" #include "PokemonBDSP/Inference/PokemonBDSP_DialogDetector.h" -#include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_Indoors.h" #include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_RouteWalk.h" #include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_Walk.h" -#include "PokemonBDSP_AutoStory_Center.h" #include "PokemonBDSP_AutoStory_Talks.h" #include "PokemonBDSP_AutoStory_Walks.h" #include "PokemonBDSP_AutoStory_WildBattle.h" @@ -103,107 +99,12 @@ Pokemon::Outcome talk_to_wanderer(StoryExecutor& executor, Pokemon::RunState&, c fail_step(stream, step.name + ": no answer from any tile below his range."); } - -// 01.01 from the save at the Jubilife Center's PC: healed at the nurse, -// out of the door and through the plaza to the street east to Route 203. -void jubilife_heal_and_out_to_street(VideoStream& stream, ProControllerContext& context){ - // The save stands us at the PC, right of the counter, facing it; west - // is the counter's end. Two tiles south clears it, then three west is - // the floor emblem's column, with the nurse north and the door south. - route_turn(stream, context, Direction::SOUTH); - pbf_move_left_joystick(context, {0, -1}, route_open_hold(Direction::SOUTH, 2), 200ms); - route_turn(stream, context, Direction::WEST); - pbf_move_left_joystick(context, {-1, 0}, route_open_hold(Direction::WEST, 3), 200ms); - if (walk_to_talk(stream, context, run_from_wild_battle, {0, 1}, 3000ms, "to the nurse").stop != WalkStop::DIALOG){ - fail_step(stream, "Jubilife Pokemon Center: the nurse did not answer."); - } - // A throughout: Yes to "rest your Pokemon?" (B would answer No). - finish_dialogue(stream, context, BUTTON_A, "Nurse"); - // Healing shows no text box for a few seconds, which reads as the end; - // her "Thank you for waiting" lines follow it. - if (dialogue_opens(stream, context, 6000ms)){ - finish_dialogue(stream, context, BUTTON_B, "Nurse, after healing"); - } - // South through the door until a girl standing below it stops us. The - // door's fade may or may not read as a transition. - WalkResult out{WalkStop::LIMIT, 0ms, 0}; - for (size_t walk = 0; walk < 3 && out.stop != WalkStop::BLOCKED; walk++){ - out = walk_until(stream, context, run_from_wild_battle, {0, -1}, 8000ms, "out of the Pokemon Center"); - if (out.stop == WalkStop::DIALOG || out.stop == WalkStop::ARRIVED){ - break; - } - } - if (out.stop != WalkStop::BLOCKED){ - fail_step(stream, std::string("Jubilife Pokemon Center: walking out ended with ") + walk_stop_name(out.stop) + ", not at the girls below the door."); - } - - // Jubilife's plaza has too few walls the grid gets right to plan on (a - // leg to a wall the map shows walked on 19 tiles). These are the holds - // that worked on the console: west onto the main road, north to the - // street east to Route 203, and back a couple of tiles. - route_turn(stream, context, Direction::WEST); - pbf_move_left_joystick(context, {-1, 0}, 720ms, 300ms); - route_turn(stream, context, Direction::NORTH); - pbf_move_left_joystick(context, {0, 1}, 3960ms, 300ms); - route_turn(stream, context, Direction::SOUTH); - pbf_move_left_joystick(context, {0, -1}, 600ms, 300ms); - context.wait_for_all_requests(); -} - -// 01.01: from the Center's PC, the nurse and out, then the holds to the street east to Route 203; -// nothing when 00.05 has left us outdoors on that street. -void jubilife_center_to_street(VideoStream& stream, ProControllerContext& context){ - // From 00.05g we are already outdoors on the street east to Route 203, - // healed on arriving in Jubilife: straight to the walk east. - bool outdoors = false; - context.wait_for_all_requests(); - if (VideoSnapshot screen = stream.video().snapshot()){ - outdoors = !indoors(*screen.frame); - } - if (outdoors){ - stream.log("[Route] 01.01: outdoors; skipping the Pokemon Center."); - }else{ - jubilife_heal_and_out_to_street(stream, context); - } -} - -// 01.01: east along the street until Barry stops us at the entrance to Route 203. -void east_to_barry(VideoStream& stream, ProControllerContext& context){ - // East along the street. The opening to the route is a few rows high; - // Barry stops us a little way in. A wall means we are a row off it: try - // rows to the south, then to the north. - static const int ROW_CHANGES[] = {0, 1, 1, -3, -1}; - bool barry = false; - for (int change : ROW_CHANGES){ - if (barry){ - break; - } - for (int i = 0; i < std::abs(change); i++){ - const Direction dir = change > 0 ? Direction::SOUTH : Direction::NORTH; - route_turn(stream, context, dir); - pbf_move_left_joystick(context, {0, change > 0 ? -1.0 : 1.0}, route_open_hold(dir, 1), 200ms); - } - context.wait_for_all_requests(); - WalkResult walk{WalkStop::LIMIT, 0ms, 0}; - for (size_t stretch = 0; stretch < 3 && walk.stop == WalkStop::LIMIT; stretch++){ - walk = walk_until(stream, context, run_from_wild_battle, {1, 0}, 9000ms, "east to Route 203"); - } - barry = walk.stop == WalkStop::DIALOG; - } - if (!barry){ - fail_step(stream, "Route 203: Barry did not stop us at the entrance."); - } -} - } void add_jubilife_events(StoryEvents& events){ events.emplace("up_the_steps", console_event(up_the_steps)); - events.emplace("talk_to_wanderer", talk_to_wanderer); - events.emplace("jubilife_center_to_street", console_event(jubilife_center_to_street)); - events.emplace("east_to_barry", console_event(east_to_barry)); } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 9d913d9c95..5e294cfc30 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -539,6 +539,13 @@ Pose arrival(const char* map, TilePos tile, Direction direction){ Pose out_of_oreburgh_gate(){ return at(ROUTE_203, 55, 9, WEST); } +// Barry's coord event on Route 203 (Diamond's zone event narc_0329), column +// 5 on rows 17 to 20 (the street's rows 21 to 24) while +// VAR_ROUTE_203_RIVAL_STATE is 0. He walks up, battles and runs off, and +// we stay on it (assumed; the event's walk east stopped there, on any row). +Pose on_barrys_trigger(){ + return Pokemon::tile_pose(ROUTE_203, {TilePos{5, 17}, TilePos{5, 18}, TilePos{5, 19}, TilePos{5, 20}}, EAST); +} // Where Route 204's door (11, 1) lets us into the Ravaged Path: (19, 50), // as in r237a. The tap stops at the fade, on that tile. Pose into_the_ravaged_path(){ @@ -632,10 +639,11 @@ StoryCheckpoint route_204_to_floaroma(){ std::vector to_oreburgh(){ return { - row("01.01", "Jubilife to Barry", std::nullopt, { - event("jubilife_center_to_street", "out of the Center to the street east to Route 203, unless we stand there"), - event("east_to_barry", "east until Barry stops us at Route 203's entrance"), - battle("barry", true, "Barry's battle; a loss goes on, as it did on the console"), + // From 00.05c's end on the street east to Route 203. + row("01.01", "Jubilife to Barry", at(JUBILIFE, 58, 22, EAST), { + route("west_of_barrys_trigger", at(ROUTE_203, 4, 18, EAST), "east along the street onto Route 203", "town"), + step_into("barrys_trigger", EAST, "the trigger (5, 17..20): Barry walks over"), + anchored(battle("barry", true, "Barry's battle; a loss goes on, as it did on the console"), on_barrys_trigger()), }), row("01.02", "Route 203 to Oreburgh", std::nullopt, { event("route_203_east_to_the_gate", "east along Route 203, fighting the trainers who stop us"), From d839c4ba1777994a5887ac7a7a409878ebe6356a Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 11:17:25 -0800 Subject: [PATCH 05/13] BDSP AutoStory: 01.02 on the shared steps 01.02 starts on Barry's trigger, where 01.01 ends, and is planned on Route 203's, the Gate's and Oreburgh's maps with the Diamond decomp's zone events (narc_0329, narc_0250, narc_0044): - a route east along Route 203 to the Gate's warp tile (55, 9), fighting the trainers who see us, then a tap east to the Gate's banner; - a route to (6, 22), a step onto the Hiker's coord event (7, 22), and a MASH scene for his HM Rock Smash and the Hidden Moves card after it (no dialogue box; the scene's B closes it, as the event's two B did); - a route east along row 22 to (27, 22), fighting Picnicker Diana and Camper Curtis, now on the Gate's trainer list with ranges that reach the row; a tap east to Oreburgh's banner; - a route to (9, 13), a step onto the coord event of the man at the entrance (10, 12..15), and a MASH scene for his walk to the Center and Barry's lines. Where it leaves us is not known, so the row ends there. Dropped: the met_hiker flag (the walk east meeting the Hiker on its way; the step onto his trigger is explicit now), and the walk east row by row past walls. Events_Route203.cpp had only these events and is gone. Stays named: nothing in 01.02. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../PokemonBDSP_AutoStory_Events.cpp | 1 - .../AutoStory/PokemonBDSP_AutoStory_Events.h | 9 +- .../PokemonBDSP_AutoStory_Events_Route203.cpp | 201 ------------------ .../PokemonBDSP_AutoStory_StoryPlaces.cpp | 31 ++- .../PokemonBDSP_AutoStory_StoryTable.cpp | 43 +++- SerialPrograms/cmake/SourceFiles.cmake | 1 - 6 files changed, 63 insertions(+), 223 deletions(-) delete mode 100644 SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route203.cpp diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.cpp index 2348d76216..0037449ea4 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.cpp @@ -18,7 +18,6 @@ const StoryEvents& story_events(){ add_lake_events(ret); add_sandgem_events(ret); add_jubilife_events(ret); - add_route203_events(ret); add_oreburgh_events(ret); add_route204_events(ret); return ret; diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h index 49bbc296c7..3923c369e3 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h @@ -10,10 +10,10 @@ * are kept as they ran there. Each fails by throwing, with a screenshot; * the executor turns that into a failed step. * - * They are in files by area: _Events_Lake (00.00 to 00.03), _Sandgem - * (00.04), _Jubilife (00.05, 01.01), _Route203 (01.02), _Oreburgh (01.03 - * and 01.04) and _Route204 (01.09's Rock Smash, 01.11). 01.05 to 01.10 - * are planned walks in the story table. + * They are in files by area: _Events_Lake (00.00 to 00.04), _Sandgem + * (00.04), _Jubilife (00.05), _Oreburgh (01.03 and 01.04) and _Route204 + * (01.09's Rock Smash, 01.11). 01.01, 01.02 and 01.05 to 01.10 are + * planned walks in the story table. * */ @@ -46,7 +46,6 @@ StoryEvent console_event(std::function -#include "CommonFramework/GlobalAutoPaths.h" -#include "Common/Cpp/Filesystem/Filesystem.h" -#include "Common/Cpp/PrettyPrint.h" -#include "CommonFramework/Globals.h" -#include "CommonFramework/ImageTypes/ImageRGB32.h" -#include "CommonFramework/VideoPipeline/VideoFeed.h" -#include "CommonTools/Async/InferenceRoutines.h" -#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" -#include "PokemonBDSP/Inference/PokemonBDSP_DialogDetector.h" -#include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_RouteWalk.h" -#include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_Walk.h" -#include "PokemonBDSP_AutoStory_Talks.h" -#include "PokemonBDSP_AutoStory_Walks.h" -#include "PokemonBDSP_AutoStory_WildBattle.h" -#include "PokemonBDSP_AutoStory_Events.h" - -namespace PokemonAutomation{ -namespace NintendoSwitch{ -namespace PokemonBDSP{ - -using namespace std::chrono_literals; -using Pokemon::Direction; - - -namespace{ - -// The walk east along Route 203: who has stopped us so far. -struct Route203Walk{ - VideoStream& stream; - ProControllerContext& context; - size_t fights = 0; - bool inside = false; - // On Route 203 only trainers start a talk; one with no battle is the - // Hiker, who meets us inside the Gate (whose fade may not read as a - // transition). - bool met_hiker = false; -}; - -// Whoever stopped the walk: a trainer to fight, or the Hiker. -void route_203_stopped_by(Route203Walk& walk){ - if (talk_or_fight(walk.stream, walk.context, "Route 203 trainer " + std::to_string(walk.fights + 1))){ - walk.fights++; - }else{ - route_status(walk.stream, "No battle: that was the Hiker, inside the Oreburgh Gate."); - walk.met_hiker = true; - walk.inside = true; - } -} - -// At a wall: the row from which east goes on. North to the top wall first -// (a step north there does not move us, so rows are counted from it), then -// a row at a time south. At the route's end this is the corner by the -// second sign, with the Gate's opening two rows down. -void route_203_row_east_on(Route203Walk& walk){ - VideoStream& stream = walk.stream; - ProControllerContext& context = walk.context; - walk_until(stream, context, run_from_wild_battle, {0, 1}, 6000ms, "north to the top wall"); - bool moved_on = false; - for (size_t row = 1; row <= 10 && !moved_on; row++){ - step_south(stream, context); - const WalkResult next = walk_until(stream, context, run_from_wild_battle, {1, 0}, 10000ms, "east along Route 203, row " + std::to_string(row) + " below the top"); - if (next.stop == WalkStop::TRANSITION){ - walk.inside = true; - } - if (next.stop == WalkStop::DIALOG || (next.stop == WalkStop::BLOCKED && dialogue_opens(stream, context, 1500ms))){ - route_203_stopped_by(walk); - } - // Two still chunks are the least a wall takes; more is progress. - moved_on = walk.inside || next.stop != WalkStop::BLOCKED || next.walked > 1200ms; - } - if (!moved_on){ - fail_step(stream, "Route 203: walls east on every row down to ten below the top wall."); - } -} - - -// 01.02: east along Route 203 into the Oreburgh Gate, fighting whoever stops us. -Pokemon::Outcome route_203_east_to_the_gate(StoryExecutor& executor, Pokemon::RunState& state, const Pokemon::StoryStep&){ - VideoStream& stream = executor.stream(); - ProControllerContext& context = executor.context(); - // Route 203 only goes east, over three stretches joined by stairs, and - // the Gate's opening is in the cliff at its north-east end. Who stops us - // differs from run to run (a trainer's sight depends on our row), so - // there is no fixed list: walk east, talk or fight whoever stops us, and - // at a wall find a row from which east goes on. - Route203Walk walk{stream, context}; - for (size_t leg = 0; leg < 40 && !walk.inside; leg++){ - const WalkResult east = walk_until(stream, context, run_from_wild_battle, {1, 0}, 10000ms, "east along Route 203"); - if (east.stop == WalkStop::TRANSITION){ - walk.inside = true; - break; - } - if (east.stop == WalkStop::LIMIT){ - continue; - } - if (east.stop == WalkStop::DIALOG || dialogue_opens(stream, context, 1500ms)){ - route_203_stopped_by(walk); - continue; - } - route_203_row_east_on(walk); - } - if (!walk.inside){ - fail_step(stream, "Route 203: did not reach the Oreburgh Gate."); - } - route_status(stream, "Route 203: " + std::to_string(walk.fights) + " trainer battle(s) on the way."); - context.wait_for(1500ms); - if (walk.met_hiker){ - state.flags.insert("met_hiker"); - } - return Pokemon::outcome_ok(); -} - -// 01.02: the Hiker, who gives HM Rock Smash, when the walk east has not met him. -void the_hiker(VideoStream& stream, ProControllerContext& context){ - // The Hiker steps up to us as we walk east. - const WalkResult to_hiker = walk_until(stream, context, run_from_wild_battle, {1, 0}, 4000ms, "to the Hiker"); - if (to_hiker.stop != WalkStop::DIALOG && !dialogue_opens(stream, context, 2000ms)){ - fail_step(stream, "Oreburgh Gate: the Hiker did not stop us."); - } - finish_dialogue(stream, context, BUTTON_B, "Hiker"); -} - -// 01.02: the "Hidden Moves" card after the Hiker. -void hidden_moves_card(VideoStream& stream, ProControllerContext& context){ - // Then a "Hidden Moves" tutorial card, closed with B. It is no dialogue - // box, and it can come up a moment after his last line. - pbf_wait(context, 1500ms); - pbf_press_button(context, BUTTON_B, 80ms, 1500ms); - pbf_press_button(context, BUTTON_B, 80ms, 1000ms); - context.wait_for_all_requests(); -} - -// 01.02: east through the Gate past Curtis and Diana, out to Oreburgh City. -void gate_east_to_oreburgh(VideoStream& stream, ProControllerContext& context){ - // East: Camper Curtis and Picnicker Diana see us; past them the exit's - // white fade, and the man in Oreburgh stops us right outside. - size_t fights = 0; - bool city = false; - size_t stuck = 0; - for (size_t leg = 0; leg < 12 && !city; leg++){ - const WalkResult walk = walk_until(stream, context, run_from_wild_battle, {1, 0}, 10000ms, "east through the Oreburgh Gate"); - if (walk.stop == WalkStop::LIMIT || walk.stop == WalkStop::TRANSITION){ - continue; - } - if (walk.stop != WalkStop::DIALOG && !dialogue_opens(stream, context, 2000ms)){ - // A card or menu left up holds the screen still: B once, then retry. - if (++stuck > 1){ - fail_step(stream, "Oreburgh Gate: a wall stopped us walking east."); - } - pbf_press_button(context, BUTTON_B, 80ms, 1500ms); - continue; - } - stuck = 0; - if (fights >= 2){ - city = true; - break; - } - fights += talk_or_fight(stream, context, "Oreburgh Gate trainer " + std::to_string(fights + 1)) ? 1 : 0; - } - if (!city){ - fail_step(stream, "Oreburgh Gate: did not reach Oreburgh City."); - } -} - -// 01.02: the man at the city's entrance and Barry, at the Pokemon Center. -void oreburgh_welcome(VideoStream& stream, ProControllerContext& context){ - // He walks us to the Pokemon Center between his lines, and Barry joins - // there: more lines after each walk. - finish_dialogue(stream, context, BUTTON_B, "Man at Oreburgh's entrance"); - for (size_t scene = 0; scene < 6 && dialogue_opens(stream, context, 6000ms); scene++){ - finish_dialogue(stream, context, BUTTON_B, "Oreburgh scene"); - } - context.wait_for_all_requests(); -} - -} - - -void add_route203_events(StoryEvents& events){ - events.emplace("route_203_east_to_the_gate", route_203_east_to_the_gate); - events.emplace("the_hiker", console_event(the_hiker)); - events.emplace("hidden_moves_card", console_event(hidden_moves_card)); - events.emplace("gate_east_to_oreburgh", console_event(gate_east_to_oreburgh)); - events.emplace("oreburgh_welcome", console_event(oreburgh_welcome)); -} - - - -} -} -} diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp index 3c05fa52b1..6496aa2f3d 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp @@ -171,17 +171,22 @@ const std::vector& plan_worlds(){ return worlds; } +// Where the object `name` of the JSON map `map` stands. +TilePos object_tile(const char* map, const char* name){ + for (const Pokemon::MapObject& object : story_map(map).objects){ + if (object.name == name){ + return TilePos{object.x, object.y}; + } + } + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, std::string(map) + " has no " + name + "."); +} + // Route 203's trainers, from the Diamond decomp's events (zone event // narc_0329): where each stands on the JSON map, the way they look and // how far. The one by the Gate wanders in BDSP and is off the map. std::vector route_203_trainer_sights(){ const auto at = [](const char* name){ - for (const Pokemon::MapObject& object : story_map("Route203").objects){ - if (object.name == name){ - return TilePos{object.x, object.y}; - } - } - throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, std::string("Route 203 has no ") + name + "."); + return object_tile("Route203", name); }; return { {.name = "Youngster (west)", .pos = at("youngster_1"), .facing = Direction::WEST, .range = 2}, @@ -191,6 +196,17 @@ std::vector route_203_trainer_sights(){ }; } +// The Oreburgh Gate's trainers (Diamond's zone event narc_0250): Picnicker +// Diana above row 22 and Camper Curtis below it. Both stopped the walk +// east along that row on the console (2026-10-29 to 10-31); the maps have +// no ranges, and 4 reaches the row from either. +std::vector oreburgh_gate_trainer_sights(){ + return { + {.name = "Picnicker Diana", .pos = object_tile("OreburghGate", "picnicker_0"), .facing = Direction::SOUTH, .range = 4}, + {.name = "Camper Curtis", .pos = object_tile("OreburghGate", "camper_1"), .facing = Direction::NORTH, .range = 4}, + }; +} + // The trainers of the JSON map `map`, in its own tiles. std::vector map_trainers(const std::string& map){ if (map == "Route202"){ @@ -199,6 +215,9 @@ std::vector map_trainers(const std::string& map){ if (map == "Route203"){ return route_203_trainer_sights(); } + if (map == "OreburghGate"){ + return oreburgh_gate_trainer_sights(); + } if (map == "Route204South"){ return route204_south_trainer_sights(); } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 5e294cfc30..dd14b44002 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -536,8 +536,8 @@ Pose arrival(const char* map, TilePos tile, Direction direction){ // tile only: from it and (54, 9) together the joined Route 203 and Jubilife // find no plan. The tap stops at the fade, which puts us on the warp tile; // r78 passed 01.06 from a save there (by the sign, the cave mouth east). -Pose out_of_oreburgh_gate(){ - return at(ROUTE_203, 55, 9, WEST); +Pose out_of_oreburgh_gate(Direction facing = WEST){ + return at(ROUTE_203, 55, 9, facing); } // Barry's coord event on Route 203 (Diamond's zone event narc_0329), column // 5 on rows 17 to 20 (the street's rows 21 to 24) while @@ -579,6 +579,37 @@ StoryCheckpoint oreburgh_to_route_203(){ }); } +// 01.02, planned on Route 203's, the Gate's and Oreburgh's maps with the +// Diamond decomp's zone events (narc_0329, narc_0250, narc_0044): east +// along Route 203 to the Gate, fighting the trainers who see us +// (route_203_trainer_sights()); the Hiker's coord event (7, 22) while +// VAR_OREBURGH_GATE_1F_HIKER_STATE is 1; east along row 22 past Diana and +// Curtis (oreburgh_gate_trainer_sights()); then the coord event of the man +// at Oreburgh's entrance, column 10 on rows 12 to 15 while +// VAR_OREBURGH_CITY_STATE is 0. Each mouth is a tap to its banner, as in +// 01.05; its warp's other end is the tile beside the far mouth. +StoryCheckpoint route_203_to_oreburgh(){ + return row("01.02", "Route 203 to Oreburgh", on_barrys_trigger(), { + route("by_the_gate", out_of_oreburgh_gate(EAST), "east along Route 203 to the Gate's warp tile (55, 9)"), + tap_into("into_oreburgh_gate", EAST, "the Gate's west mouth (56, 9)", arrival(GATE, {4, 22}, EAST)), + route("west_of_the_hikers_trigger", at(GATE, 6, 22, EAST), "east along row 22"), + step_into("hikers_trigger", EAST, "the trigger (7, 22): the Hiker walks down to us"), + // The "Hidden Moves" card after his lines is no dialogue box, and + // can come up a moment after them; the scene's B closes it. + scene("the_hiker", at(GATE, 7, 22, EAST), "HM Rock Smash, then the Hidden Moves card"), + route("by_the_east_mouth", at(GATE, 27, 22, EAST), "east along row 22, fighting Diana and Curtis"), + tap_into("into_oreburgh", EAST, "the Gate's east mouth (28, 22)", + arrival(OREBURGH, map_point(OREBURGH, "gate_mouth").next(EAST), EAST)), + route("west_of_the_welcome", at(OREBURGH, 9, 13, EAST), "east along row 13"), + step_into("welcome_trigger", EAST, "the trigger (10, 12..15): the man walks over"), + // He walks us to the Pokemon Center between his lines; Barry joins + // there with more lines after each walk. Where it leaves us is + // not known: "a row or two below the Center's front, a little west + // of its door" (01.03's save, 2026-10-29). + scene("oreburgh_welcome", std::nullopt, "the man's lines, the walk to the Center, and Barry's"), + }); +} + // Below Rowan's trigger in Jubilife: (47, 8), the east tile under the // trigger (45..47, 7), which (48, 7) beside it is not. Pose below_rowans_trigger(){ @@ -645,13 +676,7 @@ std::vector to_oreburgh(){ step_into("barrys_trigger", EAST, "the trigger (5, 17..20): Barry walks over"), anchored(battle("barry", true, "Barry's battle; a loss goes on, as it did on the console"), on_barrys_trigger()), }), - row("01.02", "Route 203 to Oreburgh", std::nullopt, { - event("route_203_east_to_the_gate", "east along Route 203, fighting the trainers who stop us"), - skip_if(event("the_hiker", "the Hiker in the Gate gives HM Rock Smash"), "met_hiker"), - event("hidden_moves_card", "the card after him, closed with B"), - event("gate_east_to_oreburgh", "east past Curtis and Diana into Oreburgh"), - event("oreburgh_welcome", "the man at the entrance, and Barry at the Center"), - }), + route_203_to_oreburgh(), row("01.03", "Oreburgh Mine to Roark", std::nullopt, { event("oreburgh_center_door", "in by the Center's door, talking to Barry in it"), event("south_into_the_mine", "straight south from the door into the mine"), diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index b8984e26f2..1c8f2bc453 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1680,7 +1680,6 @@ file(GLOB LIBRARY_SOURCES Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Oreburgh.cpp - Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route203.cpp Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route204.cpp Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Sandgem.cpp Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_NewGame.cpp From 382d151e7eff53d8d6364c84eca4245b7e89b825 Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 11:39:27 -0800 Subject: [PATCH 06/13] BDSP AutoStory: 01.02 plans Route 203 from one tile From all four of Barry's trigger rows at once the planner found no way east (StorySimulation's poses chain): walk south down the trigger's column to the cliff below row 20 first, as 01.08 does at its start. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index dd14b44002..728b7d44c3 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -590,6 +590,11 @@ StoryCheckpoint oreburgh_to_route_203(){ // 01.05; its warp's other end is the tile beside the far mouth. StoryCheckpoint route_203_to_oreburgh(){ return row("01.02", "Route 203 to Oreburgh", on_barrys_trigger(), { + // One known tile to plan from: from all four of the trigger's rows + // at once the planner finds no plan. Its column is open from row + // 17 down to the cliff below row 20. + anchored(to_walls("south_to_the_cliff", {{.direction = SOUTH, .tiles = 4}}, "down the trigger's column to the cliff"), + at(ROUTE_203, 5, 20, SOUTH)), route("by_the_gate", out_of_oreburgh_gate(EAST), "east along Route 203 to the Gate's warp tile (55, 9)"), tap_into("into_oreburgh_gate", EAST, "the Gate's west mouth (56, 9)", arrival(GATE, {4, 22}, EAST)), route("west_of_the_hikers_trigger", at(GATE, 6, 22, EAST), "east along row 22"), From a68d2c1eef699a3a4d61fec94c7f399506bf953b Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 11:44:35 -0800 Subject: [PATCH 07/13] BDSP AutoStory: 01.02 meets the Gate's trainers one route each In the grid sim (bdsp/sim, merged locally), the walk east along the Gate planned one leg to the wall on row 23, where both Curtis and Diana see it: Curtis was fought under Diana's name, and her stop on the walk on to the wall went unseen, so the route ended at (24, 23). Two routes now, to (20, 22) past Curtis's column and on to (27, 22) past Diana's. They come off the trainer list again: the grid sim does not know them beaten in 01.05, and they stopped its walk back west. The walker fights them as trainers the map lacks, one per route. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../PokemonBDSP_AutoStory_StoryPlaces.cpp | 31 ++++--------------- .../PokemonBDSP_AutoStory_StoryTable.cpp | 9 +++++- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp index 6496aa2f3d..3c05fa52b1 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp @@ -171,22 +171,17 @@ const std::vector& plan_worlds(){ return worlds; } -// Where the object `name` of the JSON map `map` stands. -TilePos object_tile(const char* map, const char* name){ - for (const Pokemon::MapObject& object : story_map(map).objects){ - if (object.name == name){ - return TilePos{object.x, object.y}; - } - } - throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, std::string(map) + " has no " + name + "."); -} - // Route 203's trainers, from the Diamond decomp's events (zone event // narc_0329): where each stands on the JSON map, the way they look and // how far. The one by the Gate wanders in BDSP and is off the map. std::vector route_203_trainer_sights(){ const auto at = [](const char* name){ - return object_tile("Route203", name); + for (const Pokemon::MapObject& object : story_map("Route203").objects){ + if (object.name == name){ + return TilePos{object.x, object.y}; + } + } + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, std::string("Route 203 has no ") + name + "."); }; return { {.name = "Youngster (west)", .pos = at("youngster_1"), .facing = Direction::WEST, .range = 2}, @@ -196,17 +191,6 @@ std::vector route_203_trainer_sights(){ }; } -// The Oreburgh Gate's trainers (Diamond's zone event narc_0250): Picnicker -// Diana above row 22 and Camper Curtis below it. Both stopped the walk -// east along that row on the console (2026-10-29 to 10-31); the maps have -// no ranges, and 4 reaches the row from either. -std::vector oreburgh_gate_trainer_sights(){ - return { - {.name = "Picnicker Diana", .pos = object_tile("OreburghGate", "picnicker_0"), .facing = Direction::SOUTH, .range = 4}, - {.name = "Camper Curtis", .pos = object_tile("OreburghGate", "camper_1"), .facing = Direction::NORTH, .range = 4}, - }; -} - // The trainers of the JSON map `map`, in its own tiles. std::vector map_trainers(const std::string& map){ if (map == "Route202"){ @@ -215,9 +199,6 @@ std::vector map_trainers(const std::string& map){ if (map == "Route203"){ return route_203_trainer_sights(); } - if (map == "OreburghGate"){ - return oreburgh_gate_trainer_sights(); - } if (map == "Route204South"){ return route204_south_trainer_sights(); } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 728b7d44c3..6f6e9667b2 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -588,6 +588,12 @@ StoryCheckpoint oreburgh_to_route_203(){ // at Oreburgh's entrance, column 10 on rows 12 to 15 while // VAR_OREBURGH_CITY_STATE is 0. Each mouth is a tap to its banner, as in // 01.05; its warp's other end is the tile beside the far mouth. +// +// Diana and Curtis are not on the trainer list: the walker fights them as +// trainers the map lacks, one per route (in the grid sim, the second of +// two on one leg stopped its walk on to the wall unseen). On the list, +// the grid sim, which does not know them beaten, had them stop 01.05's +// walk back. StoryCheckpoint route_203_to_oreburgh(){ return row("01.02", "Route 203 to Oreburgh", on_barrys_trigger(), { // One known tile to plan from: from all four of the trigger's rows @@ -602,7 +608,8 @@ StoryCheckpoint route_203_to_oreburgh(){ // The "Hidden Moves" card after his lines is no dialogue box, and // can come up a moment after them; the scene's B closes it. scene("the_hiker", at(GATE, 7, 22, EAST), "HM Rock Smash, then the Hidden Moves card"), - route("by_the_east_mouth", at(GATE, 27, 22, EAST), "east along row 22, fighting Diana and Curtis"), + route("past_curtis", at(GATE, 20, 22, EAST), "east along row 22 past Camper Curtis's column (17), fighting him"), + route("by_the_east_mouth", at(GATE, 27, 22, EAST), "east past Picnicker Diana's column (24), fighting her"), tap_into("into_oreburgh", EAST, "the Gate's east mouth (28, 22)", arrival(OREBURGH, map_point(OREBURGH, "gate_mouth").next(EAST), EAST)), route("west_of_the_welcome", at(OREBURGH, 9, 13, EAST), "east along row 13"), From 534dc28119378c5b4b5b162f4f7536eac0f883dc Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 18:17:36 -0800 Subject: [PATCH 08/13] BDSP AutoStory: 01.03 on the shared steps 01.03 starts where Oreburgh's welcome scene leaves us (now 01.02's end too) and is planned on Oreburgh's map and the mine's coal room (Diamond's zone events narc_0044 and narc_0197): - east to the fence below the Center and north, the one known tile to plan from; two taps west below the door; Barry in it (TALK, MASH); - a route down the door's column, round the Hiker's patch, to above the mine's warp tiles (44..48, 59) and a step onto them. The generator writes those tiles as doors (WARP_DOORS), so no plan stands on them; - the entrance hall, which has no map, on 19 counted taps each way and a step onto its warp row: no hold that a wild battle could end; - in the coal room (now a room world): down the corridor to the boulder, a route to below Roark, his talk and scene, a route back to the warp; - out below the mine's sign (to the wall), a route to the Center's doorstep (46, 21), and the heal. 01.04 now starts there, outside, and its out_of_the_center event is gone. TALK waits 8 s for a line, not 3: Roark's first comes after the camera zooms in on us (r98). Dropped: the nudges round the Center's door and below Roark (they made up for stick holds; taps are whole tiles), the Roark-gone check by A after his scene (the scene rule's quiet overworld ends it), and the walks until a transition. Stays named: 01.04's gym_until_roark_beaten. After a loss it walks back from the Center keeping the battles' experience, which a reload of the row's save would take away. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../Programs/AutoStory/Maps/OreburghCity.json | 2 +- .../AutoStory/PokemonBDSP_AutoStory_Events.h | 4 +- .../PokemonBDSP_AutoStory_Events_Oreburgh.cpp | 390 +----------------- .../PokemonBDSP_AutoStory_StoryExecutor.cpp | 4 +- .../PokemonBDSP_AutoStory_StoryPlaces.cpp | 6 +- .../PokemonBDSP_AutoStory_StoryTable.cpp | 103 ++++- devtools/maps/bdsp_maps.py | 3 + 7 files changed, 105 insertions(+), 407 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/Maps/OreburghCity.json b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/Maps/OreburghCity.json index 0043b0bea2..5df7f3b6d4 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/Maps/OreburghCity.json +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/Maps/OreburghCity.json @@ -61,7 +61,7 @@ "#####################################..####.#S....###.....######", "###########################################.......####.......###", "############################################.....#####.......###", - "############################################.....#####.....#####", + "############################################DDDDD#####.....#####", "######################################################..#..#####", "################################################################", "################################################################", diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h index 3923c369e3..8a47ffc628 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h @@ -11,8 +11,8 @@ * the executor turns that into a failed step. * * They are in files by area: _Events_Lake (00.00 to 00.04), _Sandgem - * (00.04), _Jubilife (00.05), _Oreburgh (01.03 and 01.04) and _Route204 - * (01.09's Rock Smash, 01.11). 01.01, 01.02 and 01.05 to 01.10 are + * (00.04), _Jubilife (00.05), _Oreburgh (01.04's Gym) and _Route204 + * (01.09's Rock Smash, 01.11). 01.01 to 01.03 and 01.05 to 01.10 are * planned walks in the story table. * */ diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Oreburgh.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Oreburgh.cpp index 7628d3ce8c..c7c85493a2 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Oreburgh.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Oreburgh.cpp @@ -1,26 +1,17 @@ -/* BDSP AutoStory - Events: Oreburgh (01.03 to 01.04) +/* BDSP AutoStory - Events: Oreburgh Gym (01.04) * * From: https://github.com/PokemonAutomation/ * - * Segment 01's walks in Oreburgh: the mine and Roark, and the Gym, as - * they ran on the console (2026-10-29 to 10-31). + * 01.04's walk into the Oreburgh Gym and up it to Roark, again from the + * Pokemon Center after each loss, as it ran on the console (2026-10-29 to + * 10-31). A loss keeps the experience, which a reload of the row's save + * would not. * */ -#include -#include "CommonFramework/GlobalAutoPaths.h" -#include "Common/Cpp/Filesystem/Filesystem.h" -#include "Common/Cpp/PrettyPrint.h" -#include "CommonFramework/Globals.h" -#include "CommonFramework/ImageTypes/ImageRGB32.h" #include "CommonFramework/VideoPipeline/VideoFeed.h" -#include "CommonTools/Async/InferenceRoutines.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" -#include "PokemonBDSP/Inference/PokemonBDSP_DialogDetector.h" -#include "PokemonBDSP/Programs/AutoStory/Data/PokemonBDSP_AutoStory_Maps.h" -#include "PokemonBDSP/Programs/AutoStory/Data/PokemonBDSP_AutoStory_StoryMaps.h" #include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_Indoors.h" -#include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_PlannedRoute.h" #include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_RouteWalk.h" #include "PokemonBDSP/Programs/AutoStory/Utils/PokemonBDSP_AutoStory_Walk.h" #include "PokemonBDSP_AutoStory_Talks.h" @@ -33,110 +24,10 @@ namespace NintendoSwitch{ namespace PokemonBDSP{ using namespace std::chrono_literals; -using Pokemon::Direction; namespace{ -// The Center's floor: Oreburgh's sand reads up to 34 % warm outside -// (r189a), the floor 56 to 64 % inside. -bool oreburgh_center_floor(const ImageViewRGB32& screen){ - size_t percent = 0; - center_floor_on_screen(screen, &percent); - return percent >= 45; -} -bool oreburgh_center_inside_now(VideoStream& stream){ - const VideoSnapshot frame = stream.video().snapshot(); - return frame && oreburgh_center_floor(*frame.frame); -} - -// North into the Center's door from this column: whether we are inside. -// Someone in the door (Barry, the first time) is talked to and the walk -// tried again. -bool into_oreburgh_center_door(VideoStream& stream, ProControllerContext& context){ - // The door's fade often reads as the time limit, not a black screen - // (r183a went in and on to the counter): look at the floor. - // Stop as soon as the floor shows: walking on to the counter left the - // door's column, and the walk back out drifted into the yard (r188b). - const WalkResult in = walk_until(stream, context, run_from_wild_battle, {0, 1}, 2500ms, "north into the Center's door", - oreburgh_center_floor); - if (in.stop == WalkStop::ARRIVED || ((in.stop == WalkStop::TRANSITION || in.stop == WalkStop::LIMIT) && oreburgh_center_inside_now(stream))){ - return true; - } - if (in.stop == WalkStop::DIALOG){ - talk_or_fight(stream, context, "Someone at the Center's door"); - }else{ - pbf_press_button(context, BUTTON_A, 80ms, 200ms); - if (!dialogue_opens(stream, context, 2000ms)){ - return false; - } - finish_dialogue(stream, context, BUTTON_B, "Barry at the Center's door"); - context.wait_for(2000ms); // he runs off - } - // Talked in the door's column: the door is free now. - walk_until(stream, context, run_from_wild_battle, {0, 1}, 2500ms, "north into the Center's door", - oreburgh_center_floor); - return oreburgh_center_inside_now(stream); -} - -// Oreburgh: from a row or two below the Pokemon Center's front, west of -// the fence below its east corner, into the Center by its door, stopping -// just inside. Talks to Barry if he stands in the door (01.03, the first -// time). -void enter_oreburgh_center(VideoStream& stream, ProControllerContext& context){ - // The save stands us a row or two below the Center's front, a little - // west of its door. The posts and the road beside the Center make north - // from there unreliable (r191a, r192a walked up the road to the city's - // north exit), and counted taps east drift. The fence running south from - // the Center's east corner stops a walk east on these rows a tile east of - // the door (by hand): walk to it, north to the Center's front, tap back - // one, and shift one tap either side. - walk_to_wall(stream, context, run_from_wild_battle, {1, 0}, 5000ms, "east to the fence below the Center"); - walk_to_wall(stream, context, run_from_wild_battle, {0, 1}, 3000ms, "north to the Center's front"); - // The door wants us near its middle: a turn and a tap west (half a tile - // too far, by hand) or a turn alone leave north blocked by the facade - // beside it. The facade blocks north for two tiles either side of the - // door, so look for it in nudges of about a third of a tile. - route_turn(stream, context, Direction::WEST); - context.wait_for_all_requests(); - bool inside = false; - const int offsets[] = {0, -1, -2, 1, -3, 2, -4, 3}; // nudges from here - int nudged = 0; - for (size_t i = 0; i < 8 && !inside; i++){ - const int offset = offsets[i]; - if (offset != nudged){ - // No turn first: a turn is a tap too and moves us (see - // talk_with_nudges()); a nudge both turns and moves a little. - for (; nudged != offset; nudged += offset > nudged ? 1 : -1){ - pbf_move_left_joystick(context, {offset > nudged ? 1.0 : -1.0, 0}, ROUTE_NUDGE_TAP, 300ms); - } - context.wait_for_all_requests(); - } - inside = into_oreburgh_center_door(stream, context); - } - if (!inside || !oreburgh_center_inside_now(stream)){ - fail_step(stream, "Oreburgh: no column east of the save went into the Pokemon Center."); - } -} - -// Oreburgh: from just inside the Pokemon Center's door, up to the nurse -// and heal; ends at the counter facing her. The door is straight south of -// her (by hand, 2026-10-31: north from the door stopped at the counter). -void heal_at_oreburgh_counter(VideoStream& stream, ProControllerContext& context){ - if (walk_to_talk(stream, context, run_from_wild_battle, {0, 1}, 6000ms, "to the nurse").stop != WalkStop::DIALOG){ - fail_step(stream, "Oreburgh Pokemon Center: the nurse did not answer."); - } - // A throughout: Yes to "rest your Pokemon?" (B would answer No). - finish_dialogue(stream, context, BUTTON_A, "Nurse"); - // Healing shows no text box for a few seconds, which reads as the end; - // her "Thank you for waiting" lines follow it. - if (dialogue_opens(stream, context, 6000ms)){ - finish_dialogue(stream, context, BUTTON_B, "Nurse, after healing"); - } -} - - - // Oreburgh, from the street in front of the Pokemon Center (its door or its // front wall) into the gym, as walked by hand on 2026-10-29: west to the // cliff, south to the posts, a row up, then 17 tiles east is the gym door's @@ -218,271 +109,6 @@ bool oreburgh_gym_battles(VideoStream& stream, ProControllerContext& context){ fail_step(stream, "Oreburgh Gym: did not reach Roark."); } -// 01.03: into the Pokemon Center by its door (talking to Barry if he stands in it). -void oreburgh_center_door(VideoStream& stream, ProControllerContext& context){ - // Planned on Bulbapedia's Oreburgh map (devtools/maps/examples/ - // oreburgh_center_to_mine.png): the column of the Center's door runs - // straight south down the yard's stairs, between the conveyors, into - // the mine (walked north up it by hand, 2026-10-31). The door is the one - // place that pins that column: go in and back out, and we stand on it - // facing south. The save stands us two tiles west of the door and a row - // down; north stops against the Center's front or its post, then a tile - // at a time east until north goes in. Barry stands in the door the first - // time: walking into him reads as a wall, so A there; he tells us Roark - // went to the mine, which Roark needs before he answers (2026-10-29: he - // ignored A in r101 and r104 until then). A save after his talk has him - // gone already. - // - // Already in the Center (a save inside its door): nothing to do, as - // 01.01 does for its Center. - context.wait_for_all_requests(); - if (VideoSnapshot screen = stream.video().snapshot()){ - if (indoors(*screen.frame)){ - stream.log("[Route] 01.03: already in the Pokemon Center."); - return; - } - } - if (in_dim_cave(stream)){ - stream.log("[Route] 01.03: already in the mine."); - return; - } - enter_oreburgh_center(stream, context); - context.wait_for(1000ms); -} - -// 01.03: straight south from the door into the mine. -void south_into_the_mine(VideoStream& stream, ProControllerContext& context){ - // Straight back south: out of the door and on into the mine. Fades go - // unseen at times (r184b missed the mine's, r185a the Center's and walked - // on into the mine hall), so count: the Center's door and the mine are - // two transitions, or about 1 s inside and 8.6 s outside of walking (by - // hand). A worker walks about on the sand path and stops the walk as a - // wall would (r95, r96): wait for him to move and walk on. Step 3 copes - // with ending in the hall or in the corridor. - // A save in the mine's entrance hall: already there. - if (in_dim_cave(stream)){ - stream.log("[Route] 01.03: already in the mine."); - return; - } - bool in_mine = false; - size_t transitions = 0; - Milliseconds walked = 0ms; - for (size_t attempt = 0; attempt < 6 && !in_mine; attempt++){ - const WalkResult down = walk_dir(stream, context, Direction::SOUTH, 15000ms, "south out of the Center and into the mine"); - walked += down.walked; - if (down.stop == WalkStop::TRANSITION){ - transitions++; - context.wait_for(1000ms); - }else if (down.stop == WalkStop::DIALOG){ - talk_or_fight(stream, context, "Someone on the way to the mine"); - }else if (down.stop == WalkStop::BLOCKED){ - context.wait_for(2000ms); - } - // Counting alone took a walk that drifted into the yard (r188b) for the - // mine: it also has to look like the mine. - in_mine = (transitions >= 2 || walked >= 9500ms) && in_dim_cave(stream); - } - if (!in_mine){ - fail_step(stream, "Oreburgh: the walk south from the Center's door did not reach the mine."); - } - context.wait_for(1500ms); -} - -// 01.03: through the mine's entrance hall to the rocky corridor. -void mine_hall(VideoStream& stream, ProControllerContext& context){ - // If the fade into the mine was missed, we are already in the corridor - // and this walk stops at its boulder; otherwise it crosses the hall. - const WalkResult hall = walk_dir(stream, context, Direction::SOUTH, 10000ms, "through the mine's entrance hall"); - if (hall.stop == WalkStop::TRANSITION){ - context.wait_for(1500ms); - } -} - -// After a wild battle on the way: back to the east end of the bottom row, -// three taps west and north to the wall on his row (Maps/OreburghMine.json: -// columns 23 to 25 have that wall above). -void line_up_below_roark_again(VideoStream& stream, ProControllerContext& context){ - // The battle may leave us on his row or the bottom one. - walk_to_wall(stream, context, run_from_wild_battle, {0, -1}, 2000ms, "south to the bottom row"); - walk_to_wall(stream, context, run_from_wild_battle, {1, 0}, 6000ms, "east along the bottom row"); - route_turn(stream, context, Direction::WEST); - for (size_t tap = 0; tap < 3; tap++){ - pbf_move_left_joystick(context, {-1, 0}, 120ms, 300ms); - } - walk_to_wall(stream, context, run_from_wild_battle, {0, 1}, 2000ms, "north to the wall on Roark's row"); -} - -// From his row east of his rock: west to the rock, down and two taps west -// below him, and A with nudges. Whether his talk opened. -bool talk_to_roark_from_his_row(VideoStream& stream, ProControllerContext& context){ - // A wild battle on the way eats into the walk's time (r100): walk again. - for (size_t walk = 0; walk < 3; walk++){ - if (walk_to_wall(stream, context, run_from_wild_battle, {-1, 0}, 6000ms, "west to the rock beside Roark").wild_battles == 0){ - break; - } - } - walk_to_wall(stream, context, run_from_wild_battle, {0, -1}, 2000ms, "south to the bottom wall"); - route_turn(stream, context, Direction::WEST); - pbf_move_left_joystick(context, {-1, 0}, 120ms, 300ms); - pbf_move_left_joystick(context, {-1, 0}, 120ms, 300ms); - route_turn(stream, context, Direction::NORTH); - context.wait_for_all_requests(); - if (run_from_late_encounter(stream, context, run_from_wild_battle, "below Roark")){ - return false; - } - if (VideoSnapshot screen = stream.video().snapshot()){ - const std::string folder = SCREENSHOTS_PATH() + "AutoStory/route/"; - Filesystem::create_directories(Filesystem::Path(folder)); - screen.frame->save(folder + now_to_filestring() + "-below-roark.png"); - } - // The camera zooms in and his first line, "OK, stand back and watch - // this.", can take some seconds (r98). - // His rocks answer A too ("It's a rugged rock..."): his talk is the - // one that zooms the camera in on us (by hand), which the rock's - // message does not. Compare the view above the dialogue box. - return talk_with_nudges(stream, context, run_from_wild_battle, Direction::NORTH, "Roark", 8000ms, - [&](const ImageViewRGB32& before, const ImageViewRGB32& after){ - const ImageFloatBox above_box{0.0, 0.0, 1.0, 0.6}; - const double change = walk_screen_change( - extract_box_reference(before, above_box), extract_box_reference(after, above_box) - ); - stream.log("[01.03] View change when the talk opened: " + std::to_string(change) + " (Roark zooms in)."); - return change > 35; // by hand: 50 for his zoom - }); -} - -// His scene (by hand, 2026-10-31): see roark_in_the_mine(). Fails if he -// is still there after it. -void wait_out_roarks_scene(VideoStream& stream, ProControllerContext& context){ - bool gone = false; - for (size_t round = 0; round < 3 && !gone; round++){ - for (size_t press = 0; press < 14; press++){ - pbf_press_button(context, BUTTON_B, 80ms, 2420ms); - } - pbf_press_button(context, BUTTON_A, 80ms, 200ms); - gone = !dialogue_opens(stream, context, 2500ms); - } - if (!gone){ - fail_step(stream, "Oreburgh Mine: Roark is still there after the talk."); - } -} - -// From below Roark, back up the corridor and out of the mine. -void out_of_oreburgh_mine( - VideoStream& stream, ProControllerContext& context, const StoryWorld& maps, - RouteTrainers& no_trainers, const Pokemon::TilePos& roark -){ - const auto world = [&](const Pokemon::TilePos& pos){ return maps.to_world(MAP_OREBURGH_MINE, pos); }; - walk_dir(stream, context, Direction::SOUTH, 2000ms, "back to the bottom wall"); - std::vector at{roark.next(Direction::SOUTH)}; - - // Back up the corridor, then north out through the hall. A route leg - // north to the top's wall walks on through it into the hall (r99), and - // no wall stops us a row short of it, so the route ends on the corner - // at (14,10), where that leg started, and the walk does the rest. - const Pokemon::TilePos exit = world(map_point("OreburghMine", "corridor_exit_start")); - at = walk_route(stream, context, run_from_wild_battle, maps, at, no_trainers, RouteWalkPlan{[&](const Pokemon::TilePos& pos){ return pos == exit; }, "Back to the corridor's top", {}, route_plan_costs()}); - // Up into the entrance hall (a transition, as on the way in), then on - // north out of the mine: in r103 that walk left the mine without a - // transition we saw and ended against the sign above the stairs, which - // the moving belts make read as the time limit. - if (walk_dir(stream, context, Direction::NORTH, 10000ms, "into the entrance hall").stop != WalkStop::TRANSITION){ - fail_step(stream, "Oreburgh Mine: walking north from the corridor did not reach the entrance hall."); - } - context.wait_for(1500ms); - if (walk_dir(stream, context, Direction::NORTH, 10000ms, "out of the mine").stop == WalkStop::DIALOG){ - fail_step(stream, "Oreburgh Mine: someone stopped us on the way out of the mine."); - } - context.wait_for(1500ms); -} - -// 01.03: the planned route down the corridor to Roark, his talk, and back out of the mine. -void roark_in_the_mine(VideoStream& stream, ProControllerContext& context){ - // Planned on the coal room's tile grid (Maps/OreburghMine.json): the - // corridor's rocks zigzag a row at a time, the room's second row passes - // under the worker on the first, and the east side leads down to the - // bottom row below Roark. - const StoryWorld& maps = oreburgh_mine_maps(); - auto world = [&](const Pokemon::TilePos& pos){ return maps.to_world(MAP_OREBURGH_MINE, pos); }; - RouteTrainers no_trainers{{}, [&](const std::string& who){ talk_or_fight(stream, context, who); }}; - std::vector at; - for (const Pokemon::TilePos& pos : map_region("OreburghMine", "corridor_top")){ - at.push_back(world(pos)); - } - // Roark stands with a rock on each side, so the rock east of him is the - // anchor: plan to his row's open stretch east of the rock, walk north to - // the wall above it and west until the rock stops us, two tiles east of - // him (on the console, r97). Then south to the bottom wall and two tiles - // west puts us below him. - const Pokemon::TilePos roark = world(map_point("OreburghMine", "roark")); - at = walk_route(stream, context, run_from_wild_battle, maps, at, no_trainers, RouteWalkPlan{[&](const Pokemon::TilePos& pos){ return pos.y >= roark.y && pos.y <= roark.y + 1 && pos.x >= roark.x + 2 && pos.x <= roark.x + 7; }, "To the stretch east of Roark", {}, route_plan_costs()}); - walk_to_wall(stream, context, run_from_wild_battle, {0, 1}, 2000ms, "north to the wall on Roark's row"); - // His rock and the bottom wall end these legs (see walk_to_wall()). The - // two taps west from there land within a third of a tile or so of his - // column (s03e2 missed him by that much), so look for him with nudges - // either side. Any tap here can start a wild battle, which leaves us - // off his column (r180a, even on his row west of his rock): then line up - // again from the east end of the bottom row, three taps west and north to the wall on his row - // (Maps/OreburghMine.json: columns 23 to 25 have that wall above). - bool talked = false; - for (size_t attempt = 0; attempt < 3 && !talked; attempt++){ - if (attempt > 0){ - // The battle may leave us on his row or the bottom one. - line_up_below_roark_again(stream, context); - } - talked = talk_to_roark_from_his_row(stream, context); - } - if (!talked){ - fail_step(stream, "Oreburgh Mine: no talk opened below Roark (has Barry told us about the mine?)."); - } - // His scene (by hand, 2026-10-31): the camera zooms in, about eight - // lines that each wait for a press ("OK, stand back and watch this.", - // Rock Smash, "...That'd be me!"), then he smashes his rock and leaves. - // finish_dialogue() ended early on it, and stepping onto his tile could - // not tell him from the time the stop takes to read (r184, r186 "passed" - // with him still there, and Barry kept the gym shut). Press B through it - // on a clock, then ask his tile: once he is gone, A there opens nothing. - // B and A in the overworld facing a wall do nothing. - wait_out_roarks_scene(stream, context); - out_of_oreburgh_mine(stream, context, maps, no_trainers, roark); -} - -// 01.03: into the Pokemon Center and heal at the counter. -void oreburgh_center_heal(VideoStream& stream, ProControllerContext& context){ - // End at the nurse, healed: the counter is a fixed start for 01.04, - // where the mine's mouth is not (2026-10-31, at the user's request). Out - // of the mine we stand below its sign; a tile east is the Center door's - // column, and north on it goes in, or stops on the front rows. - hold_tiles(stream, context, Direction::EAST, 1); - walk_until(stream, context, run_from_wild_battle, {0, 1}, 12000ms, "north into the Center's door", - [](const ImageViewRGB32& screen){ size_t percent = 0; center_floor_on_screen(screen, &percent); return percent >= 45; }); - size_t floor = 0; - if (VideoSnapshot frame = stream.video().snapshot()){ - center_floor_on_screen(*frame.frame, &floor); - } - if (floor < 45){ - route_turn(stream, context, Direction::SOUTH); - pbf_move_left_joystick(context, {0, -1}, 480ms, 300ms); - enter_oreburgh_center(stream, context); - } - heal_at_oreburgh_counter(stream, context); -} - -// 01.04: out of the Pokemon Center from the counter. -void out_of_the_center(VideoStream& stream, ProControllerContext& context){ - // 01.03 leaves us at the Center's counter, facing the nurse; the door - // is straight south. Not on the Center's floor (a save in the gym): - // nothing to leave. - context.wait_for_all_requests(); - if (VideoSnapshot screen = stream.video().snapshot()){ - if (!center_floor_on_screen(*screen.frame)){ - stream.log("[Route] 01.04: not in the Center."); - return; - } - } - walk_out_of_center(stream, context, "Oreburgh"); -} - // 01.04: west along the row into the gym and up it to Roark, again from the Center after a loss. void gym_until_roark_beaten(VideoStream& stream, ProControllerContext& context){ // Losing costs some money and keeps the experience, so each try comes @@ -506,12 +132,6 @@ void gym_until_roark_beaten(VideoStream& stream, ProControllerContext& context){ void add_oreburgh_events(StoryEvents& events){ - events.emplace("oreburgh_center_door", console_event(oreburgh_center_door)); - events.emplace("south_into_the_mine", console_event(south_into_the_mine)); - events.emplace("mine_hall", console_event(mine_hall)); - events.emplace("roark_in_the_mine", console_event(roark_in_the_mine)); - events.emplace("oreburgh_center_heal", console_event(oreburgh_center_heal)); - events.emplace("out_of_the_center", console_event(out_of_the_center)); events.emplace("gym_until_roark_beaten", console_event(gym_until_roark_beaten)); } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp index aab4658b3d..e87167f910 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp @@ -474,8 +474,10 @@ Outcome StoryExecutor::talk(RunState& state, const StoryStep& step){ } pbf_press_button(context(), BUTTON_A, 80ms, 200ms); context().wait_for_all_requests(); + // Roark's first line in the mine comes after the camera zooms in on + // us, which can take some seconds (r98; the old event waited 8 s). ShortDialogWatcher dialog(COLOR_YELLOW); - if (wait_until(stream(), context(), 3000ms, {{dialog}}) != 0){ + if (wait_until(stream(), context(), 8000ms, {{dialog}}) != 0){ fail_step(stream(), label_of(step) + ": nobody answered."); } return Pokemon::outcome_ok(); diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp index 3c05fa52b1..78c7b02584 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp @@ -130,12 +130,12 @@ Pokemon::MapData ravaged_path_smashed(){ return map; } -// The interiors (houses, the lab, the Gym, the Gate, the Ravaged Path), -// each its own world, named by its JSON map. +// The interiors (houses, the lab, the Gym, the Gate, the mine's coal room, +// the Ravaged Path), each its own world, named by its JSON map. const std::map& room_worlds(){ static const std::map rooms = []{ std::map ret; - for (const char* room : {"PlayerHouse2F", "PlayerHouse1F", "RivalHouse1F", "RivalHouse2F", "RowansLab", "OreburghGym", "OreburghGate"}){ + for (const char* room : {"PlayerHouse2F", "PlayerHouse1F", "RivalHouse1F", "RivalHouse2F", "RowansLab", "OreburghGym", "OreburghGate", "OreburghMine"}){ ret[room].add(room, story_map(room), {0, 0}); } ret["RavagedPath"].add("RavagedPath", ravaged_path_smashed(), {0, 0}); diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 6f6e9667b2..4476af2198 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -59,6 +59,10 @@ const char* const JUBILIFE = "JubilifeCity"; const char* const TRAINERS_SCHOOL = "TrainersSchool"; const char* const OREBURGH = "OreburghCity"; const char* const GYM = "OreburghGym"; +// The mine's entrance hall (Diamond's MAP_OREBURGH_MINE_B1F) has no map: +// a pose there names it. The coal room below it, Roark's, does. +const char* const MINE_HALL = "OreburghMineB1F"; +const char* const MINE = "OreburghMine"; const char* const GATE = "OreburghGate"; const char* const ROUTE_203 = "Route203"; const char* const ROUTE_204_SOUTH = "Route204South"; @@ -552,6 +556,20 @@ Pose into_the_ravaged_path(){ return at(RAVAGED_PATH, "entrance", NORTH); } +// Where Oreburgh's welcome scene leaves us, Barry in the Center's door: "a row +// or two below the Center's front, a little west of its door" (01.03's +// save, 2026-10-29); "two tiles west of the door and a row down" (the old +// event). Not Diamond's: its man walks us to the Gym, (23, 23). +Pose after_the_welcome(){ + return Pokemon::tile_pose(OREBURGH, { + TilePos{43, 21}, TilePos{44, 21}, TilePos{45, 21}, TilePos{43, 22}, TilePos{44, 22}, TilePos{45, 22} + }); +} +// Out of Oreburgh's Pokemon Center: on (46, 21), facing south (r217d, r218d). +Pose out_of_oreburgh_center(){ + return at(OREBURGH, "pokemon_center_doorstep", SOUTH); +} + // 01.05, planned on Oreburgh's and the Gate's maps with the Diamond decomp's // zone events (narc_0044, narc_0250) and Platinum's script for the scene // (scripts_oreburgh_city.s, the same trigger and variable). Barry's coord @@ -615,10 +633,68 @@ StoryCheckpoint route_203_to_oreburgh(){ route("west_of_the_welcome", at(OREBURGH, 9, 13, EAST), "east along row 13"), step_into("welcome_trigger", EAST, "the trigger (10, 12..15): the man walks over"), // He walks us to the Pokemon Center between his lines; Barry joins - // there with more lines after each walk. Where it leaves us is - // not known: "a row or two below the Center's front, a little west - // of its door" (01.03's save, 2026-10-29). - scene("oreburgh_welcome", std::nullopt, "the man's lines, the walk to the Center, and Barry's"), + // there with more lines after each walk. + scene("oreburgh_welcome", after_the_welcome(), "the man's lines, the walk to the Center, and Barry's"), + }); +} + +// 01.03, planned on Oreburgh's map and the coal room's (Diamond's zone +// events narc_0044 and narc_0197): Barry in the Center's door says Roark +// went to the mine (Roark ignored A until then, r101 and r104); down the +// door's column to the mine's warp tiles (44..48, 59); straight down the +// entrance hall, which has no map, to its warps (11..13, 21); in the coal +// room down to Roark, whose scene ends with him gone (Platinum's +// scripts_oreburgh_mine_b2f.s: he smashes the rock east of him and walks +// off east); back up and out; and the Center's nurse, so 01.04 starts on +// the doorstep. The Center's door is column 46 on the console: we came out +// of it on (46, 21), 20 taps east of the Gym's door (r217d, r218d), and +// north from below the mine's sign and a tile east went in (2026-10-31). +// +// The hall is walked on counted taps, not held: it is a cave, and a wild +// battle on a hold toward a fade would read as the fade. Its warp tiles +// are only entered on the step after, which meets no wild Pokemon. Down, +// from the city's (46, 59) we land on its (12, 1); up, from the coal +// room's warp we land on its (11, 21) and come out on the city's (45, 59), +// below the mine's sign (the old walk north stopped against it, r103). +StoryCheckpoint oreburgh_mine_to_roark(){ + const Pose below_roark = next_to(MINE, "roark", SOUTH, NORTH); + return row("01.03", "Oreburgh Mine to Roark", after_the_welcome(), { + // The fence south of the Center's east corner (column 49) stops a + // walk east on these rows a tile east of the door, as by hand. + anchored(to_walls("to_the_centers_fence", {{.direction = EAST, .tiles = 6}, {.direction = NORTH, .tiles = 2}}, + "east to the fence below the Center's east corner, north to the Center's front"), at(OREBURGH, 48, 21, NORTH)), + anchored(legs("below_the_centers_door", {{.direction = WEST, .tiles = 2}}, "taps west below the door"), + at(OREBURGH, "pokemon_center_doorstep", NORTH)), + // He stands in the door the first time; walking into him reads as a wall. + talk("barry", "Barry in the Center's door"), + scene("barrys_lines", at(OREBURGH, "pokemon_center_doorstep", NORTH), "Roark has gone to the mine"), + // The Hiker wanders (46..48, 25..27), in the door's column: the + // route goes round him. + route("above_the_mine", at(OREBURGH, 46, 58, SOUTH), "down the door's column to above the mine's warp tiles", "town"), + step_into("into_the_mine", SOUTH, "the warp tile (46, 59)", inside(MINE_HALL)), + // We land on the warp tile we came by, (12, 1): 19 taps end on row + // 20, a step short of the warp row. + legs("down_the_hall", {{.direction = SOUTH, .tiles = 19}}, "down column 12 of the entrance hall"), + step_into("into_the_coal_room", SOUTH, "the hall's warp tiles (11..13, 21)", + Pokemon::tile_pose(MINE, {TilePos{15, 2}, TilePos{15, 1}}, SOUTH)), + // One known tile to plan from: the corridor's column 15 ends at the + // boulder (15, 10), where the old walk south stopped too. + anchored(to_walls("down_to_the_boulder", {{.direction = SOUTH, .tiles = 9}}, "down the corridor to the boulder (15, 10)"), + at(MINE, 15, 9, SOUTH)), + route("below_roark", below_roark, "down the corridor and the room's east side, west along the bottom row"), + // His first line comes after the camera zooms in on us (r98); his + // rocks either side answer A too, but he is the one north of us. + talk("roark", "Roark, north of us between his rocks"), + scene("roark_smashes_the_rock", below_roark, "his lines, Rock Smash on the rock east of him, and he walks off"), + route("below_the_coal_rooms_warp", at(MINE, 15, 2, NORTH), "back up the corridor"), + step_into("up_to_the_hall", NORTH, "the warp tile (15, 1)", inside(MINE_HALL)), + legs("up_the_hall", {{.direction = NORTH, .tiles = 19}}, "up column 11 of the entrance hall"), + step_into("out_of_the_mine", NORTH, "the hall's warp tiles (11..13, 1)", + Pokemon::tile_pose(OREBURGH, {TilePos{45, 59}, TilePos{45, 58}}, NORTH)), + anchored(to_walls("up_to_the_mines_sign", {{.direction = NORTH, .tiles = 3}}, "north against the mine's sign (45, 56)"), + at(OREBURGH, 45, 57, NORTH)), + route("below_the_centers_door_again", at(OREBURGH, "pokemon_center_doorstep", NORTH), "up to below the Center's door", "town"), + heal("heal_oreburgh", "the nurse; out onto the doorstep, where 01.04 starts", out_of_oreburgh_center()), }); } @@ -689,16 +765,13 @@ std::vector to_oreburgh(){ anchored(battle("barry", true, "Barry's battle; a loss goes on, as it did on the console"), on_barrys_trigger()), }), route_203_to_oreburgh(), - row("01.03", "Oreburgh Mine to Roark", std::nullopt, { - event("oreburgh_center_door", "in by the Center's door, talking to Barry in it"), - event("south_into_the_mine", "straight south from the door into the mine"), - event("mine_hall", "through the entrance hall"), - event("roark_in_the_mine", "down the corridor to Roark, his talk, and back out"), - event("oreburgh_center_heal", "the Center's nurse: 01.04 starts at her counter"), - }), - row("01.04", "Oreburgh Gym", std::nullopt, { - event("out_of_the_center", "out from the counter"), - event("gym_until_roark_beaten", "west into the gym, up it to Roark; again from the Center after a loss"), + oreburgh_mine_to_roark(), + // Stays an event: after a loss it walks back from the Center with + // the experience the battles gave, which a reload of this row's + // save would take away (Roark won twice by hand before he lost). + row("01.04", "Oreburgh Gym", out_of_oreburgh_center(), { + event("gym_until_roark_beaten", "west into the gym, up it to Roark; again from the Center after a loss", + next_to(GYM, "roark", SOUTH, NORTH)), }), oreburgh_to_route_203(), }; @@ -743,7 +816,7 @@ std::vector to_floaroma(){ // The map the save screen's card names at each row's start, as the console // read it there (lab-B's logs, 2026-10-31 to 11-02). A building's card -// names its town: 00.04 starts in Rowan's lab, 01.04 at Oreburgh's nurse. +// names its town: 00.04 starts in Rowan's lab. const std::map& start_save_cards(){ static const std::map cards{ {"00.01", "Twinleaf Town"}, diff --git a/devtools/maps/bdsp_maps.py b/devtools/maps/bdsp_maps.py index 6454bb3b47..2f5c1fdf61 100644 --- a/devtools/maps/bdsp_maps.py +++ b/devtools/maps/bdsp_maps.py @@ -411,6 +411,9 @@ def box(x0, y0, x1, y1): 'JubilifeCity': [(0, 22), (0, 23), (40, 40), (21, 42)], # The way up to the entrance hall: stepping on it leaves the room. 'OreburghMine': [(15, 1)], + # The mine's mouth: 01.03 walks down to the row above it and steps on. + # We come out on it too, and walk north off it to a wall first. + 'OreburghCity': [(x, 59) for x in range(44, 49)], } From 72b9552334d89841573a1317bdd1e77f67a77497 Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 18:19:11 -0800 Subject: [PATCH 09/13] BDSP AutoStory: 01.11 on the shared steps 01.11 starts at 01.10's end, (11, 29) facing north, and walks as the console did (r250a, r251a): 8 taps west along row 29 (LEGS), north until the old woman stops us (to_wall, anchored below her at (3, 26)), her talk; a tap west (LEGS, anchored below the old man at (2, 26), facing north, so the talk's turn only turns), his talk. Dropped: the event's tolerance of one uncounted tap west (7 of 8); LEGS wants all 8. Events_Route204.cpp keeps only 01.09's Rock Smash. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../AutoStory/PokemonBDSP_AutoStory_Events.h | 4 +-- .../PokemonBDSP_AutoStory_Events_Route204.cpp | 36 ++----------------- .../PokemonBDSP_AutoStory_StoryTable.cpp | 31 +++++++++++----- 3 files changed, 26 insertions(+), 45 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h index 8a47ffc628..b58b8914f7 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h @@ -12,8 +12,8 @@ * * They are in files by area: _Events_Lake (00.00 to 00.04), _Sandgem * (00.04), _Jubilife (00.05), _Oreburgh (01.04's Gym) and _Route204 - * (01.09's Rock Smash, 01.11). 01.01 to 01.03 and 01.05 to 01.10 are - * planned walks in the story table. + * (01.09's Rock Smash). 01.01 to 01.03 and 01.05 to 01.11 are planned + * walks in the story table. * */ diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route204.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route204.cpp index 157c99cbcc..f7975a6685 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route204.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route204.cpp @@ -1,9 +1,8 @@ -/* BDSP AutoStory - Events: Route 204 to Floaroma (01.09, 01.11) +/* BDSP AutoStory - Events: the Ravaged Path (01.09) * * From: https://github.com/PokemonAutomation/ * - * The Ravaged Path's Rock Smash, and segment 01's walks to the old couple - * in Floaroma's flower field, as they ran on the console (2026-10-31). + * The Ravaged Path's Rock Smash, as it ran on the console (2026-10-31). * */ @@ -72,42 +71,11 @@ void smash_the_rock(VideoStream& stream, ProControllerContext& context){ } } -// 01.11: west 8 along the flower field's bottom row, north until the old woman stops us. -void west_8_north_to_the_old_woman(VideoStream& stream, ProControllerContext& context){ - { - const WalkResult west = walk_tiles_dpad(stream, context, run_from_wild_battle, {-1, 0}, 8, "west 8 to the flower field"); - if (west.stop != WalkStop::LIMIT || west.moved_chunks < 7){ - fail_step(stream, "Floaroma: west 8 to the flower field moved " + std::to_string(west.moved_chunks) + " tiles."); - } - // Blocked, or out of taps with the last ones bumping: either way - // she is in front of us (r250a: 3 steps, 2 bumps, "limit"). - const WalkResult north = walk_tiles_dpad(stream, context, run_from_wild_battle, {0, 1}, 5, "north until the old woman"); - if (north.stop != WalkStop::BLOCKED && north.moved_chunks >= 5){ - fail_step(stream, "Floaroma: nothing stopped the walk north to the old woman."); - } - } -} - -// 01.11: one tile west, then a tap north: the old man stands there, so the tap only turns. -void below_the_old_man(VideoStream& stream, ProControllerContext& context){ - const WalkResult west = walk_tiles_dpad(stream, context, run_from_wild_battle, {-1, 0}, 1, "west 1 below the old man"); - if (west.moved_chunks < 1){ - fail_step(stream, "Floaroma: the step west below the old man did not move."); - } - // He stands there, so one tap only turns us to him; the talk after fails - // if nobody answers. No counting: Floaroma's cloud shadows read as moves - // (r84: blocked taps counted, view change 20). - pbf_press_dpad(context, DPAD_UP, 160ms, 500ms); - context.wait_for_all_requests(); -} - } void add_route204_events(StoryEvents& events){ events.emplace("smash_the_rock", console_event(smash_the_rock)); - events.emplace("west_8_north_to_the_old_woman", console_event(west_8_north_to_the_old_woman)); - events.emplace("below_the_old_man", console_event(below_the_old_man)); } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 4476af2198..33fd1562df 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -777,6 +777,27 @@ std::vector to_oreburgh(){ }; } +// 01.11 on Floaroma's map: the old woman (3, 25) and the old man (2, 25) +// west of her stand still above the flower field's bottom row (r251a). +// The walk to her is the one that ran on the console: 8 taps west along +// row 29, then north until she stops us (r250a: 3 steps, then bumps). +StoryCheckpoint floaromas_old_couple(){ + const Pose below_the_old_woman = next_to(FLOAROMA, "old_woman", SOUTH, NORTH); + const Pose below_the_old_man = next_to(FLOAROMA, "old_man", SOUTH, NORTH); + return row("01.11", "Floaroma's old couple", at(FLOAROMA, "route_204_arrival", NORTH), { + legs("west_along_the_field", {{.direction = WEST, .tiles = 8}}, "8 taps west along row 29"), + anchored(to_walls("up_to_the_old_woman", {{.direction = NORTH, .tiles = 5}}, "north until she stops us"), + below_the_old_woman), + talk("old_woman", "she gives Mew when a Let's Go save is on the console"), + scene("old_woman_talks", below_the_old_woman, "her lines"), + // He stands above that tile, so talk() turning north only turns. + anchored(legs("below_the_old_man", {{.direction = WEST, .tiles = 1}}, "a tile west"), below_the_old_man), + talk("old_man", "he gives Jirachi with a Sword/Shield save"), + scene("old_man_talks", below_the_old_man, "his lines"), + save(), + }); +} + std::vector to_floaroma(){ return { row("01.06", "Route 203 to Jubilife", out_of_oreburgh_gate(), { @@ -802,15 +823,7 @@ std::vector to_floaroma(){ }), through_the_ravaged_path(), route_204_to_floaroma(), - row("01.11", "Floaroma's old couple", std::nullopt, { - event("west_8_north_to_the_old_woman", "west 8, north until she stops us"), - talk("old_woman", "she gives Mew when a Let's Go save is on the console"), - scene("old_woman_talks", std::nullopt, "her lines"), - event("below_the_old_man", "a tile west, a tap north"), - talk("old_man", "he gives Jirachi with a Sword/Shield save"), - scene("old_man_talks", std::nullopt, "his lines"), - save(), - }), + floaromas_old_couple(), }; } From 2aba355d67d5e3d13ceca9b9db7fbe4aa1d6f556 Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 18:20:29 -0800 Subject: [PATCH 10/13] BDSP AutoStory: 00.05's steps on the shared steps 00.05 starts from a save at (48, 62), below Jubilife's steps (45..47, 61) against the wall east of them, where 00.04d's Dawn scene now says it leaves us: the old event went "a tile west, then up the steps" from there, two taps north (2026-10-30). That tile is the event's numbers on the map, not a measured one (#134). up_the_steps is a LEGS step of the same taps, a tile west and two north, ending on (47, 60); the route to the Center plans from that one tile, not the steps' region (46..47, 58..60). Events_Jubilife.cpp keeps only 00.05b's wandering clowns. The Events header lists what stays named and why. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../AutoStory/PokemonBDSP_AutoStory_Events.h | 17 +++++------ .../PokemonBDSP_AutoStory_Events_Jubilife.cpp | 24 ++-------------- .../PokemonBDSP_AutoStory_StoryTable.cpp | 28 ++++++++++++++----- 3 files changed, 33 insertions(+), 36 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h index b58b8914f7..eb34744814 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events.h @@ -4,16 +4,17 @@ * * The story's steps that only BDSP has, by name: a step of the table whose * variant names one of these runs it (StoryExecutor::run()). Some are the - * scripted scenes (the lake's briefcase, the starter, Dawn's catching - * tutorial); most are segment 01's walks, which were measured on the - * console as holds, taps and walks until stopped rather than planned, and - * are kept as they ran there. Each fails by throwing, with a screenshot; - * the executor turns that into a failed step. + * scripted scenes (the Azure Flute, the lake's briefcase, the starter, + * Dawn's catching tutorial and the catch); the rest do what the shared + * steps cannot, as they ran on the console: the Poke Mart lady's Potions + * and the stairs into Jubilife (00.04c, 00.04d), a clown who wanders + * (00.05b), the Gym's tries from the Pokemon Center (01.04) and Rock Smash + * (01.09). Each fails by throwing, with a screenshot; the executor turns + * that into a failed step. * * They are in files by area: _Events_Lake (00.00 to 00.04), _Sandgem - * (00.04), _Jubilife (00.05), _Oreburgh (01.04's Gym) and _Route204 - * (01.09's Rock Smash). 01.01 to 01.03 and 01.05 to 01.11 are planned - * walks in the story table. + * (00.04c, 00.04d), _Jubilife (00.05b), _Oreburgh (01.04) and _Route204 + * (01.09). * */ diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp index 9919b71635..af124bdb90 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Jubilife.cpp @@ -1,9 +1,9 @@ -/* BDSP AutoStory - Events: Jubilife City (00.05) +/* BDSP AutoStory - Events: Jubilife City (00.05b) * * From: https://github.com/PokemonAutomation/ * - * The Jubilife beats of 00.05 the story table cannot plan: up the steps, - * and the talk to a wandering clown. + * The Jubilife beat of 00.05b the story table cannot plan: the talk to a + * wandering clown. * */ @@ -31,23 +31,6 @@ using Pokemon::Direction; namespace{ -// 00.05: from the save below Jubilife's steps, against the wall east of -// them: a tile west (the first press only turns), then up the steps. -void up_the_steps(VideoStream& stream, ProControllerContext& context){ - // D-pad taps, a tile each: the stick holds this was (200 ms west, 480 ms - // north) left us between tiles, and every leg after it a column off - // (r57 to r61). By hand: a tap west and taps north from the save land - // on the map's tiles (between the lamps at x 43 and 49 after six). - route_turn(stream, context, Direction::WEST); - walk_tiles_dpad(stream, context, run_from_wild_battle, {-1, 0}, 1, "To the steps"); - route_turn(stream, context, Direction::NORTH); - const WalkResult up = walk_tiles_dpad(stream, context, run_from_wild_battle, {0, 1}, 2, "Up the steps"); - if (up.stop == WalkStop::DIALOG || up.stop == WalkStop::TRANSITION){ - fail_step(stream, std::string("Up the steps: ") + walk_stop_name(up.stop) + "."); - } -} - - // 00.05b: a talk to someone who wanders a tile either side of home along a // row (the clowns by the Mart and the Poketch Company, WANDER_AROUND with // x range 1). Waiting under home alone missed him for a minute (r66: he @@ -103,7 +86,6 @@ Pokemon::Outcome talk_to_wanderer(StoryExecutor& executor, Pokemon::RunState&, c void add_jubilife_events(StoryEvents& events){ - events.emplace("up_the_steps", console_event(up_the_steps)); events.emplace("talk_to_wanderer", talk_to_wanderer); } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 33fd1562df..a6c2906d84 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -11,9 +11,9 @@ * on the console (r72 to r261, 2026-10-30); 00.05 to 00.05c, measured there * first, are now planned on Jubilife's map with the people and triggers of * the Diamond decomp's zone events and scripts. Segment 01 ran on the - * console end to end (2026-10-31), its walks as events; 01.05 to 01.10 - * are now planned on the maps the same way (2026-11-02), and have not - * run on a console as plans yet. + * console end to end (2026-10-31), its walks as events; all of it but + * 01.04's Gym is now planned on the maps the same way (2026-11-02), and + * has not run on a console as plans yet. * */ @@ -422,6 +422,16 @@ std::vector to_the_catch(){ }; } +// Where Dawn's scene leaves 00.04d, and 00.05's save: below Jubilife's +// steps (45..47, 61), against the wall east of them, (48, 62). BDSP starts +// her scene as we come in below the steps, not on Diamond's trigger above +// them (45..48, 60): 00.05's old event went "a tile west, then up the +// steps" from its save, two taps north (2026-10-30). Not measured as a +// tile: the event's numbers and the map's (#134). +Pose below_jubilifes_steps(){ + return at(JUBILIFE, 48, 62); +} + std::vector to_jubilife(){ StoryStep potions = make(StoryStepKind::SHOP, "potions", "Potions before Route 202's trainers: the Poke Mart lady's 10 (she stands still, as in the decomp)"); @@ -439,7 +449,7 @@ std::vector to_jubilife(){ row("00.04d", "Route 202's trainers, Dawn in Jubilife", at(ROUTE_202, "save_spot"), { route("north_to_jubilife", on(ROUTE_202, "jubilife_exit"), "north past Route 202's trainers, fighting who sees us"), stairs, - scene("dawn_scene", std::nullopt, "Dawn walks over while we stand still"), + scene("dawn_scene", below_jubilifes_steps(), "Dawn walks over while we stand still"), }), }; } @@ -449,11 +459,15 @@ Pose below_the_school(){ return next_to(JUBILIFE, "trainers_school_door", SOUTH, SOUTH); } -// 00.05: the steps were measured on the console (2026-10-30); the rest is +// 00.05: the steps as measured on the console (2026-10-30); the rest is // planned on the map. StoryCheckpoint the_town_map(){ - return row("00.05", "Jubilife: the Center, the Trainers' School and the Town Map", std::nullopt, { - event("up_the_steps", "a tile west of the save below the steps, then up them", on(JUBILIFE, "up_the_steps")), + return row("00.05", "Jubilife: the Center, the Trainers' School and the Town Map", below_jubilifes_steps(), { + // D-pad taps, a tile each: the stick holds this was (200 ms west, + // 480 ms north) left us between tiles, and every leg after it a + // column off (r57 to r61). + legs("up_the_steps", {{.direction = WEST, .tiles = 1}, {.direction = NORTH, .tiles = 2}}, + "a tile west of the save, then up the steps to (47, 60)"), // Planned on the map: the hand-measured walls (west to the sign, east // across the road, north) leaned on the old turn's nudge and ended // beside the Trainers' School once turns stopped stepping (r57, r58). From 7e7cd4a6cadaaf85fa71f063118c2ea11e0bac63 Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 18:22:54 -0800 Subject: [PATCH 11/13] BDSP AutoStory: 01.03 talks to Barry below the decomp's Center door The Center's door is the decomp's (47, 20), as Sandgem's and Jubilife's doors were where the console came out of them. The map's doorstep (46, 21) only says where 01.04's 20 taps to the Gym were counted from, so out of the Center we may be on either tile. Barry's talk and the heal are now from (47, 21), a tap west of the fence, not two. The heal still lines up on the lit doorway when north finds no door. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../PokemonBDSP_AutoStory_StoryTable.cpp | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index a6c2906d84..641f5cadaf 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -579,9 +579,15 @@ Pose after_the_welcome(){ TilePos{43, 21}, TilePos{44, 21}, TilePos{45, 21}, TilePos{43, 22}, TilePos{44, 22}, TilePos{45, 22} }); } -// Out of Oreburgh's Pokemon Center: on (46, 21), facing south (r217d, r218d). +// Below Oreburgh's Pokemon Center's door (47, 20), facing it. +Pose below_oreburghs_center(){ + return at(OREBURGH, 47, 21, NORTH); +} +// Out of Oreburgh's Pokemon Center, facing south: below its door, or on +// the map's doorstep (46, 21), from which 01.04's 20 taps west reach the +// Gym's door column (r217d, r218d). Pose out_of_oreburgh_center(){ - return at(OREBURGH, "pokemon_center_doorstep", SOUTH); + return Pokemon::tile_pose(OREBURGH, {TilePos{47, 21}, map_point(OREBURGH, "pokemon_center_doorstep")}, SOUTH); } // 01.05, planned on Oreburgh's and the Gate's maps with the Diamond decomp's @@ -660,9 +666,11 @@ StoryCheckpoint route_203_to_oreburgh(){ // room down to Roark, whose scene ends with him gone (Platinum's // scripts_oreburgh_mine_b2f.s: he smashes the rock east of him and walks // off east); back up and out; and the Center's nurse, so 01.04 starts on -// the doorstep. The Center's door is column 46 on the console: we came out -// of it on (46, 21), 20 taps east of the Gym's door (r217d, r218d), and -// north from below the mine's sign and a tile east went in (2026-10-31). +// the doorstep. The Center's door is the decomp's (47, 20): out of +// Sandgem's and Jubilife's Centers the console stood in their doors' +// columns. The map's doorstep (46, 21) is the Gym's door column plus the +// 20 taps of 01.04 (r217d, r218d), which do not say where the taps began; +// the heal lines up on the lit doorway if north from (47, 21) misses. // // The hall is walked on counted taps, not held: it is a cave, and a wild // battle on a hold toward a fade would read as the fade. Its warp tiles @@ -677,11 +685,11 @@ StoryCheckpoint oreburgh_mine_to_roark(){ // walk east on these rows a tile east of the door, as by hand. anchored(to_walls("to_the_centers_fence", {{.direction = EAST, .tiles = 6}, {.direction = NORTH, .tiles = 2}}, "east to the fence below the Center's east corner, north to the Center's front"), at(OREBURGH, 48, 21, NORTH)), - anchored(legs("below_the_centers_door", {{.direction = WEST, .tiles = 2}}, "taps west below the door"), - at(OREBURGH, "pokemon_center_doorstep", NORTH)), + anchored(legs("below_the_centers_door", {{.direction = WEST, .tiles = 1}}, "a tap west below the door"), + below_oreburghs_center()), // He stands in the door the first time; walking into him reads as a wall. talk("barry", "Barry in the Center's door"), - scene("barrys_lines", at(OREBURGH, "pokemon_center_doorstep", NORTH), "Roark has gone to the mine"), + scene("barrys_lines", below_oreburghs_center(), "Roark has gone to the mine"), // The Hiker wanders (46..48, 25..27), in the door's column: the // route goes round him. route("above_the_mine", at(OREBURGH, 46, 58, SOUTH), "down the door's column to above the mine's warp tiles", "town"), @@ -707,7 +715,7 @@ StoryCheckpoint oreburgh_mine_to_roark(){ Pokemon::tile_pose(OREBURGH, {TilePos{45, 59}, TilePos{45, 58}}, NORTH)), anchored(to_walls("up_to_the_mines_sign", {{.direction = NORTH, .tiles = 3}}, "north against the mine's sign (45, 56)"), at(OREBURGH, 45, 57, NORTH)), - route("below_the_centers_door_again", at(OREBURGH, "pokemon_center_doorstep", NORTH), "up to below the Center's door", "town"), + route("below_the_centers_door_again", below_oreburghs_center(), "up to below the Center's door", "town"), heal("heal_oreburgh", "the nurse; out onto the doorstep, where 01.04 starts", out_of_oreburgh_center()), }); } From e7282a53dd0a21f3167ce4f0965dc7fdfa56e75a Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 18:41:07 -0800 Subject: [PATCH 12/13] BDSP AutoStory: a map for the mine's entrance hall; Dawn's scene on Jubilife Two fixes for #173's CI (the BDSP simulation tests): - 01.03's taps through the entrance hall had no world to walk on ("no world holds OreburghMineB1F"). The hall gets its map from the Diamond decomp (narc_0313, zone event narc_0196; the Hiker hidden by his flag), with its way up (11..13, 1) as doors, and a room world. Down, we land on (12, 1); up, on (11, 21). - 00.04d's Dawn scene ended on Jubilife while the stairs step before it left the pose on Route 202, so the scene waited for a fade that never comes (the grid sim's "no fade ... map mismatch"; on the console it would have failed after 120 s). The stairs step now ends below Jubilife's steps, (48, 62). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../AutoStory/Maps/OreburghMineB1F.json | 43 +++++++++++++++++++ .../PokemonBDSP_AutoStory_StoryPlaces.cpp | 4 +- .../PokemonBDSP_AutoStory_StoryTable.cpp | 15 ++++--- devtools/maps/bdsp_maps.py | 6 +++ 4 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/Maps/OreburghMineB1F.json diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/Maps/OreburghMineB1F.json b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/Maps/OreburghMineB1F.json new file mode 100644 index 0000000000..1d564db27c --- /dev/null +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/Maps/OreburghMineB1F.json @@ -0,0 +1,43 @@ +{ + "name": "OreburghMineB1F", + "source": {"decomp_file": "pret/pokediamond: files/fielddata/land_data/land_data_release/narc_0313.bin; zone_event narc_0196", "revision": "default branch", "date": "2026-10-31"}, + "tiles": [ + "################################", + "###########DDD##################", + "######...##...##.###############", + "######...##...##.###############", + "####.................###########", + "####.................###########", + "####.................###########", + "####.................###########", + "####.................###########", + "####.................###########", + "######.............#############", + "######.............#############", + "######.............#############", + "######.............#############", + "########.........###############", + "########.........###############", + "########.........###############", + "########.........###############", + "##########.....#################", + "##########.....#################", + "##########.....#################", + "##########.....#################", + "############D###################", + "################################", + "################################", + "################################", + "################################", + "################################", + "################################", + "################################", + "################################", + "################################" + ], + "objects": [ + {"name": "worker_0", "kind": "npc", "x": 7, "y": 4}, + {"name": "item_1", "kind": "item", "x": 19, "y": 4}, + {"name": "twin_2", "kind": "npc", "x": 6, "y": 3} + ] +} diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp index 78c7b02584..c5c2e2021b 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp @@ -130,12 +130,12 @@ Pokemon::MapData ravaged_path_smashed(){ return map; } -// The interiors (houses, the lab, the Gym, the Gate, the mine's coal room, +// The interiors (houses, the lab, the Gym, the Gate, the mine's two floors, // the Ravaged Path), each its own world, named by its JSON map. const std::map& room_worlds(){ static const std::map rooms = []{ std::map ret; - for (const char* room : {"PlayerHouse2F", "PlayerHouse1F", "RivalHouse1F", "RivalHouse2F", "RowansLab", "OreburghGym", "OreburghGate", "OreburghMine"}){ + for (const char* room : {"PlayerHouse2F", "PlayerHouse1F", "RivalHouse1F", "RivalHouse2F", "RowansLab", "OreburghGym", "OreburghGate", "OreburghMineB1F", "OreburghMine"}){ ret[room].add(room, story_map(room), {0, 0}); } ret["RavagedPath"].add("RavagedPath", ravaged_path_smashed(), {0, 0}); diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index 641f5cadaf..b9be1da438 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -59,8 +59,8 @@ const char* const JUBILIFE = "JubilifeCity"; const char* const TRAINERS_SCHOOL = "TrainersSchool"; const char* const OREBURGH = "OreburghCity"; const char* const GYM = "OreburghGym"; -// The mine's entrance hall (Diamond's MAP_OREBURGH_MINE_B1F) has no map: -// a pose there names it. The coal room below it, Roark's, does. +// The mine's entrance hall (Diamond's MAP_OREBURGH_MINE_B1F) and the coal +// room below it, Roark's. const char* const MINE_HALL = "OreburghMineB1F"; const char* const MINE = "OreburghMine"; const char* const GATE = "OreburghGate"; @@ -441,6 +441,9 @@ std::vector to_jubilife(){ StoryStep stairs = step_into("into_jubilife", NORTH, "Jubilife's south edge is a wall with stairs in it, west of where the route may leave us (r78)"); stairs.variant = "jubilife_stairs"; + // On Jubilife from here on: the scene after it plays where we stand, with + // no fade to wait for. + stairs.pose_after = below_jubilifes_steps(); return { row("00.04c", "Potions, back to Route 202's save spot", door_front(SANDGEM, "pokemon_center_door"), { potions, @@ -662,8 +665,8 @@ StoryCheckpoint route_203_to_oreburgh(){ // events narc_0044 and narc_0197): Barry in the Center's door says Roark // went to the mine (Roark ignored A until then, r101 and r104); down the // door's column to the mine's warp tiles (44..48, 59); straight down the -// entrance hall, which has no map, to its warps (11..13, 21); in the coal -// room down to Roark, whose scene ends with him gone (Platinum's +// entrance hall to its warps (11..13, 21); in the coal room down to +// Roark, whose scene ends with him gone (Platinum's // scripts_oreburgh_mine_b2f.s: he smashes the rock east of him and walks // off east); back up and out; and the Center's nurse, so 01.04 starts on // the doorstep. The Center's door is the decomp's (47, 20): out of @@ -693,7 +696,7 @@ StoryCheckpoint oreburgh_mine_to_roark(){ // The Hiker wanders (46..48, 25..27), in the door's column: the // route goes round him. route("above_the_mine", at(OREBURGH, 46, 58, SOUTH), "down the door's column to above the mine's warp tiles", "town"), - step_into("into_the_mine", SOUTH, "the warp tile (46, 59)", inside(MINE_HALL)), + step_into("into_the_mine", SOUTH, "the warp tile (46, 59)", at(MINE_HALL, 12, 1, SOUTH)), // We land on the warp tile we came by, (12, 1): 19 taps end on row // 20, a step short of the warp row. legs("down_the_hall", {{.direction = SOUTH, .tiles = 19}}, "down column 12 of the entrance hall"), @@ -709,7 +712,7 @@ StoryCheckpoint oreburgh_mine_to_roark(){ talk("roark", "Roark, north of us between his rocks"), scene("roark_smashes_the_rock", below_roark, "his lines, Rock Smash on the rock east of him, and he walks off"), route("below_the_coal_rooms_warp", at(MINE, 15, 2, NORTH), "back up the corridor"), - step_into("up_to_the_hall", NORTH, "the warp tile (15, 1)", inside(MINE_HALL)), + step_into("up_to_the_hall", NORTH, "the warp tile (15, 1)", at(MINE_HALL, 11, 21, NORTH)), legs("up_the_hall", {{.direction = NORTH, .tiles = 19}}, "up column 11 of the entrance hall"), step_into("out_of_the_mine", NORTH, "the hall's warp tiles (11..13, 1)", Pokemon::tile_pose(OREBURGH, {TilePos{45, 59}, TilePos{45, 58}}, NORTH)), diff --git a/devtools/maps/bdsp_maps.py b/devtools/maps/bdsp_maps.py index 2f5c1fdf61..1d54c8ac99 100644 --- a/devtools/maps/bdsp_maps.py +++ b/devtools/maps/bdsp_maps.py @@ -125,6 +125,9 @@ # walk north into the hall went up column 14 (the warp is column 15: a # stick hold drifts, or BDSP's stairs are wider). 'OreburghMine': {'header': 'OREBURGH_MINE_B2F', 'rect': (0, 0, 32, 32)}, + # B1F, the entrance hall: 01.03 crosses it on column 12 going down and + # column 11 coming up (the console's walks went straight through). + 'OreburghMineB1F': {'header': 'OREBURGH_MINE_B1F', 'rect': (0, 0, 32, 32)}, # Platinum's matrix 051 (Diamond's matrix is not in the cache), rows # 0..53. Console (2026-10-31, r235b and D-pad probes): in from the south # door onto (19, 50), up the stairs (18..20, 45..47) to the wall at row @@ -414,6 +417,9 @@ def box(x0, y0, x1, y1): # The mine's mouth: 01.03 walks down to the row above it and steps on. # We come out on it too, and walk north off it to a wall first. 'OreburghCity': [(x, 59) for x in range(44, 49)], + # The hall's way up to the city: its other warp row (11..13, 21) has + # cave mouths below it, so a step south from row 20 goes through. + 'OreburghMineB1F': [(11, 1), (12, 1), (13, 1)], } From 8f308aab44e712a0be60d325d8a8324e75f06917 Mon Sep 17 00:00:00 2001 From: dayfine Date: Mon, 2 Nov 2026 18:57:41 -0800 Subject: [PATCH 13/13] BDSP AutoStory: 00.04d's stairs are an event step, not a STEP The stairs into Jubilife were a STEP whose variant names the event jubilife_stairs. Since the last commit gave it a pose after (below Jubilife's steps, so Dawn's scene waits for no fade), a walk check that holds STEPs to their pose after expected it on Jubilife (the grid sim, which stubs events: "into_jubilife: ended on Route 202"). It is an event like the others now (event(), GAME), run the same way by its variant. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../PokemonBDSP_AutoStory_Events_Sandgem.cpp | 2 +- .../AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Sandgem.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Sandgem.cpp index e5b30ec0c0..1473ffd8ec 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Sandgem.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Sandgem.cpp @@ -145,7 +145,7 @@ void walk_to_route_202_save_spot( } // North into Jubilife until Dawn's scene starts (00.04d's -// into_jubilife). Jubilife's south edge is a wall with stairs in it, +// jubilife_stairs). Jubilife's south edge is a wall with stairs in it, // west of where the route may leave us (r78 stood at its east end). // Entering starts a scene: Dawn walks over while we stand still. So // walk north; if the wall stops us and no dialogue follows, the stairs diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp index b9be1da438..03069d92a0 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryTable.cpp @@ -438,12 +438,12 @@ std::vector to_jubilife(){ potions.items = {{.item = "potion", .quantity = 10}}; potions.variant = "sandgem_potions"; potions.pose_after = at(ROUTE_202, "save_spot"); - StoryStep stairs = step_into("into_jubilife", NORTH, - "Jubilife's south edge is a wall with stairs in it, west of where the route may leave us (r78)"); - stairs.variant = "jubilife_stairs"; - // On Jubilife from here on: the scene after it plays where we stand, with - // no fade to wait for. - stairs.pose_after = below_jubilifes_steps(); + // An event, not a step: it walks north and west until Dawn's scene + // starts. It leaves us on Jubilife, so the scene after it plays where + // we stand, with no fade to wait for. + const StoryStep stairs = event("jubilife_stairs", + "Jubilife's south edge is a wall with stairs in it, west of where the route may leave us (r78)", + below_jubilifes_steps()); return { row("00.04c", "Potions, back to Route 202's save spot", door_front(SANDGEM, "pokemon_center_door"), { potions,