Skip to content

Commit 30da764

Browse files
author
ig-14
committed
Add periodic reset every 50 iterations to prevent menu navigation errors
1 parent 52c0aca commit 30da764

File tree

3 files changed

+222
-46
lines changed

3 files changed

+222
-46
lines changed

SerialPrograms/Source/PokemonLGPE/Commands/PokemonLGPE_DateSpam.cpp

Lines changed: 178 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#include "Common/Cpp/Time.h"
88
#include "CommonFramework/Exceptions/OperationFailedException.h"
99
#include "CommonFramework/ImageTools/ImageBoxes.h"
10+
#include "CommonFramework/ImageTools/ImageStats.h"
11+
#include "CommonFramework/VideoPipeline/VideoFeed.h"
12+
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
1013
#include "CommonTools/Async/InferenceRoutines.h"
1114
#include "Controllers/SerialPABotBase/Connection/MessageConverter.h"
1215
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
@@ -21,75 +24,204 @@ namespace NintendoSwitch{
2124
namespace PokemonLGPE{
2225

2326
void verify_date_time_menu_selected(ConsoleHandle& console, JoyconContext& context){
24-
// Verify that "Date and Time" menu item is selected (not "Time Zone")
25-
// After home_to_date_time(..., true), we should be in the "Date and Time" menu screen
26-
// Menu items: "Synchronize Clock via Internet" (top), "Time Zone" (middle), "Date and Time" (bottom)
27-
// We need "Date and Time" (bottom) to be selected before rolling the date
27+
// Comprehensive verification: ensure we're on "Date and Time" menu item AND Sync Clock is OFF
28+
// Menu structure: "Synchronize Clock via Internet" (top), "Time Zone" (middle), "Date and Time" (bottom)
29+
// CRITICAL: Must be on "Date and Time" before rolling date, never on "Time Zone" or "Sync Clock"
2830

2931
context.wait_for_all_requests();
30-
context.wait_for(Milliseconds(300));
32+
context.wait_for(Milliseconds(400));
33+
34+
Milliseconds tv = context->timing_variation();
35+
Milliseconds unit = 100ms + tv;
3136

32-
// Use single snapshot check instead of polling to avoid visual pulsing
37+
// STEP 1: Check and disable "Synchronize Clock via Internet" if it's ON
38+
console.log("Step 1: Checking 'Synchronize Clock via Internet' status...");
3339
VideoSnapshot snapshot = console.video().snapshot();
3440
if (!snapshot){
35-
console.log("WARNING: No video available for menu verification. Proceeding anyway...", COLOR_RED);
41+
console.log("WARNING: No video available. Proceeding blind...", COLOR_RED);
3642
return;
3743
}
3844

39-
// Box positions based on Switch menu layout - "Date and Time" text is at bottom
40-
ImageFloatBox date_time_box(0.50, 0.78, 0.15, 0.03); // "Date and Time" menu item (bottom)
41-
ImageFloatBox time_zone_box(0.50, 0.70, 0.15, 0.03); // "Time Zone" menu item (middle)
42-
ImageFloatBox sync_clock_box(0.50, 0.62, 0.15, 0.03); // "Synchronize Clock via Internet" (top)
45+
// Add visual overlay boxes so you can see where we're looking
46+
VideoOverlaySet overlays(console.overlay());
4347

44-
// Check once if "Date and Time" is selected (using snapshot timestamp, no polling)
45-
SelectedSettingWatcher date_time_watcher(date_time_box, time_zone_box, sync_clock_box);
46-
bool date_time_selected = date_time_watcher.process_frame(*snapshot, snapshot.timestamp());
48+
// Based on your screenshot: menu items are in the lower half of the screen
49+
// "Synchronize Clock via Internet" is the first item, with "On"/"Off" status on the right
50+
// "Time Zone" shows "Denver" on the right around y=0.70
51+
// So "Synchronize Clock" status should be above that, around y=0.55-0.65
4752

48-
if (date_time_selected){
49-
// Successfully detected "Date and Time" is selected
50-
console.log("Verified 'Date and Time' menu item is selected.");
51-
return;
52-
}
53+
ImageFloatBox sync_status_box1(0.78, 0.21, 0.05, 0.05); // Try y=0.50
5354

54-
// "Date and Time" is not selected - navigate to it
55-
console.log("'Date and Time' not selected. Navigating to it...", COLOR_YELLOW);
55+
overlays.add(COLOR_RED, sync_status_box1);
5656

57-
Milliseconds tv = context->timing_variation();
58-
Milliseconds unit = 80ms + tv;
57+
ImageStats sync_status1 = image_stats(extract_box_reference(snapshot, sync_status_box1));
5958

60-
// Check if "Time Zone" is selected (middle option)
61-
SelectedSettingWatcher time_zone_watcher(time_zone_box, date_time_box, sync_clock_box);
62-
bool time_zone_selected = time_zone_watcher.process_frame(*snapshot, snapshot.timestamp());
59+
// Debug: Log all positions
60+
console.log("Box1 (RED, y:0.21) RGB: [" + std::to_string((int)sync_status1.average.r) + ", " +
61+
std::to_string((int)sync_status1.average.g) + ", " +
62+
std::to_string((int)sync_status1.average.b) + "] sum=" +
63+
std::to_string((int)sync_status1.average.sum()));
64+
console.log("LOOK AT THE COLORED BOXES ON SCREEN - which one covers the 'On' or 'Off' text?");
6365

64-
if (time_zone_selected){
65-
// "Time Zone" is selected, need to go down one more to reach "Date and Time"
66-
console.log("'Time Zone' selected. Moving down one to 'Date and Time'...", COLOR_YELLOW);
67-
pbf_move_joystick(context, 128, 255, unit, unit);
66+
// Use the detected values
67+
ImageStats sync_status = sync_status1;
68+
69+
// "On" is cyan/teal text: green and blue are higher than red
70+
// "Off" is white text: all RGB components are similar and high
71+
// The cyan "On" text shows as [43, 56, 53] - green and blue slightly higher than red
72+
// Detection: if G > R+5 AND B > R, it's likely cyan "On"
73+
// If all components are similar (within 10 of each other), it's white "Off"
74+
75+
bool is_cyan = (sync_status.average.g > sync_status.average.r + 5) &&
76+
(sync_status.average.b >= sync_status.average.r);
77+
bool is_white = (std::abs(sync_status.average.r - sync_status.average.g) < 10) &&
78+
(std::abs(sync_status.average.r - sync_status.average.b) < 10) &&
79+
(std::abs(sync_status.average.g - sync_status.average.b) < 10);
80+
81+
bool sync_appears_on = is_cyan && !is_white;
82+
83+
console.log("Is cyan: " + std::string(is_cyan ? "YES" : "NO") +
84+
", Is white: " + std::string(is_white ? "YES" : "NO") +
85+
", Appears ON: " + std::string(sync_appears_on ? "YES" : "NO"));
86+
87+
if (sync_appears_on){
88+
console.log("DETECTED: 'Synchronize Clock via Internet' is ON. Disabling it...", COLOR_YELLOW);
89+
90+
// Strategy: First scroll down to bottom (Date and Time), then scroll up exactly 2 times to Sync Clock
91+
// This ensures we know exactly where we are
92+
console.log("Navigating to bottom of menu first...");
93+
for (int i = 0; i < 5; i++){
94+
pbf_move_joystick(context, 128, 255, unit, unit); // Down - go to bottom
95+
context.wait_for_all_requests();
96+
context.wait_for(Milliseconds(100));
97+
}
98+
99+
console.log("Now navigating UP to 'Synchronize Clock via Internet'...");
100+
// From "Date and Time" (bottom), go up 2 times to reach "Synchronize Clock" (top)
101+
pbf_move_joystick(context, 128, 0, unit, unit); // Up to Time Zone
68102
context.wait_for_all_requests();
69-
context.wait_for(Milliseconds(300));
70-
} else {
71-
// Might be on "Synchronize Clock via Internet" (top) - need to go down twice
72-
console.log("Top option selected. Moving down twice to 'Date and Time'...", COLOR_YELLOW);
73-
pbf_move_joystick(context, 128, 255, unit, unit);
103+
context.wait_for(Milliseconds(250));
104+
pbf_move_joystick(context, 128, 0, unit, unit); // Up to Synchronize Clock
74105
context.wait_for_all_requests();
75-
context.wait_for(Milliseconds(200));
76-
pbf_move_joystick(context, 128, 255, unit, unit);
106+
context.wait_for(Milliseconds(400));
107+
108+
// Press A to toggle it OFF
109+
console.log("Pressing A to toggle OFF...");
110+
pbf_press_button(context, BUTTON_A, unit, unit);
111+
context.wait_for_all_requests();
112+
context.wait_for(Milliseconds(600)); // Wait for toggle animation
113+
114+
console.log("Toggled 'Synchronize Clock via Internet' OFF. Now navigating back to 'Date and Time'...");
115+
116+
// Navigate back down to "Date and Time" (2 times down)
117+
pbf_move_joystick(context, 128, 255, unit, unit); // Down to Time Zone
118+
context.wait_for_all_requests();
119+
context.wait_for(Milliseconds(250));
120+
pbf_move_joystick(context, 128, 255, unit, unit); // Down to Date and Time
121+
context.wait_for_all_requests();
122+
context.wait_for(Milliseconds(400));
123+
124+
console.log("Back on 'Date and Time' menu item.");
125+
} else {
126+
console.log("'Synchronize Clock via Internet' is OFF (or detection failed - check RGB values above).");
127+
}
128+
129+
// STEP 2: Ensure we're on "Date and Time" menu item (bottom option)
130+
console.log("Step 2: Ensuring 'Date and Time' menu item is selected...");
131+
132+
// After handling Sync Clock, we should be on "Date and Time" already if we navigated correctly
133+
// But let's verify and fix if needed
134+
135+
// Simple approach: Just scroll down multiple times to guarantee we're at the bottom
136+
// The menu will stop at "Date and Time" (bottom item) even if we scroll too much
137+
console.log("Scrolling to bottom to ensure 'Date and Time' is selected...");
138+
for (int i = 0; i < 5; i++){
139+
pbf_move_joystick(context, 128, 255, unit, unit); // Down
77140
context.wait_for_all_requests();
78-
context.wait_for(Milliseconds(300));
141+
context.wait_for(Milliseconds(150));
79142
}
80143

81-
// Final quick check after navigation (single snapshot, no polling)
82144
context.wait_for_all_requests();
83-
context.wait_for(Milliseconds(200));
145+
context.wait_for(Milliseconds(400));
146+
147+
// Final verification with visual boxes to see where menu items actually are
84148
snapshot = console.video().snapshot();
85149
if (snapshot){
86-
date_time_selected = date_time_watcher.process_frame(*snapshot, snapshot.timestamp());
87-
if (!date_time_selected){
88-
console.log("WARNING: Could not verify 'Date and Time' is selected after navigation. Proceeding anyway...", COLOR_RED);
89-
} else {
90-
console.log("Successfully navigated to 'Date and Time' menu item.");
91-
}
150+
// Show boxes at different Y positions to find where menu items are
151+
// These boxes cover the LEFT side where menu item TEXT appears (not status text)
152+
ImageFloatBox menu_check_box1(0.15, 0.15, 0.40, 0.05); // Very top
153+
ImageFloatBox menu_check_box2(0.15, 0.25, 0.40, 0.05); // Upper area
154+
ImageFloatBox menu_check_box3(0.15, 0.35, 0.40, 0.05); // Middle area
155+
ImageFloatBox menu_check_box4(0.15, 0.45, 0.40, 0.05); // Lower-middle area
156+
ImageFloatBox menu_check_box5(0.15, 0.55, 0.40, 0.05); // Lower area
157+
158+
VideoOverlaySet menu_overlays(console.overlay());
159+
menu_overlays.add(COLOR_CYAN, menu_check_box1);
160+
menu_overlays.add(COLOR_MAGENTA, menu_check_box2);
161+
menu_overlays.add(COLOR_GREEN, menu_check_box3);
162+
menu_overlays.add(COLOR_ORANGE, menu_check_box4);
163+
menu_overlays.add(COLOR_PURPLE, menu_check_box5);
164+
165+
ImageStats menu_stats1 = image_stats(extract_box_reference(snapshot, menu_check_box1));
166+
ImageStats menu_stats2 = image_stats(extract_box_reference(snapshot, menu_check_box2));
167+
ImageStats menu_stats3 = image_stats(extract_box_reference(snapshot, menu_check_box3));
168+
ImageStats menu_stats4 = image_stats(extract_box_reference(snapshot, menu_check_box4));
169+
ImageStats menu_stats5 = image_stats(extract_box_reference(snapshot, menu_check_box5));
170+
171+
console.log("Menu boxes - CYAN(y:0.15):" + std::to_string((int)menu_stats1.average.sum()) +
172+
" MAGENTA(y:0.25):" + std::to_string((int)menu_stats2.average.sum()) +
173+
" GREEN(y:0.35):" + std::to_string((int)menu_stats3.average.sum()) +
174+
" ORANGE(y:0.45):" + std::to_string((int)menu_stats4.average.sum()) +
175+
" PURPLE(y:0.55):" + std::to_string((int)menu_stats5.average.sum()));
176+
console.log("LOOK: Which colored box covers the HIGHLIGHTED menu item (should have blue border)?");
177+
console.log("The highlighted item should be 'Date and Time' (bottom option).");
178+
}
179+
180+
console.log("Ready to roll date. 'Date and Time' should now be selected.");
181+
}
182+
183+
void reset_sync_clock_state(ConsoleHandle& console, JoyconContext& context){
184+
// Reset the menu state by toggling "Synchronize Clock via Internet" ON then OFF
185+
// This helps clear any accumulated navigation errors
186+
187+
console.log("=== RESETTING SYNC CLOCK STATE ===", COLOR_BLUE);
188+
189+
Milliseconds tv = context->timing_variation();
190+
Milliseconds unit = 100ms + tv;
191+
192+
context.wait_for_all_requests();
193+
context.wait_for(Milliseconds(300));
194+
195+
// Navigate to bottom first to establish known position
196+
console.log("Scrolling to bottom...");
197+
for (int i = 0; i < 5; i++){
198+
pbf_move_joystick(context, 128, 255, unit, unit);
199+
context.wait_for_all_requests();
200+
context.wait_for(Milliseconds(100));
92201
}
202+
203+
// Navigate up to "Synchronize Clock via Internet" (top item)
204+
console.log("Navigating UP to 'Synchronize Clock via Internet'...");
205+
pbf_move_joystick(context, 128, 0, unit, unit); // Up to Time Zone
206+
context.wait_for_all_requests();
207+
context.wait_for(Milliseconds(200));
208+
pbf_move_joystick(context, 128, 0, unit, unit); // Up to Synchronize Clock
209+
context.wait_for_all_requests();
210+
context.wait_for(Milliseconds(400));
211+
212+
// Toggle it ON
213+
console.log("Toggling ON...");
214+
pbf_press_button(context, BUTTON_A, unit, unit);
215+
context.wait_for_all_requests();
216+
context.wait_for(Milliseconds(500));
217+
218+
// Toggle it OFF
219+
console.log("Toggling OFF...");
220+
pbf_press_button(context, BUTTON_A, unit, unit);
221+
context.wait_for_all_requests();
222+
context.wait_for(Milliseconds(500));
223+
224+
console.log("Sync clock state reset complete.");
93225
}
94226

95227
void roll_date_forward_1(JoyconContext& context){

SerialPrograms/Source/PokemonLGPE/Commands/PokemonLGPE_DateSpam.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ namespace PokemonLGPE{
1919
// If wrong menu item is selected, navigate to correct it
2020
void verify_date_time_menu_selected(ConsoleHandle& console, JoyconContext& context);
2121

22+
// Reset the sync clock state by toggling it ON then OFF
23+
// This helps reset the menu state and prevents accumulated navigation errors
24+
void reset_sync_clock_state(ConsoleHandle& console, JoyconContext& context);
25+
2226
void roll_date_forward_1 (JoyconContext& context);
2327
void roll_date_backward_N (JoyconContext& context, uint8_t skips);
2428

SerialPrograms/Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ void DailyItemFarmer::program(SingleSwitchProgramEnvironment& env, CancellableSc
167167
*/
168168

169169
uint8_t year = MAX_YEAR;
170+
uint32_t iterations_since_reset = 0; // Track iterations for periodic reset
171+
const uint32_t RESET_INTERVAL = 50; // Reset every 50 date changes
170172

171173
//Roll the date back before doing anything else.
172174
start_local_trade(env, context);
@@ -222,6 +224,44 @@ void DailyItemFarmer::program(SingleSwitchProgramEnvironment& env, CancellableSc
222224

223225
home_to_date_time(env.console, context, true);
224226

227+
// Check if we need to reset the menu state (every 50 iterations)
228+
iterations_since_reset++;
229+
if (iterations_since_reset >= RESET_INTERVAL){
230+
env.log("=== PERIODIC RESET AFTER " + std::to_string(RESET_INTERVAL) + " ITERATIONS ===", COLOR_BLUE);
231+
232+
// Toggle sync clock ON then OFF to reset menu state
233+
reset_sync_clock_state(env.console, context);
234+
235+
// Exit to home and re-enter to reset everything
236+
pbf_press_button(context, BUTTON_HOME, 160ms, ConsoleSettings::instance().SETTINGS_TO_HOME_DELAY0);
237+
context.wait_for_all_requests();
238+
239+
// Wait for wireless to stabilize
240+
pbf_press_button(context, BUTTON_ZL, 160ms, 840ms);
241+
pbf_press_button(context, BUTTON_ZL, 160ms, 840ms);
242+
pbf_press_button(context, BUTTON_ZL, 160ms, 840ms);
243+
context.wait_for_all_requests();
244+
context.wait_for(1000ms);
245+
246+
// Go back to date/time menu and reset to oldest year
247+
home_to_date_time(env.console, context, true);
248+
verify_date_time_menu_selected(env.console, context);
249+
250+
env.log("Rolling date back to oldest year after reset.");
251+
roll_date_backward_N(context, MAX_YEAR);
252+
year = 0;
253+
iterations_since_reset = 0;
254+
255+
pbf_press_button(context, BUTTON_HOME, 160ms, ConsoleSettings::instance().SETTINGS_TO_HOME_DELAY0);
256+
pbf_press_button(context, BUTTON_HOME, 160ms, ConsoleSettings::instance().SETTINGS_TO_HOME_DELAY0);
257+
pbf_press_button(context, BUTTON_B, 200ms, 1800ms);
258+
pbf_mash_button(context, BUTTON_B, 5000ms);
259+
context.wait_for_all_requests();
260+
261+
env.log("Reset complete. Continuing with fresh state.");
262+
continue; // Skip the normal date rolling this iteration
263+
}
264+
225265
// Verify "Date and Time" menu item is selected before rolling date
226266
verify_date_time_menu_selected(env.console, context);
227267

0 commit comments

Comments
 (0)