Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
92a3502
FRLG AutoStory stage 5: Route 25 and Bill's S.S. Ticket
dayfine Nov 3, 2026
df1e266
Merge remote-tracking branch 'origin/frlg/stage4-cerulean' into frlg/…
dayfine Nov 3, 2026
db1a21a
FRLG AutoStory teach: move tutors, as for Route 4's Mega Kick
dayfine Nov 3, 2026
ff5bf0a
FRLG AutoStory 00.20: an Oddish from Route 24's grass
dayfine Nov 3, 2026
413dee4
FRLG AutoStory 00.18: walk around Bill on the way out of the Sea Cottage
dayfine Nov 3, 2026
dc384b1
FRLG image tests: expected values from the file names
dayfine Nov 3, 2026
7e5a549
FRLG AutoStory 00.14: Mega Kick from Route 4's tutor on the way to Ce…
dayfine Nov 3, 2026
7a05318
FRLG AutoStory: hold a tile longer per map connection a leg crosses
dayfine Nov 3, 2026
b5e3a2e
FRLG AutoStory 00.20: mark the Oddish row a stopgap for console B's save
dayfine Nov 3, 2026
51eb5de
FRLG AutoStory: plan the walk after pacing from both of its tiles
dayfine Nov 3, 2026
1c22de0
FRLG AutoStory 00.20: walk west to the cliff, out of Shane's sight
dayfine Nov 3, 2026
360701b
FRLG AutoStory: fight a trainer who sees the player while pacing
dayfine Nov 3, 2026
7b6a28c
Merge commit '4e3cf21ebd0c94f71196c7468d0606cf773ef5b5' into HEAD
dayfine Nov 5, 2026
0cbf80f
FRLG AutoStory stage 5: align with PR #231 lint conventions
dayfine Nov 6, 2026
0ea1d97
Merge origin/frlg/stage4-cerulean into frlg/stage5-bill
dayfine Nov 6, 2026
6484afe
Merge origin/frlg/stage4-cerulean into frlg/stage5-bill
dayfine Nov 7, 2026
e1afaa5
Merge remote-tracking branch 'origin/frlg/stage4-cerulean' into frlg/…
dayfine Nov 8, 2026
79bb621
Merge frlg/stage4-cerulean into frlg/stage5-bill
dayfine Nov 8, 2026
115defd
Merge remote-tracking branch 'origin/frlg/stage4-cerulean' into HEAD
dayfine Nov 9, 2026
4112bf7
Merge frlg/stage4-cerulean into frlg/stage5-bill
dayfine Nov 9, 2026
bbef25b
Merge frlg/stage4-cerulean (story action table) into frlg/stage5-bill
dayfine Nov 9, 2026
2574ea5
Merge frlg/stage4-cerulean into frlg/stage5-bill
dayfine Nov 9, 2026
219902a
Merge frlg/stage4-cerulean: check the save stands at the checkpoint's…
dayfine Nov 9, 2026
356b927
FRLG AutoStory: keep the simulation tests' line endings
dayfine Nov 9, 2026
dd8ce6d
Merge frlg/stage4-cerulean: time an interrupt's step from its screen …
dayfine Nov 9, 2026
3ce2b45
Merge frlg/stage4-cerulean: check a loaded save's start against a kep…
dayfine Nov 9, 2026
755329d
Merge frlg/stage4-cerulean: check a loaded save's start against a kep…
dayfine Nov 9, 2026
2ab5af7
Merge 19d082561 (#122 via parent) into frlg/stage5-bill
dayfine Nov 9, 2026
b93d1d3
Merge FRLG between-step interrupts (0ec989dd4) into #219
dayfine Nov 9, 2026
82e3821
Merge FRLG between-step interrupts (3f472f67a) into #219
dayfine Nov 9, 2026
12c744e
Merge FRLG interrupt actions move (4b520be72) into #219
dayfine Nov 9, 2026
480f132
Merge frlg/stage4-cerulean into frlg/stage5-bill (hold watchers for t…
dayfine Nov 9, 2026
24a17a1
Merge frlg/stage4-cerulean into frlg/stage5-bill
dayfine Nov 9, 2026
8f6fdc5
Merge frlg/stage4-cerulean into frlg/stage5-bill (wait for a battle's…
dayfine Nov 9, 2026
93c1b56
Merge frlg/stage4-cerulean into frlg/stage5-bill (scene ends after it…
dayfine Nov 9, 2026
5c8b08f
Merge frlg/stage4-cerulean into frlg/stage5-bill: a step on the Switc…
dayfine Nov 9, 2026
bb75eb0
Merge frlg/stage4-cerulean into frlg/stage5-bill
dayfine Nov 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class PlaceNameMatcher : public OCR::SmallDictionaryMatcher{
{"route-3", "Route 3"},
{"route-4", "Route 4"},
{"cerulean-city", "Cerulean City"},
{"route-24", "Route 24"},
{"route-25", "Route 25"},
}){
JsonArray names;
names.push_back(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
*
* Reads where the game would be saved: the place name in blue at the top
* of the card the START menu's SAVE shows ("PALLET TOWN" over PLAYER,
* BADGES and TIME). It knows the places from a new game to Route 4, and
* Cerulean City, in English only so far: in another language nothing is
* read. Route 3, Route 4 and Cerulean City have no test capture yet.
* BADGES and TIME). It knows the places from a new game to Route 4,
* Cerulean City, Route 24 and Route 25 (Bill's Sea Cottage is on it), in
* English only so far: in another language nothing is read. Route 3,
* Route 4, Cerulean City, Route 24 and Route 25 have no test capture yet.
*
*/

Expand All @@ -31,8 +32,9 @@ namespace PokemonFRLG{
ImageFloatBox save_card_title_box();

// The place on the save card: "pallet-town", "viridian-city",
// "viridian-forest", "pewter-city", "route-1" to "route-4", "cerulean-city"; empty if it
// can't be read, as in a language the reader has no names for.
// "viridian-forest", "pewter-city", "route-1" to "route-4", "cerulean-city",
// "route-24", "route-25"; empty if it can't be read, as in a language the
// reader has no names for.
std::string read_save_card_location(Logger& logger, Language language, const ImageViewRGB32& screen);


Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Teach Screen Reader

Check warning on line 1 in SerialPrograms/Source/VideoGames/PokemonFRLG/Inference/Menus/PokemonFRLG_TeachScreenReader.cpp

View workflow job for this annotation

GitHub Actions / code-health

Code health (advisory)

<file>: file_lines=518 (advisory above 500, limit 1000)
*
* From: https://github.com/PokemonAutomation/
*
Expand Down Expand Up @@ -489,22 +489,23 @@

void add_tests_TeachScreenReader(UnitTestDatabase& database){
// FireRed on console B, 2026-11-03: TM03 taught to the lead from the
// bag, B on the move to forget, and YES to stop.
// bag, B on the move to forget, and YES to stop. Listed in the order
// the screens came up.
for (const char* image : {
"01_BagItems_eng.png",
"02_BagKeyItems_eng.png",
"03_KeyItemsTmCase_eng.png",
"04_TmCaseMenu_eng.png",
"05_TmCaseList_eng.png",
"06_Tm03Menu_eng.png",
"07_TeachWhich_eng.png",
"08_WantsToLearn_eng.png",
"09_KnowsFour_eng.png",
"10_DeleteQuestion_eng.png",
"11_WhichMove_eng.png",
"12_KnownMoves_eng.png",
"13_StopQuestion_eng.png",
"14_DidNotLearn_eng.png",
"BagItems_eng.png",
"BagKeyItems_eng.png",
"KeyItemsTmCase_eng.png",
"TmCaseMenu_eng.png",
"TmCaseList_eng.png",
"Tm03Menu_eng.png",
"TeachWhich_eng.png",
"WantsToLearn_eng.png",
"KnowsFour_eng.png",
"DeleteQuestion_eng.png",
"WhichMove_eng.png",
"KnownMoves_eng.png",
"StopQuestion_eng.png",
"DidNotLearn_eng.png",
}){
database.add<Test_TeachScreen>(std::string("PokemonFRLG/TeachScreenReader/") + image);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,23 @@ std::optional<Reanchor> plan_reanchor(
return std::nullopt;
}

std::optional<std::vector<RouteStep>> holds_to_one_tile(
const std::vector<MapData>& maps, const std::vector<MapPosition>& tiles
){
std::vector<Hypothesis> positions;
for (const MapPosition& tile : tiles){
add_unique(positions, Hypothesis{0, tile});
}
if (positions.empty()){
return std::nullopt;
}
const std::vector<Found> found = find_player({maps}, positions, false);
if (found.empty()){
return std::nullopt;
}
return found[0].holds;
}



} // namespace PokemonFRLG
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ std::optional<Reanchor> plan_reanchor(
const RouteCosts& costs = default_route_costs()
);

// Holds to walls that bring the player to one tile from every one of
// `tiles`, found as plan_reanchor() finds them, with no trainer about: for
// a player known to be on one of a few tiles without a stop (a wild
// battle's pacing). Empty if `tiles` are one tile; the last hold ends on
// it otherwise. Nothing if no holds bring them together.
std::optional<std::vector<RouteStep>> holds_to_one_tile(
const std::vector<MapData>& maps, const std::vector<MapPosition>& tiles
);


// Registers overworld reanchor unit tests.
void add_tests_OverworldReanchor(UnitTestDatabase& database);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Pokemon::LegSpec leg_spec(const RouteStep& step, MoveSpeed speed){
leg.tile_time = tile_time(step, speed);
leg.stop_on_interrupt = !step.to_wall;
leg.stop_if_blocked = step.to_wall;
leg.stalled_steps = step.connection_steps;
return leg;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Overworld Route

Check warning on line 1 in SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldRoute.cpp

View workflow job for this annotation

GitHub Actions / code-health

Code health (advisory)

<file>: file_lines=1000 (advisory above 500, limit 1000)
*
* From: https://github.com/PokemonAutomation/
*
Expand All @@ -7,6 +7,7 @@
#include <algorithm>
#include <format>
#include <functional>
#include <ranges>
#include <string>
#include "Common/Cpp/Exceptions.h"
#include "Common/Cpp/TestRunners/UnitTest.h"
Expand Down Expand Up @@ -333,7 +334,7 @@
return leg_costs;
}

RouteStep to_route_step(const std::vector<MapData>& maps, const Pokemon::Leg<Located>& leg){

Check warning on line 337 in SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldRoute.cpp

View workflow job for this annotation

GitHub Actions / code-health

Code health (advisory)

PokemonAutomation::NintendoSwitch::PokemonFRLG::to_route_step( const std :: vector<MapData> & maps , const Pokemon :: Leg<Located> & leg): function_lines=33 (advisory above 25, limit 50)
RouteStep step;
switch (leg.kind){
case Pokemon::LegKind::WALK:
Expand All @@ -360,6 +361,10 @@
// wasn't watched for battles (console B, 2026-11-01).
step.wild = leg.wild || leg.start.state.surfing || leg.kind == Pokemon::LegKind::ACTION;
}
const std::vector<MapPosition> tiles = leg_tiles(maps, MapPosition{maps[leg.start.map].name, leg.start.state.position}, step);
for (int c : std::views::iota(1, (int)tiles.size()) | std::views::filter([&](int n){ return tiles[n].map != tiles[n - 1].map; })){
step.connection_steps.push_back(c);
}
return step;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ struct RouteStep{
Direction facing_after = Direction::NORTH;
// Where the player is after the step.
MapPosition end;
// WALK: the steps (from 1) onto a connected map. The game holds the
// player up a tile before each while it loads the map: a hold timed
// by the tiles alone ended a tile short (console B, 2026-11-03, rows
// 00.14, 00.16 and 00.20).
std::vector<int> connection_steps = {};
};
// Formats a RouteStep as a string.
std::string to_string(const RouteStep& step);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Overworld Sim

Check warning on line 1 in SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldSim.cpp

View workflow job for this annotation

GitHub Actions / code-health

Code health (advisory)

<file>: file_lines=753 (advisory above 500, limit 1000)
*
* From: https://github.com/PokemonAutomation/
*
Expand Down Expand Up @@ -355,7 +355,7 @@
}

// The steps a hold of `duration` takes, `short_by` fewer.
void OverworldSim::walk_hold(Direction direction, Milliseconds duration, int short_by){

Check warning on line 358 in SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldSim.cpp

View workflow job for this annotation

GitHub Actions / code-health

Code health (advisory)

PokemonAutomation::NintendoSwitch::PokemonFRLG::OverworldSim::walk_hold( Direction direction , Milliseconds duration , int short_by): function_lines=34 (advisory above 25, limit 50)
const Milliseconds tile = m_script.timing.tile;
const Milliseconds end = m_now + duration;
Milliseconds pressed = m_now;
Expand All @@ -371,6 +371,15 @@
bump(direction, pressed);
return;
}
if (step->map != m_map && !step->warped){
// The step onto a connected map waits a tile while the game
// loads it: a hold timed by its tiles alone ended a tile short
// (console B, 2026-11-03, rows 00.14, 00.16 and 00.20).
pressed += tile;
if (pressed >= end){
return;
}
}
if (step->walked_out){
m_state.facing = Direction::SOUTH;
}
Expand Down Expand Up @@ -590,7 +599,7 @@
fail("walk_overworld_route(): a wild battle, not the warp to " + step.end.map + ": the player is off the route.");
}

std::optional<WalkedTiles> OverworldSimWalker::walk_step(const RouteStep& step, std::optional<Direction> facing){

Check warning on line 602 in SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldSim.cpp

View workflow job for this annotation

GitHub Actions / code-health

Code health (advisory)

PokemonAutomation::NintendoSwitch::PokemonFRLG::OverworldSimWalker::walk_step( const RouteStep & step , std :: optional<Direction> facing): function_lines=46 (advisory above 25, limit 50)
if (step.action == RouteAction::FACE){
m_sim.tap(step.direction);
return std::nullopt;
Expand All @@ -610,6 +619,9 @@
leg.tile_time = TILE_TIME;
leg.stop_on_interrupt = !step.to_wall;
leg.stop_if_blocked = step.to_wall && m_rules.stop_if_blocked;
if (m_rules.hold_over_connections){
leg.stalled_steps = step.connection_steps;
}
Pokemon::LegCalls calls;
calls.hold_watching = [&](Milliseconds hold) -> std::optional<Pokemon::HoldOutcome>{
const std::optional<SimSeen> seen = hold_watching(step, hold, ints);
Expand Down
Loading
Loading