Skip to content

Commit f6c3fc3

Browse files
author
Gin
committed
add missing files
1 parent 17099f9 commit f6c3fc3

File tree

3 files changed

+343
-0
lines changed

3 files changed

+343
-0
lines changed
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
/* Pokemon LA MMO Routines
2+
*
3+
* Functions to run MMO related tasks
4+
*
5+
* From: https://github.com/PokemonAutomation/
6+
*
7+
*/
8+
9+
#include "CommonFramework/Exceptions/OperationFailedException.h"
10+
#include "CommonFramework/ImageTools/ImageBoxes.h"
11+
#include "CommonFramework/VideoPipeline/VideoFeed.h"
12+
#include "CommonTools/Async/InferenceRoutines.h"
13+
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
14+
#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h"
15+
#include "PokemonLA/Inference/Map/PokemonLA_PokemonMapSpriteReader.h"
16+
#include "PokemonLA/Inference/Map/PokemonLA_MapDetector.h"
17+
#include "PokemonLA/Inference/Map/PokemonLA_MapMissionTabReader.h"
18+
#include "PokemonLA/Inference/Map/PokemonLA_MapZoomLevelReader.h"
19+
#include "PokemonLA/Inference/Map/PokemonLA_MMOSpriteStarSymbolDetector.h"
20+
#include "PokemonLA/Inference/Objects/PokemonLA_MMOQuestionMarkDetector.h"
21+
#include "PokemonLA/Inference/PokemonLA_DialogDetector.h"
22+
#include "PokemonLA/PokemonLA_Locations.h"
23+
#include "PokemonLA/PokemonLA_TravelLocations.h"
24+
#include "PokemonLA/Programs/PokemonLA_RegionNavigation.h"
25+
#include <sstream>
26+
27+
namespace PokemonAutomation{
28+
namespace NintendoSwitch{
29+
namespace PokemonLA{
30+
31+
32+
std::vector<std::string> load_mmo_names(){
33+
return {
34+
"fieldlands-mmo",
35+
"mirelands-mmo",
36+
"coastlands-mmo",
37+
"highlands-mmo",
38+
"icelands-mmo"
39+
};
40+
}
41+
42+
const std::vector<std::string>& MMO_NAMES(){
43+
const static std::vector<std::string> mmo_names = load_mmo_names();
44+
return mmo_names;
45+
}
46+
47+
48+
std::set<std::string> enter_region_and_read_MMO(
49+
SingleSwitchProgramEnvironment& env, ProControllerContext& context,
50+
const std::string& mmo_name,
51+
const std::set<std::string>& desired_MMOs,
52+
const std::set<std::string>& desired_star_MMOs,
53+
bool debug_mode,
54+
int& num_mmo_pokemon_found,
55+
int& num_star_mmo_found
56+
){
57+
MapRegion region = MapRegion::NONE;
58+
TravelLocation location = TravelLocations::instance().Fieldlands_Fieldlands;
59+
Camp camp = Camp::FIELDLANDS_FIELDLANDS;
60+
for(size_t i = 0; i < 5; i++){
61+
if (mmo_name == MMO_NAMES()[i]){
62+
switch (i){
63+
case 0:
64+
region = MapRegion::FIELDLANDS;
65+
location = TravelLocations::instance().Fieldlands_Fieldlands;
66+
camp = Camp::FIELDLANDS_FIELDLANDS;
67+
break;
68+
case 1:
69+
region = MapRegion::MIRELANDS;
70+
location = TravelLocations::instance().Mirelands_Mirelands;
71+
camp = Camp::MIRELANDS_MIRELANDS;
72+
break;
73+
case 2:
74+
region = MapRegion::COASTLANDS;
75+
location = TravelLocations::instance().Coastlands_Beachside;
76+
camp = Camp::COASTLANDS_BEACHSIDE;
77+
break;
78+
case 3:
79+
region = MapRegion::HIGHLANDS;
80+
location = TravelLocations::instance().Highlands_Highlands;
81+
camp = Camp::HIGHLANDS_HIGHLANDS;
82+
break;
83+
case 4:
84+
region = MapRegion::ICELANDS;
85+
location = TravelLocations::instance().Icelands_Snowfields;
86+
camp = Camp::ICELANDS_SNOWFIELDS;
87+
break;
88+
}
89+
}
90+
}
91+
if (region == MapRegion::NONE){
92+
throw InternalProgramError(&env.console.logger(), PA_CURRENT_FUNCTION, "No MMO region name found.");
93+
}
94+
95+
env.log("Go to " + std::string(MAP_REGION_NAMES[int(region)]) + " to check MMO.");
96+
goto_camp_from_jubilife(env, env.console, context, location);
97+
98+
// Open map
99+
pbf_press_button(context, BUTTON_MINUS, 50, 100);
100+
context.wait_for_all_requests();
101+
102+
// Take a photo of the map before
103+
VideoSnapshot question_mark_image = env.console.video().snapshot();
104+
105+
// Fix zoom level:
106+
const int zoom_level = read_map_zoom_level(question_mark_image);
107+
if (zoom_level < 0){
108+
OperationFailedException::fire(
109+
ErrorReport::SEND_ERROR_REPORT,
110+
"Canot read map zoom level.",
111+
env.console
112+
);
113+
}
114+
115+
if (zoom_level == 0){
116+
pbf_press_button(context, BUTTON_ZR, 50, 50);
117+
context.wait_for_all_requests();
118+
question_mark_image = env.console.video().snapshot();
119+
}else if (zoom_level == 2){
120+
pbf_press_button(context, BUTTON_ZL, 50, 50);
121+
context.wait_for_all_requests();
122+
question_mark_image = env.console.video().snapshot();
123+
}
124+
125+
// Move cursor away so that it does not show a text box that occludes MMO sprites.
126+
pbf_move_left_joystick(context, 0, 0, 300, 30);
127+
context.wait_for_all_requests();
128+
129+
// Fix Missions & Requests tab:
130+
if (is_map_mission_tab_raised(question_mark_image)){
131+
pbf_press_button(context, BUTTON_R, 50, 100);
132+
context.wait_for_all_requests();
133+
question_mark_image = env.console.video().snapshot();
134+
}
135+
136+
// Now detect question marks:
137+
MMOQuestionMarkDetector question_mark_detector(env.logger());
138+
139+
const auto quest_results = question_mark_detector.detect_MMOs_on_region_map(question_mark_image);
140+
env.log("Detected MMO question marks:");
141+
for(const auto& box : quest_results){
142+
std::ostringstream os;
143+
os << "- " << box.center_x() << ", " << box.center_y() << " " << box.width() << " x " << box.height();
144+
env.log(os.str());
145+
}
146+
147+
// Clean the detected boxes, make them square.
148+
std::vector<ImagePixelBox> new_boxes;
149+
for (size_t i = 0; i < quest_results.size(); i++){
150+
const auto& box = quest_results[i];
151+
152+
pxint_t radius = (pxint_t)((box.width() + box.height()) / 4 + 0.5);
153+
pxint_t center_x = (pxint_t)box.center_x();
154+
pxint_t center_y = (pxint_t)box.center_y();
155+
auto new_box = ImagePixelBox(center_x - radius, center_y - radius, center_x + radius, center_y + radius);
156+
new_boxes.push_back(new_box);
157+
}
158+
159+
// Leave map view, back to overworld
160+
pbf_press_button(context, BUTTON_B, 20, 50);
161+
162+
// Now go to Mai to see the reviewed map
163+
goto_Mai_from_camp(env.logger(), context, camp);
164+
165+
pbf_mash_button(context, BUTTON_A, 350);
166+
context.wait_for_all_requests();
167+
168+
// Wait for the last dialog box before the MMO pokemon sprites are revealed.
169+
{
170+
EventDialogDetector event_dialog_detector(env.logger(), env.console.overlay(), true);
171+
int ret = wait_until(env.console, context, std::chrono::seconds(10), {{event_dialog_detector}});
172+
if (ret < 0){
173+
OperationFailedException::fire(
174+
ErrorReport::SEND_ERROR_REPORT,
175+
"Dialog box not detected when waiting for MMO map.",
176+
env.console
177+
);
178+
}
179+
}
180+
pbf_press_button(context, BUTTON_B, 50, 50);
181+
182+
while (true){
183+
EventDialogDetector event_dialog_detector(env.logger(), env.console.overlay(), true);
184+
MapDetector map_detector;
185+
context.wait_for_all_requests();
186+
int ret = wait_until(
187+
env.console, context, std::chrono::seconds(10),
188+
{event_dialog_detector, map_detector}
189+
);
190+
switch (ret){
191+
case 0:
192+
env.console.log("Detected dialog.");
193+
pbf_press_button(context, BUTTON_B, 20, 105);
194+
continue;
195+
case 1:
196+
env.console.log("Found revealed map thanks to Munchlax!");
197+
break;
198+
default:
199+
OperationFailedException::fire(
200+
ErrorReport::SEND_ERROR_REPORT,
201+
"Map not detected after talking to Mai.",
202+
env.console
203+
);
204+
}
205+
break;
206+
}
207+
208+
#if 0
209+
MapDetector map_detector;
210+
ret = wait_until(env.console, context, std::chrono::seconds(5), {{map_detector}});
211+
if (ret < 0){
212+
OperationFailedException::fire(
213+
env.console, ErrorReport::SEND_ERROR_REPORT,
214+
"Map not detected after talking to Mai.",
215+
true
216+
);
217+
}
218+
env.console.log("Found revealed map thanks to Munchlax!");
219+
#endif
220+
221+
VideoOverlaySet mmo_sprites_overlay(env.console);
222+
for (size_t i = 0; i < new_boxes.size(); i++){
223+
mmo_sprites_overlay.add(COLOR_BLUE, pixelbox_to_floatbox(question_mark_image, new_boxes[i]));
224+
}
225+
226+
// Move cursor away so that it does not show a text box that occludes MMO sprites.
227+
pbf_move_left_joystick(context, 0, 0, 300, 30);
228+
context.wait_for_all_requests();
229+
230+
std::set<std::string> found;
231+
232+
// Check MMO results:
233+
std::vector<std::string> sprites;
234+
VideoSnapshot sprites_screen = env.console.video().snapshot();
235+
for (size_t i = 0; i < new_boxes.size(); i++){
236+
auto result = match_sprite_on_map(env.logger(), sprites_screen, new_boxes[i], region, debug_mode);
237+
env.console.log("Found MMO sprite " + result.slug);
238+
num_mmo_pokemon_found++;
239+
240+
sprites.push_back(result.slug);
241+
if (desired_MMOs.find(result.slug) != desired_MMOs.end()){
242+
found.insert(result.slug);
243+
}
244+
}
245+
246+
// Check star MMO results:
247+
std::vector<ImagePixelBox> star_boxes;
248+
for (size_t i = 0; i < new_boxes.size(); i++){
249+
const auto& sprite_box = new_boxes[i];
250+
pxint_t radius = (pxint_t)sprite_box.width() / 2;
251+
pxint_t center_x = (pxint_t)sprite_box.center_x();
252+
pxint_t center_y = (pxint_t)sprite_box.center_y();
253+
ImagePixelBox star_box(
254+
center_x + radius/10,
255+
center_y - radius*16/10,
256+
center_x + radius * 5/4,
257+
center_y
258+
);
259+
star_boxes.push_back(std::move(star_box));
260+
}
261+
262+
MMOSpriteStarSymbolDetector star_detector(sprites_screen, star_boxes);
263+
264+
env.log("Detect star symbols...");
265+
wait_until(env.console, context, std::chrono::seconds(5), {{star_detector}});
266+
for (size_t i = 0; i < new_boxes.size(); i++){
267+
std::ostringstream os;
268+
os << "- " << sprites[i] << " box [" << star_boxes[i].min_x << ", " << star_boxes[i].min_y
269+
<< star_boxes[i].max_x << ", " << star_boxes[i].max_y << "]"
270+
<< " motion: " << star_detector.animation_value(i)
271+
<< " color: " << star_detector.symbol_color(i);
272+
if (star_detector.is_star(i)){
273+
num_star_mmo_found++;
274+
os << ", has star";
275+
if (desired_star_MMOs.find(sprites[i]) != desired_star_MMOs.end()){
276+
found.insert(sprites[i]);
277+
}
278+
}
279+
env.log(os.str());
280+
}
281+
return found;
282+
}
283+
284+
285+
286+
}
287+
}
288+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* Pokemon LA MMO Routines
2+
*
3+
* Functions to run MMO related tasks
4+
*
5+
* From: https://github.com/PokemonAutomation/
6+
*
7+
*/
8+
9+
#include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h"
10+
#include <set>
11+
#include <string>
12+
13+
namespace PokemonAutomation{
14+
namespace NintendoSwitch{
15+
16+
class SingleSwitchProgramEnvironment;
17+
18+
namespace PokemonLA{
19+
20+
// The name of each MMO event happening at each region. Their slugs are:
21+
// - "fieldlands-mmo"
22+
// - "mirelands-mmo"
23+
// - "coastlands-mmo"
24+
// - "highlands-mmo"
25+
// - "icelands-mmo"
26+
const std::vector<std::string>& MMO_NAMES();
27+
28+
29+
// After we find an MMO on map specified by `mmo_name`,
30+
// start from Jubilife Village gate, with camera facing towards the village, run towards the gate
31+
// and travel to the region with that MMO. Go to Mai to show all MMO pokemon on map and read their
32+
// sprites and star symbols.
33+
// The function returns when the map opened by Mai is shown with all pokemon revealed.
34+
// Return true if an MMO pokemon matches slugs in `desired_MMOs`, or if an MMO pokemon with a star
35+
// matches slugs in `desired_star_MMOs`.
36+
// - mmo_name: MMO event slug, e.g. "fieldlands-mmo"
37+
// - num_mmo_found: update this value by adding how many MMO pokemon found during this function.
38+
// - num_star_mmo_found: update this value by adding how many MMO pokemon with star symbol found.
39+
std::set<std::string> enter_region_and_read_MMO(
40+
SingleSwitchProgramEnvironment& env, ProControllerContext& context,
41+
const std::string& mmo_name,
42+
const std::set<std::string>& desired_MMOs,
43+
const std::set<std::string>& desired_star_MMOs,
44+
bool debug,
45+
int& num_mmo_found,
46+
int& num_star_mmo_found
47+
);
48+
49+
50+
}
51+
}
52+
}

SerialPrograms/Source/PokemonLA/Programs/PokemonLA_RegionNavigation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ void mash_A_to_enter_sub_area(
3333
void mash_A_to_change_region(
3434
ProgramEnvironment& env, VideoStream& stream, ProControllerContext& context
3535
);
36+
37+
// Start from Jubilife Village gate, with camera facing towards the village, run towards the gate
38+
// and travel to a location.
3639
void goto_camp_from_jubilife(
3740
ProgramEnvironment& env, VideoStream& stream, ProControllerContext& context,
3841
const TravelLocation& location

0 commit comments

Comments
 (0)