From b76d4cba19f318815a1d9519f566279dee3a0996 Mon Sep 17 00:00:00 2001 From: dayfine Date: Sun, 25 Oct 2026 02:04:18 -0700 Subject: [PATCH 1/2] AutoStory: build the start/end select databases with one shared helper SV built six near-identical databases by hand. make_story_select_database() in Pokemon/AutoStory builds a section of a story list with the same labels (name()) and slugs (index in the whole list), so other games can reuse it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../AutoStory/Pokemon_AutoStorySelect.h | 37 ++++++++ .../AutoStory/PokemonSV_AutoStory.cpp | 91 ++++--------------- SerialPrograms/cmake/SourceFiles.cmake | 1 + 3 files changed, 57 insertions(+), 72 deletions(-) create mode 100644 SerialPrograms/Source/Pokemon/AutoStory/Pokemon_AutoStorySelect.h diff --git a/SerialPrograms/Source/Pokemon/AutoStory/Pokemon_AutoStorySelect.h b/SerialPrograms/Source/Pokemon/AutoStory/Pokemon_AutoStorySelect.h new file mode 100644 index 0000000000..80b4f94338 --- /dev/null +++ b/SerialPrograms/Source/Pokemon/AutoStory/Pokemon_AutoStorySelect.h @@ -0,0 +1,37 @@ +/* AutoStory Select + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_Pokemon_AutoStorySelect_H +#define PokemonAutomation_Pokemon_AutoStorySelect_H + +#include +#include +#include +#include "CommonTools/Options/StringSelectOption.h" + +namespace PokemonAutomation{ +namespace Pokemon{ + + +// A dropdown database of the story segments or checkpoints [begin, end) of +// `list`, labeled by their name() and slugged by their index in the whole +// list, so a slug picks the same entry whichever section it was chosen from. +template +StringSelectDatabase make_story_select_database( + const std::vector>& list, + size_t begin, size_t end +){ + StringSelectDatabase ret; + for (size_t i = begin; i < end && i < list.size(); i++){ + ret.add_entry(StringSelectEntry(std::to_string(i), list[i]->name())); + } + return ret; +} + + +} +} +#endif diff --git a/SerialPrograms/Source/VideoGames/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp b/SerialPrograms/Source/VideoGames/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp index a805a15080..aec8b25ff5 100644 --- a/SerialPrograms/Source/VideoGames/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp +++ b/SerialPrograms/Source/VideoGames/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp @@ -28,6 +28,7 @@ #include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" #include "VideoGames/PokemonSV/PokemonSV_Settings.h" #include "Pokemon/Pokemon_Strings.h" +#include "Pokemon/AutoStory/Pokemon_AutoStorySelect.h" #include "VideoGames/PokemonSwSh/Inference/PokemonSwSh_IvJudgeReader.h" #include "VideoGames/PokemonSV/Inference/PokemonSV_MainMenuDetector.h" #include "VideoGames/PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.h" @@ -149,51 +150,24 @@ const std::vector>& ALL_AUTO_STORY_SEGMENT_LI } -StringSelectDatabase make_all_segments_database(){ - StringSelectDatabase ret; - int index_num = 0; - for (const auto& segment : ALL_AUTO_STORY_SEGMENT_LIST()){ - ret.add_entry(StringSelectEntry(std::to_string(index_num), segment->name())); - index_num++; - } - return ret; -} const StringSelectDatabase& ALL_SEGMENTS_SELECT_DATABASE(){ - static StringSelectDatabase database = make_all_segments_database(); + static StringSelectDatabase database = make_story_select_database( + ALL_AUTO_STORY_SEGMENT_LIST(), 0, ALL_AUTO_STORY_SEGMENT_LIST().size() + ); return database; } -StringSelectDatabase make_tutorial_segments_database(){ - StringSelectDatabase ret; - const StringSelectDatabase& all_segments = ALL_SEGMENTS_SELECT_DATABASE(); - size_t start = 0; - size_t end = INDEX_OF_LAST_TUTORIAL_SEGMENT + 1; - for (size_t i = start; i < end; i++){ - const auto& segment = all_segments[i]; - ret.add_entry(segment); - } - return ret; -} - const StringSelectDatabase& TUTORIAL_SEGMENTS_SELECT_DATABASE(){ - static StringSelectDatabase database = make_tutorial_segments_database(); + static StringSelectDatabase database = make_story_select_database( + ALL_AUTO_STORY_SEGMENT_LIST(), 0, INDEX_OF_LAST_TUTORIAL_SEGMENT + 1 + ); return database; } -StringSelectDatabase make_mainstory_segments_database(){ - StringSelectDatabase ret; - const StringSelectDatabase& all_segments = ALL_SEGMENTS_SELECT_DATABASE(); - size_t start = INDEX_OF_LAST_TUTORIAL_SEGMENT + 1; - size_t end = all_segments.case_list().size(); - for (size_t i = start; i < end; i++){ - const auto& segment = all_segments[i]; - ret.add_entry(segment); - } - return ret; -} - const StringSelectDatabase& MAINSTORY_SEGMENTS_SELECT_DATABASE(){ - static StringSelectDatabase database = make_mainstory_segments_database(); + static StringSelectDatabase database = make_story_select_database( + ALL_AUTO_STORY_SEGMENT_LIST(), INDEX_OF_LAST_TUTORIAL_SEGMENT + 1, ALL_AUTO_STORY_SEGMENT_LIST().size() + ); return database; } @@ -323,51 +297,24 @@ const std::vector>& ALL_AUTO_STORY_CHECKPO return checkpoint_list; } -StringSelectDatabase make_all_checkpoints_database(){ - StringSelectDatabase ret; - int index_num = 0; - for (const auto& segment : ALL_AUTO_STORY_CHECKPOINT_LIST()){ - ret.add_entry(StringSelectEntry(std::to_string(index_num), segment->name())); - index_num++; - } - return ret; -} const StringSelectDatabase& ALL_CHECKPOINTS_SELECT_DATABASE(){ - static StringSelectDatabase database = make_all_checkpoints_database(); + static StringSelectDatabase database = make_story_select_database( + ALL_AUTO_STORY_CHECKPOINT_LIST(), 0, ALL_AUTO_STORY_CHECKPOINT_LIST().size() + ); return database; } -StringSelectDatabase make_tutorial_checkpoints_database(){ - StringSelectDatabase ret; - const StringSelectDatabase& all_checkpoints = ALL_CHECKPOINTS_SELECT_DATABASE(); - size_t start = 0; - size_t end = INDEX_OF_LAST_TUTORIAL_CHECKPOINT + 1; - for (size_t i = start; i < end; i++){ - const auto& segment = all_checkpoints[i]; - ret.add_entry(segment); - } - return ret; -} - const StringSelectDatabase& TUTORIAL_CHECKPOINTS_SELECT_DATABASE(){ - static StringSelectDatabase database = make_tutorial_checkpoints_database(); + static StringSelectDatabase database = make_story_select_database( + ALL_AUTO_STORY_CHECKPOINT_LIST(), 0, INDEX_OF_LAST_TUTORIAL_CHECKPOINT + 1 + ); return database; } -StringSelectDatabase make_mainstory_checkpoints_database(){ - StringSelectDatabase ret; - const StringSelectDatabase& all_checkpoints = ALL_CHECKPOINTS_SELECT_DATABASE(); - size_t start = INDEX_OF_LAST_TUTORIAL_CHECKPOINT + 1; - size_t end = all_checkpoints.case_list().size(); - for (size_t i = start; i < end; i++){ - const auto& segment = all_checkpoints[i]; - ret.add_entry(segment); - } - return ret; -} - const StringSelectDatabase& MAINSTORY_CHECKPOINTS_SELECT_DATABASE(){ - static StringSelectDatabase database = make_mainstory_checkpoints_database(); + static StringSelectDatabase database = make_story_select_database( + ALL_AUTO_STORY_CHECKPOINT_LIST(), INDEX_OF_LAST_TUTORIAL_CHECKPOINT + 1, ALL_AUTO_STORY_CHECKPOINT_LIST().size() + ); return database; } diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index e04611c3ef..3c444ef3c5 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1435,6 +1435,7 @@ file(GLOB LIBRARY_SOURCES Source/Pokemon/Options/Pokemon_NameSelectWidget.h Source/Pokemon/Options/Pokemon_StatsHuntFilter.cpp Source/Pokemon/Options/Pokemon_StatsHuntFilter.h + Source/Pokemon/AutoStory/Pokemon_AutoStorySelect.h Source/Pokemon/Pokemon_AdvRng.cpp Source/Pokemon/Pokemon_AdvRng.h Source/Pokemon/Pokemon_BdspRng.cpp From 5d23a5601d4cf3be62084b1a4922af816a33bd4f Mon Sep 17 00:00:00 2001 From: dayfine Date: Sun, 1 Nov 2026 13:12:06 -0800 Subject: [PATCH 2/2] AutoStory: test the shared select database with the helper that builds it Moved here from #44 (user decision): a section of a story list keeps its whole-list slugs and the end is clamped to the list. #44 keeps story_index() and its tests. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E --- .../VideoGames/PokemonSV/PokemonSV_Tests.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/SerialPrograms/Source/VideoGames/PokemonSV/PokemonSV_Tests.cpp b/SerialPrograms/Source/VideoGames/PokemonSV/PokemonSV_Tests.cpp index 80f1d0b6f8..95ea9b1525 100644 --- a/SerialPrograms/Source/VideoGames/PokemonSV/PokemonSV_Tests.cpp +++ b/SerialPrograms/Source/VideoGames/PokemonSV/PokemonSV_Tests.cpp @@ -5,6 +5,7 @@ */ #include "Common/Cpp/TestRunners/UnitTestDatabase.h" +#include "Pokemon/AutoStory/Pokemon_AutoStorySelect.h" #include "Inference/PokemonSV_WhiteButtonDetector.h" #include "Inference/Boxes/PokemonSV_BoxDetection.h" #include "Inference/Boxes/PokemonSV_BoxEggDetector.h" @@ -148,7 +149,46 @@ class Test_BlueberryPoints : public ImageUnitTest{ } +namespace{ + +// A stand-in for a story segment or checkpoint: only its name is read. +struct NamedEntry{ + std::string label; + std::string name() const{ return label; } +}; + +class Test_AutoStorySelectDatabase : public UnitTest{ +public: + Test_AutoStorySelectDatabase() + : UnitTest("Pokemon::AutoStorySelectDatabase - a section keeps whole-list slugs") + {} + + virtual UnitTestResult run(Logger&, CancellableScope&) const override{ + std::vector> list; + for (const char* label : {"a", "b", "c", "d"}){ + list.emplace_back(std::make_unique(NamedEntry{label})); + } + const StringSelectDatabase database = Pokemon::make_story_select_database(list, 2, 10); + const std::vector& entries = database.case_list(); + if (entries.size() != 2){ + return "Expected 2 entries (the end is clamped to the list), got " + std::to_string(entries.size()); + } + if (entries[0].slug != "2" || entries[0].display_name != "c" || entries[1].slug != "3" || entries[1].display_name != "d"){ + return "Expected slugs 2, 3 labeled c, d; got " + entries[0].slug + " " + entries[0].display_name + + ", " + entries[1].slug + " " + entries[1].display_name; + } + return true; + } +}; + +void add_tests_AutoStory(UnitTestDatabase& database){ + database.add(); +} + +} + void add_tests(UnitTestDatabase& database){ + add_tests_AutoStory(database); database.add(); // Full-frame references, in the CommandLineTests repo: they exercise the production