Skip to content

Commit 042fbd2

Browse files
authored
Add a way to buy more than one kind of item in StallBuyer (#808)
1 parent 4c934e1 commit 042fbd2

File tree

2 files changed

+148
-105
lines changed

2 files changed

+148
-105
lines changed

SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_StallBuyer.cpp

Lines changed: 128 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,39 @@ namespace PokemonLZA{
2424

2525
using namespace Pokemon;
2626

27+
StallBuyerRow::StallBuyerRow(int index, std::string&& ordinal)
28+
: StaticTableRow(ordinal)
29+
, item(LockMode::LOCK_WHILE_RUNNING, "The number of the " + ordinal + " item you want to purchase.")
30+
, quantity(LockMode::LOCK_WHILE_RUNNING, 0, 0, 999)
31+
, ordinal(std::move(ordinal))
32+
, index(index)
33+
{
34+
PA_ADD_STATIC(item);
35+
PA_ADD_OPTION(quantity);
36+
}
37+
38+
StallBuyerTable::StallBuyerTable()
39+
: StaticTableOption("<b>Number to Purchase:</b><br>The number of items you want to purchase.", LockMode::LOCK_WHILE_RUNNING)
40+
{
41+
add_row(std::make_unique<StallBuyerRow>(0, "first"));
42+
add_row(std::make_unique<StallBuyerRow>(1, "second"));
43+
add_row(std::make_unique<StallBuyerRow>(2, "third"));
44+
add_row(std::make_unique<StallBuyerRow>(3, "fourth"));
45+
add_row(std::make_unique<StallBuyerRow>(4, "fifth"));
46+
add_row(std::make_unique<StallBuyerRow>(5, "sixth"));
47+
add_row(std::make_unique<StallBuyerRow>(6, "seventh"));
48+
49+
finish_construction();
50+
}
51+
std::vector<std::string> StallBuyerTable::make_header() const{
52+
std::vector<std::string> ret{
53+
"Item",
54+
"Quantity"
55+
};
56+
return ret;
57+
}
58+
59+
2760
StallBuyer_Descriptor::StallBuyer_Descriptor()
2861
: SingleSwitchProgramDescriptor(
2962
"PokemonLZA:StallBuyer",
@@ -55,34 +88,14 @@ std::unique_ptr<StatsTracker> StallBuyer_Descriptor::make_stats() const{
5588

5689

5790
StallBuyer::StallBuyer()
58-
: ITEM_POSITION(
59-
"<b>Item Position to Purchase:</b>",
60-
{
61-
{ItemPosition::FirstItem, "FirstItem", "First Item" },
62-
{ItemPosition::SecondItem, "SecondItem", "Second Item" },
63-
{ItemPosition::ThirdItem, "ThirdItem", "Third Item" },
64-
{ItemPosition::FourthItem, "FourthItem", "Fourth Item" },
65-
{ItemPosition::FifthItem, "FifthItem", "Fifth Item" },
66-
{ItemPosition::SixthItem, "SixthItem", "Sixth Item" },
67-
{ItemPosition::SeventhItem, "SeventhItem", "Seventh Item" },
68-
},
69-
LockMode::LOCK_WHILE_RUNNING,
70-
ItemPosition::FirstItem
71-
)
72-
, NUM_PURCHASE(
73-
"<b>Number to Purchase:</b><br>The number of items you want to purchase.",
74-
LockMode::LOCK_WHILE_RUNNING,
75-
100, 1, 999
76-
)
77-
, GO_HOME_WHEN_DONE(false)
91+
: GO_HOME_WHEN_DONE(false)
7892
, NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600))
7993
, NOTIFICATIONS({
8094
&NOTIFICATION_STATUS_UPDATE,
8195
&NOTIFICATION_PROGRAM_FINISH,
8296
&NOTIFICATION_ERROR_FATAL,
8397
})
8498
{
85-
PA_ADD_OPTION(ITEM_POSITION);
8699
PA_ADD_OPTION(NUM_PURCHASE);
87100
PA_ADD_OPTION(GO_HOME_WHEN_DONE);
88101
PA_ADD_OPTION(NOTIFICATIONS);
@@ -146,88 +159,109 @@ void StallBuyer::program(SingleSwitchProgramEnvironment& env, ProControllerConte
146159
StallBuyer_Descriptor::Stats& stats = env.current_stats<StallBuyer_Descriptor::Stats>();
147160
assert_16_9_720p_min(env.logger(), env.console);
148161

149-
while (true) {
150-
context.wait_for_all_requests();
162+
std::optional<int> stall_amount_item;
151163

152-
ButtonWatcher buttonA(
153-
COLOR_RED,
154-
ButtonType::ButtonA,
155-
{0.1, 0.1, 0.8, 0.8},
156-
&env.console.overlay()
157-
);
158-
SelectionArrowWatcher select(
159-
COLOR_YELLOW, &env.console.overlay(),
160-
SelectionArrowType::RIGHT,
161-
{0.715, 0.165, 0.045, 0.440}
162-
);
163-
SelectionArrowWatcher confirm(
164-
COLOR_YELLOW, &env.console.overlay(),
165-
SelectionArrowType::RIGHT,
166-
{0.665, 0.600, 0.145, 0.080}
167-
);
168-
FlatWhiteDialogWatcher dialog(COLOR_RED, &env.console.overlay());
164+
for (StaticTableRow* row : NUM_PURCHASE.table()){
165+
StallBuyerRow& stall_buyer_row = static_cast<StallBuyerRow&>(*row);
169166

170-
int ret = wait_until(
171-
env.console, context,
172-
30000ms,
173-
{
174-
buttonA,
175-
select,
176-
confirm,
177-
dialog,
178-
}
167+
for (int purchases = 0; purchases < stall_buyer_row.quantity; /*Do not increment, it will be done in the loop*/){
168+
context.wait_for_all_requests();
169+
170+
ButtonWatcher buttonA(
171+
COLOR_RED,
172+
ButtonType::ButtonA,
173+
{0.1, 0.1, 0.8, 0.8},
174+
&env.console.overlay()
179175
);
180-
context.wait_for(100ms);
181-
182-
switch (ret){
183-
case 0:
184-
env.log("Detected A button.");
185-
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
186-
continue;
187-
188-
case 1:
189-
{
190-
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);
194-
for (int i = 0; i < presses; i++){
195-
pbf_press_dpad(context, direction, 160ms, 80ms);
196-
}
197-
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
198-
continue;
199-
}
200-
case 2:
201-
env.log("Detected purchase confirm screen.");
202-
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
203-
stats.purchases++;
204-
env.update_stats();
205-
206-
if (stats.purchases == NUM_PURCHASE) {
207-
// pbf_mash_button(context, BUTTON_B, 5000ms);
208-
// intentionally don't leave the purchase menu to not get attacked
209-
GO_HOME_WHEN_DONE.run_end_of_program(context);
210-
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);
211-
return;
176+
SelectionArrowWatcher select(
177+
COLOR_YELLOW, &env.console.overlay(),
178+
SelectionArrowType::RIGHT,
179+
{0.715, 0.165, 0.045, 0.440}
180+
);
181+
SelectionArrowWatcher confirm(
182+
COLOR_YELLOW, &env.console.overlay(),
183+
SelectionArrowType::RIGHT,
184+
{0.665, 0.600, 0.145, 0.080}
185+
);
186+
FlatWhiteDialogWatcher dialog(COLOR_RED, &env.console.overlay());
187+
188+
int ret = wait_until(
189+
env.console, context,
190+
30000ms,
191+
{
192+
buttonA,
193+
select,
194+
confirm,
195+
dialog,
196+
}
197+
);
198+
context.wait_for(100ms);
199+
200+
switch (ret){
201+
case 0:
202+
env.log("Detected A button.");
203+
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
204+
continue;
205+
206+
case 1:
207+
{
208+
env.log("Detected item selection screen.");
209+
if (!stall_amount_item.has_value()){
210+
stall_amount_item = detect_stall_amount_item(env, stats);
211+
env.log("Detected stall with " + std::to_string(stall_amount_item.value()) + " items to sell.");
212+
for (StaticTableRow* item : NUM_PURCHASE.table()){
213+
StallBuyerRow& casted_item = static_cast<StallBuyerRow&>(*item);
214+
if (casted_item.index >= stall_amount_item.value() && casted_item.quantity > 0){
215+
throw UserSetupError(
216+
env.logger(),
217+
"Stall is of size " + std::to_string(stall_amount_item.value()) + " and Number to Purchase for " +
218+
casted_item.ordinal + " item is " + std::to_string(casted_item.quantity) + "."
219+
);
220+
}
221+
}
222+
}
223+
auto [direction, presses] = compute_needed_inputs(stall_buyer_row.index, stall_amount_item.value());
224+
for (int i = 0; i < presses; i++){
225+
pbf_press_dpad(context, direction, 160ms, 80ms);
226+
}
227+
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
228+
continue;
212229
}
230+
case 2:
231+
env.log("Detected purchase confirm screen.");
232+
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
233+
stats.purchases++;
234+
purchases++;
235+
env.update_stats();
213236

214-
continue;
237+
if (purchases == stall_buyer_row.quantity){
238+
std::stringstream ss;
239+
ss << "Purchased " << stall_buyer_row.quantity << " of " << stall_buyer_row.ordinal << " item.";
240+
send_program_status_notification(env, NOTIFICATION_STATUS_UPDATE, ss.str());
241+
break;
242+
}
215243

216-
case 3:
217-
env.log("Detected white dialog.");
218-
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
219-
continue;
244+
continue;
220245

221-
default:
222-
stats.errors++;
223-
env.update_stats();
224-
OperationFailedException::fire(
225-
ErrorReport::SEND_ERROR_REPORT,
226-
"No recognized state after 30 seconds.",
227-
env.console
228-
);
246+
case 3:
247+
env.log("Detected white dialog.");
248+
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
249+
continue;
250+
251+
default:
252+
stats.errors++;
253+
env.update_stats();
254+
OperationFailedException::fire(
255+
ErrorReport::SEND_ERROR_REPORT,
256+
"No recognized state after 30 seconds.",
257+
env.console
258+
);
259+
}
229260
}
230261
}
262+
// intentionally don't leave the purchase menu to not get attacked
263+
GO_HOME_WHEN_DONE.run_end_of_program(context);
264+
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);
231265
}
232266

233267

SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_StallBuyer.h

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "Common/Cpp/Options/SimpleIntegerOption.h"
1111
#include "CommonFramework/Notifications/EventNotificationsTable.h"
12+
#include "CommonFramework/Options/LabelCellOption.h"
1213
#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h"
1314
#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h"
1415

@@ -18,6 +19,24 @@ namespace PokemonLZA{
1819

1920

2021

22+
class StallBuyerRow : public StaticTableRow{
23+
public:
24+
StallBuyerRow(int index, std::string&& ordinal);
25+
26+
LabelCellOption item;
27+
SimpleIntegerCell<uint16_t> quantity;
28+
std::string ordinal;
29+
int index;
30+
};
31+
32+
class StallBuyerTable : public StaticTableOption {
33+
public:
34+
StallBuyerTable();
35+
virtual std::vector<std::string> make_header() const;
36+
};
37+
38+
39+
2140
class StallBuyer_Descriptor : public SingleSwitchProgramDescriptor{
2241
public:
2342
StallBuyer_Descriptor();
@@ -35,17 +54,7 @@ class StallBuyer : public SingleSwitchProgramInstance{
3554
virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override;
3655

3756
private:
38-
enum class ItemPosition{
39-
FirstItem,
40-
SecondItem,
41-
ThirdItem,
42-
FourthItem,
43-
FifthItem,
44-
SixthItem,
45-
SeventhItem
46-
};
47-
EnumDropdownOption<ItemPosition> ITEM_POSITION;
48-
SimpleIntegerOption<uint16_t> NUM_PURCHASE;
57+
StallBuyerTable NUM_PURCHASE;
4958
GoHomeWhenDoneOption GO_HOME_WHEN_DONE;
5059
EventNotificationOption NOTIFICATION_STATUS_UPDATE;
5160
EventNotificationsOption NOTIFICATIONS;

0 commit comments

Comments
 (0)