Skip to content

Commit a4392ed

Browse files
authored
Merge pull request #555 from kichithewolf/LGPE-fossil-revival
LGPE fossil revival
2 parents f487ba9 + 516934d commit a4392ed

File tree

5 files changed

+363
-0
lines changed

5 files changed

+363
-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: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
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, 800ms);
96+
pbf_wait(context, 1000ms); //Wait for scientist to turn and face player
97+
context.wait_for_all_requests();
98+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
99+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
100+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
101+
pbf_press_button(context, BUTTON_A, 100ms, 500ms);
102+
context.wait_for_all_requests();
103+
104+
pbf_wait(context, 500ms);
105+
context.wait_for_all_requests();
106+
107+
//Select fossil slot
108+
env.log("Selecting fossil.");
109+
for (uint16_t c = 0; c < (uint16_t)SLOT.current_value(); c++){
110+
pbf_move_joystick(context, 128, 255, 100ms, 200ms);
111+
}
112+
context.wait_for_all_requests();
113+
114+
//Mash A until revival over
115+
BlackScreenOverWatcher revival_over(COLOR_RED);
116+
int ret = run_until<JoyconContext>(
117+
env.console, context,
118+
[](JoyconContext& context){
119+
pbf_mash_button(context, BUTTON_A, 15000ms);
120+
},
121+
{revival_over}
122+
);
123+
context.wait_for_all_requests();
124+
if (ret != 0){
125+
env.log("Failed to revive fossil.", COLOR_RED);
126+
OperationFailedException::fire(
127+
ErrorReport::SEND_ERROR_REPORT,
128+
"Failed to revive fossil.",
129+
env.console
130+
);
131+
}
132+
else {
133+
env.log("Fossil revived.");
134+
}
135+
136+
//Now mash B until next black screen (end of summary/tucked pokemon away)
137+
BlackScreenOverWatcher summary_over(COLOR_YELLOW);
138+
int ret2 = run_until<JoyconContext>(
139+
env.console, context,
140+
[](JoyconContext& context){
141+
pbf_mash_button(context, BUTTON_B, 15000ms);
142+
},
143+
{summary_over}
144+
);
145+
context.wait_for_all_requests();
146+
if (ret2 != 0){
147+
env.log("Did not detect summary over.", COLOR_RED);
148+
OperationFailedException::fire(
149+
ErrorReport::SEND_ERROR_REPORT,
150+
"Did not detect summary over.",
151+
env.console
152+
);
153+
}
154+
else {
155+
env.log("Summary closed/Pokemon tucked away in box/team.");
156+
}
157+
158+
//Close out come back soon text.
159+
pbf_mash_button(context, BUTTON_B, 1000ms);
160+
context.wait_for_all_requests();
161+
}
162+
163+
void FossilRevival::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){
164+
JoyconContext context(scope, env.console.controller<JoyconController>());
165+
assert_16_9_720p_min(env.logger(), env.console);
166+
FossilRevival_Descriptor::Stats& stats = env.current_stats<FossilRevival_Descriptor::Stats>();
167+
168+
/*
169+
Settings:
170+
Text speed fast
171+
172+
is first time dialog different? clear it out first.
173+
selection dialog still appears if only one fossil type
174+
175+
Setup:
176+
Stand in front of the scientist in cinnebar.
177+
Save the game.
178+
Start the program in-game.
179+
*/
180+
181+
bool shiny_found = false;
182+
while (!shiny_found) {
183+
//Run revives
184+
for (uint16_t i = 0; i < NUM_REVIVALS; i++) {
185+
env.log("Running trade.");
186+
run_revives(env, context);
187+
188+
stats.revives++;
189+
env.update_stats();
190+
}
191+
192+
env.log("Done reviving. Checking boxes.");
193+
send_program_status_notification(
194+
env, NOTIFICATION_STATUS_UPDATE,
195+
"Done reviving. Checking boxes."
196+
);
197+
198+
//Wait a bit.
199+
pbf_wait(context, 2500ms);
200+
context.wait_for_all_requests();
201+
202+
//Open menu, open party, open boxes
203+
env.log("Opening boxes.");
204+
pbf_press_button(context, BUTTON_X, 200ms, 500ms);
205+
pbf_press_button(context, BUTTON_A, 200ms, 1500ms);
206+
pbf_press_button(context, BUTTON_Y, 200ms, 2000ms);
207+
context.wait_for_all_requests();
208+
209+
//Sort by order caught
210+
env.log("Sorting by order caught.");
211+
pbf_press_button(context, BUTTON_Y, 200ms, 1000ms);
212+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
213+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
214+
context.wait_for_all_requests();
215+
216+
//Press left to go to last (most recent) Pokemon
217+
env.log("Opening summary of most recent Pokemon.");
218+
pbf_move_joystick(context, 0, 128, 100ms, 100ms);
219+
context.wait_for_all_requests();
220+
221+
//View summary - it takes a moment to load
222+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
223+
pbf_move_joystick(context, 128, 255, 100ms, 100ms);
224+
pbf_move_joystick(context, 128, 255, 100ms, 100ms);
225+
pbf_press_button(context, BUTTON_A, 200ms, 100ms);
226+
context.wait_for_all_requests();
227+
228+
pbf_wait(context, 5000ms);
229+
context.wait_for_all_requests();
230+
231+
//Now check for shinies. Check everything that was traded.
232+
env.log("Checking received Pokemon.");
233+
for (uint16_t i = 0; i < NUM_REVIVALS; i++) {
234+
VideoSnapshot screen = env.console.video().snapshot();
235+
ShinySymbolDetector shiny_checker(COLOR_YELLOW);
236+
bool check = shiny_checker.read(env.console.logger(), screen);
237+
238+
if (check) {
239+
env.log("Shiny detected!");
240+
stats.shinies++;
241+
env.update_stats();
242+
send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny found!", {}, "", screen, true);
243+
shiny_found = true;
244+
245+
//Back out to menu and favorite the shiny.
246+
env.log("Favoriting shiny.");
247+
pbf_press_button(context, BUTTON_B, 200ms, 5000ms);
248+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
249+
pbf_move_joystick(context, 128, 0, 100ms, 100ms);
250+
pbf_move_joystick(context, 128, 0, 100ms, 100ms);
251+
pbf_move_joystick(context, 128, 0, 100ms, 200ms);
252+
pbf_press_button(context, BUTTON_A, 200ms, 800ms);
253+
pbf_press_button(context, BUTTON_A, 200ms, 800ms);
254+
pbf_press_button(context, BUTTON_B, 200ms, 800ms);
255+
256+
//Go into summary again
257+
env.log("Navigating back into summary.");
258+
pbf_press_button(context, BUTTON_A, 200ms, 1000ms);
259+
pbf_move_joystick(context, 128, 255, 100ms, 100ms);
260+
pbf_move_joystick(context, 128, 255, 100ms, 100ms);
261+
pbf_press_button(context, BUTTON_A, 200ms, 100ms);
262+
context.wait_for_all_requests();
263+
pbf_wait(context, 5000ms);
264+
context.wait_for_all_requests();
265+
}
266+
else {
267+
env.log("Not shiny.");
268+
}
269+
270+
//Move left, check next.
271+
pbf_move_joystick(context, 0, 128, 100ms, 100ms);
272+
pbf_press_button(context, BUTTON_X, 0ms, 1000ms);
273+
context.wait_for_all_requests();
274+
}
275+
276+
if (!shiny_found) {
277+
env.log("Out of Pokemon to check and no shiny found. Resetting game.");
278+
send_program_status_notification(
279+
env, NOTIFICATION_STATUS_UPDATE,
280+
"Out of Pokemon to check and no shiny found. Resetting game."
281+
);
282+
283+
//Reset game
284+
pbf_press_button(context, BUTTON_HOME, 200ms, 2000ms);
285+
reset_game_from_home(env, env.console, context, 3000ms);
286+
context.wait_for_all_requests();
287+
288+
stats.resets++;
289+
env.update_stats();
290+
}
291+
}
292+
293+
if (GO_HOME_WHEN_DONE) {
294+
pbf_press_button(context, BUTTON_HOME, 200ms, 1000ms);
295+
}
296+
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);
297+
}
298+
299+
300+
}
301+
}
302+
}
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)