Skip to content

Commit 4714ba0

Browse files
authored
Update recovery routine for MaterialFarmer (#494)
* update recovery routine for material farmer * align character with direction detector, instead of with fixed joystick movements * bug fix
1 parent 343ee7a commit 4714ba0

File tree

4 files changed

+129
-135
lines changed

4 files changed

+129
-135
lines changed

SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_MaterialFarmerTools.cpp

Lines changed: 122 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ MaterialFarmerOptions::MaterialFarmerOptions(
6868
, RUN_TIME_IN_MINUTES(
6969
"<b>Run Duration:</b><br>Run the material farmer for this many minutes.",
7070
LockMode::UNLOCK_WHILE_RUNNING,
71-
70
71+
32
7272
)
7373
// , SAVE_GAME_BEFORE_SANDWICH(
7474
// "<b>Save Game before each round:</b>",
@@ -165,7 +165,14 @@ void MaterialFarmerOptions::value_changed(void* object){
165165

166166
}
167167

168-
168+
// return new start time, so that minutes remaining is rounded up to a multiple of 32
169+
WallClock new_start_time_after_reset(WallClock old_start_time, uint16_t run_time_in_minutes){
170+
auto farming_time_remaining = minutes_remaining(old_start_time, std::chrono::minutes(run_time_in_minutes));
171+
// round up the time to multiple of 32 (30 minutes per sandwich, plus 2 minutes for sandwich making)
172+
size_t desired_minutes_remaining = ((farming_time_remaining.count()/32)+1)*32;
173+
WallClock new_start_time = current_time() + std::chrono::minutes(desired_minutes_remaining) - std::chrono::minutes(run_time_in_minutes);
174+
return new_start_time;
175+
}
169176

170177

171178
void run_material_farmer(
@@ -184,88 +191,128 @@ void run_material_farmer(
184191
WallClock last_sandwich_time = WallClock::min();
185192
LetsGoHpWatcher hp_watcher(COLOR_RED);
186193

194+
// ensure we save before running the material farmer.
195+
// but no need to save if already saving prior to each sandwich
196+
if (!(options.SANDWICH_OPTIONS.enabled() && options.SANDWICH_OPTIONS.SAVE_GAME_BEFORE_SANDWICH)){
197+
save_game_from_overworld(env.program_info(), console, context);
198+
}
199+
187200
/*
188201
- Use Let's Go along the path. Fly back to pokecenter when it reaches the end of the path.
189202
- Keeping repeating this for RUN_TIME_IN_MINUTES minutes
190203
*/
204+
size_t consecutive_failures = 0;
205+
size_t max_consecutive_failures = 15;
191206
while (true){
192-
// check time left on material farming
193-
auto farming_time_remaining = minutes_remaining(start_time, std::chrono::minutes(options.RUN_TIME_IN_MINUTES));
194-
console.log(
195-
"Time left in Material Farming: " +
196-
std::to_string(farming_time_remaining.count()) + " min",
197-
COLOR_PURPLE
198-
);
199-
if (farming_time_remaining < std::chrono::minutes(0)){
200-
console.log("Time's up. Stop the Material farming program.", COLOR_RED);
201-
break;
202-
}
203-
204-
// Check time left on sandwich
205-
if (options.SANDWICH_OPTIONS.enabled()){
206-
auto sandwich_time_remaining = minutes_remaining(last_sandwich_time, std::chrono::minutes(options.TIME_PER_SANDWICH));
207+
try{
208+
while (true){
209+
// check time left on material farming
210+
auto farming_time_remaining = minutes_remaining(start_time, std::chrono::minutes(options.RUN_TIME_IN_MINUTES));
207211
console.log(
208-
"Time left on sandwich: " +
209-
std::to_string(sandwich_time_remaining.count()) + " min",
212+
"Time left in Material Farming: " +
213+
std::to_string(farming_time_remaining.count()) + " min",
210214
COLOR_PURPLE
211-
);
212-
if (sandwich_time_remaining < std::chrono::minutes(0)){
213-
console.log("Sandwich not active. Make a sandwich.");
214-
last_sandwich_time = make_sandwich_material_farm(env, console, context, options, stats);
215-
console.overlay().add_log("Sandwich made.");
216-
217-
// Log time remaining in Material farming
218-
farming_time_remaining = minutes_remaining(start_time, std::chrono::minutes(options.RUN_TIME_IN_MINUTES));
219-
console.log(
220-
"Time left in Material Farming: " +
221-
std::to_string(farming_time_remaining.count()) + " min",
222-
COLOR_PURPLE
223-
);
224-
// Log time remaining on Sandwich
225-
sandwich_time_remaining = minutes_remaining(last_sandwich_time, std::chrono::minutes(options.TIME_PER_SANDWICH));
215+
);
216+
if (farming_time_remaining < std::chrono::minutes(0)){
217+
console.log("Time's up. Stop the Material farming program.", COLOR_RED);
218+
return;
219+
}
220+
221+
// Check time left on sandwich
222+
if (options.SANDWICH_OPTIONS.enabled()){
223+
auto sandwich_time_remaining = minutes_remaining(last_sandwich_time, std::chrono::minutes(options.TIME_PER_SANDWICH));
226224
console.log(
227225
"Time left on sandwich: " +
228226
std::to_string(sandwich_time_remaining.count()) + " min",
229227
COLOR_PURPLE
230-
);
228+
);
229+
if (sandwich_time_remaining < std::chrono::minutes(0)){
230+
console.log("Sandwich not active. Make a sandwich.");
231+
last_sandwich_time = make_sandwich_material_farm(env, console, context, options, stats);
232+
console.overlay().add_log("Sandwich made.");
233+
234+
// Log time remaining in Material farming
235+
farming_time_remaining = minutes_remaining(start_time, std::chrono::minutes(options.RUN_TIME_IN_MINUTES));
236+
console.log(
237+
"Time left in Material Farming: " +
238+
std::to_string(farming_time_remaining.count()) + " min",
239+
COLOR_PURPLE
240+
);
241+
// Log time remaining on Sandwich
242+
sandwich_time_remaining = minutes_remaining(last_sandwich_time, std::chrono::minutes(options.TIME_PER_SANDWICH));
243+
console.log(
244+
"Time left on sandwich: " +
245+
std::to_string(sandwich_time_remaining.count()) + " min",
246+
COLOR_PURPLE
247+
);
248+
}
231249
}
250+
251+
// heal before starting Let's go
252+
console.log("Heal before starting Let's go", COLOR_PURPLE);
253+
console.log("Heal threshold: " + tostr_default(options.AUTO_HEAL_PERCENT), COLOR_PURPLE);
254+
check_hp(env, console, context, options, hp_watcher, stats);
255+
256+
/*
257+
- Starts from pokemon center.
258+
- Flies to start position. Runs a Let's Go iteration.
259+
- Then returns to pokemon center, regardless of whether
260+
it completes the action or gets caught in a battle
261+
*/
262+
run_from_battles_and_back_to_pokecenter(env, console, context, stats,
263+
[&](ProgramEnvironment& env, ConsoleHandle& console, BotBaseContext& context){
264+
// Move to starting position for Let's Go hunting path
265+
console.log("Move to starting position for Let's Go hunting path.", COLOR_PURPLE);
266+
move_to_start_position_for_letsgo1(console, context);
267+
268+
// run let's go while updating the HP watcher
269+
console.log("Starting Let's Go hunting path.", COLOR_PURPLE);
270+
run_until(
271+
console, context,
272+
[&](BotBaseContext& context){
273+
run_lets_go_iteration(console, context, encounter_tracker, options.NUM_FORWARD_MOVES_PER_LETS_GO_ITERATION);
274+
},
275+
{hp_watcher}
276+
);
277+
}
278+
);
279+
280+
context.wait_for_all_requests();
232281
}
282+
}catch (OperationFailedException& e){
283+
stats.m_errors++;
284+
env.update_stats();
285+
e.send_notification(env, options.NOTIFICATION_ERROR_RECOVERABLE);
233286

234-
// heal before starting Let's go
235-
console.log("Heal before starting Let's go", COLOR_PURPLE);
236-
console.log("Heal threshold: " + tostr_default(options.AUTO_HEAL_PERCENT), COLOR_PURPLE);
237-
check_hp(env, console, context, options, hp_watcher, stats);
238-
239-
/*
240-
- Starts from pokemon center.
241-
- Flies to start position. Runs a Let's Go iteration.
242-
- Then returns to pokemon center, regardless of whether
243-
it completes the action or gets caught in a battle
244-
*/
245-
run_from_battles_and_back_to_pokecenter(env, console, context, stats,
246-
[&](ProgramEnvironment& env, ConsoleHandle& console, BotBaseContext& context){
247-
// Move to starting position for Let's Go hunting path
248-
console.log("Move to starting position for Let's Go hunting path.", COLOR_PURPLE);
249-
move_to_start_position_for_letsgo1(console, context);
250-
251-
// run let's go while updating the HP watcher
252-
console.log("Starting Let's Go hunting path.", COLOR_PURPLE);
253-
run_until(
254-
console, context,
255-
[&](BotBaseContext& context){
256-
run_lets_go_iteration(console, context, encounter_tracker, options.NUM_FORWARD_MOVES_PER_LETS_GO_ITERATION);
257-
},
258-
{hp_watcher}
259-
);
260-
}
261-
);
262-
263-
context.wait_for_all_requests();
264-
}
287+
// save screenshot after operation failed,
288+
// dump_snapshot(console);
289+
290+
if (options.SAVE_DEBUG_VIDEO){
291+
// Take a video to give more context for debugging
292+
pbf_press_button(context, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 2 * TICKS_PER_SECOND);
293+
context.wait_for_all_requests();
294+
}
265295

296+
consecutive_failures++;
297+
if (consecutive_failures >= max_consecutive_failures){
298+
throw e;
299+
}
300+
301+
env.log("Reset game to handle recoverable error.");
302+
reset_game(env.program_info(), console, context);
303+
stats.m_game_resets++;
304+
env.update_stats();
266305

306+
// update start time, so that minutes remaining is rounded up to a multiple of 32
307+
start_time = new_start_time_after_reset(start_time, options.RUN_TIME_IN_MINUTES);
308+
// also update last sandwich time
309+
last_sandwich_time = WallClock::min();
310+
}
311+
}
267312
}
268313

314+
315+
269316
void check_hp(
270317
ProgramEnvironment& env,
271318
ConsoleHandle& console,
@@ -290,69 +337,20 @@ void check_hp(
290337

291338

292339

293-
// start at North Province (Area 3) Pokecenter. make sandwich then go back to Pokecenter to reset position
294-
// return the time that the sandwich was made
340+
// make sandwich then go back to Pokecenter to reset position
341+
// if gets caught up in a battle, try again.
295342
WallClock make_sandwich_material_farm(
296343
ProgramEnvironment& env,
297344
ConsoleHandle& console,
298345
BotBaseContext& context,
299346
MaterialFarmerOptions& options,
300347
MaterialFarmerStats& stats
301348
){
349+
302350
if (options.SANDWICH_OPTIONS.SAVE_GAME_BEFORE_SANDWICH){
303351
save_game_from_overworld(env.program_info(), console, context);
304352
}
305353

306-
WallClock last_sandwich_time;
307-
size_t consecutive_failures = 0;
308-
size_t max_consecutive_failures = 10;
309-
while (true){
310-
try{
311-
last_sandwich_time = try_make_sandwich_material_farm(env, console, context, options, stats);
312-
break;
313-
}catch(OperationFailedException& e){
314-
stats.m_errors++;
315-
env.update_stats();
316-
e.send_notification(env, options.NOTIFICATION_ERROR_RECOVERABLE);
317-
318-
// save screenshot after operation failed,
319-
dump_snapshot(console);
320-
321-
if (options.SAVE_DEBUG_VIDEO){
322-
// Take a video to give more context for debugging
323-
pbf_press_button(context, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 2 * TICKS_PER_SECOND);
324-
context.wait_for_all_requests();
325-
}
326-
327-
consecutive_failures++;
328-
if (consecutive_failures >= max_consecutive_failures){
329-
throw OperationFailedException(
330-
ErrorReport::SEND_ERROR_REPORT, console,
331-
"Failed to make sandwich "+ std::to_string(max_consecutive_failures) + " times in a row.",
332-
true
333-
);
334-
}
335-
336-
env.log("Failed to make sandwich. Reset game to handle recoverable error.");
337-
reset_game(env.program_info(), console, context);
338-
stats.m_game_resets++;
339-
env.update_stats();
340-
}
341-
}
342-
343-
return last_sandwich_time;
344-
}
345-
346-
347-
// make sandwich then go back to Pokecenter to reset position
348-
// if gets caught up in a battle, try again.
349-
WallClock try_make_sandwich_material_farm(
350-
ProgramEnvironment& env,
351-
ConsoleHandle& console,
352-
BotBaseContext& context,
353-
MaterialFarmerOptions& options,
354-
MaterialFarmerStats& stats
355-
){
356354
WallClock last_sandwich_time = WallClock::min();
357355
while(last_sandwich_time == WallClock::min()){
358356
run_from_battles_and_back_to_pokecenter(env, console, context, stats,
@@ -373,7 +371,7 @@ WallClock try_make_sandwich_material_farm(
373371

374372
// make sandwich
375373
picnic_from_overworld(env.program_info(), console, context);
376-
pbf_move_left_joystick(context, 128, 0, 30, 40);
374+
pbf_move_left_joystick(context, 128, 0, 100, 40); // walk forward to picnic table
377375
enter_sandwich_recipe_list(env.program_info(), console, context);
378376
make_sandwich_option(env, console, context, options.SANDWICH_OPTIONS);
379377
last_sandwich_time = current_time();
@@ -468,7 +466,9 @@ void move_to_start_position_for_letsgo1(
468466
pbf_move_left_joystick(context, 128, 0, 300, 10);
469467

470468
// look right, towards the start position
471-
pbf_move_right_joystick(context, 255, 128, 130, 10);
469+
DirectionDetector direction;
470+
direction.change_direction(console, context, 5.76);
471+
// pbf_move_right_joystick(context, 255, 128, 130, 10);
472472
pbf_move_left_joystick(context, 128, 0, 10, 10);
473473

474474
// get on ride
@@ -498,7 +498,8 @@ void move_to_start_position_for_letsgo1(
498498
pbf_press_button(context, BUTTON_B, 50, 10);
499499

500500
// look right
501-
pbf_move_right_joystick(context, 255, 128, 20, 10);
501+
// pbf_move_right_joystick(context, 255, 128, 20, 10);
502+
direction.change_direction(console, context, 5.46);
502503

503504
// move forward slightly
504505
pbf_move_left_joystick(context, 128, 0, 50, 10);

SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_MaterialFarmerTools.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,6 @@ WallClock make_sandwich_material_farm(
109109
MaterialFarmerStats& stats
110110
);
111111

112-
WallClock try_make_sandwich_material_farm(
113-
ProgramEnvironment& env,
114-
ConsoleHandle& console,
115-
BotBaseContext& context,
116-
MaterialFarmerOptions& options,
117-
MaterialFarmerStats& stats
118-
);
119-
120112
void move_to_start_position_for_letsgo0(ConsoleHandle& console, BotBaseContext& context);
121113

122114
void move_to_start_position_for_letsgo1(ConsoleHandle& console, BotBaseContext& context);

SerialPrograms/Source/PokemonSV/Programs/PokemonSV_Navigation.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -681,14 +681,13 @@ void fly_to_closest_pokecenter_on_map(const ProgramInfo& info, ConsoleHandle& co
681681
true
682682
);
683683
}
684-
}catch (OperationFailedException&){ // pokecenter was detected, but failed to fly there
684+
}catch (OperationFailedException& e){
685685
try_count++;
686686
if (try_count >= MAX_TRY_COUNT){
687-
throw OperationFailedException(
688-
ErrorReport::SEND_ERROR_REPORT, console,
689-
"fly_to_closest_pokecenter_on_map(): At max warpable map level, pokecenter was detected, but failed to fly there.",
690-
true
691-
);
687+
// either:
688+
// - pokecenter was detected, but failed to fly there.
689+
// - could not find pokecenter icon.
690+
throw e;
692691
}
693692
console.log("Failed to find the fly menuitem. Restart the closest Pokecenter travel process.");
694693
press_Bs_to_back_to_overworld(info, console, context);

SerialPrograms/Source/PokemonSV/Programs/Sandwiches/PokemonSV_SandwichRoutines.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ bool enter_sandwich_recipe_list(const ProgramInfo& info, ConsoleHandle& console,
8484
switch (ret){
8585
case 0:
8686
console.log("Detected picnic. Maybe button A press dropped.");
87+
// walk forward and press A again
88+
pbf_move_left_joystick(context, 128, 0, 100, 40);
8789
pbf_press_button(context, BUTTON_A, 20, 80);
8890
continue;
8991
case 1:

0 commit comments

Comments
 (0)