yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld_commands.cc
Go to the documentation of this file.
2
3#include "absl/strings/numbers.h"
4#include "absl/strings/str_format.h"
7
8
9namespace yaze {
10namespace cli {
11namespace handlers {
12
14 Rom* rom, const resources::ArgumentParser& parser,
15 resources::OutputFormatter& formatter) {
16 auto tile_id_str = parser.GetString("tile").value();
17
18 int tile_id;
19 if (!absl::SimpleHexAtoi(tile_id_str, &tile_id)) {
20 return absl::InvalidArgumentError("Invalid tile ID format. Must be hex.");
21 }
22
23 // Load the Overworld from ROM
24 zelda3::Overworld overworld(rom);
25 auto ow_status = overworld.Load(rom);
26 if (!ow_status.ok()) {
27 return ow_status;
28 }
29
30 // Call the helper function to find tile matches
31 auto matches_or = overworld::FindTileMatches(overworld, tile_id);
32 if (!matches_or.ok()) {
33 return matches_or.status();
34 }
35 const auto& matches = matches_or.value();
36
37 // Format the output
38 formatter.BeginObject("Overworld Tile Search");
39 formatter.AddField("tile_id", absl::StrFormat("0x%03X", tile_id));
40 formatter.AddField("matches_found", static_cast<int>(matches.size()));
41
42 formatter.BeginArray("matches");
43 for (const auto& match : matches) {
44 formatter.BeginObject();
45 formatter.AddField("map_id", absl::StrFormat("0x%02X", match.map_id));
46 formatter.AddField("world", overworld::WorldName(match.world));
47 formatter.AddField("local_x", match.local_x);
48 formatter.AddField("local_y", match.local_y);
49 formatter.AddField("global_x", match.global_x);
50 formatter.AddField("global_y", match.global_y);
51 formatter.EndObject();
52 }
53 formatter.EndArray();
54 formatter.EndObject();
55
56 return absl::OkStatus();
57}
58
60 Rom* rom, const resources::ArgumentParser& parser,
61 resources::OutputFormatter& formatter) {
62 auto screen_id_str = parser.GetString("screen").value();
63
64 int screen_id;
65 if (!absl::SimpleHexAtoi(screen_id_str, &screen_id)) {
66 return absl::InvalidArgumentError("Invalid screen ID format. Must be hex.");
67 }
68
69 // Load the Overworld from ROM
70 zelda3::Overworld overworld(rom);
71 auto ow_status = overworld.Load(rom);
72 if (!ow_status.ok()) {
73 return ow_status;
74 }
75
76 // Call the helper function to build the map summary
77 auto summary_or = overworld::BuildMapSummary(overworld, screen_id);
78 if (!summary_or.ok()) {
79 return summary_or.status();
80 }
81 const auto& summary = summary_or.value();
82
83 // Format the output using OutputFormatter
84 formatter.BeginObject("Overworld Map Description");
85 formatter.AddField("screen_id", absl::StrFormat("0x%02X", summary.map_id));
86 formatter.AddField("world", overworld::WorldName(summary.world));
87
88 formatter.BeginObject("grid");
89 formatter.AddField("x", summary.map_x);
90 formatter.AddField("y", summary.map_y);
91 formatter.AddField("local_index", summary.local_index);
92 formatter.EndObject();
93
94 formatter.BeginObject("size");
95 formatter.AddField("label", summary.area_size);
96 formatter.AddField("is_large", summary.is_large_map);
97 formatter.AddField("parent", absl::StrFormat("0x%02X", summary.parent_map));
98 formatter.AddField("quadrant", summary.large_quadrant);
99 formatter.EndObject();
100
101 formatter.AddField("message_id", absl::StrFormat("0x%04X", summary.message_id));
102 formatter.AddField("area_graphics", absl::StrFormat("0x%02X", summary.area_graphics));
103 formatter.AddField("area_palette", absl::StrFormat("0x%02X", summary.area_palette));
104 formatter.AddField("main_palette", absl::StrFormat("0x%02X", summary.main_palette));
105 formatter.AddField("animated_gfx", absl::StrFormat("0x%02X", summary.animated_gfx));
106 formatter.AddField("subscreen_overlay", absl::StrFormat("0x%04X", summary.subscreen_overlay));
107 formatter.AddField("area_specific_bg_color", absl::StrFormat("0x%04X", summary.area_specific_bg_color));
108
109 // Format array fields
110 formatter.BeginArray("sprite_graphics");
111 for (uint8_t gfx : summary.sprite_graphics) {
112 formatter.AddArrayItem(absl::StrFormat("0x%02X", gfx));
113 }
114 formatter.EndArray();
115
116 formatter.BeginArray("sprite_palettes");
117 for (uint8_t pal : summary.sprite_palettes) {
118 formatter.AddArrayItem(absl::StrFormat("0x%02X", pal));
119 }
120 formatter.EndArray();
121
122 formatter.BeginArray("area_music");
123 for (uint8_t music : summary.area_music) {
124 formatter.AddArrayItem(absl::StrFormat("0x%02X", music));
125 }
126 formatter.EndArray();
127
128 formatter.BeginArray("static_graphics");
129 for (uint8_t sgfx : summary.static_graphics) {
130 formatter.AddArrayItem(absl::StrFormat("0x%02X", sgfx));
131 }
132 formatter.EndArray();
133
134 formatter.BeginObject("overlay");
135 formatter.AddField("enabled", summary.has_overlay);
136 formatter.AddField("id", absl::StrFormat("0x%04X", summary.overlay_id));
137 formatter.EndObject();
138
139 formatter.EndObject();
140
141 return absl::OkStatus();
142}
143
145 Rom* rom, const resources::ArgumentParser& parser,
146 resources::OutputFormatter& formatter) {
147 auto screen_id_str = parser.GetString("screen").value_or("all");
148
149 // Load the Overworld from ROM
150 zelda3::Overworld overworld(rom);
151 auto ow_status = overworld.Load(rom);
152 if (!ow_status.ok()) {
153 return ow_status;
154 }
155
156 // Build the query
158 if (screen_id_str != "all") {
159 int map_id;
160 if (!absl::SimpleHexAtoi(screen_id_str, &map_id)) {
161 return absl::InvalidArgumentError("Invalid screen ID format. Must be hex.");
162 }
163 query.map_id = map_id;
164 }
165
166 // Call the helper function to collect warp entries
167 auto warps_or = overworld::CollectWarpEntries(overworld, query);
168 if (!warps_or.ok()) {
169 return warps_or.status();
170 }
171 const auto& warps = warps_or.value();
172
173 // Format the output
174 formatter.BeginObject("Overworld Warps");
175 formatter.AddField("screen_filter", screen_id_str);
176 formatter.AddField("total_warps", static_cast<int>(warps.size()));
177
178 formatter.BeginArray("warps");
179 for (const auto& warp : warps) {
180 formatter.BeginObject();
181 formatter.AddField("type", overworld::WarpTypeName(warp.type));
182 formatter.AddField("map_id", absl::StrFormat("0x%02X", warp.map_id));
183 formatter.AddField("world", overworld::WorldName(warp.world));
184 formatter.AddField("position", absl::StrFormat("(%d,%d)", warp.pixel_x, warp.pixel_y));
185 formatter.AddField("map_pos", absl::StrFormat("0x%04X", warp.map_pos));
186
187 if (warp.entrance_id.has_value()) {
188 formatter.AddField("entrance_id", absl::StrFormat("0x%02X", warp.entrance_id.value()));
189 }
190 if (warp.entrance_name.has_value()) {
191 formatter.AddField("entrance_name", warp.entrance_name.value());
192 }
193 if (warp.room_id.has_value()) {
194 formatter.AddField("room_id", absl::StrFormat("0x%04X", warp.room_id.value()));
195 }
196
197 formatter.AddField("deleted", warp.deleted);
198 formatter.AddField("is_hole", warp.is_hole);
199 formatter.EndObject();
200 }
201 formatter.EndArray();
202 formatter.EndObject();
203
204 return absl::OkStatus();
205}
206
208 Rom* rom, const resources::ArgumentParser& parser,
209 resources::OutputFormatter& formatter) {
210 auto screen_id_str = parser.GetString("screen").value_or("all");
211
212 // Load the Overworld from ROM
213 zelda3::Overworld overworld(rom);
214 auto ow_status = overworld.Load(rom);
215 if (!ow_status.ok()) {
216 return ow_status;
217 }
218
219 // Build the query
221 if (screen_id_str != "all") {
222 int map_id;
223 if (!absl::SimpleHexAtoi(screen_id_str, &map_id)) {
224 return absl::InvalidArgumentError("Invalid screen ID format. Must be hex.");
225 }
226 query.map_id = map_id;
227 }
228
229 // Call the helper function to collect sprites
230 auto sprites_or = overworld::CollectOverworldSprites(overworld, query);
231 if (!sprites_or.ok()) {
232 return sprites_or.status();
233 }
234 const auto& sprites = sprites_or.value();
235
236 // Format the output
237 formatter.BeginObject("Overworld Sprites");
238 formatter.AddField("screen_filter", screen_id_str);
239 formatter.AddField("total_sprites", static_cast<int>(sprites.size()));
240
241 formatter.BeginArray("sprites");
242 for (const auto& sprite : sprites) {
243 formatter.BeginObject();
244 formatter.AddField("sprite_id", absl::StrFormat("0x%02X", sprite.sprite_id));
245 formatter.AddField("map_id", absl::StrFormat("0x%02X", sprite.map_id));
246 formatter.AddField("world", overworld::WorldName(sprite.world));
247 formatter.AddField("position", absl::StrFormat("(%d,%d)", sprite.x, sprite.y));
248
249 if (sprite.sprite_name.has_value()) {
250 formatter.AddField("name", sprite.sprite_name.value());
251 }
252
253 formatter.EndObject();
254 }
255 formatter.EndArray();
256 formatter.EndObject();
257
258 return absl::OkStatus();
259}
260
262 Rom* rom, const resources::ArgumentParser& parser,
263 resources::OutputFormatter& formatter) {
264 auto entrance_id_str = parser.GetString("entrance").value();
265
266 int entrance_id;
267 if (!absl::SimpleHexAtoi(entrance_id_str, &entrance_id)) {
268 return absl::InvalidArgumentError(
269 "Invalid entrance ID format. Must be hex.");
270 }
271
272 // Load the Overworld from ROM
273 zelda3::Overworld overworld(rom);
274 auto ow_status = overworld.Load(rom);
275 if (!ow_status.ok()) {
276 return ow_status;
277 }
278
279 // Call the helper function to get entrance details
280 auto details_or = overworld::GetEntranceDetails(overworld, entrance_id);
281 if (!details_or.ok()) {
282 return details_or.status();
283 }
284 const auto& details = details_or.value();
285
286 // Format the output
287 formatter.BeginObject("Overworld Entrance");
288 formatter.AddField("entrance_id", absl::StrFormat("0x%02X", details.entrance_id));
289 formatter.AddField("map_id", absl::StrFormat("0x%02X", details.map_id));
290 formatter.AddField("world", overworld::WorldName(details.world));
291 formatter.AddField("position", absl::StrFormat("(%d,%d)", details.x, details.y));
292 formatter.AddField("area_position", absl::StrFormat("(%d,%d)", details.area_x, details.area_y));
293 formatter.AddField("map_pos", absl::StrFormat("0x%04X", details.map_pos));
294 formatter.AddField("is_hole", details.is_hole);
295
296 if (details.entrance_name.has_value()) {
297 formatter.AddField("name", details.entrance_name.value());
298 }
299
300 formatter.EndObject();
301
302 return absl::OkStatus();
303}
304
306 Rom* rom, const resources::ArgumentParser& parser,
307 resources::OutputFormatter& formatter) {
308 auto screen_id_str = parser.GetString("screen").value_or("all");
309
310 // Load the Overworld from ROM
311 zelda3::Overworld overworld(rom);
312 auto ow_status = overworld.Load(rom);
313 if (!ow_status.ok()) {
314 return ow_status;
315 }
316
317 // TODO: Implement comprehensive tile statistics
318 // The AnalyzeTileUsage helper requires a specific tile_id,
319 // so we need a different approach to gather overall tile statistics.
320 // This could involve:
321 // 1. Iterating through all tiles in the overworld maps
322 // 2. Building a frequency map of tile usage
323 // 3. Computing statistics like unique tiles, most common tiles, etc.
324
325 formatter.BeginObject("Overworld Tile Statistics");
326 formatter.AddField("screen_filter", screen_id_str);
327 formatter.AddField("status", "partial_implementation");
328 formatter.AddField("message",
329 "Comprehensive tile statistics not yet implemented. "
330 "Use overworld-find-tile for specific tile analysis.");
331 formatter.AddField("total_tiles", 0);
332 formatter.AddField("unique_tiles", 0);
333
334 formatter.BeginArray("tile_counts");
335 formatter.EndArray();
336 formatter.EndObject();
337
338 return absl::OkStatus();
339}
340
341} // namespace handlers
342} // namespace cli
343} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
Utility for parsing common CLI argument patterns.
std::optional< std::string > GetString(const std::string &name) const
Parse a named argument (e.g., –format=json or –format json)
Utility for consistent output formatting across commands.
void BeginArray(const std::string &key)
Begin an array.
void AddArrayItem(const std::string &item)
Add an item to current array.
void BeginObject(const std::string &title="")
Start a JSON object or text section.
void EndObject()
End a JSON object or text section.
void AddField(const std::string &key, const std::string &value)
Add a key-value pair.
Represents the full Overworld data, light and dark world.
Definition overworld.h:217
absl::Status Load(Rom *rom)
Load all overworld data from ROM.
Definition overworld.cc:36
absl::StatusOr< MapSummary > BuildMapSummary(zelda3::Overworld &overworld, int map_id)
absl::StatusOr< std::vector< WarpEntry > > CollectWarpEntries(const zelda3::Overworld &overworld, const WarpQuery &query)
absl::StatusOr< EntranceDetails > GetEntranceDetails(const zelda3::Overworld &overworld, uint8_t entrance_id)
absl::StatusOr< std::vector< OverworldSprite > > CollectOverworldSprites(const zelda3::Overworld &overworld, const SpriteQuery &query)
absl::StatusOr< std::vector< TileMatch > > FindTileMatches(zelda3::Overworld &overworld, uint16_t tile_id, const TileSearchOptions &options)
std::string WarpTypeName(WarpType type)
std::string WorldName(int world)