9#include "absl/strings/numbers.h"
10#include "absl/strings/str_format.h"
23namespace ow = app::service::OverworldOverlay;
27 std::istringstream ss(s);
29 while (std::getline(ss, tok,
',')) {
30 tok.erase(0, tok.find_first_not_of(
" \t"));
32 tok.erase(tok.find_last_not_of(
" \t") + 1);
37 else if (tok ==
"entrances")
39 else if (tok ==
"exits")
41 else if (tok ==
"holes")
43 else if (tok ==
"items")
45 else if (tok ==
"grid")
47 else if (tok ==
"all")
50 return absl::InvalidArgumentError(
51 absl::StrFormat(
"Unknown overlay '%s' (expected sprites, entrances, "
52 "exits, holes, items, grid, all)",
59 if (value ==
"on" || value ==
"true" || value ==
"1")
61 if (value ==
"off" || value ==
"false" || value ==
"0")
63 return absl::InvalidArgumentError(
"--area-overlay must be on or off");
67 if (
auto out = parser.
GetString(
"out"); out.has_value())
77 const auto out = OutputArg(parser);
78 if (!out.has_value() || out->empty()) {
79 return absl::InvalidArgumentError(
"--out <path.png> is required");
81 if (
const auto scale = parser.
GetString(
"scale"); scale.has_value()) {
84 if (
const auto ov = parser.
GetString(
"overlays"); ov.has_value()) {
87 if (
const auto ao = parser.
GetString(
"area-overlay"); ao.has_value()) {
90 if (
const auto phase = parser.
GetString(
"phase"); phase.has_value()) {
92 if (!absl::SimpleAtoi(*phase, &value) || value < 0 || value > 2) {
93 return absl::InvalidArgumentError(
"--phase must be 0, 1, or 2");
96 return absl::OkStatus();
103 if (rom !=
nullptr && !rom->
filename().empty()) {
117 if (!util::ParseHexString(*parser.
GetString(
"screen"), &screen)) {
118 return absl::InvalidArgumentError(
"--screen must be hex (e.g. 0x40)");
121 const std::string output_path = *OutputArg(parser);
125 invocation_context));
129 if (
auto ov = parser.
GetString(
"overlays"); ov.has_value()) {
132 if (
auto phase = parser.
GetString(
"phase"); phase.has_value()) {
133 absl::SimpleAtoi(*phase, &req.
phase);
135 if (
auto sc = parser.
GetString(
"scale"); sc.has_value()) {
138 if (
auto ao = parser.
GetString(
"area-overlay"); ao.has_value()) {
143 return absl::FailedPreconditionError(
"ROM not loaded");
148 if (!gd_status.ok()) {
149 return absl::InternalError(
150 absl::StrFormat(
"Failed to load game data: %s", gd_status.message()));
157 invocation_context));
158 std::ofstream out(resolved_output, std::ios::binary);
160 return absl::InternalError(
161 absl::StrFormat(
"Cannot open output file: %s", output_path));
163 out.write(
reinterpret_cast<const char*
>(result.png_data.data()),
164 static_cast<std::streamsize
>(result.png_data.size()));
167 return absl::InternalError(
168 absl::StrFormat(
"Write failed for: %s", output_path));
171 formatter.
AddField(
"requested_screen",
172 absl::StrFormat(
"0x%02X", result.requested_screen));
174 absl::StrFormat(
"0x%02X", result.parent_screen));
175 formatter.
AddField(
"area_size", result.area_size);
176 formatter.
AddField(
"subscreen_overlay",
177 result.subscreen_overlay < 0
178 ? std::string(
"none")
179 : absl::StrFormat(
"0x%02X", result.subscreen_overlay));
181 for (
int s : result.screens)
186 : absl::StrFormat(
"%d", req.
phase));
187 formatter.
AddField(
"output", output_path);
188 formatter.
AddField(
"width", result.width);
189 formatter.
AddField(
"height", result.height);
190 formatter.
AddField(
"scale", absl::StrFormat(
"%.2f", req.
scale));
191 formatter.
AddField(
"size_bytes",
static_cast<int>(result.png_data.size()));
194 "marker x/y are area-local pixels at scale 1; tile = x/16, y/16");
196 for (
const auto& m : result.markers) {
199 formatter.
AddField(
"id", absl::StrFormat(
"0x%02X", m.id));
201 formatter.
AddField(
"phase", m.phase);
202 formatter.
AddField(
"list_index", m.list_index);
206 formatter.
AddField(
"tile", absl::StrFormat(
"(%d,%d)", m.x / 16, m.y / 16));
210 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::StatusOr< OverworldRenderResult > RenderOverworldArea(const OverworldRenderRequest &req)
absl::Status ValidateArgs(const resources::ArgumentParser &parser) override
Validate command arguments.
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.
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)
absl::Status RequireArgs(const std::vector< std::string > &required) const
Validate that required arguments are present.
#define ASSIGN_OR_RETURN(type_variable_name, expression)
constexpr uint32_t kItems
constexpr uint32_t kHoles
constexpr uint32_t kSprites
constexpr uint32_t kEntrances
constexpr uint32_t kExits
absl::StatusOr< float > ParseRenderScale(absl::string_view value)
absl::StatusOr< bool > ParseAreaOverlay(const std::string &value)
absl::StatusOr< uint32_t > ParseOverworldOverlays(const std::string &s)
std::optional< std::string > OutputArg(const resources::ArgumentParser &parser)
absl::StatusOr< std::filesystem::path > ResolveStableArtifactPath(const std::filesystem::path &path)
absl::Status RejectArtifactRomAliases(absl::string_view option_name, const std::filesystem::path &artifact_path, const CommandInvocationContext &invocation_context)
absl::Status LoadGameData(Rom &rom, GameData &data, const LoadOptions &options)
Loads all Zelda3-specific game data from a generic ROM.
#define RETURN_IF_ERROR(expr)
std::optional< std::filesystem::path > active_rom_path
std::optional< std::filesystem::path > source_rom_path