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/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_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 388b396eae..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 intro's briefcase, the starter, the Starly battle, - * the Pokedex); 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.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.04c, 00.04d), _Jubilife (00.05b), _Oreburgh (01.04) and _Route204 + * (01.09). * */ @@ -46,7 +47,6 @@ StoryEvent console_event(std::function #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" @@ -35,37 +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.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 // x range 1). Waiting under home alone missed him for a minute (r66: he @@ -117,107 +82,11 @@ 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("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_Events_Lake.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Lake.cpp index 80b271cd1e..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,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, 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,24 +116,7 @@ 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. -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. @@ -151,9 +134,8 @@ 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_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_Events_Route203.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route203.cpp deleted file mode 100644 index 6b15500f78..0000000000 --- a/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_Events_Route203.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* BDSP AutoStory - Events: Route 203 (01.02) - * - * From: https://github.com/PokemonAutomation/ - * - * Segment 01's walks along Route 203: east to the Oreburgh Gate and through - * it to Oreburgh, as they ran on the console (2026-10-29 to 10-31). - * - */ - -#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/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_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_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_StoryExecutor.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryExecutor.cpp index c7a5c8a090..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(); @@ -501,6 +503,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_StoryPlaces.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/AutoStory/PokemonBDSP_AutoStory_StoryPlaces.cpp index 3c05fa52b1..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 Ravaged Path), -// each its own world, named by its JSON map. +// 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"}){ + 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 021fb6d3c5..03069d92a0 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. * */ @@ -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) and the coal +// room below it, Roark's. +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"; @@ -301,11 +305,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"), @@ -328,8 +334,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"), }), }; } @@ -412,15 +422,28 @@ 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)"); 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"; + // 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, @@ -429,7 +452,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"), }), }; } @@ -439,11 +462,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). @@ -456,8 +483,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()), }); @@ -523,8 +557,15 @@ 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 +// 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. @@ -532,6 +573,26 @@ 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} + }); +} +// 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 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 // 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 @@ -559,6 +620,109 @@ 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. +// +// 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 + // 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"), + 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("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"), + 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. + 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 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 +// 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 +// 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 = 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", 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"), + 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"), + 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)", 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)), + 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", 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()), + }); +} + // 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(){ @@ -619,33 +783,46 @@ 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"), - }), - 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"), + // 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.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"), + route_203_to_oreburgh(), + 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(), }; } +// 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(), { @@ -671,21 +848,13 @@ 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(), }; } // 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/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; } diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 147c7849dc..6e336fe5b5 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1682,7 +1682,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 diff --git a/devtools/maps/bdsp_maps.py b/devtools/maps/bdsp_maps.py index 6454bb3b47..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 @@ -411,6 +414,12 @@ 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)], + # 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)], }