@@ -38,14 +38,17 @@ PrizeCornerReset_Descriptor::PrizeCornerReset_Descriptor()
3838
3939struct PrizeCornerReset_Descriptor ::Stats : public StatsTracker{
4040 Stats ()
41- : resets(m_stats[" Resets" ])
41+ : prizes(m_stats[" Prizes" ])
42+ , resets(m_stats[" Resets" ])
4243 , shinies(m_stats[" Shinies" ])
4344 , errors(m_stats[" Errors" ])
4445 {
46+ m_display_order.emplace_back (" Prizes" );
4547 m_display_order.emplace_back (" Resets" );
4648 m_display_order.emplace_back (" Shinies" );
4749 m_display_order.emplace_back (" Errors" , HIDDEN_IF_ZERO);
4850 }
51+ std::atomic<uint64_t >& prizes;
4952 std::atomic<uint64_t >& resets;
5053 std::atomic<uint64_t >& shinies;
5154 std::atomic<uint64_t >& errors;
@@ -54,6 +57,11 @@ std::unique_ptr<StatsTracker> PrizeCornerReset_Descriptor::make_stats() const{
5457 return std::unique_ptr<StatsTracker>(new Stats ());
5558}
5659
60+ PrizeCornerReset::~PrizeCornerReset (){
61+ SLOT.remove_listener (*this );
62+ NUM_REDEEM.remove_listener (*this );
63+ }
64+
5765PrizeCornerReset::PrizeCornerReset ()
5866 : SLOT(
5967 " <b>Slot:</b><br>Position of the prize in the selection dialog." ,
@@ -67,6 +75,15 @@ PrizeCornerReset::PrizeCornerReset()
6775 LockMode::LOCK_WHILE_RUNNING,
6876 0
6977 )
78+ , NUM_REDEEM(
79+ " <b>Number of redemptions:</b><br>How many times to redeem a prize per reset. "
80+ " Make sure your party has enough room, and that you have enough coins for multiple redemptions."
81+ " <br> ex. When buying 3 Dratini (2,800 * 3 = 8,400 coins) in FireRed, have a party of 3, with 3 open slots. "
82+ " This cannot be done in LeafGreen, as Dratini costs more, so the max there would be 2 Dratini (4,600 * 2 = 9,200 coins) and your party size would be 4, with 2 open slots." ,
83+ LockMode::LOCK_WHILE_RUNNING,
84+ 1 , 1 , 5
85+ )
86+ , WARNING(" " )
7087 , TAKE_VIDEO(" <b>Take Video:</b><br>Record a video when the shiny is found." , LockMode::UNLOCK_WHILE_RUNNING, true )
7188 , GO_HOME_WHEN_DONE(true )
7289 , NOTIFICATION_SHINY(
@@ -82,9 +99,38 @@ PrizeCornerReset::PrizeCornerReset()
8299 })
83100{
84101 PA_ADD_OPTION (SLOT);
102+ PA_ADD_OPTION (NUM_REDEEM);
103+ PA_ADD_OPTION (WARNING);
85104 PA_ADD_OPTION (TAKE_VIDEO);
86105 PA_ADD_OPTION (GO_HOME_WHEN_DONE);
87106 PA_ADD_OPTION (NOTIFICATIONS);
107+
108+ PrizeCornerReset::on_config_value_changed (this );
109+ SLOT.add_listener (*this );
110+ NUM_REDEEM.add_listener (*this );
111+ WARNING.set_visibility (ConfigOptionState::HIDDEN);
112+ }
113+
114+ void PrizeCornerReset::on_config_value_changed (void * object){
115+ std::string error = check_amount_redeemed ((uint16_t )SLOT.current_value (), NUM_REDEEM);
116+
117+ if (error.empty ()){
118+ WARNING.set_visibility (ConfigOptionState::HIDDEN);
119+ }else {
120+ WARNING.set_text (" <font color=\" red\" >" + error + " </font>" );
121+ WARNING.set_visibility (ConfigOptionState::ENABLED);
122+ }
123+ }
124+
125+ std::string PrizeCornerReset::check_amount_redeemed (uint16_t slot_num, uint32_t redeem_num) const {
126+ if (slot_num == 4 && redeem_num != 1 ) { // Only 1 Porygon in both FR and LG
127+ return " Error: Cannot redeem more than 1 Porygon per reset due to coin case limit." ;
128+ } else if (slot_num == 3 && redeem_num > 2 ) { // 2 Dratini LG or 1 Scyther FR
129+ return " Error: Maximum redemption of 2 Dratini in LG or 1 Scyther in FR per reset due to coin case limit." ;
130+ } else if (slot_num == 2 && redeem_num > 3 ) { // Max of 3 for both games
131+ return " Error: Maximum redemption of 3 Dratini/Pinsir due to coin case limit." ;
132+ } // Abra/Clefairy will run out of party space first before coins.
133+ return " " ;
88134}
89135
90136void PrizeCornerReset::obtain_prize (SingleSwitchProgramEnvironment& env, ProControllerContext& context){
@@ -134,16 +180,25 @@ void PrizeCornerReset::obtain_prize(SingleSwitchProgramEnvironment& env, ProCont
134180
135181 // Select prize
136182 pbf_press_button (context, BUTTON_A, 320ms, 640ms);
137- pbf_press_button (context, BUTTON_A, 320ms, 640ms);
183+ pbf_press_button (context, BUTTON_A, 320ms, 640ms); // Yes to redeem
138184
139185 // Exit dialog
140186 pbf_mash_button (context, BUTTON_B, 2000ms);
141187 context.wait_for_all_requests ();
188+
189+ stats.prizes ++;
190+ env.update_stats ();
142191}
143192
144193void PrizeCornerReset::program (SingleSwitchProgramEnvironment& env, ProControllerContext& context){
145194 PrizeCornerReset_Descriptor::Stats& stats = env.current_stats <PrizeCornerReset_Descriptor::Stats>();
146195
196+ std::string amount_check;
197+ amount_check = check_amount_redeemed ((uint16_t )SLOT.current_value (), NUM_REDEEM);
198+ if (amount_check != " " ) {
199+ throw UserSetupError (env.console , " Invalid number of redemptions for the selected prize. Please check your selected options." );
200+ }
201+
147202 home_black_border_check (env.console , context);
148203
149204 /*
@@ -155,34 +210,51 @@ void PrizeCornerReset::program(SingleSwitchProgramEnvironment& env, ProControlle
155210 bool shiny_found = false ;
156211
157212 while (!shiny_found){
158- obtain_prize (env, context);
213+ for (uint16_t i = 0 ; i < NUM_REDEEM; i++){
214+ env.log (" Obtaining prize." );
215+ obtain_prize (env, context);
216+ }
159217 stats.errors += open_slot_six (env.console , context);
160218 env.update_stats ();
161219
162- VideoSnapshot screen = env.console .video ().snapshot ();
220+ env.log (" Checking prizes." );
221+ for (uint16_t i = 0 ; i < NUM_REDEEM; i++){
222+ VideoSnapshot screen = env.console .video ().snapshot ();
163223
164- ShinySymbolDetector shiny_checker (COLOR_YELLOW);
165- shiny_found = shiny_checker.read (env.console .logger (), screen);
224+ ShinySymbolDetector shiny_checker (COLOR_YELLOW);
225+ bool check = shiny_checker.read (env.console .logger (), screen);
166226
167- if (shiny_found){
168- env.log (" Shiny found!" );
169- stats.shinies ++;
170- env.update_stats ();
171- send_program_notification (
172- env,
173- NOTIFICATION_SHINY,
174- COLOR_YELLOW,
175- " Shiny found!" ,
176- {}, " " ,
177- screen,
178- true
179- );
180- if (TAKE_VIDEO){
181- pbf_press_button (context, BUTTON_CAPTURE, 2000ms, 0ms);
227+ if (check){
228+ env.log (" Shiny found!" );
229+ stats.shinies ++;
230+ env.update_stats ();
231+ send_program_notification (
232+ env,
233+ NOTIFICATION_SHINY,
234+ COLOR_YELLOW,
235+ " Shiny found!" ,
236+ {}, " " ,
237+ screen,
238+ true
239+ );
240+ if (TAKE_VIDEO){
241+ pbf_press_button (context, BUTTON_CAPTURE, 2000ms, 0ms);
242+ }
243+ shiny_found = true ;
244+ }else {
245+ env.log (" Prize is not shiny." );
182246 }
183- break ;
184- }else {
185- env.log (" Prize is not shiny." );
247+
248+ if (i < NUM_REDEEM - 1 ) {
249+ // Check the next pokemon
250+ pbf_press_dpad (context, DPAD_UP, 320ms, 320ms);
251+ pbf_wait (context, 1000ms);
252+ context.wait_for_all_requests ();
253+ }
254+ }
255+
256+ if (!shiny_found){
257+ env.log (" Out of Pokemon to check." );
186258 env.log (" Soft resetting." );
187259 send_program_status_notification (
188260 env, NOTIFICATION_STATUS_UPDATE,
0 commit comments