9#include "absl/strings/numbers.h"
10#include "absl/strings/str_format.h"
33 return absl::InvalidArgumentError(
34 absl::StrFormat(
"Map ID out of range: 0x%02X", map_id));
36 return absl::OkStatus();
43 const std::string&
name) {
46 if (!value.has_value() || !ParseHexString(*value, &map_id)) {
47 return absl::InvalidArgumentError(
48 absl::StrFormat(
"--%s must be a hex map id (e.g. 0x40 or 40)",
name));
55 const auto value = parser.
GetString(
"tile");
57 if (!value.has_value() || !ParseHexString(*value, &tile_id)) {
58 return absl::InvalidArgumentError(
59 "--tile must be a hex tile16 id (e.g. 0x0255)");
61 if (tile_id < 0 || tile_id > 0xFFFF) {
62 return absl::InvalidArgumentError(
63 absl::StrFormat(
"Tile ID out of range: 0x%X", tile_id));
69 const std::string&
name) {
72 return absl::InvalidArgumentError(absl::StrFormat(
73 "--%s must be a decimal tile coordinate (or 0x-prefixed hex): %s",
name,
74 value.status().message()));
101 if (profile.has_expanded_tile32) {
122 &want.light_world, &want.dark_world, &want.special_world};
124 &got.light_world, &got.dark_world, &got.special_world};
125 for (
int world = 0; world < 3; ++world) {
126 const auto& w = *want_worlds[world];
127 const auto& g = *got_worlds[world];
128 if (w.size() != g.size()) {
129 return absl::DataLossError(
"Reloaded tile grid has a different size");
131 for (
size_t x = 0; x < w.size(); ++x) {
135 for (
size_t y = 0; y < w[x].size() && y < g[x].size(); ++y) {
136 if (w[x][y] != g[x][y]) {
137 return absl::DataLossError(absl::StrFormat(
138 "Saved overworld does not read back: %s World tile (%d,%d) is "
139 "0x%04X, expected 0x%04X",
141 static_cast<int>(y), g[x][y], w[x][y]));
144 return absl::DataLossError(
"Reloaded tile grid column size differs");
147 return absl::OkStatus();
154 uint16_t tile_id,
bool do_write,
bool mock_rom,
158 if (before == tile_id) {
159 formatter.
AddField(
"write_status",
"not-needed");
160 return absl::OkStatus();
163 const std::vector<uint8_t> before_rom = rom.
vector();
173 const auto& after_rom = rom.
vector();
174 int changed_bytes = 0;
175 int changed_ranges = 0;
176 int outside_bytes = 0;
177 size_t first_outside = 0;
178 bool in_range =
false;
179 for (
size_t i = 0; i < after_rom.size(); ++i) {
181 i >= before_rom.size() || after_rom[i] != before_rom[i];
182 changed_bytes += differs ? 1 : 0;
183 changed_ranges += (differs && !in_range) ? 1 : 0;
189 for (
const auto& [start, end] : save_ranges) {
190 owned |= i >= start && i < end;
192 if (!owned && outside_bytes++ == 0) {
196 formatter.
AddField(
"changed_bytes", changed_bytes);
197 formatter.
AddField(
"changed_ranges", changed_ranges);
198 formatter.
AddField(
"bytes_outside_save_ranges", outside_bytes);
199 if (outside_bytes > 0) {
200 return absl::FailedPreconditionError(absl::StrFormat(
201 "Overworld save changed %d byte(s) outside its documented ranges, "
202 "first at PC $%06X; nothing was written",
203 outside_bytes, first_outside));
205 formatter.
AddField(
"verified_grid",
true);
208 formatter.
AddField(
"write_status",
"dry-run");
209 return absl::OkStatus();
212 formatter.
AddField(
"save_status",
"mock-rom-skipped");
213 return absl::OkStatus();
220 formatter.
AddField(
"save_status",
"saved");
226 return absl::DataLossError(
227 "Saved ROM file differs from the verified image");
229 formatter.
AddField(
"verified_reload",
true);
230 return absl::OkStatus();
241 const auto inspection =
244 formatter.
AddField(
"available", inspection.available);
245 formatter.
AddField(
"provenance", inspection.provenance);
246 formatter.
AddField(
"limitation", inspection.limitation);
247 formatter.
AddField(
"overlay_may_replace_tiles",
248 inspection.overlay_may_replace_tiles);
250 formatter.
AddHexField(
"parent_area", inspection.parent_area, 2);
252 static_cast<int>(inspection.matches.size()));
254 for (
const auto& match : inspection.matches) {
255 const auto& row = inspection.rows[match.row_index];
257 formatter.
AddHexField(
"screen_id", match.screen_id, 2);
258 formatter.
AddHexField(
"source_area", match.parent_area, 2);
259 formatter.
AddField(
"tile_x", match.tile_x);
260 formatter.
AddField(
"tile_y", match.tile_y);
261 formatter.
AddField(
"world_x", match.world_x);
262 formatter.
AddField(
"world_y", match.world_y);
263 formatter.
AddHexField(
"map16_id", match.tile16_id, 3);
264 formatter.
AddHexField(
"first_word", match.first_word, 4);
265 formatter.
AddHexField(
"masked_trigger", match.masked_trigger, 3);
266 formatter.
AddHexField(
"destination_marker", row.destination_marker, 4);
267 formatter.
AddHexField(
"arrival_direction", row.direction, 4);
268 if (row.destination_area >= 0) {
269 formatter.
AddHexField(
"destination_area", row.destination_area, 2);
271 formatter.
AddField(
"destination_area",
"unresolved");
277 return absl::OkStatus();
295 AddTileLocationFields(formatter, location);
298 return absl::OkStatus();
305 if (rom !=
nullptr && !rom->
filename().empty()) {
320 const bool do_write = parser.
HasFlag(
"write");
321 const bool mock_rom = parser.
HasFlag(
"mock-rom");
322 if (rom ==
nullptr || !rom->
is_loaded()) {
323 return absl::FailedPreconditionError(
"ROM not loaded");
326 if (
auto path = parser.
GetString(
"manifest"); path.has_value()) {
335 std::filesystem::path(rom->
filename()));
336 if (do_write && !mock_rom && !parser.
HasFlag(
"allow-project-rom") &&
338 return absl::PermissionDeniedError(absl::StrFormat(
339 "Refusing --write to %s: it is inside an Oracle of Secrets checkout "
340 "(Oracle_main.asm next to its Roms/ folder). Copy the ROM (with "
341 "Data/dungeons/custom_collision.json) and write the copy, or pass "
342 "--allow-project-rom deliberately.",
343 active_path.string()));
348 std::optional<Rom> preview_rom;
350 preview_rom.emplace(*rom);
357 const int tile16_count =
static_cast<int>(overworld.
tiles16().size());
358 if (tile_value >= tile16_count) {
359 return absl::OutOfRangeError(absl::StrFormat(
360 "Tile ID 0x%04X is past the last tile16 definition (0x%04X)",
361 tile_value, tile16_count - 1));
367 formatter.
AddField(
"mode", do_write ?
"write" :
"dry-run");
368 AddTileLocationFields(formatter, location);
370 formatter.
AddHexField(
"tile_after", tile_value, 4);
371 const absl::Status status = ApplyTileEdit(*rom, overworld, location,
372 static_cast<uint16_t
>(tile_value),
373 do_write, mock_rom, formatter);
375 formatter.
AddField(
"error", std::string(status.message()));
387 if (parser.
GetString(
"map").has_value()) {
391 if (
auto world = parser.
GetString(
"world"); world.has_value()) {
394 options.
world = world_id;
399 auto ow_status = overworld.
Load(rom);
400 if (!ow_status.ok()) {
406 overworld,
static_cast<uint16_t
>(tile_id), options);
407 if (!matches_or.ok()) {
408 return matches_or.status();
410 const auto& matches = matches_or.value();
414 formatter.
AddField(
"tile_id", absl::StrFormat(
"0x%04X", tile_id));
415 formatter.
AddField(
"matches_found",
static_cast<int>(matches.size()));
417 "x/y are area-relative (overworld-get-tile/set-tile "
418 "input); local_x/local_y are within map_id; "
419 "global_x/global_y index the world grid");
422 for (
const auto& match : matches) {
424 formatter.
AddField(
"map_id", absl::StrFormat(
"0x%02X", match.map_id));
427 match.local_x, match.local_y);
430 absl::StrFormat(
"0x%02X", area->parent_map));
431 formatter.
AddField(
"x", area->area_x);
432 formatter.
AddField(
"y", area->area_y);
434 formatter.
AddField(
"local_x", match.local_x);
435 formatter.
AddField(
"local_y", match.local_y);
436 formatter.
AddField(
"global_x", match.global_x);
437 formatter.
AddField(
"global_y", match.global_y);
443 return absl::OkStatus();
453 auto ow_status = overworld.
Load(rom);
454 if (!ow_status.ok()) {
460 if (!summary_or.ok()) {
461 return summary_or.status();
463 const auto& summary = summary_or.value();
466 formatter.
AddField(
"screen_id", absl::StrFormat(
"0x%02X", summary.map_id));
470 formatter.
AddField(
"x", summary.map_x);
471 formatter.
AddField(
"y", summary.map_y);
472 formatter.
AddField(
"local_index", summary.local_index);
476 formatter.
AddField(
"label", summary.area_size);
477 formatter.
AddField(
"is_large", summary.is_large_map);
478 formatter.
AddField(
"parent", absl::StrFormat(
"0x%02X", summary.parent_map));
479 formatter.
AddField(
"quadrant", summary.large_quadrant);
481 if (
const auto* parent = overworld.
overworld_map(summary.parent_map);
485 absl::StrFormat(
"%dx%d", columns * 32, rows * 32));
490 absl::StrFormat(
"0x%04X", summary.message_id));
492 absl::StrFormat(
"0x%02X", summary.area_graphics));
494 absl::StrFormat(
"0x%02X", summary.area_palette));
496 absl::StrFormat(
"0x%02X", summary.main_palette));
498 absl::StrFormat(
"0x%02X", summary.animated_gfx));
499 formatter.
AddField(
"subscreen_overlay",
500 absl::StrFormat(
"0x%04X", summary.subscreen_overlay));
501 formatter.
AddField(
"area_specific_bg_color",
502 absl::StrFormat(
"0x%04X", summary.area_specific_bg_color));
507 if (entrances_or.ok()) {
508 for (
const auto& entrance : entrances_or.value()) {
509 if (entrance.map_id_ == screen_id) {
511 formatter.
AddField(
"entrance_id", entrance.entrance_id_);
512 formatter.
AddField(
"x", entrance.x_);
513 formatter.
AddField(
"y", entrance.y_);
514 formatter.
AddField(
"is_hole",
false);
522 for (
const auto& hole : holes_or.value()) {
523 if (hole.map_id_ == screen_id) {
525 formatter.
AddField(
"entrance_id", hole.entrance_id_);
528 formatter.
AddField(
"is_hole",
true);
539 for (
const auto& exit : exits_or.value()) {
540 if (exit.map_id_ == screen_id) {
542 formatter.
AddField(
"room_id", exit.room_id_);
552 for (uint8_t gfx : summary.sprite_graphics) {
558 for (uint8_t pal : summary.sprite_palettes) {
564 for (uint8_t music : summary.area_music) {
565 formatter.
AddArrayItem(absl::StrFormat(
"0x%02X", music));
570 for (uint8_t sgfx : summary.static_graphics) {
571 formatter.
AddArrayItem(absl::StrFormat(
"0x%02X", sgfx));
576 formatter.
AddField(
"enabled", summary.has_overlay);
577 formatter.
AddField(
"id", absl::StrFormat(
"0x%04X", summary.overlay_id));
582 return absl::OkStatus();
588 auto screen_id_str = parser.
GetString(
"screen").value_or(
"all");
592 auto ow_status = overworld.
Load(rom);
593 if (!ow_status.ok()) {
599 if (screen_id_str !=
"all") {
601 if (!ParseHexString(screen_id_str, &map_id)) {
602 return absl::InvalidArgumentError(
603 "Invalid screen ID format. Must be hex.");
610 if (!warps_or.ok()) {
611 return warps_or.status();
613 const auto& warps = warps_or.value();
617 formatter.
AddField(
"screen_filter", screen_id_str);
618 formatter.
AddField(
"total_warps",
static_cast<int>(warps.size()));
621 for (
const auto& warp : warps) {
624 formatter.
AddField(
"map_id", absl::StrFormat(
"0x%02X", warp.map_id));
627 absl::StrFormat(
"(%d,%d)", warp.pixel_x, warp.pixel_y));
628 formatter.
AddField(
"map_pos", absl::StrFormat(
"0x%04X", warp.map_pos));
630 if (warp.entrance_id.has_value()) {
632 absl::StrFormat(
"0x%02X", warp.entrance_id.value()));
634 if (warp.entrance_name.has_value()) {
635 formatter.
AddField(
"entrance_name", warp.entrance_name.value());
637 if (warp.room_id.has_value()) {
639 absl::StrFormat(
"0x%04X", warp.room_id.value()));
642 formatter.
AddField(
"deleted", warp.deleted);
643 formatter.
AddField(
"is_hole", warp.is_hole);
649 return absl::OkStatus();
655 auto screen_id_str = parser.
GetString(
"screen").value_or(
"all");
658 std::string phase_filter =
"all";
659 if (
auto phase_str = parser.
GetString(
"phase"); phase_str.has_value()) {
661 if (!absl::SimpleAtoi(*phase_str, &phase) || phase < 0 || phase > 2) {
662 return absl::InvalidArgumentError(
"--phase must be 0, 1, or 2");
665 phase_filter = *phase_str;
670 auto ow_status = overworld.
Load(rom);
671 if (!ow_status.ok()) {
676 std::optional<int> requested_screen;
677 if (screen_id_str !=
"all") {
679 if (!ParseHexString(screen_id_str, &map_id)) {
680 return absl::InvalidArgumentError(
681 "Invalid screen ID format. Must be hex.");
684 if (map ==
nullptr) {
685 return absl::InvalidArgumentError(
686 absl::StrFormat(
"Screen 0x%02X is out of range", map_id));
688 requested_screen = map_id;
689 query.
map_id = map->parent();
693 if (!sprites_or.ok()) {
694 return sprites_or.status();
696 const auto& sprites = sprites_or.value();
699 formatter.
AddField(
"screen_filter", screen_id_str);
700 if (requested_screen.has_value()) {
701 formatter.
AddField(
"parent_area", absl::StrFormat(
"0x%02X", *query.
map_id));
703 formatter.
AddField(
"phase_filter", phase_filter);
706 "0=beginning, 1=first_part, 2=second_part (vanilla: game state "
707 "<2 / 2 / >=3; Oracle ZSOW: GameState 0-1 / GameState 2 day / night or "
709 formatter.
AddField(
"total_sprites",
static_cast<int>(sprites.size()));
712 for (
const auto& sprite : sprites) {
714 formatter.
AddField(
"phase", sprite.phase);
716 formatter.
AddField(
"list_index", sprite.list_index);
718 absl::StrFormat(
"0x%02X", sprite.sprite_id));
719 formatter.
AddField(
"map_id", absl::StrFormat(
"0x%02X", sprite.map_id));
722 absl::StrFormat(
"(%d,%d)", sprite.x, sprite.y));
724 "tile", absl::StrFormat(
"(%d,%d)", sprite.local_x, sprite.local_y));
733 return absl::OkStatus();
739 auto screen_id_str = parser.
GetString(
"screen").value_or(
"all");
743 auto ow_status = overworld.
Load(rom);
744 if (!ow_status.ok()) {
749 std::optional<int> map_filter;
750 if (screen_id_str !=
"all") {
752 if (!ParseHexString(screen_id_str, &map_id)) {
753 return absl::InvalidArgumentError(
754 "Invalid screen ID format. Must be hex.");
765 formatter.
AddField(
"screen_filter", screen_id_str);
769 for (
const auto& item : items) {
770 if (map_filter.has_value() &&
771 static_cast<int>(item.room_map_id_) != map_filter.value()) {
775 std::string world_name =
"Unknown";
782 formatter.
AddField(
"item_id", absl::StrFormat(
"0x%02X", item.id_));
784 if (item.id_ < item_names.size()) {
785 formatter.
AddField(
"item_name", item_names[item.id_]);
788 formatter.
AddField(
"map_id", absl::StrFormat(
"0x%02X", item.room_map_id_));
789 formatter.
AddField(
"world", world_name);
791 absl::StrFormat(
"(%d,%d)", item.game_x_, item.game_y_));
793 absl::StrFormat(
"(%d,%d)", item.x_, item.y_));
799 formatter.
AddField(
"total_items", total_items);
802 return absl::OkStatus();
808 auto entrance_id_str = parser.
GetString(
"entrance").value();
811 if (!ParseHexString(entrance_id_str, &entrance_id)) {
812 return absl::InvalidArgumentError(
813 "Invalid entrance ID format. Must be hex.");
818 auto ow_status = overworld.
Load(rom);
819 if (!ow_status.ok()) {
825 if (!details_or.ok()) {
826 return details_or.status();
828 const auto& details = details_or.value();
833 absl::StrFormat(
"0x%02X", details.entrance_id));
834 formatter.
AddField(
"map_id", absl::StrFormat(
"0x%02X", details.map_id));
837 absl::StrFormat(
"(%d,%d)", details.x, details.y));
838 formatter.
AddField(
"area_position", absl::StrFormat(
"(%d,%d)", details.area_x,
840 formatter.
AddField(
"map_pos", absl::StrFormat(
"0x%04X", details.map_pos));
841 formatter.
AddField(
"is_hole", details.is_hole);
843 if (details.entrance_name.has_value()) {
844 formatter.
AddField(
"name", details.entrance_name.value());
849 return absl::OkStatus();
856 const bool has_screen = parser.
GetString(
"screen").has_value();
857 const bool has_map = parser.
GetString(
"map").has_value();
858 if (has_screen || has_map) {
860 ParseMapIdArg(parser, has_screen ?
"screen" :
"map"));
861 if (has_screen && has_map) {
863 if (other != map_id) {
864 return absl::InvalidArgumentError(
865 "--screen and --map name different screens; pass one");
870 if (
auto world = parser.
GetString(
"world"); world.has_value()) {
873 query.
world = world_id;
875 if (parser.
GetString(
"tile").has_value()) {
877 query.
tile_id =
static_cast<uint16_t
>(tile_id);
880 if (parser.
GetString(
"top").has_value()) {
881 auto top_or = parser.
GetInt(
"top");
882 if (!top_or.ok() || *top_or < 0) {
883 return absl::InvalidArgumentError(
884 "--top must be a non-negative count (0 lists every tile)");
894 formatter.
BeginObject(
"Overworld Tile Statistics");
897 ? absl::StrFormat(
"0x%02X", *query.
map_id)
898 : std::string(
"all"));
901 : std::string(
"all"));
902 formatter.
AddField(
"screens_scanned", summary.screens_scanned);
903 formatter.
AddField(
"total_tiles", summary.total_tiles);
904 formatter.
AddField(
"unique_tiles",
static_cast<int>(summary.tiles.size()));
906 if (query.
tile_id.has_value()) {
909 for (
const auto& usage : summary.tiles) {
910 if (usage.tile_id == *query.
tile_id) {
912 screens = usage.screens;
917 formatter.
AddField(
"tile_id", absl::StrFormat(
"0x%04X", *query.
tile_id));
919 formatter.
AddField(
"screens", screens);
924 for (
const auto& world : summary.worlds) {
927 formatter.
AddField(
"screens", world.screens);
928 formatter.
AddField(
"total_tiles", world.total_tiles);
929 formatter.
AddField(
"unique_tiles", world.unique_tiles);
937 for (
const auto& screen : summary.screens) {
939 formatter.
AddField(
"map_id", absl::StrFormat(
"0x%02X", screen.map_id));
942 absl::StrFormat(
"0x%02X", screen.parent_map));
943 formatter.
AddField(
"total_tiles", screen.total_tiles);
944 formatter.
AddField(
"unique_tiles", screen.unique_tiles);
945 formatter.
AddField(
"top_tile", absl::StrFormat(
"0x%04X", screen.top_tile));
946 formatter.
AddField(
"top_tile_count", screen.top_tile_count);
947 if (query.
tile_id.has_value()) {
948 formatter.
AddField(
"tile_count", screen.tile_count);
954 const size_t shown = top == 0 ? summary.tiles.size()
955 : std::min<size_t>(summary.tiles.size(), top);
956 formatter.
AddField(
"tile_counts_shown",
static_cast<int>(shown));
958 for (
size_t i = 0; i < shown; ++i) {
959 const auto& usage = summary.tiles[i];
961 formatter.
AddField(
"tile_id", absl::StrFormat(
"0x%04X", usage.tile_id));
962 formatter.
AddField(
"count", usage.count);
963 formatter.
AddField(
"screens", usage.screens);
969 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
absl::Status AttachLyraPrivateReservation(const core::HackManifest &manifest)
const auto & vector() const
absl::Status SaveToFile(const SaveSettings &settings)
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
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.
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 ExecuteWithContext(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter, const resources::CommandInvocationContext &invocation_context) override
Execute with immutable, invocation-scoped ROM path identity.
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)
bool HasFlag(const std::string &name) const
Check if a flag is present.
absl::StatusOr< int > GetInt(const std::string &name) const
Parse an integer argument (supports hex with 0x prefix)
Loads and queries the hack manifest JSON for yaze-ASM integration.
absl::Status LoadFromFile(const std::string &filepath)
Load manifest from a JSON file path.
absl::Status SaveMap32Expanded()
Save expanded tile32 definitions (v1+ ROMs)
absl::Status Load(Rom *rom)
Load all overworld data from ROM.
std::vector< std::pair< uint32_t, uint32_t > > GetProjectedWriteRanges() const
Get the projected write ranges (PC offsets) for overworld map saves.
absl::Status SaveMap32Tiles()
Save tile32 definitions to ROM.
const std::vector< gfx::Tile16 > & tiles16() const
absl::Status CreateTile32Tilemap()
Build tile32 tilemap from current tile16 data.
const std::vector< OverworldMap > & overworld_maps() const
auto overworld_map(int i) const
absl::Status SaveOverworldMaps()
Save compressed map tile data to ROM.
#define ASSIGN_OR_RETURN(type_variable_name, expression)
absl::Status VerifyTileGridRoundTrip(const Rom &rom, const zelda3::Overworld &expected)
void AddTileLocationFields(resources::OutputFormatter &formatter, const overworld::AreaTileLocation &location)
absl::Status ApplyTileEdit(Rom &rom, zelda3::Overworld &overworld, const overworld::AreaTileLocation &location, uint16_t tile_id, bool do_write, bool mock_rom, resources::OutputFormatter &formatter)
absl::StatusOr< int > ParseCoordinateArg(const resources::ArgumentParser &parser, const std::string &name)
absl::StatusOr< int > ParseMapIdArg(const resources::ArgumentParser &parser, const std::string &name)
absl::Status SaveOverworldTileGrid(Rom &rom, zelda3::Overworld &overworld)
absl::StatusOr< int > ParseTileIdArg(const resources::ArgumentParser &parser)
absl::Status ValidateMapId(int map_id)
bool IsOracleProjectRomPath(const std::filesystem::path &rom_path)
absl::StatusOr< TileUsageSummary > CollectTileUsage(zelda3::Overworld &overworld, const TileUsageQuery &query)
absl::StatusOr< int > InferWorldFromMapId(int map_id)
absl::StatusOr< MapSummary > BuildMapSummary(zelda3::Overworld &overworld, int map_id)
absl::Status WriteAreaTile(zelda3::Overworld &overworld, const AreaTileLocation &location, uint16_t tile_id)
absl::StatusOr< std::vector< WarpEntry > > CollectWarpEntries(const zelda3::Overworld &overworld, const WarpQuery &query)
absl::StatusOr< int > ParseWorldSpecifier(std::string_view value)
absl::StatusOr< AreaTileLocation > ResolveAreaTileForMap(const zelda3::Overworld &overworld, int map_id, int x, int y)
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< uint16_t > ReadAreaTile(zelda3::Overworld &overworld, const AreaTileLocation &location)
absl::StatusOr< AreaTileLocation > LocateScreenTile(const zelda3::Overworld &overworld, int screen_id, int screen_x, int screen_y)
absl::StatusOr< std::vector< TileMatch > > FindTileMatches(zelda3::Overworld &overworld, uint16_t tile_id, const TileSearchOptions &options)
std::string WarpTypeName(WarpType type)
const char * SpritePhaseName(int phase)
std::string WorldName(int world)
std::pair< int, int > AreaScreenSpan(const zelda3::OverworldMap &parent_map)
void AddSpriteNameFields(resources::OutputFormatter &formatter, int sprite_id)
bool ParseHexString(absl::string_view str, uint64_t *out)
absl::StatusOr< std::vector< OverworldEntrance > > LoadEntrances(Rom *rom)
absl::StatusOr< std::vector< OverworldItem > > LoadItems(Rom *rom, std::vector< OverworldMap > &overworld_maps)
constexpr int kNumOverworldMaps
std::vector< std::vector< uint16_t > > OverworldBlockset
Represents tile32 data for the overworld.
SpecialEntranceInspection InspectSpecialEntrances(const Rom &rom, Overworld &overworld, int map_id)
absl::StatusOr< std::vector< OverworldExit > > LoadExits(Rom *rom)
OverworldRomProfile DetectOverworldRomProfile(const Rom &rom)
absl::StatusOr< std::vector< OverworldEntrance > > LoadHoles(Rom *rom)
#define RETURN_IF_ERROR(expr)
bool load_resource_labels
std::optional< int > phase
std::optional< int > map_id
std::optional< int > world
std::optional< int > map_id
std::optional< uint16_t > tile_id
std::optional< int > map_id
std::optional< int > world
std::optional< int > map_id
std::optional< std::filesystem::path > active_rom_path
std::optional< std::filesystem::path > source_rom_path
static const std::vector< std::string > & GetItemNames()