Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 128 additions & 94 deletions SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_StallBuyer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,39 @@ namespace PokemonLZA{

using namespace Pokemon;

StallBuyerRow::StallBuyerRow(int index, std::string&& ordinal)
: StaticTableRow(ordinal)
, item(LockMode::LOCK_WHILE_RUNNING, "The number of the " + ordinal + " item you want to purchase.")
, quantity(LockMode::LOCK_WHILE_RUNNING, 0, 0, 999)
, ordinal(std::move(ordinal))
, index(index)
{
PA_ADD_STATIC(item);
PA_ADD_OPTION(quantity);
}

StallBuyerTable::StallBuyerTable()
: StaticTableOption("<b>Number to Purchase:</b><br>The number of items you want to purchase.", LockMode::LOCK_WHILE_RUNNING)
{
add_row(std::make_unique<StallBuyerRow>(0, "first"));
add_row(std::make_unique<StallBuyerRow>(1, "second"));
add_row(std::make_unique<StallBuyerRow>(2, "third"));
add_row(std::make_unique<StallBuyerRow>(3, "fourth"));
add_row(std::make_unique<StallBuyerRow>(4, "fifth"));
add_row(std::make_unique<StallBuyerRow>(5, "sixth"));
add_row(std::make_unique<StallBuyerRow>(6, "seventh"));

finish_construction();
}
std::vector<std::string> StallBuyerTable::make_header() const{
std::vector<std::string> ret{
"Item",
"Quantity"
};
return ret;
}


StallBuyer_Descriptor::StallBuyer_Descriptor()
: SingleSwitchProgramDescriptor(
"PokemonLZA:StallBuyer",
Expand Down Expand Up @@ -55,34 +88,14 @@ std::unique_ptr<StatsTracker> StallBuyer_Descriptor::make_stats() const{


StallBuyer::StallBuyer()
: ITEM_POSITION(
"<b>Item Position to Purchase:</b>",
{
{ItemPosition::FirstItem, "FirstItem", "First Item" },
{ItemPosition::SecondItem, "SecondItem", "Second Item" },
{ItemPosition::ThirdItem, "ThirdItem", "Third Item" },
{ItemPosition::FourthItem, "FourthItem", "Fourth Item" },
{ItemPosition::FifthItem, "FifthItem", "Fifth Item" },
{ItemPosition::SixthItem, "SixthItem", "Sixth Item" },
{ItemPosition::SeventhItem, "SeventhItem", "Seventh Item" },
},
LockMode::LOCK_WHILE_RUNNING,
ItemPosition::FirstItem
)
, NUM_PURCHASE(
"<b>Number to Purchase:</b><br>The number of items you want to purchase.",
LockMode::LOCK_WHILE_RUNNING,
100, 1, 999
)
, GO_HOME_WHEN_DONE(false)
: GO_HOME_WHEN_DONE(false)
, NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600))
, NOTIFICATIONS({
&NOTIFICATION_STATUS_UPDATE,
&NOTIFICATION_PROGRAM_FINISH,
&NOTIFICATION_ERROR_FATAL,
})
{
PA_ADD_OPTION(ITEM_POSITION);
PA_ADD_OPTION(NUM_PURCHASE);
PA_ADD_OPTION(GO_HOME_WHEN_DONE);
PA_ADD_OPTION(NOTIFICATIONS);
Expand Down Expand Up @@ -146,88 +159,109 @@ void StallBuyer::program(SingleSwitchProgramEnvironment& env, ProControllerConte
StallBuyer_Descriptor::Stats& stats = env.current_stats<StallBuyer_Descriptor::Stats>();
assert_16_9_720p_min(env.logger(), env.console);

while (true) {
context.wait_for_all_requests();
std::optional<int> stall_amount_item;

ButtonWatcher buttonA(
COLOR_RED,
ButtonType::ButtonA,
{0.1, 0.1, 0.8, 0.8},
&env.console.overlay()
);
SelectionArrowWatcher select(
COLOR_YELLOW, &env.console.overlay(),
SelectionArrowType::RIGHT,
{0.715, 0.165, 0.045, 0.440}
);
SelectionArrowWatcher confirm(
COLOR_YELLOW, &env.console.overlay(),
SelectionArrowType::RIGHT,
{0.665, 0.600, 0.145, 0.080}
);
FlatWhiteDialogWatcher dialog(COLOR_RED, &env.console.overlay());
for (StaticTableRow* row : NUM_PURCHASE.table()){
StallBuyerRow& stall_buyer_row = static_cast<StallBuyerRow&>(*row);

int ret = wait_until(
env.console, context,
30000ms,
{
buttonA,
select,
confirm,
dialog,
}
for (int purchases = 0; purchases < stall_buyer_row.quantity; /*Do not increment, it will be done in the loop*/){
context.wait_for_all_requests();

ButtonWatcher buttonA(
COLOR_RED,
ButtonType::ButtonA,
{0.1, 0.1, 0.8, 0.8},
&env.console.overlay()
);
context.wait_for(100ms);

switch (ret){
case 0:
env.log("Detected A button.");
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
continue;

case 1:
{
env.log("Detected item selection screen.");
int stall_amount_item = detect_stall_amount_item(env, stats);
env.log("Detected stall with " + std::to_string(stall_amount_item) + " items to sell.");
auto [direction, presses] = compute_needed_inputs(static_cast<int>(ITEM_POSITION.get()), stall_amount_item);
for (int i = 0; i < presses; i++){
pbf_press_dpad(context, direction, 160ms, 80ms);
}
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
continue;
}
case 2:
env.log("Detected purchase confirm screen.");
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
stats.purchases++;
env.update_stats();

if (stats.purchases == NUM_PURCHASE) {
// pbf_mash_button(context, BUTTON_B, 5000ms);
// intentionally don't leave the purchase menu to not get attacked
GO_HOME_WHEN_DONE.run_end_of_program(context);
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);
return;
SelectionArrowWatcher select(
COLOR_YELLOW, &env.console.overlay(),
SelectionArrowType::RIGHT,
{0.715, 0.165, 0.045, 0.440}
);
SelectionArrowWatcher confirm(
COLOR_YELLOW, &env.console.overlay(),
SelectionArrowType::RIGHT,
{0.665, 0.600, 0.145, 0.080}
);
FlatWhiteDialogWatcher dialog(COLOR_RED, &env.console.overlay());

int ret = wait_until(
env.console, context,
30000ms,
{
buttonA,
select,
confirm,
dialog,
}
);
context.wait_for(100ms);

switch (ret){
case 0:
env.log("Detected A button.");
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
continue;

case 1:
{
env.log("Detected item selection screen.");
if (!stall_amount_item.has_value()){
stall_amount_item = detect_stall_amount_item(env, stats);
env.log("Detected stall with " + std::to_string(stall_amount_item.value()) + " items to sell.");
for (StaticTableRow* item : NUM_PURCHASE.table()){
StallBuyerRow& casted_item = static_cast<StallBuyerRow&>(*item);
if (casted_item.index >= stall_amount_item.value() && casted_item.quantity > 0){
throw UserSetupError(
env.logger(),
"Stall is of size " + std::to_string(stall_amount_item.value()) + " and Number to Purchase for " +
casted_item.ordinal + " item is " + std::to_string(casted_item.quantity) + "."
);
}
}
}
auto [direction, presses] = compute_needed_inputs(stall_buyer_row.index, stall_amount_item.value());
for (int i = 0; i < presses; i++){
pbf_press_dpad(context, direction, 160ms, 80ms);
}
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
continue;
}
case 2:
env.log("Detected purchase confirm screen.");
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
stats.purchases++;
purchases++;
env.update_stats();

continue;
if (purchases == stall_buyer_row.quantity){
std::stringstream ss;
ss << "Purchased " << stall_buyer_row.quantity << " of " << stall_buyer_row.ordinal << " item.";
send_program_status_notification(env, NOTIFICATION_STATUS_UPDATE, ss.str());
break;
}

case 3:
env.log("Detected white dialog.");
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
continue;
continue;

default:
stats.errors++;
env.update_stats();
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"No recognized state after 30 seconds.",
env.console
);
case 3:
env.log("Detected white dialog.");
pbf_press_button(context, BUTTON_A, 160ms, 80ms);
continue;

default:
stats.errors++;
env.update_stats();
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"No recognized state after 30 seconds.",
env.console
);
}
}
}
// intentionally don't leave the purchase menu to not get attacked
GO_HOME_WHEN_DONE.run_end_of_program(context);
send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH);
}


Expand Down
31 changes: 20 additions & 11 deletions SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_StallBuyer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "Common/Cpp/Options/SimpleIntegerOption.h"
#include "CommonFramework/Notifications/EventNotificationsTable.h"
#include "CommonFramework/Options/LabelCellOption.h"
#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h"
#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h"

Expand All @@ -18,6 +19,24 @@ namespace PokemonLZA{



class StallBuyerRow : public StaticTableRow{
public:
StallBuyerRow(int index, std::string&& ordinal);

LabelCellOption item;
SimpleIntegerCell<uint16_t> quantity;
std::string ordinal;
int index;
};

class StallBuyerTable : public StaticTableOption {
public:
StallBuyerTable();
virtual std::vector<std::string> make_header() const;
};



class StallBuyer_Descriptor : public SingleSwitchProgramDescriptor{
public:
StallBuyer_Descriptor();
Expand All @@ -35,17 +54,7 @@ class StallBuyer : public SingleSwitchProgramInstance{
virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override;

private:
enum class ItemPosition{
FirstItem,
SecondItem,
ThirdItem,
FourthItem,
FifthItem,
SixthItem,
SeventhItem
};
EnumDropdownOption<ItemPosition> ITEM_POSITION;
SimpleIntegerOption<uint16_t> NUM_PURCHASE;
StallBuyerTable NUM_PURCHASE;
GoHomeWhenDoneOption GO_HOME_WHEN_DONE;
EventNotificationOption NOTIFICATION_STATUS_UPDATE;
EventNotificationsOption NOTIFICATIONS;
Expand Down