From fbdcd899580668ff4e9a3de5b904956f8e299e55 Mon Sep 17 00:00:00 2001 From: Gin <> Date: Mon, 29 Jun 2026 10:38:54 -0700 Subject: [PATCH] Add movement option after entering game --- .../PokemonLZA_ShinyHunt_OverworldReset.cpp | 104 +++++++++++++++++- .../PokemonLZA_ShinyHunt_OverworldReset.h | 33 +++++- 2 files changed, 134 insertions(+), 3 deletions(-) diff --git a/SerialPrograms/Source/VideoGames/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.cpp b/SerialPrograms/Source/VideoGames/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.cpp index 3216383d2b..e028cab816 100644 --- a/SerialPrograms/Source/VideoGames/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.cpp +++ b/SerialPrograms/Source/VideoGames/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.cpp @@ -9,6 +9,7 @@ #include "CommonTools/Async/InferenceRoutines.h" #include "CommonTools/StartupChecks/VideoResolutionCheck.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" #include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" #include "Pokemon/Pokemon_Strings.h" #include "VideoGames/PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h" @@ -62,15 +63,47 @@ std::unique_ptr ShinyHunt_OverworldReset_Descriptor::make_stats() ShinyHunt_OverworldReset::ShinyHunt_OverworldReset() : RESET_DELAY( - "Reset Delay:
Wait this long after the game loads before resetting.", + "Reset Delay:
Wait this long after the game loads and player character moves before resetting.", LockMode::UNLOCK_WHILE_RUNNING, "5000 ms" ) , ROTATE_CAMERA( - "Rotate Camera:
Rotate camera upon entering the game.", + "Rotate Camera:
Rotate camera during waiting.", LockMode::UNLOCK_WHILE_RUNNING, false ) + , MOVEMENT( + "Movement:
" + "Move the player after entering the game to close gap. ", + { + {Movement::NONE, "none", "No Movement"}, + {Movement::RUN, "run", "Run (Hold B)"}, + {Movement::ROLL, "roll", "Roll (Press Y)"}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + Movement::NONE + ) + , RUN_DIRECTION( + "Run Direction:
Run in this direction, relative to the camera.", + { + {RunDirection::FORWARD, "forward", "Forward"}, + {RunDirection::BACKWARD, "backward", "Backward"}, + {RunDirection::LEFT, "left", "Left"}, + {RunDirection::RIGHT, "right", "Right"}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + RunDirection::FORWARD + ) + , RUN_DURATION( + "Run Duration:
Run for this long.", + LockMode::UNLOCK_WHILE_RUNNING, + "2000 ms" + ) + , ROLLS( + "Rolls:
Roll this many times in the direction the player is facing.", + LockMode::UNLOCK_WHILE_RUNNING, + 1, 1 + ) , SHINY_DETECTED( "Shiny Detected", "", "5000 ms", @@ -86,10 +119,76 @@ ShinyHunt_OverworldReset::ShinyHunt_OverworldReset() }) { PA_ADD_STATIC(SHINY_REQUIRES_AUDIO); + PA_ADD_OPTION(MOVEMENT); PA_ADD_OPTION(RESET_DELAY); PA_ADD_OPTION(ROTATE_CAMERA); + PA_ADD_OPTION(RUN_DIRECTION); + PA_ADD_OPTION(RUN_DURATION); + PA_ADD_OPTION(ROLLS); PA_ADD_OPTION(SHINY_DETECTED); PA_ADD_OPTION(NOTIFICATIONS); + + ShinyHunt_OverworldReset::on_config_value_changed(this); + MOVEMENT.add_listener(*this); +} +ShinyHunt_OverworldReset::~ShinyHunt_OverworldReset(){ + MOVEMENT.remove_listener(*this); +} +void ShinyHunt_OverworldReset::on_config_value_changed(void* object){ + switch (MOVEMENT){ + case Movement::NONE: + RUN_DIRECTION.set_visibility(ConfigOptionState::HIDDEN); + RUN_DURATION.set_visibility(ConfigOptionState::HIDDEN); + ROLLS.set_visibility(ConfigOptionState::HIDDEN); + break; + case Movement::RUN: + RUN_DIRECTION.set_visibility(ConfigOptionState::ENABLED); + RUN_DURATION.set_visibility(ConfigOptionState::ENABLED); + ROLLS.set_visibility(ConfigOptionState::HIDDEN); + break; + case Movement::ROLL: + RUN_DIRECTION.set_visibility(ConfigOptionState::HIDDEN); + RUN_DURATION.set_visibility(ConfigOptionState::HIDDEN); + ROLLS.set_visibility(ConfigOptionState::ENABLED); + break; + } +} + + +void ShinyHunt_OverworldReset::move_after_loading(ProControllerContext& context){ + switch (MOVEMENT){ + case Movement::NONE: + return; + case Movement::RUN:{ + JoystickPosition direction; + switch (RUN_DIRECTION){ + case RunDirection::FORWARD: + direction = {0, +1}; + break; + case RunDirection::BACKWARD: + direction = {0, -1}; + break; + case RunDirection::LEFT: + direction = {-1, 0}; + break; + case RunDirection::RIGHT: + direction = {+1, 0}; + break; + } + // Hold B alongside the joystick for the whole duration so the player + // runs instead of walks. + Milliseconds duration = RUN_DURATION; + ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); + pbf_move_left_joystick(context, direction, duration, 0ms); + return; + } + case Movement::ROLL: + // Each roll takes about a second to finish before the next one can start. + for (uint8_t c = 0; c < ROLLS; c++){ + pbf_press_button(context, BUTTON_Y, 100ms, 1000ms); + } + return; + } } void ShinyHunt_OverworldReset::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ @@ -122,6 +221,7 @@ void ShinyHunt_OverworldReset::program(SingleSwitchProgramEnvironment& env, ProC [&](ProControllerContext& context){ reset_game_from_home(env, env.console, context); + move_after_loading(context); if (ROTATE_CAMERA){ pbf_move_right_joystick(context, {+1, 0}, RESET_DELAY, 0ms); }else{ diff --git a/SerialPrograms/Source/VideoGames/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.h b/SerialPrograms/Source/VideoGames/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.h index 42cb558211..951a61ce02 100644 --- a/SerialPrograms/Source/VideoGames/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.h +++ b/SerialPrograms/Source/VideoGames/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_OverworldReset.h @@ -8,6 +8,8 @@ #define PokemonAutomation_PokemonLZA_ShinyHunt_OverworldReset_H #include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/EnumDropdownOption.h" +#include "Common/Cpp/Options/SimpleIntegerOption.h" #include "Common/Cpp/Options/TimeDurationOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" @@ -30,19 +32,48 @@ class ShinyHunt_OverworldReset_Descriptor : public SingleSwitchProgramDescriptor }; -class ShinyHunt_OverworldReset : public SingleSwitchProgramInstance{ +class ShinyHunt_OverworldReset : public SingleSwitchProgramInstance, ConfigOption::Listener{ public: using Descriptor = ShinyHunt_OverworldReset_Descriptor; ShinyHunt_OverworldReset(); + virtual ~ShinyHunt_OverworldReset(); virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; private: + // How the player moves after entering the game to close any + // gap to target spawns. + enum class Movement{ + NONE, + RUN, + ROLL, + }; + + // Direction to run, relative to the camera. + enum class RunDirection{ + FORWARD, + BACKWARD, + LEFT, + RIGHT, + }; + + // Show only the movement options that apply to the selected `MOVEMENT`. + // Controls the visibility of RUN_DIRECTION, RUN_DURATION and ROLLS. + virtual void on_config_value_changed(void* object) override; + + // Perform the movement selected by `MOVEMENT` after the game loads. + void move_after_loading(ProControllerContext& context); + PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; MillisecondsOption RESET_DELAY; BooleanCheckBoxOption ROTATE_CAMERA; + EnumDropdownOption MOVEMENT; + EnumDropdownOption RUN_DIRECTION; + MillisecondsOption RUN_DURATION; + SimpleIntegerOption ROLLS; + ShinySoundDetectedActionOption SHINY_DETECTED; EventNotificationOption NOTIFICATION_STATUS;