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
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,15 @@ bool NormalDialogDetector::process_frame(const ImageViewRGB32& frame, WallClock
FlatWhiteDialogDetector::FlatWhiteDialogDetector(Color color, VideoOverlay* overlay)
: m_color(color)
, m_overlay(overlay)
, m_top(0.267838, 0.785156, 0.467618, 0.019531)
, m_bottom(0.265, 0.930, 0.465, 0.020)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, if you want to easily get box coordinates, you can use the Box Draw program. So if you're wondering why all the new programs have 6 digits of precision for all box coordinates it's because we're all being lazy and using Box Draw to create them for us.

, m_arrow_box(0.727, 0.868, 0.037, 0.086)
{}
void FlatWhiteDialogDetector::make_overlays(VideoOverlaySet& items) const{
items.add(m_color, m_top);
items.add(m_color, m_bottom);
items.add(m_color, m_arrow_box);
}
bool FlatWhiteDialogDetector::detect(const ImageViewRGB32& screen){
if (!is_white(extract_box_reference(screen, m_top), 500.0, 20.0)){
if (!is_white(extract_box_reference(screen, m_bottom), 500.0, 20.0)){
m_last_detected_box.reset();
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class FlatWhiteDialogDetector : public StaticScreenDetector{

const Color m_color;
VideoOverlay* m_overlay;
const ImageFloatBox m_top;
const ImageFloatBox m_bottom;
const ImageFloatBox m_arrow_box;

ImageFloatBox m_last_detected;
Expand Down
2 changes: 2 additions & 0 deletions SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

// General
#include "Programs/PokemonLZA_ClothingBuyer.h"
#include "Programs/PokemonLZA_BerryBuyer.h"

// Farming
#include "Programs/Farming/PokemonLZA_RestaurantFarmer.h"
Expand Down Expand Up @@ -47,6 +48,7 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{

ret.emplace_back("---- General ----");
ret.emplace_back(make_single_switch_program<ClothingBuyer_Descriptor, ClothingBuyer>());
ret.emplace_back(make_single_switch_program<BerryBuyer_Descriptor, BerryBuyer>());

ret.emplace_back("---- Farming ----");
ret.emplace_back(make_single_switch_program<RestaurantFarmer_Descriptor, RestaurantFarmer>());
Expand Down
188 changes: 188 additions & 0 deletions SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BerryBuyer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/* Berry Buyer
*
* From: https://github.com/PokemonAutomation/
*
*/

#include "CommonFramework/Exceptions/OperationFailedException.h"
#include "CommonFramework/Notifications/ProgramNotifications.h"
#include "CommonFramework/ProgramStats/StatsTracking.h"
#include "CommonTools/Async/InferenceRoutines.h"
#include "CommonTools/StartupChecks/VideoResolutionCheck.h"
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
#include "Pokemon/Pokemon_Strings.h"
#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h"
#include "PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h"
#include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h"
#include "PokemonLZA_BerryBuyer.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonLZA{

using namespace Pokemon;

BerryBuyer_Descriptor::BerryBuyer_Descriptor()
: SingleSwitchProgramDescriptor(
"PokemonLZA:BerryBuyer",
STRING_POKEMON + " LZA", "Berry Buyer",
"Programs/PokemonLZA/BerryBuyer.html",
"Buy EV reducing berries from stall.",
ProgramControllerClass::StandardController_NoRestrictions,
FeedbackType::REQUIRED,
AllowCommandsWhenRunning::DISABLE_COMMANDS
)
{}

class BerryBuyer_Descriptor::Stats : public StatsTracker{
public:
Stats()
: purchases(m_stats["Purchases"])
, errors(m_stats["Errors"])
{
m_display_order.emplace_back("Purchases");
m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO);
}

std::atomic<uint64_t>& purchases;
std::atomic<uint64_t>& errors;
};
std::unique_ptr<StatsTracker> BerryBuyer_Descriptor::make_stats() const{
return std::unique_ptr<StatsTracker>(new Stats());
}


BerryBuyer::BerryBuyer()
: BERRY_TYPE(
"<b>Berry to Purchase:",
{
{BerryType::POMEG, "pomeg", "Pomeg (HP)"},
{BerryType::KELPSY, "kelpsy", "Kelpsy (Attack)"},
{BerryType::QUALOT, "qualot", "Qualot (Defence)"},
{BerryType::HONDEW, "hondew", "Hondew (Special Attack)"},
{BerryType::GREPA, "grepa", "Grepa (Special Defence)"},
{BerryType::TAMATO, "tamato", "Tamato (Speed)"},
},
LockMode::LOCK_WHILE_RUNNING,
BerryType::POMEG
)
, NUM_PURCHASE(
"<b>Number to Purchase:</b><br>The number of berries you want to purchase.",
LockMode::LOCK_WHILE_RUNNING,
100, 1, 999
)
, 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(BERRY_TYPE);
PA_ADD_OPTION(NUM_PURCHASE);
PA_ADD_OPTION(GO_HOME_WHEN_DONE);
PA_ADD_OPTION(NOTIFICATIONS);
}

void BerryBuyer::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){
BerryBuyer_Descriptor::Stats& stats = env.current_stats<BerryBuyer_Descriptor::Stats>();
assert_16_9_720p_min(env.logger(), env.console);
while (true) {
context.wait_for_all_requests();

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.235, 0.045, 0.080}
);
SelectionArrowWatcher confirm(
COLOR_YELLOW, &env.console.overlay(),
SelectionArrowType::RIGHT,
{0.715, 0.600, 0.045, 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 berry selection screen.");
switch(BERRY_TYPE){
case BerryType::HONDEW:
pbf_press_dpad(context, DPAD_DOWN, 160ms, 80ms);
case BerryType::QUALOT:
pbf_press_dpad(context, DPAD_DOWN, 160ms, 80ms);
case BerryType::KELPSY:
pbf_press_dpad(context, DPAD_DOWN, 160ms, 80ms);
case BerryType::POMEG:
break;
case BerryType::GREPA:
pbf_press_dpad(context, DPAD_UP, 160ms, 80ms);
case BerryType::TAMATO:
pbf_press_dpad(context, DPAD_UP, 160ms, 80ms);
pbf_press_dpad(context, DPAD_UP, 160ms, 80ms);
break;
}
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;
}

continue;

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
);
}
}
}


}
}
}

56 changes: 56 additions & 0 deletions SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BerryBuyer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* Berry Buyer
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_PokemonLZA_BerryBuyer_H
#define PokemonAutomation_PokemonLZA_BerryBuyer_H

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

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonLZA{

class BerryBuyer_Descriptor : public SingleSwitchProgramDescriptor{
public:
BerryBuyer_Descriptor();

class Stats;
virtual std::unique_ptr<StatsTracker> make_stats() const override;
};

class BerryBuyer : public SingleSwitchProgramInstance{
public:
BerryBuyer();

virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override;

private:
enum class BerryType{
POMEG,
KELPSY,
QUALOT,
HONDEW,
GREPA,
TAMATO,
};
EnumDropdownOption<BerryType> BERRY_TYPE;
SimpleIntegerOption<uint16_t> NUM_PURCHASE;
GoHomeWhenDoneOption GO_HOME_WHEN_DONE;
EventNotificationOption NOTIFICATION_STATUS_UPDATE;
EventNotificationsOption NOTIFICATIONS;
};





}
}
}
#endif
2 changes: 2 additions & 0 deletions SerialPrograms/SourceFiles.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1567,6 +1567,8 @@ file(GLOB LIBRARY_SOURCES
Source/PokemonLZA/Programs/Farming/PokemonLZA_RestaurantFarmer.h
Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp
Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.h
Source/PokemonLZA/Programs/PokemonLZA_BerryBuyer.cpp
Source/PokemonLZA/Programs/PokemonLZA_BerryBuyer.h
Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.cpp
Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.h
Source/PokemonLZA/Programs/PokemonLZA_GameEntry.cpp
Expand Down