Skip to content

Commit a1f787d

Browse files
committed
Add automatic breeding feature
This feature allows automatic Egg breeding/hatching. It is currently quite stable, but relatively slow since it hatches only one Egg a a time.
1 parent c1aeba5 commit a1f787d

File tree

2 files changed

+325
-1
lines changed

2 files changed

+325
-1
lines changed

src/swsh/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,70 @@ re-enable the process. You can either press it once, or twice:
149149
TODO: Implement a process that will actually start the Max Raid Battle so you can see
150150
if the Pokémon is shiny, and either restart the game to retry, or gain back control to
151151
battle it.
152+
153+
### Auto Breeding [Feature 4 - four button presses]
154+
155+
This feature will automatically get Pokémon Eggs and hatch them.
156+
157+
**Pre-requisites:**
158+
159+
- Be next to the Bridge Field Pokémon Nursery. This is the nursery that will provide the
160+
Eggs to be hatched.
161+
- **Be on your bike.**
162+
- Your team needs to be full, with a Pokémon with the Flame Body ability in any slot
163+
**except** the second one.
164+
- Your bike needs to be fully upgraded.
165+
- In the X Menu, the Settings button should be in the bottom right corner and the Map
166+
button should be in the bottom left corner (their default position).
167+
168+
You also need to known the Egg Cycle count of the Egg that are going to hatch.
169+
170+
This feature depends on Eggs being available at the Nursery more often that they hatch,
171+
except for 5-cycle eggs. You may need to increase the changes of getting an Egg (by having
172+
the Oval Charm, and/or having two Pokémon having different IDs and/or species in the
173+
Nursery).
174+
175+
**Note:** This feature does not require a special text speed to be set beforehand.
176+
However, it will modify these parameters during operation, and when done, the text speed
177+
will be set to “Fast”.
178+
179+
After the feature is started, the LED will blink once per second. Press the button the
180+
following number of times, depending on the Egg Cycle number:
181+
182+
| Egg Cycles | # presses | Approx. hatches / hour |
183+
| ---------- | --------- | ---------------------- |
184+
| 5 | 1 | 64 |
185+
| 10 | 2 | 60 |
186+
| 15 | 3 | 50 |
187+
| 20 | 4 | 40 |
188+
| 25 | 5 | 33 |
189+
| 30 | 6 | 30 |
190+
| 35 | 7 | 24 |
191+
| 40 | 8 | 22 |
192+
193+
Once your selection is made, the buzzer will beep the number of times the button was
194+
pressed, to confirm your selection.
195+
196+
At start, the following process is applied:
197+
198+
1. Set text speed to “fast”
199+
2. Warp to the nearest location (which is the Bridge Field Pokémon Nursery)
200+
3. Move around, to make sure an Egg is available.
201+
202+
The following steps will then be applied in a loop:
203+
204+
1. Warp to the nearest location (which is the Bridge Field Pokémon Nursery)
205+
2. Get an Egg from the Nursery Helper, put it in slot 2, sending slot 2 to Box
206+
3. Move around in circles (not too near the grass to avoid collisions)
207+
4. Wait during the hatching animation
208+
5. (for egg cycles = 5) move around more to give more time for an Egg to be available
209+
210+
The time for an Egg to hatch tends to vary a little bit, so the program will wait a bit
211+
more than necessary before stopping moving around and waiting for the Egg to hatch. The
212+
RX/TX LEDs light up during the wait; they should light up right after the “What?” dialog
213+
appears.
214+
215+
During the Egg hatch animation (RX/TX lighted up, L blinking) you can interrupt the
216+
process by pressing the button. The process will give you back control. Press it again
217+
while on the Switch main menu (cursor on the game icon) to get back back into the
218+
automation “main menu” where you can choose another automation task.

src/swsh/swsh.c

Lines changed: 258 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ static void set_text_speed(bool fast_speed, bool save);
1515
static void use_wishing_piece_and_pause(void);
1616
static void restart_game(void);
1717
static void change_raid(void);
18+
static void auto_breeding(void);
19+
static void reposition_player(bool first_time);
20+
static void go_to_nursery_helper(void);
21+
static void get_egg(void);
22+
static void move_in_circles(uint16_t cycles, bool go_up_first);
23+
static bool hatch_egg(void);
1824

1925
int main(void)
2026
{
@@ -39,7 +45,6 @@ int main(void)
3945
_delay_ms(100);
4046
}
4147

42-
4348
switch (count) {
4449
case 1:
4550
temporary_control();
@@ -53,6 +58,10 @@ int main(void)
5358
max_raid();
5459
break;
5560

61+
case 4:
62+
auto_breeding();
63+
break;
64+
5665
default:
5766
/* Wrong selection */
5867
delay(100, 200, 1500);
@@ -369,3 +378,251 @@ void change_raid(void)
369378
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 25 }, /* Wait */
370379
);
371380
}
381+
382+
383+
/*
384+
* Automatically get Eggs from the Bridge Field Pokémon Nursery and hatch them.
385+
*/
386+
void auto_breeding(void)
387+
{
388+
/* Hatching time for each Egg cycles */
389+
const struct {
390+
uint16_t hatch_time; /* Time passed spinning for the Egg to hatch */
391+
uint16_t wait_time; /* Time passed spinning to get another Egg */
392+
} egg_cycles[] = {
393+
{ 350, 150 }, /* 5 Egg cycles, approx. 64 Eggs/hour */
394+
{ 560, 0 }, /* 10 Egg cycles, approx. 60 Eggs/hour */
395+
{ 1100, 0 }, /* 15 Egg cycles, approx. 50 Eggs/hour */
396+
{ 1400, 0 }, /* 20 Egg cycles, approx. 40 Eggs/hour */
397+
{ 1750, 0 }, /* 25 Egg cycles, approx. 33 Eggs/hour */
398+
{ 2050, 0 }, /* 30 Egg cycles, approx. 30 Eggs/hour */
399+
{ 2400, 0 }, /* 35 Egg cycles, approx. 24 Eggs/hour */
400+
{ 2700, 0 }, /* 40 Egg cycles, approx. 22 Eggs/hour */
401+
};
402+
403+
/* Note that the automation is mashing B while on the bike, so its speed is irregular.
404+
This explains while the spin time is not linear compared to the Egg cycles. */
405+
406+
/* Select the egg cycle */
407+
uint16_t hatch_time;
408+
uint16_t wait_time;
409+
410+
for (;;) {
411+
uint8_t cycle_idx = count_button_presses(500, 500) - 1;
412+
413+
if (cycle_idx < (sizeof(egg_cycles) / sizeof(*egg_cycles))) {
414+
/* Selection OK, beep once per press */
415+
for (uint8_t i = 0 ; i <= cycle_idx ; i += 1) {
416+
beep();
417+
_delay_ms(200);
418+
}
419+
420+
hatch_time = egg_cycles[cycle_idx].hatch_time;
421+
wait_time = egg_cycles[cycle_idx].wait_time;
422+
423+
break;
424+
}
425+
426+
/* Wrong selection */
427+
delay(100, 200, 1500);
428+
}
429+
430+
/* FIXME: Find a way to ensure the player character is on their bike instead of just
431+
toggling the state. For now, just require the player to start on the bike. */
432+
#ifdef PUT_PLAYER_ON_BIKE
433+
SEND_BUTTON_SEQUENCE(KEEP_LEDS,
434+
{ BT_P, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Get on bike */
435+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 25 }, /* Wait for bike animation to finish */
436+
);
437+
#endif
438+
439+
reposition_player(/* first_time */ true);
440+
go_to_nursery_helper();
441+
442+
/* We do not known if an egg is already available, so we just spin the first time */
443+
move_in_circles(hatch_time + wait_time, /* go_up_first */ true);
444+
445+
for (;;) {
446+
reposition_player(/* first_time */ false);
447+
go_to_nursery_helper();
448+
get_egg();
449+
move_in_circles(hatch_time, /* go_up_first */ true);
450+
451+
if (hatch_egg()) {
452+
/* Operation stopped by the user */
453+
break;
454+
}
455+
456+
if (wait_time) {
457+
move_in_circles(wait_time, /* go_up_first */ false);
458+
}
459+
}
460+
461+
/* Give temporary control before returning to the menu */
462+
temporary_control();
463+
}
464+
465+
466+
/*
467+
* Use the Flying Taxi to warp to the current position (the nursery) to reposition the
468+
* player.
469+
*
470+
* first_time must be true the first time this function is called; it will then put the
471+
* X menu’s cursor on the Map icon. It will also set the text speed to Fast.
472+
*/
473+
void reposition_player(bool first_time)
474+
{
475+
/* Uses held A button to makes the text go faster. */
476+
477+
set_leds(NO_LEDS);
478+
479+
if (first_time) {
480+
SEND_BUTTON_SEQUENCE(KEEP_LEDS,
481+
{ BT_X, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Open menu */
482+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 25 }, /* Wait for menu */
483+
{ BT_NONE, DP_TOPLEFT, SEQ_HOLD, 25 }, /* Move to top/left position */
484+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release the buttons */
485+
486+
{ BT_NONE, DP_BOTTOM, SEQ_MASH, 1 }, /* Move to Map position */
487+
{ BT_NONE, DP_LEFT, SEQ_MASH, 1 }, /* Move to Parameters position */
488+
489+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Enter Parameters */
490+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 26 }, /* Wait for menu */
491+
492+
{ BT_NONE, DP_RIGHT, SEQ_MASH, 2 }, /* Select speed */
493+
494+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 10 }, /* Validate parameters */
495+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release A to advance */
496+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 10 }, /* Validate parameters */
497+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release A to advance */
498+
{ BT_A, DP_NEUTRAL, SEQ_MASH, 1 }, /* Validate dialog */
499+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 25 }, /* Wait for menu */
500+
501+
{ BT_NONE, DP_RIGHT, SEQ_MASH, 1 }, /* Move to Map position */
502+
);
503+
} else {
504+
SEND_BUTTON_SEQUENCE(KEEP_LEDS,
505+
{ BT_X, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Open menu */
506+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 25 }, /* Wait for menu */
507+
);
508+
}
509+
510+
SEND_BUTTON_SEQUENCE(KEEP_LEDS,
511+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Open map */
512+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 55 }, /* Wait for map */
513+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 15 }, /* Warp? */
514+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release A */
515+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Accept */
516+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 60 }, /* Wait for warp to complete */
517+
);
518+
}
519+
520+
521+
/*
522+
* Go in front of the nursery helper.
523+
* reposition_player must be called first.
524+
*/
525+
void go_to_nursery_helper(void)
526+
{
527+
set_leds(TX_LED);
528+
529+
send_update(BT_NONE, DP_NEUTRAL, S_SCALED(S_BOTLEFT, 25), S_NEUTRAL);
530+
531+
for (uint8_t i = 0 ; i < 21 ; i += 1) {
532+
send_update(BT_NONE, DP_NEUTRAL, S_BOTTOM, S_NEUTRAL);
533+
}
534+
535+
send_update(BT_NONE, DP_NEUTRAL, S_RIGHT, S_NEUTRAL);
536+
send_update(BT_NONE, DP_NEUTRAL, S_RIGHT, S_NEUTRAL);
537+
538+
/* Reset the sticks and wait for the player to be standing still */
539+
pause_automation();
540+
_delay_ms(400);
541+
}
542+
543+
544+
/*
545+
* Get an Egg from the nursery helper.
546+
* go_to_nursery_helper must be called first.
547+
*/
548+
void get_egg(void)
549+
{
550+
SEND_BUTTON_SEQUENCE(KEEP_LEDS,
551+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 10 }, /* Wait after movement */
552+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 15 }, /* Open “accept egg” dialog */
553+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release A */
554+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Accept egg */
555+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 75 }, /* Wait for dialog */
556+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Open “what do you want” dialog */
557+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 50 }, /* Wait for dialog */
558+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 20 }, /* Choose “include in team” */
559+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release A */
560+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Open team dialog */
561+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 45 }, /* Wait for dialog */
562+
{ BT_NONE, DP_BOTTOM, SEQ_MASH, 1 }, /* Go to second Pokémon */
563+
{ BT_A, DP_BOTTOM, SEQ_HOLD, 65 }, /* Select second Pokémon */
564+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release A */
565+
{ BT_A, DP_BOTTOM, SEQ_HOLD, 35 }, /* Validate “… sent to box” dialog */
566+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release A */
567+
{ BT_A, DP_BOTTOM, SEQ_MASH, 1 }, /* Validate “Take care” dialog */
568+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 25 }, /* Wait for dialog to close */
569+
);
570+
}
571+
572+
/*
573+
* Move in circle for the specified number of cycles.
574+
* go_to_nursery_helper must be called first for correct positioning.
575+
*/
576+
void move_in_circles(uint16_t cycles, bool go_up_first)
577+
{
578+
set_leds(RX_LED);
579+
580+
if (go_up_first) {
581+
send_update(BT_NONE, DP_NEUTRAL, S_SCALED(S_TOP, 25), S_NEUTRAL);
582+
583+
for (uint8_t i = 0 ; i < 10 ; i += 1) {
584+
send_update(BT_NONE, DP_NEUTRAL, S_TOP, S_NEUTRAL);
585+
send_update(BT_B, DP_NEUTRAL, S_TOP, S_NEUTRAL);
586+
}
587+
588+
for (uint8_t i = 0 ; i < 50 ; i += 1) {
589+
send_update(BT_NONE, DP_NEUTRAL, S_TOPRIGHT, S_NEUTRAL);
590+
}
591+
}
592+
593+
for (uint16_t i = 0 ; i < (cycles / 2) ; i += 1) {
594+
send_update(BT_NONE, DP_NEUTRAL, S_RIGHT, S_LEFT);
595+
send_update(BT_B, DP_NEUTRAL, S_RIGHT, S_LEFT);
596+
}
597+
598+
/* Reset sticks position */
599+
pause_automation();
600+
}
601+
602+
603+
/*
604+
* Hatch an egg. The “What?” dialog must be shown on screen.
605+
* Returns true if the process was interrupted by the user.
606+
*/
607+
bool hatch_egg(void)
608+
{
609+
set_leds(BOTH_LEDS);
610+
611+
SEND_BUTTON_SEQUENCE(KEEP_LEDS,
612+
{ BT_A, DP_NEUTRAL, SEQ_MASH, 1 }, /* Validate “What?” dialog */
613+
)
614+
615+
/* Egg hatching animation */
616+
if (delay(250, 250, 12500)) {
617+
return true;
618+
}
619+
620+
SEND_BUTTON_SEQUENCE(KEEP_LEDS,
621+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 25 }, /* Speed up egg dialog text */
622+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Release A */
623+
{ BT_A, DP_NEUTRAL, SEQ_HOLD, 1 }, /* Validate egg dialog */
624+
{ BT_NONE, DP_NEUTRAL, SEQ_HOLD, 80 }, /* Wait for fadeout */
625+
)
626+
627+
return false;
628+
}

0 commit comments

Comments
 (0)