Skip to content

Commit 54a822c

Browse files
author
Gin
committed
Separate sewer hunting programs from ShuttleRun to SewerHunter
1 parent 7b853d0 commit 54a822c

File tree

6 files changed

+302
-110
lines changed

6 files changed

+302
-110
lines changed

SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "Programs/ShinyHunting/PokemonLZA_WildZoneCafe.h"
3535
#include "Programs/ShinyHunting/PokemonLZA_ShinyHunt_FlySpotReset.h"
3636
#include "Programs/ShinyHunting/PokemonLZA_ShuttleRun.h"
37+
#include "Programs/ShinyHunting/PokemonLZA_SewerHunter.h"
3738

3839
// Non-Shiny Hunting
3940
#include "Programs/NonShinyHunting/PokemonLZA_StatsReset.h"
@@ -85,10 +86,11 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{
8586
if (IS_BETA_VERSION){
8687
ret.emplace_back(make_single_switch_program<ShinyHunt_WildZoneCafe_Descriptor, ShinyHunt_WildZoneCafe>());
8788
ret.emplace_back(make_single_switch_program<ShinyHunt_FlySpotReset_Descriptor, ShinyHunt_FlySpotReset>());
88-
ret.emplace_back(make_single_switch_program<ShinyHunt_ShuttleRun_Descriptor, ShinyHunt_ShuttleRun>());
8989
}
9090
if (PreloadSettings::instance().DEVELOPER_MODE){
9191
ret.emplace_back(make_single_switch_program<BeldumHunter_Descriptor, BeldumHunter>());
92+
ret.emplace_back(make_single_switch_program<ShinyHunt_ShuttleRun_Descriptor, ShinyHunt_ShuttleRun>());
93+
ret.emplace_back(make_single_switch_program<ShinyHunt_SewerHunter_Descriptor, ShinyHunt_SewerHunter>());
9294
}
9395

9496
// ret.emplace_back("---- Non-Shiny Hunting ----");
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/* Shiny Hunt - Sewer Hunter
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#include "CommonFramework/Exceptions/OperationFailedException.h"
8+
#include "CommonFramework/ProgramStats/StatsTracking.h"
9+
#include "CommonFramework/Notifications/ProgramNotifications.h"
10+
#include "CommonFramework/VideoPipeline/VideoOverlay.h"
11+
#include "CommonTools/Async/InferenceRoutines.h"
12+
#include "CommonTools/VisualDetectors/BlackScreenDetector.h"
13+
#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h"
14+
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
15+
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h"
16+
#include "Pokemon/Pokemon_Strings.h"
17+
#include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h"
18+
#include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h"
19+
#include "PokemonLZA_SewerHunter.h"
20+
21+
namespace PokemonAutomation::NintendoSwitch::PokemonLZA {
22+
23+
using namespace Pokemon;
24+
25+
26+
ShinyHunt_SewerHunter_Descriptor::ShinyHunt_SewerHunter_Descriptor()
27+
: SingleSwitchProgramDescriptor(
28+
"PokemonLZA:ShinyHunt-SewerHunter", STRING_POKEMON + " LZA",
29+
"Sewer Hunter",
30+
"Programs/PokemonLZA/ShinyHunt-SewerHunter.html",
31+
"Shiny hunt in two sewer subzones",
32+
ProgramControllerClass::StandardController_NoRestrictions, FeedbackType::REQUIRED,
33+
AllowCommandsWhenRunning::DISABLE_COMMANDS, {}
34+
)
35+
{}
36+
class ShinyHunt_SewerHunter_Descriptor::Stats : public StatsTracker{
37+
public:
38+
Stats()
39+
: resets(m_stats["Rounds"])
40+
, shinies(m_stats["Shiny Sounds"])
41+
, errors(m_stats["Errors"])
42+
{
43+
m_display_order.emplace_back("Rounds");
44+
m_display_order.emplace_back("Shiny Sounds");
45+
m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO);
46+
}
47+
48+
std::atomic<uint64_t>& resets;
49+
std::atomic<uint64_t>& shinies;
50+
std::atomic<uint64_t>& errors;
51+
};
52+
std::unique_ptr<StatsTracker> ShinyHunt_SewerHunter_Descriptor::make_stats() const{
53+
return std::unique_ptr<StatsTracker>(new Stats());
54+
}
55+
56+
57+
ShinyHunt_SewerHunter::ShinyHunt_SewerHunter()
58+
: DURATION("<b>Duration:</b><br>Run the program this long.", LockMode::UNLOCK_WHILE_RUNNING, "5 h")
59+
, ROUTE("<b>Hunt Route:</b>",
60+
{
61+
{Route::KLEFKI, "klefki", "Klefki"},
62+
{Route::KLEFKI_INKAY_GOOMY, "klefki_inkay_goomy", "Klefki+Inkay+Goomy"},
63+
{Route::LITWICK, "litwick", "Litwick"},
64+
{Route::LITWICK_SKRELP, "litwick_skrelp", "Litwick+Skrelp+Haunter"},
65+
{Route::SKRELP, "skrelp", "Skrelp"},
66+
{Route::SKRELP_INKAY, "skrelp_inkay", "Skrelp+Inkay"},
67+
{Route::SKRELP_ARIADOS, "skrelp_ariados", "Skrelp+Ariados"},
68+
},
69+
LockMode::LOCK_WHILE_RUNNING,
70+
Route::KLEFKI
71+
)
72+
, SHINY_DETECTED("Shiny Detected", "", "1000 ms", ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY)
73+
, NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600))
74+
, NOTIFICATIONS({
75+
&NOTIFICATION_STATUS,
76+
&NOTIFICATION_PROGRAM_FINISH,
77+
&NOTIFICATION_ERROR_RECOVERABLE,
78+
&NOTIFICATION_ERROR_FATAL,
79+
})
80+
{
81+
PA_ADD_STATIC(SHINY_REQUIRES_AUDIO);
82+
PA_ADD_OPTION(DURATION);
83+
PA_ADD_OPTION(ROUTE);
84+
PA_ADD_OPTION(SHINY_DETECTED);
85+
PA_ADD_OPTION(NOTIFICATIONS);
86+
}
87+
88+
namespace {
89+
90+
void fly_back_to_sewers_entrance(ConsoleHandle& console, ProControllerContext& context) {
91+
pbf_press_button(context, BUTTON_PLUS, 240ms, 80ms); // open map
92+
context.wait_for_all_requests();
93+
pbf_wait(context, 500ms);
94+
pbf_press_button(context, BUTTON_Y, 100ms, 100ms); // select fly point
95+
{
96+
BlackScreenOverWatcher black_screen(COLOR_BLUE);
97+
int ret = run_until<ProControllerContext>(
98+
console, context,
99+
[](ProControllerContext& context){
100+
pbf_mash_button(context, BUTTON_A, 10000ms);
101+
},
102+
{black_screen}
103+
);
104+
if (ret != 0){
105+
OperationFailedException::fire(
106+
ErrorReport::SEND_ERROR_REPORT,
107+
"fly_back_to_sewers_entrance(): cannot detect black screen after mashing A.",
108+
console
109+
);
110+
}
111+
}
112+
wait_until_overworld(console, context);
113+
}
114+
115+
void run_forward_backward_to_wall(
116+
SingleSwitchProgramEnvironment& env, ProControllerContext& context,
117+
PokemonAutomation::Milliseconds duration
118+
){
119+
ssf_press_button(context, BUTTON_B, 0ms, 500ms, 0ms);
120+
pbf_move_left_joystick(context, 128, 0, duration, 0ms);
121+
pbf_move_left_joystick(context, 128, 255, duration + 500ms, 0ms);
122+
pbf_wait(context, 500ms);
123+
}
124+
125+
void route_klefki(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
126+
ssf_press_button(context, BUTTON_B, 0ms, 500ms, 0ms);
127+
pbf_move_left_joystick(context, 128, 0, 4900ms, 0ms);
128+
pbf_move_left_joystick(context, 0, 128, 1000ms, 0ms);
129+
pbf_press_button(context, BUTTON_L, 100ms, 500ms);
130+
fly_back_to_sewers_entrance(env.console, context);
131+
}
132+
133+
void route_klefki_inkay_goomy(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
134+
ssf_press_button(context, BUTTON_B, 0ms, 500ms, 0ms);
135+
pbf_move_left_joystick(context, 128, 0, 8500ms, 0ms);
136+
pbf_move_left_joystick(context, 255, 128, 1300ms, 0ms);
137+
pbf_press_button(context, BUTTON_L, 100ms, 500ms);
138+
fly_back_to_sewers_entrance(env.console, context);
139+
}
140+
141+
void route_litwick(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
142+
run_forward_backward_to_wall(env, context, 5s);
143+
}
144+
145+
void route_litwick_skrelp(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
146+
run_forward_backward_to_wall(env, context, 9000ms);
147+
}
148+
149+
void route_skrelp(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
150+
fly_back_to_sewers_entrance(env.console, context);
151+
pbf_wait(context, 1000ms);
152+
}
153+
154+
void route_skrelp_inkay(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
155+
ssf_press_button(context, BUTTON_B, 0ms, 500ms, 0ms);
156+
pbf_move_left_joystick(context, 128, 0, 3900ms, 0ms);
157+
fly_back_to_sewers_entrance(env.console, context);
158+
}
159+
160+
void route_skrelp_ariados(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
161+
run_forward_backward_to_wall(env, context, 6s);
162+
}
163+
164+
} // namespace
165+
166+
167+
void ShinyHunt_SewerHunter::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
168+
ShinyHunt_SewerHunter_Descriptor::Stats& stats =
169+
env.current_stats<ShinyHunt_SewerHunter_Descriptor::Stats>();
170+
ShinySoundHandler shiny_sound_handler(SHINY_DETECTED);
171+
PokemonLA::ShinySoundDetector shiny_detector(env.console, [&](float error_coefficient) -> bool {
172+
// Warning: This callback will be run from a different thread than this function.
173+
stats.shinies++;
174+
env.update_stats();
175+
env.console.overlay().add_log("Shiny Sound Detected!", COLOR_YELLOW);
176+
return shiny_sound_handler.on_shiny_sound(
177+
env, env.console,
178+
stats.shinies,
179+
error_coefficient
180+
);
181+
});
182+
std::function<void(SingleSwitchProgramEnvironment&, ProControllerContext&)> route;
183+
switch (ROUTE) {
184+
case Route::KLEFKI:
185+
route = route_klefki;
186+
break;
187+
case Route::KLEFKI_INKAY_GOOMY:
188+
route = route_klefki_inkay_goomy;
189+
break;
190+
case Route::LITWICK:
191+
route = route_litwick;
192+
break;
193+
case Route::LITWICK_SKRELP:
194+
route = route_litwick_skrelp;
195+
break;
196+
case Route::SKRELP:
197+
route = route_skrelp;
198+
break;
199+
case Route::SKRELP_INKAY:
200+
route = route_skrelp_inkay;
201+
break;
202+
case Route::SKRELP_ARIADOS:
203+
route = route_skrelp_ariados;
204+
break;
205+
default:
206+
OperationFailedException::fire(
207+
ErrorReport::SEND_ERROR_REPORT,
208+
"route not implemented",
209+
env.console
210+
);
211+
}
212+
WallClock start_time = current_time();
213+
pbf_press_button(context, BUTTON_L, 100ms, 100ms); // connect
214+
215+
run_until<ProControllerContext>(
216+
env.console, context,
217+
[&](ProControllerContext& context){
218+
do{
219+
shiny_sound_handler.process_pending(context);
220+
send_program_status_notification(env, NOTIFICATION_STATUS);
221+
route(env, context);
222+
context.wait_for_all_requests();
223+
stats.resets++;
224+
env.update_stats();
225+
}while (current_time() < start_time + DURATION.get());
226+
},
227+
{{shiny_detector}}
228+
);
229+
230+
shiny_sound_handler.process_pending(context);
231+
go_home(env.console, context);
232+
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);
233+
}
234+
235+
236+
} // namespace PokemonAutomation::NintendoSwitch::PokemonLZA
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* Shiny Hunt - Sewer Hunter
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#ifndef PokemonAutomation_PokemonLZA_Sewer_Hunter_H
8+
#define PokemonAutomation_PokemonLZA_Sewer_Hunter_H
9+
10+
#include "Common/Cpp/Options/EnumDropdownOption.h"
11+
#include "Common/Cpp/Options/TimeDurationOption.h"
12+
#include "CommonFramework/Notifications/EventNotificationsTable.h"
13+
#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h"
14+
#include "PokemonLA/Options/PokemonLA_ShinyDetectedAction.h"
15+
#include "PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h"
16+
17+
namespace PokemonAutomation {
18+
namespace NintendoSwitch {
19+
namespace PokemonLZA {
20+
21+
22+
class ShinyHunt_SewerHunter_Descriptor : public SingleSwitchProgramDescriptor {
23+
public:
24+
ShinyHunt_SewerHunter_Descriptor();
25+
26+
class Stats;
27+
virtual std::unique_ptr<StatsTracker> make_stats() const override;
28+
};
29+
30+
31+
class ShinyHunt_SewerHunter : public SingleSwitchProgramInstance {
32+
public:
33+
ShinyHunt_SewerHunter();
34+
35+
virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override;
36+
37+
enum class Route{
38+
KLEFKI,
39+
KLEFKI_INKAY_GOOMY,
40+
LITWICK,
41+
LITWICK_SKRELP,
42+
SKRELP,
43+
SKRELP_INKAY,
44+
SKRELP_ARIADOS
45+
};
46+
47+
private:
48+
PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO;
49+
MillisecondsOption DURATION;
50+
EnumDropdownOption<Route> ROUTE;
51+
ShinySoundDetectedActionOption SHINY_DETECTED;
52+
EventNotificationOption NOTIFICATION_STATUS;
53+
EventNotificationsOption NOTIFICATIONS;
54+
};
55+
56+
57+
} // namespace PokemonLZA
58+
} // namespace NintendoSwitch
59+
} // namespace PokemonAutomation
60+
#endif

0 commit comments

Comments
 (0)