77#include " CommonFramework/ProgramStats/StatsTracking.h"
88#include " CommonTools/Async/InferenceRoutines.h"
99#include " CommonFramework/Exceptions/OperationFailedException.h"
10+ #include " CommonFramework/Notifications/ProgramNotifications.h"
11+ #include " CommonFramework/VideoPipeline/VideoFeed.h"
1012#include " NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
1113#include " Pokemon/Pokemon_Strings.h"
14+ #include " Pokemon/Pokemon_Notification.h"
15+ #include " PokemonLZA/Inference/Boxes/PokemonLZA_BoxDetection.h"
16+ #include " PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.h"
1217#include " PokemonLZA/Inference/PokemonLZA_ButtonDetector.h"
1318#include " PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h"
1419#include " PokemonLZA/Inference/PokemonLZA_DialogDetector.h"
20+ #include " PokemonLZA/Programs/PokemonLZA_GameEntry.h"
1521#include " PokemonLZA/Programs/PokemonLZA_MenuNavigation.h"
16- #include " PokemonLZA/Inference/Boxes/PokemonLZA_BoxDetection .h"
22+ #include " NintendoSwitch/Programs/NintendoSwitch_GameEntry .h"
1723#include " PokemonLZA_AutoFossil.h"
1824
1925#include < sstream>
@@ -53,13 +59,19 @@ class AutoFossil_Descriptor::Stats : public StatsTracker{
5359public:
5460 Stats ()
5561 : fossils(m_stats[" Fossils" ])
62+ , alphas(m_stats[" Alphas" ])
63+ , shinies(m_stats[" Shinies" ])
5664 , errors(m_stats[" Errors" ])
5765 {
5866 m_display_order.emplace_back (" Fossils" );
67+ m_display_order.emplace_back (" Alphas" );
68+ m_display_order.emplace_back (" Shinies" );
5969 m_display_order.emplace_back (" Errors" , HIDDEN_IF_ZERO);
6070 }
6171
6272 std::atomic<uint64_t >& fossils;
73+ std::atomic<uint64_t >& alphas;
74+ std::atomic<uint64_t >& shinies;
6375 std::atomic<uint64_t >& errors;
6476};
6577
@@ -68,23 +80,60 @@ std::unique_ptr<StatsTracker> AutoFossil_Descriptor::make_stats() const{
6880}
6981
7082
71- AutoFossil::AutoFossil (){}
83+ AutoFossil::AutoFossil ()
84+ : NUM_BOXES(" <b>Boxes of Fossils to Revive:</b>" ,
85+ LockMode::LOCK_WHILE_RUNNING,
86+ 1 , 1 , 32
87+ )
88+ , FOUND_SHINY_OR_ALPHA(
89+ " Found Shiny or Alpha" ,
90+ true , true ,
91+ ImageAttachmentMode::JPG,
92+ {" Notifs" , " Showcase" }
93+ )
94+ , NOTIFICATION_STATUS(" Status Update" , true , false , std::chrono::seconds(3600 ))
95+ , NOTIFICATIONS({
96+ &NOTIFICATION_STATUS,
97+ &FOUND_SHINY_OR_ALPHA,
98+ &NOTIFICATION_PROGRAM_FINISH,
99+ &NOTIFICATION_ERROR_RECOVERABLE,
100+ &NOTIFICATION_ERROR_FATAL,
101+ })
102+ {
103+ PA_ADD_OPTION (STOP_ON);
104+ PA_ADD_OPTION (NUM_BOXES);
105+ PA_ADD_OPTION (NOTIFICATIONS);
106+ }
72107
73108
74109void AutoFossil::program (SingleSwitchProgramEnvironment& env, ProControllerContext& context){
75- // AutoFossil_Descriptor::Stats& stats = env.current_stats<AutoFossil_Descriptor::Stats>();
76- overworld_to_box_system (env.console , context);
77- return ;
78-
79- // Example loop structure
80- size_t num_fossils_to_revive = 3 ;
81- for (size_t i = 0 ; i < num_fossils_to_revive; i++){
82- revive_one_fossil (env, context);
83- std::ostringstream os;
84- os << " Got Fossil " << i + 1 << " /" << num_fossils_to_revive;
85- std::string log_str = os.str ();
86- env.log (log_str);
87- env.console .overlay ().add_log (log_str);
110+ while (true ){
111+ size_t num_fossils_to_revive = size_t (NUM_BOXES) * 30 ;
112+ for (size_t i = 0 ; i < num_fossils_to_revive; i++){
113+ revive_one_fossil (env, context);
114+ std::ostringstream os;
115+ os << " Got Fossil " << i + 1 << " /" << num_fossils_to_revive;
116+ std::string log_str = os.str ();
117+ env.log (log_str);
118+ env.console .overlay ().add_log (log_str);
119+ }
120+
121+ overworld_to_box_system (env.console , context);
122+ for (uint8_t i = 0 ; i < NUM_BOXES; i++){
123+ bool found_match = check_fossils_in_one_box (env, context);
124+ if (found_match){
125+ return ;
126+ }
127+ if (i != NUM_BOXES - 1 ){
128+ // go to next page
129+ pbf_press_button (context, BUTTON_R, 200ms, 200ms);
130+ }
131+ }
132+ // checked all boxes, no match
133+ go_home (env.console , context);
134+ reset_game_from_home (env, env.console , context);
135+
136+ send_program_status_notification (env, NOTIFICATION_STATUS);
88137 }
89138}
90139
@@ -149,27 +198,96 @@ void AutoFossil::revive_one_fossil(SingleSwitchProgramEnvironment& env, ProContr
149198 case 3 :
150199 env.log (" Detected blue dialog." );
151200 pbf_press_button (context, BUTTON_B, 80ms, 40ms);
201+ // in normal cases when blue dialog box is detected, we already seen the selection
202+ // arrow. But just in case somehow the program misses the selection arrow detection,
203+ // we can still set it to true here to ensure subsequent program execution is smooth.
204+ seen_selection_arrow = true ;
152205 continue ;
153206
154207 default :
155208 stats.errors ++;
156209 env.update_stats ();
157210 OperationFailedException::fire (
158211 ErrorReport::SEND_ERROR_REPORT,
159- " run_lobby (): No recognized state after 60 seconds." ,
212+ " revive_one_fossil (): No recognized state after 60 seconds." ,
160213 env.console
161214 );
162215 }
163216 }
164217}
165218
166219// start at box system, check fossils one by one
167- void AutoFossil::check_fossils_in_box (SingleSwitchProgramEnvironment& env, ProControllerContext& context, size_t num_boxes){
168- uint8_t box_x = 0 , box_y = 0 ;
220+ bool AutoFossil::check_fossils_in_one_box (SingleSwitchProgramEnvironment& env, ProControllerContext& context){
221+ AutoFossil_Descriptor::Stats& stats = env.current_stats <AutoFossil_Descriptor::Stats>();
222+
223+ uint8_t box_row = 1 , box_col = 0 ;
224+ bool next_cell_right = true ;
169225 BoxDetector box_detector (COLOR_RED, &env.console .overlay ());
226+ BoxPageInfoWatcher info_watcher (&env.console .overlay ());
170227 for (size_t i = 0 ; i < 30 ; i++){
171- box_detector.move_cursor (env.program_info (), env.console , context, box_x, box_y);
228+ env.console .overlay ().add_log (" To cell: (" + std::to_string (box_row) + " , " + std::to_string (box_col) + " )" );
229+ box_detector.move_cursor (env.program_info (), env.console , context, box_row, box_col);
230+
231+ info_watcher.reset_state ();
232+ wait_until (env.console , context, WallClock::max (), {info_watcher});
233+
234+ std::ostringstream os;
235+ os << i + 1 << " /" << int (NUM_BOXES)*30 << " : " << info_watcher.info_str ();
236+ std::string log_str = os.str ();
237+ env.log (log_str);
238+ env.console .overlay ().add_log (log_str);
239+ if (info_watcher.is_alpha ()){
240+ stats.alphas ++;
241+ env.update_stats ();
242+ }
243+ if (info_watcher.is_shiny ()){
244+ stats.shinies ++;
245+ env.update_stats ();
246+ }
247+
248+ bool is_match = false ;
249+ switch (STOP_ON){
250+ case PokemonLA::StopOn::Shiny:
251+ is_match = info_watcher.is_shiny ();
252+ break ;
253+ case PokemonLA::StopOn::Alpha:
254+ is_match = info_watcher.is_alpha ();
255+ break ;
256+ case PokemonLA::StopOn::ShinyOrAlpha:
257+ is_match = info_watcher.is_shiny () || info_watcher.is_alpha ();
258+ break ;
259+ case PokemonLA::StopOn::ShinyAndAlpha:
260+ is_match = info_watcher.is_shiny () && info_watcher.is_alpha ();
261+ break ;
262+ }
263+ if (is_match){
264+ send_program_notification (
265+ env, FOUND_SHINY_OR_ALPHA,
266+ Pokemon::COLOR_STAR_SHINY,
267+ " Found " + info_watcher.info_str () + " !" ,
268+ {}, " " ,
269+ env.console .video ().snapshot (), true
270+ );
271+ return true ;
272+ }
273+
274+ if (next_cell_right){
275+ if (box_col == 5 ){
276+ box_row++;
277+ next_cell_right = false ;
278+ } else {
279+ box_col++;
280+ }
281+ } else {
282+ if (box_col == 0 ){
283+ box_row++;
284+ next_cell_right = true ;
285+ } else {
286+ box_col--;
287+ }
288+ }
172289 }
290+ return false ;
173291}
174292
175293}
0 commit comments