Skip to content

Commit 5706733

Browse files
committed
LGPE fossil revival shiny hunt
1 parent 3c6a0bc commit 5706733

File tree

5 files changed

+361
-0
lines changed

5 files changed

+361
-0
lines changed

SerialPrograms/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,8 @@ file(GLOB MAIN_SOURCES
13801380
Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.h
13811381
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp
13821382
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.h
1383+
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_FossilRevival.cpp
1384+
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_FossilRevival.h
13831385
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp
13841386
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h
13851387
Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.cpp

SerialPrograms/SerialPrograms.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ SOURCES += \
677677
Source/PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.cpp \
678678
Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp \
679679
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp \
680+
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_FossilRevival.cpp \
680681
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp \
681682
Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.cpp \
682683
Source/PokemonLGPE/PokemonLGPE_Panels.cpp \
@@ -1870,6 +1871,7 @@ HEADERS += \
18701871
Source/PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.h \
18711872
Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.h \
18721873
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.h \
1874+
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_FossilRevival.h \
18731875
Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h \
18741876
Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.h \
18751877
Source/PokemonLGPE/PokemonLGPE_Panels.h \

SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "Programs/Farming/PokemonLGPE_DailyItemFarmer.h"
1313
#include "Programs/ShinyHunting/PokemonLGPE_AlolanTrade.h"
14+
#include "Programs/ShinyHunting/PokemonLGPE_FossilRevival.h"
1415
#include "Programs/ShinyHunting/PokemonLGPE_GiftReset.h"
1516

1617
namespace PokemonAutomation{
@@ -32,6 +33,7 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{
3233

3334
ret.emplace_back("---- Shiny Hunting ----");
3435
ret.emplace_back(make_single_switch_program<AlolanTrade_Descriptor, AlolanTrade>());
36+
ret.emplace_back(make_single_switch_program<FossilRevival_Descriptor, FossilRevival>());
3537
ret.emplace_back(make_single_switch_program<GiftReset_Descriptor, GiftReset>());
3638

3739
return ret;
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
/* LGPE Fossil Revival
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#include "CommonFramework/Exceptions/OperationFailedException.h"
8+
#include "CommonFramework/Notifications/ProgramNotifications.h"
9+
#include "CommonFramework/ProgramStats/StatsTracking.h"
10+
#include "CommonFramework/VideoPipeline/VideoFeed.h"
11+
#include "CommonTools/Async/InferenceRoutines.h"
12+
#include "CommonTools/StartupChecks/VideoResolutionCheck.h"
13+
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
14+
#include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h"
15+
#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h"
16+
#include "Pokemon/Pokemon_Strings.h"
17+
#include "CommonTools/VisualDetectors/BlackScreenDetector.h"
18+
#include "PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.h"
19+
#include "PokemonLGPE/Programs/PokemonLGPE_GameEntry.h"
20+
#include "PokemonLGPE_FossilRevival.h"
21+
22+
namespace PokemonAutomation{
23+
namespace NintendoSwitch{
24+
namespace PokemonLGPE{
25+
26+
FossilRevival_Descriptor::FossilRevival_Descriptor()
27+
: SingleSwitchProgramDescriptor(
28+
"PokemonLGPE:FossilRevival",
29+
Pokemon::STRING_POKEMON + " LGPE", "Fossil Revival",
30+
"ComputerControl/blob/master/Wiki/Programs/PokemonLGPE/FossilRevival.md",
31+
"Shiny hunt fossil Pokemon by reviving and resetting.",
32+
FeedbackType::REQUIRED,
33+
AllowCommandsWhenRunning::DISABLE_COMMANDS,
34+
{ControllerFeature::NintendoSwitch_RightJoycon},
35+
FasterIfTickPrecise::NOT_FASTER
36+
)
37+
{}
38+
39+
struct FossilRevival_Descriptor::Stats : public StatsTracker{
40+
Stats()
41+
: revives(m_stats["Revives"])
42+
, resets(m_stats["Resets"])
43+
, shinies(m_stats["Shinies"])
44+
{
45+
m_display_order.emplace_back("Revives");
46+
m_display_order.emplace_back("Resets");
47+
m_display_order.emplace_back("Shinies");
48+
}
49+
std::atomic<uint64_t>& revives;
50+
std::atomic<uint64_t>& resets;
51+
std::atomic<uint64_t>& shinies;
52+
};
53+
std::unique_ptr<StatsTracker> FossilRevival_Descriptor::make_stats() const{
54+
return std::unique_ptr<StatsTracker>(new Stats());
55+
}
56+
57+
FossilRevival::FossilRevival()
58+
: SLOT(
59+
"<b>Fossil slot:</b><br>Position of the fossil in the selection dialog.",
60+
{
61+
{0, "slot0", "Slot 1"},
62+
{1, "slot1", "Slot 2"},
63+
{2, "slot2", "Slot 3"},
64+
},
65+
LockMode::LOCK_WHILE_RUNNING,
66+
0
67+
)
68+
,NUM_REVIVALS(
69+
"<b>Number of fossils to revive:</b>",
70+
LockMode::LOCK_WHILE_RUNNING,
71+
30, 1
72+
)
73+
, GO_HOME_WHEN_DONE(false)
74+
, NOTIFICATION_SHINY(
75+
"Shiny Found",
76+
true, true, ImageAttachmentMode::JPG,
77+
{"Notifs", "Showcase"}
78+
)
79+
, NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600))
80+
, NOTIFICATIONS({
81+
&NOTIFICATION_SHINY,
82+
&NOTIFICATION_STATUS_UPDATE,
83+
&NOTIFICATION_PROGRAM_FINISH,
84+
})
85+
{
86+
PA_ADD_OPTION(SLOT);
87+
PA_ADD_OPTION(NUM_REVIVALS);
88+
PA_ADD_OPTION(GO_HOME_WHEN_DONE);
89+
PA_ADD_OPTION(NOTIFICATIONS);
90+
}
91+
92+
void FossilRevival::run_revives(SingleSwitchProgramEnvironment& env, JoyconContext& context){
93+
//Press A to get to selection
94+
env.log("Starting dialog.");
95+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
96+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
97+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
98+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
99+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
100+
context.wait_for_all_requests();
101+
102+
pbf_wait(context, 700ms);
103+
context.wait_for_all_requests();
104+
105+
//Select fossil slot
106+
env.log("Selecting fossil.");
107+
for (uint16_t c = 0; c < (uint16_t)SLOT.current_value(); c++){
108+
pbf_move_joystick(context, 128, 255, 100ms, 200ms);
109+
}
110+
pbf_press_button(context, BUTTON_A, 200ms, 300ms);
111+
context.wait_for_all_requests();
112+
113+
//Mash A until revival over
114+
BlackScreenOverWatcher revival_over(COLOR_RED);
115+
int ret = run_until<JoyconContext>(
116+
env.console, context,
117+
[](JoyconContext& context){
118+
pbf_mash_button(context, BUTTON_A, 15000ms);
119+
},
120+
{revival_over}
121+
);
122+
context.wait_for_all_requests();
123+
if (ret != 0){
124+
env.log("Failed to revive fossil.", COLOR_RED);
125+
OperationFailedException::fire(
126+
ErrorReport::SEND_ERROR_REPORT,
127+
"Failed to revive fossil.",
128+
env.console
129+
);
130+
}
131+
else {
132+
env.log("Fossil revived.");
133+
}
134+
135+
//Now mash B until next black screen (end of summary/tucked pokemon away)
136+
BlackScreenOverWatcher summary_over(COLOR_YELLOW);
137+
int ret2 = run_until<JoyconContext>(
138+
env.console, context,
139+
[](JoyconContext& context){
140+
pbf_mash_button(context, BUTTON_B, 15000ms);
141+
},
142+
{summary_over}
143+
);
144+
context.wait_for_all_requests();
145+
if (ret2 != 0){
146+
env.log("Did not detect summary over.", COLOR_RED);
147+
OperationFailedException::fire(
148+
ErrorReport::SEND_ERROR_REPORT,
149+
"Did not detect summary over.",
150+
env.console
151+
);
152+
}
153+
else {
154+
env.log("Summary closed/Pokemon tucked away in box/team.");
155+
}
156+
157+
//Close out come back soon text.
158+
pbf_mash_button(context, BUTTON_B, 500ms);
159+
context.wait_for_all_requests();
160+
}
161+
162+
void FossilRevival::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){
163+
JoyconContext context(scope, env.console.controller<JoyconController>());
164+
assert_16_9_720p_min(env.logger(), env.console);
165+
FossilRevival_Descriptor::Stats& stats = env.current_stats<FossilRevival_Descriptor::Stats>();
166+
167+
/*
168+
Settings:
169+
Text speed fast
170+
171+
is first time dialog different?
172+
173+
Setup:
174+
Stand in front of the scientist in cinnebar.
175+
Save the game.
176+
Start the program in-game.
177+
*/
178+
179+
bool shiny_found = false;
180+
while (!shiny_found) {
181+
//Run revives
182+
for (uint16_t i = 0; i < NUM_REVIVALS; i++) {
183+
env.log("Running trade.");
184+
run_revives(env, context);
185+
186+
stats.revives++;
187+
env.update_stats();
188+
}
189+
190+
env.log("Done reviving. Checking boxes.");
191+
send_program_status_notification(
192+
env, NOTIFICATION_STATUS_UPDATE,
193+
"Done reviving. Checking boxes."
194+
);
195+
196+
//Wait a bit.
197+
pbf_wait(context, 2500ms);
198+
context.wait_for_all_requests();
199+
200+
//Open menu, open party, open boxes
201+
env.log("Opening boxes.");
202+
pbf_press_button(context, BUTTON_X, 200ms, 500ms);
203+
pbf_press_button(context, BUTTON_A, 200ms, 1500ms);
204+
pbf_press_button(context, BUTTON_Y, 200ms, 2000ms);
205+
context.wait_for_all_requests();
206+
207+
//Sort by order caught
208+
env.log("Sorting by order caught.");
209+
pbf_press_button(context, BUTTON_Y, 200ms, 1000ms);
210+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
211+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
212+
context.wait_for_all_requests();
213+
214+
//Press left to go to last (most recent) Pokemon
215+
env.log("Opening summary of most recent Pokemon.");
216+
pbf_move_joystick(context, 0, 128, 100ms, 100ms);
217+
context.wait_for_all_requests();
218+
219+
//View summary - it takes a moment to load
220+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
221+
pbf_move_joystick(context, 128, 255, 100ms, 100ms);
222+
pbf_move_joystick(context, 128, 255, 100ms, 100ms);
223+
pbf_press_button(context, BUTTON_A, 200ms, 100ms);
224+
context.wait_for_all_requests();
225+
226+
pbf_wait(context, 5000ms);
227+
context.wait_for_all_requests();
228+
229+
//Now check for shinies. Check everything that was traded.
230+
env.log("Checking received Pokemon.");
231+
for (uint16_t i = 0; i < NUM_REVIVALS; i++) {
232+
VideoSnapshot screen = env.console.video().snapshot();
233+
ShinySymbolDetector shiny_checker(COLOR_YELLOW);
234+
bool check = shiny_checker.read(env.console.logger(), screen);
235+
236+
if (check) {
237+
env.log("Shiny detected!");
238+
stats.shinies++;
239+
env.update_stats();
240+
send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny found!", {}, "", screen, true);
241+
shiny_found = true;
242+
243+
//Back out to menu and favorite the shiny.
244+
env.log("Favoriting shiny.");
245+
pbf_press_button(context, BUTTON_B, 200ms, 5000ms);
246+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
247+
pbf_move_joystick(context, 128, 0, 100ms, 100ms);
248+
pbf_move_joystick(context, 128, 0, 100ms, 100ms);
249+
pbf_move_joystick(context, 128, 0, 100ms, 200ms);
250+
pbf_press_button(context, BUTTON_A, 200ms, 800ms);
251+
pbf_press_button(context, BUTTON_A, 200ms, 800ms);
252+
pbf_press_button(context, BUTTON_B, 200ms, 800ms);
253+
254+
//Go into summary again
255+
env.log("Navigating back into summary.");
256+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
257+
pbf_move_joystick(context, 128, 255, 100ms, 100ms);
258+
pbf_move_joystick(context, 128, 255, 100ms, 100ms);
259+
pbf_press_button(context, BUTTON_A, 200ms, 100ms);
260+
context.wait_for_all_requests();
261+
pbf_wait(context, 5000ms);
262+
context.wait_for_all_requests();
263+
}
264+
else {
265+
env.log("Not shiny.");
266+
}
267+
268+
//Move left, check next.
269+
pbf_move_joystick(context, 0, 128, 100ms, 100ms);
270+
pbf_press_button(context, BUTTON_X, 0ms, 1000ms);
271+
context.wait_for_all_requests();
272+
}
273+
274+
if (!shiny_found) {
275+
env.log("Out of Pokemon to check and no shiny found. Resetting game.");
276+
send_program_status_notification(
277+
env, NOTIFICATION_STATUS_UPDATE,
278+
"Out of Pokemon to check and no shiny found. Resetting game."
279+
);
280+
281+
//Reset game
282+
pbf_press_button(context, BUTTON_HOME, 200ms, 2000ms);
283+
reset_game_from_home(env, env.console, context, 3000ms);
284+
context.wait_for_all_requests();
285+
286+
stats.resets++;
287+
env.update_stats();
288+
}
289+
}
290+
291+
if (GO_HOME_WHEN_DONE) {
292+
pbf_press_button(context, BUTTON_HOME, 200ms, 1000ms);
293+
}
294+
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);
295+
}
296+
297+
298+
}
299+
}
300+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/* LGPE Fossil Revival
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#ifndef PokemonAutomation_PokemonLGPE_FossilRevival_H
8+
#define PokemonAutomation_PokemonLGPE_FossilRevival_H
9+
10+
#include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h"
11+
#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h"
12+
#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h"
13+
#include "CommonFramework/Notifications/EventNotificationsTable.h"
14+
#include "Common/Cpp/Options/EnumDropdownOption.h"
15+
#include "Common/Cpp/Options/SimpleIntegerOption.h"
16+
17+
namespace PokemonAutomation{
18+
namespace NintendoSwitch{
19+
namespace PokemonLGPE{
20+
21+
class FossilRevival_Descriptor : public SingleSwitchProgramDescriptor{
22+
public:
23+
FossilRevival_Descriptor();
24+
struct Stats;
25+
virtual std::unique_ptr<StatsTracker> make_stats() const override;
26+
};
27+
28+
class FossilRevival : public SingleSwitchProgramInstance{
29+
public:
30+
FossilRevival();
31+
virtual void program(SingleSwitchProgramEnvironment& env, CancellableScope& scope) override;
32+
33+
private:
34+
void run_revives(SingleSwitchProgramEnvironment& env, JoyconContext& context);
35+
36+
IntegerEnumDropdownOption SLOT;
37+
SimpleIntegerOption<uint32_t> NUM_REVIVALS;
38+
39+
GoHomeWhenDoneOption GO_HOME_WHEN_DONE;
40+
41+
EventNotificationOption NOTIFICATION_SHINY;
42+
EventNotificationOption NOTIFICATION_STATUS_UPDATE;
43+
EventNotificationsOption NOTIFICATIONS;
44+
};
45+
46+
47+
48+
49+
}
50+
}
51+
}
52+
#endif
53+
54+
55+

0 commit comments

Comments
 (0)