Skip to content

Commit 6af5f44

Browse files
authored
Merge pull request #572 from fyex/auction-money-fix
Fix SV Auction Farmer reading currencies and not being able to check all offers
2 parents c48cc7e + a4ef715 commit 6af5f44

File tree

1 file changed

+117
-43
lines changed

1 file changed

+117
-43
lines changed

SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_AuctionFarmer.cpp

Lines changed: 117 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "CommonFramework/ProgramStats/StatsTracking.h"
1515
#include "CommonFramework/VideoPipeline/VideoFeed.h"
1616
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
17+
#include "CommonTools/ImageMatch/ImageCropper.h"
1718
#include "CommonTools/Images/BinaryImage_FilterRgb32.h"
1819
#include "CommonTools/OCR/OCR_NumberReader.h"
1920
#include "CommonTools/Async/InferenceRoutines.h"
@@ -208,7 +209,7 @@ std::vector<std::pair<AuctionOffer, ImageFloatBox>> AuctionFarmer::check_offers(
208209
VideoSnapshot screen = env.console.video().snapshot();
209210
std::vector<ImagePixelBox> dialog_boxes = detect_dialog_boxes(screen);
210211
std::deque<OverlayBoxScope> bubbles_boxes;
211-
std::deque<OverlayBoxScope> offer_boxes;
212+
std::deque<OverlayBoxScope> offer_overlay_boxes;
212213
std::vector<std::pair<AuctionOffer, ImageFloatBox>> offers;
213214

214215
if (dialog_boxes.empty()){
@@ -217,57 +218,65 @@ std::vector<std::pair<AuctionOffer, ImageFloatBox>> AuctionFarmer::check_offers(
217218
}
218219

219220
// read dialog bubble
221+
ImageFloatBox top_offer_box(0.05, 0.02, 0.90, 0.49);
222+
ImageFloatBox bottom_offer_box(0.05, 0.49, 0.90, 0.49);
223+
std::vector<ImageFloatBox> offer_boxes = {top_offer_box};
224+
if (LANGUAGE == Language::Spanish || LANGUAGE == Language::ChineseTraditional) {
225+
offer_boxes.emplace_back(bottom_offer_box);
226+
}
227+
220228
for (ImagePixelBox dialog_box : dialog_boxes){
221-
// std::cout << "dialog_box: ["
222-
// << dialog_box.min_x << "," << dialog_box.min_y << "] - ["
223-
// << dialog_box.max_x << "," << dialog_box.max_y << "]" << std::endl;
229+
for (ImageFloatBox offer_box : offer_boxes) {
230+
// std::cout << "dialog_box: ["
231+
// << dialog_box.min_x << "," << dialog_box.min_y << "] - ["
232+
// << dialog_box.max_x << "," << dialog_box.max_y << "]" << std::endl;
224233

225-
ImageFloatBox dialog_float_box = pixelbox_to_floatbox(screen, dialog_box);
226-
bubbles_boxes.emplace_back(env.console, dialog_float_box, COLOR_GREEN);
234+
ImageFloatBox dialog_float_box = pixelbox_to_floatbox(screen, dialog_box);
235+
bubbles_boxes.emplace_back(env.console, dialog_float_box, COLOR_GREEN);
227236

228237

229-
// OverlayBoxScope dialog_overlay(env.console, dialog_box, COLOR_DARK_BLUE);
230-
ImageFloatBox offer_box(0.05, 0.02, 0.90, 0.49);
231-
ImageFloatBox translated_offer_box = translate_to_parent(
232-
screen,
233-
dialog_float_box,
234-
floatbox_to_pixelbox(dialog_box.width(), dialog_box.height(), offer_box)
235-
);
236-
// std::cout << "translated_offer_box: ["
237-
// << translated_offer_box.x << "," << translated_offer_box.y << "] - ["
238-
// << translated_offer_box.width << "," << translated_offer_box.height << "]" << std::endl;
238+
// OverlayBoxScope dialog_overlay(env.console, dialog_box, COLOR_DARK_BLUE);
239+
ImageFloatBox translated_offer_box = translate_to_parent(
240+
screen,
241+
dialog_float_box,
242+
floatbox_to_pixelbox(dialog_box.width(), dialog_box.height(), offer_box)
243+
);
244+
// std::cout << "translated_offer_box: ["
245+
// << translated_offer_box.x << "," << translated_offer_box.y << "] - ["
246+
// << translated_offer_box.width << "," << translated_offer_box.height << "]" << std::endl;
239247

240-
offer_boxes.emplace_back(env.console, translated_offer_box, COLOR_BLUE);
248+
offer_overlay_boxes.emplace_back(env.console, translated_offer_box, COLOR_BLUE);
241249

242-
// OverlayBoxScope offer_overlay(env.console, translated_offer_box, COLOR_BLUE);
243-
244-
ImageViewRGB32 dialog = extract_box_reference(screen, dialog_box);
245-
ImageViewRGB32 offer_image = extract_box_reference(dialog, offer_box);
250+
// OverlayBoxScope offer_overlay(env.console, translated_offer_box, COLOR_BLUE);
246251

247-
// std::cout << offer_image.width() << " x " << offer_image.height() << std::endl;
252+
ImageViewRGB32 dialog = extract_box_reference(screen, dialog_box);
253+
ImageViewRGB32 offer_image = extract_box_reference(dialog, offer_box);
248254

255+
// std::cout << offer_image.width() << " x " << offer_image.height() << std::endl;
249256

250-
const double LOG10P_THRESHOLD = -1.5;
251-
std::string best_item;
252-
OCR::StringMatchResult result = AuctionItemNameReader::instance().read_substring(
253-
env.console, LANGUAGE,
254-
offer_image,
255-
OCR::BLACK_TEXT_FILTERS()
256-
);
257257

258-
result.clear_beyond_log10p(LOG10P_THRESHOLD);
259-
if (best_item.empty() && !result.results.empty()){
260-
auto iter = result.results.begin();
261-
if (iter->first < LOG10P_THRESHOLD){
262-
best_item = iter->second.token;
258+
const double LOG10P_THRESHOLD = -1.5;
259+
std::string best_item;
260+
OCR::StringMatchResult result = AuctionItemNameReader::instance().read_substring(
261+
env.console, LANGUAGE,
262+
offer_image,
263+
OCR::BLACK_TEXT_FILTERS()
264+
);
265+
266+
result.clear_beyond_log10p(LOG10P_THRESHOLD);
267+
if (best_item.empty() && !result.results.empty()) {
268+
auto iter = result.results.begin();
269+
if (iter->first < LOG10P_THRESHOLD) {
270+
best_item = iter->second.token;
263271

264-
AuctionOffer offer{ best_item };
265-
std::pair<AuctionOffer, ImageFloatBox> pair(offer, dialog_float_box);
266-
offers.emplace_back(pair);
272+
AuctionOffer offer{ best_item };
273+
std::pair<AuctionOffer, ImageFloatBox> pair(offer, dialog_float_box);
274+
offers.emplace_back(pair);
275+
}
267276
}
268277
}
269278
}
270-
// context.wait_for(std::chrono::seconds(100));
279+
// context.wait_for(std::chrono::seconds(100));
271280
return offers;
272281
}
273282

@@ -366,17 +375,82 @@ void AuctionFarmer::reset_position(SingleSwitchProgramEnvironment& env, ProContr
366375
}
367376

368377

369-
uint64_t read_next_bid(VideoStream& stream, ProControllerContext& context, bool high){
378+
uint64_t read_next_bid(VideoStream& stream, ProControllerContext& context, Language language, bool high){
379+
// How much to cut off from the bid text in order to not read currencies and exclamation marks as numbers.
380+
// Values are pixels for a 1920x1080 screen, negative values are padding
381+
static const std::map<Language, std::pair<int8_t, int8_t>> cutoffs = {
382+
{ Language::English, {22, 6} },
383+
{ Language::Japanese, {-5, 54} },
384+
{ Language::Spanish, {6, 32} },
385+
{ Language::French, {-5, 45} },
386+
{ Language::German, {-5, 22} },
387+
{ Language::Italian, {-5, 35} },
388+
{ Language::Korean, {-5, 42} },
389+
{ Language::ChineseSimplified, {22, 7} },
390+
{ Language::ChineseTraditional, {22,7} }
391+
};
392+
393+
394+
static const std::map<Language, float> high_x = {
395+
{ Language::English, 0.75f },
396+
{ Language::Japanese, 0.75f },
397+
{ Language::Spanish, 0.73f },
398+
{ Language::French, 0.68f },
399+
{ Language::German, 0.73f },
400+
{ Language::Italian, 0.75f },
401+
{ Language::Korean, 0.75f },
402+
{ Language::ChineseSimplified, 0.75f },
403+
{ Language::ChineseTraditional, 0.75f }
404+
};
405+
406+
static const std::map<Language, float> low_x = {
407+
{ Language::English, 0.75f },
408+
{ Language::Japanese, 0.75f },
409+
{ Language::Spanish, 0.75f },
410+
{ Language::French, 0.75f },
411+
{ Language::German, 0.73f },
412+
{ Language::Italian, 0.75f },
413+
{ Language::Korean, 0.75f },
414+
{ Language::ChineseSimplified, 0.75f },
415+
{ Language::ChineseTraditional, 0.75f }
416+
};
417+
370418
float box_y = high ? 0.42f : 0.493f;
371-
OverlayBoxScope box(stream.overlay(), { 0.73, box_y, 0.17, 0.048 });
419+
float box_x = high ? high_x.at(language) : low_x.at(language);
420+
float width = 0.9f - box_x; // max_x is always the same for all languages
421+
OverlayBoxScope box(stream.overlay(), { box_x, box_y, width, 0.048 });
422+
372423
std::unordered_map<uint64_t, size_t> read_bids;
373424
size_t highest_read = 0;
374425
uint64_t read_value = 0;
375426

376427
// read next bid multiple times since the selection arrow sometimes blocks the first digit
377428
for (size_t i = 0; i < 10; i++){
378429
VideoSnapshot screen = stream.video().snapshot();
379-
uint64_t read_bid = OCR::read_number(stream.logger(), extract_box_reference(screen, box));
430+
double screen_scale = (double)screen->width() / 1920.0;
431+
double vertical_padding = 5.0; // small amount of pixels so numbers do not touch the edge of the view when reading them
432+
433+
ImageViewRGB32 raw_bid_image = extract_box_reference(screen, box);
434+
ImagePixelBox bid_bounding_box = ImageMatch::enclosing_rectangle_with_pixel_filter(
435+
raw_bid_image,
436+
[](Color pixel) {
437+
return (uint32_t)pixel.red() + pixel.green() + pixel.blue() < 250;
438+
});
439+
440+
int32_t max_width = static_cast<int32_t>(raw_bid_image.width() - 1);
441+
int32_t max_height = static_cast<int32_t>(raw_bid_image.height() - 1);
442+
int32_t scaled_vertical_padding = static_cast<int32_t>(vertical_padding * screen_scale);
443+
int32_t left_cutoff = static_cast<int32_t>(cutoffs.at(language).first * screen_scale);
444+
int32_t right_cutoff = static_cast<int32_t>(cutoffs.at(language).second * screen_scale);
445+
446+
ImagePixelBox cut_bid_bounding_box(
447+
std::max(0, std::min(max_width, static_cast<int32_t>(bid_bounding_box.min_x) + left_cutoff)),
448+
std::max(0, std::min(max_height, static_cast<int32_t>(bid_bounding_box.min_y) - scaled_vertical_padding)),
449+
std::max(0, std::min(max_width, static_cast<int32_t>(bid_bounding_box.max_x) - right_cutoff)),
450+
std::max(0, std::min(max_height, static_cast<int32_t>(bid_bounding_box.max_y) + scaled_vertical_padding))
451+
);
452+
453+
uint64_t read_bid = OCR::read_number(stream.logger(), extract_box_reference(raw_bid_image, cut_bid_bounding_box));
380454

381455
if (read_bids.find(read_bid) == read_bids.end()){
382456
read_bids[read_bid] = 0;
@@ -418,11 +492,11 @@ void AuctionFarmer::bid_on_item(SingleSwitchProgramEnvironment& env, ProControll
418492
pbf_press_button(context, BUTTON_A, 20, TICKS_PER_SECOND);
419493
break;
420494
case 1:
421-
current_bid = read_next_bid(env.console, context, true);
495+
current_bid = read_next_bid(env.console, context, LANGUAGE, true);
422496
pbf_press_button(context, BUTTON_A, 20, TICKS_PER_SECOND);
423497
break;
424498
case 2:
425-
current_bid = read_next_bid(env.console, context, false);
499+
current_bid = read_next_bid(env.console, context, LANGUAGE, false);
426500
pbf_press_button(context, BUTTON_A, 20, TICKS_PER_SECOND);
427501
break;
428502
case 3:

0 commit comments

Comments
 (0)