77#include " CommonFramework/Exceptions/OperationFailedException.h"
88#include " CommonFramework/Notifications/ProgramNotifications.h"
99#include " CommonFramework/ProgramStats/StatsTracking.h"
10+ #include " CommonFramework/VideoPipeline/VideoFeed.h"
1011#include " CommonTools/Async/InferenceRoutines.h"
1112#include " CommonTools/StartupChecks/VideoResolutionCheck.h"
13+ #include " CommonTools/VisualDetectors/BlackScreenDetector.h"
1214#include " NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
1315#include " Pokemon/Pokemon_Strings.h"
1416#include " PokemonLZA/Inference/PokemonLZA_ButtonDetector.h"
@@ -67,11 +69,6 @@ StallBuyer::StallBuyer()
6769 LockMode::LOCK_WHILE_RUNNING,
6870 ItemPosition::FirstItem
6971 )
70- , NUM_ITEM(
71- " <b>Number of available items in the stall:</b><br>Number of available items in the stall." ,
72- LockMode::LOCK_WHILE_RUNNING,
73- 6 , 2 , 7
74- )
7572 , NUM_PURCHASE(
7673 " <b>Number to Purchase:</b><br>The number of items you want to purchase." ,
7774 LockMode::LOCK_WHILE_RUNNING,
@@ -86,15 +83,57 @@ StallBuyer::StallBuyer()
8683 })
8784{
8885 PA_ADD_OPTION (ITEM_POSITION);
89- PA_ADD_OPTION (NUM_ITEM);
9086 PA_ADD_OPTION (NUM_PURCHASE);
9187 PA_ADD_OPTION (GO_HOME_WHEN_DONE);
9288 PA_ADD_OPTION (NOTIFICATIONS);
9389}
9490
95- std::pair<DpadPosition, int > compute_needed_inputs (int item_position, int num_item){
91+ int detect_stall_amount_item (SingleSwitchProgramEnvironment& env, StallBuyer_Descriptor::Stats& stats){
92+ // When buying from a stall, the first item is always selected.
93+ // Detect which one is currently selected (with white background)
94+ // 0.700 as y is the bottom option, then each one is shifted by 0.072
95+ ImageFloatBox seven_item_stall_box (0.858 , 0.700 - 7 * 0.072 , 0.024 , 0.019 );
96+ ImageFloatBox six_item_stall_box (0.858 , 0.700 - 6 * 0.072 , 0.024 , 0.019 );
97+ ImageFloatBox five_item_stall_box (0.858 , 0.700 - 5 * 0.072 , 0.024 , 0.019 );
98+ ImageFloatBox two_item_stall_box (0.858 , 0.700 - 2 * 0.072 , 0.024 , 0.019 );
99+
100+ WhiteScreenDetector seven_item_stall_detector (COLOR_BLUE, seven_item_stall_box);
101+ WhiteScreenDetector six_item_stall_detector (COLOR_BLUE, six_item_stall_box);
102+ WhiteScreenDetector five_item_stall_detector (COLOR_BLUE, five_item_stall_box);
103+ WhiteScreenDetector two_item_stall_detector (COLOR_BLUE, two_item_stall_box);
104+
105+ VideoSnapshot snapshot = env.console .video ().snapshot ();
106+ bool is_seven_item_stall = seven_item_stall_detector.detect (snapshot);
107+ bool is_six_item_stall = six_item_stall_detector.detect (snapshot);
108+ bool is_five_item_stall = five_item_stall_detector.detect (snapshot);
109+ bool is_two_item_stall = two_item_stall_detector.detect (snapshot);
110+
111+ int count = is_seven_item_stall + is_six_item_stall + is_five_item_stall + is_two_item_stall;
112+ if (count == 1 ){
113+ // Exactly one kind of stall detected
114+ if (is_seven_item_stall){
115+ return 7 ;
116+ }else if (is_six_item_stall){
117+ return 6 ;
118+ }else if (is_five_item_stall){
119+ return 5 ;
120+ }else {
121+ return 2 ;
122+ }
123+ }else {
124+ stats.errors ++;
125+ env.update_stats ();
126+ OperationFailedException::fire (
127+ ErrorReport::SEND_ERROR_REPORT,
128+ " No recognized stall size." ,
129+ env.console
130+ );
131+ }
132+ }
133+
134+ std::pair<DpadPosition, int > compute_needed_inputs (int item_position, int stall_amount_item){
96135 int down_presses = item_position;
97- int up_presses = num_item - item_position + 1 ;
136+ int up_presses = stall_amount_item - item_position + 1 ;
98137
99138 if (down_presses <= up_presses){
100139 return { DPAD_DOWN, down_presses };
@@ -106,13 +145,6 @@ std::pair<DpadPosition, int> compute_needed_inputs(int item_position, int num_it
106145void StallBuyer::program (SingleSwitchProgramEnvironment& env, ProControllerContext& context){
107146 StallBuyer_Descriptor::Stats& stats = env.current_stats <StallBuyer_Descriptor::Stats>();
108147 assert_16_9_720p_min (env.logger (), env.console );
109- int item_position = static_cast <int >(ITEM_POSITION.get ());
110- if (item_position >= NUM_ITEM){
111- throw UserSetupError (
112- env.logger (),
113- " Item position to purchase must be less than or equal to number of available items in the stall."
114- );
115- }
116148
117149 while (true ) {
118150 context.wait_for_all_requests ();
@@ -147,21 +179,24 @@ void StallBuyer::program(SingleSwitchProgramEnvironment& env, ProControllerConte
147179 );
148180 context.wait_for (100ms);
149181
150- auto [direction, presses] = compute_needed_inputs (item_position, NUM_ITEM);
151182 switch (ret){
152183 case 0 :
153184 env.log (" Detected A button." );
154185 pbf_press_button (context, BUTTON_A, 160ms, 80ms);
155186 continue ;
156187
157188 case 1 :
189+ {
158190 env.log (" Detected item selection screen." );
191+ int stall_amount_item = detect_stall_amount_item (env, stats);
192+ env.log (" Detected stall with " + std::to_string (stall_amount_item) + " items to sell." );
193+ auto [direction, presses] = compute_needed_inputs (static_cast <int >(ITEM_POSITION.get ()), stall_amount_item);
159194 for (int i = 0 ; i < presses; i++){
160195 pbf_press_dpad (context, direction, 160ms, 80ms);
161196 }
162197 pbf_press_button (context, BUTTON_A, 160ms, 80ms);
163198 continue ;
164-
199+ }
165200 case 2 :
166201 env.log (" Detected purchase confirm screen." );
167202 pbf_press_button (context, BUTTON_A, 160ms, 80ms);
0 commit comments