37 std::ofstream out_file(output_path);
38 if (!out_file.is_open()) {
39 return absl::InternalError(
"Failed to open output file: " + output_path);
83 return absl::OkStatus();
88 out <<
"// =============================================================================" << std::endl;
89 out <<
"// YAZE Overworld Golden Data - Generated from: " <<
rom_path_ << std::endl;
90 out <<
"// Generated on: " << __DATE__ <<
" " << __TIME__ << std::endl;
91 out <<
"// =============================================================================" << std::endl;
93 out <<
"#pragma once" << std::endl;
95 out <<
"#include <cstdint>" << std::endl;
96 out <<
"#include <array>" << std::endl;
97 out <<
"#include <vector>" << std::endl;
98 out <<
"#include \"app/zelda3/overworld/overworld_map.h\"" << std::endl;
100 out <<
"namespace yaze {" << std::endl;
101 out <<
"namespace test {" << std::endl;
107 out <<
"} // namespace test" << std::endl;
108 out <<
"} // namespace yaze" << std::endl;
112 out <<
"// =============================================================================" << std::endl;
113 out <<
"// Basic ROM Information" << std::endl;
114 out <<
"// =============================================================================" << std::endl;
117 out <<
"constexpr std::string_view kGoldenROMTitle = \"" << rom.
title() <<
"\";" << std::endl;
118 out <<
"constexpr size_t kGoldenROMSize = " << rom.
size() <<
";" << std::endl;
122 auto header_checksum = rom.
ReadWord(0x7FDC);
123 auto header_checksum_complement = rom.
ReadWord(0x7FDE);
124 if (header_checksum.ok() && header_checksum_complement.ok()) {
125 out <<
"constexpr uint16_t kGoldenHeaderChecksum = 0x"
126 << std::hex << std::setw(4) << std::setfill(
'0')
127 << *header_checksum <<
";" << std::endl;
128 out <<
"constexpr uint16_t kGoldenHeaderChecksumComplement = 0x"
129 << std::hex << std::setw(4) << std::setfill(
'0')
130 << *header_checksum_complement <<
";" << std::endl;
136 out <<
"// =============================================================================" << std::endl;
137 out <<
"// ASM Version Information" << std::endl;
138 out <<
"// =============================================================================" << std::endl;
141 auto asm_version = rom.
ReadByte(0x140145);
142 if (asm_version.ok()) {
143 out <<
"constexpr uint8_t kGoldenASMVersion = 0x"
144 << std::hex << std::setw(2) << std::setfill(
'0')
145 <<
static_cast<int>(*asm_version) <<
";" << std::endl;
147 if (*asm_version == 0xFF) {
148 out <<
"constexpr bool kGoldenIsVanillaROM = true;" << std::endl;
149 out <<
"constexpr bool kGoldenHasZSCustomOverworld = false;" << std::endl;
151 out <<
"constexpr bool kGoldenIsVanillaROM = false;" << std::endl;
152 out <<
"constexpr bool kGoldenHasZSCustomOverworld = true;" << std::endl;
153 out <<
"constexpr uint8_t kGoldenZSCustomOverworldVersion = "
154 <<
static_cast<int>(*asm_version) <<
";" << std::endl;
160 if (asm_version.ok() && *asm_version >= 0x03) {
161 out <<
"// v3 Feature Flags" << std::endl;
163 auto main_palettes = rom.
ReadByte(0x140146);
164 auto area_bg = rom.
ReadByte(0x140147);
165 auto subscreen_overlay = rom.
ReadByte(0x140148);
166 auto animated_gfx = rom.
ReadByte(0x140149);
167 auto custom_tiles = rom.
ReadByte(0x14014A);
168 auto mosaic = rom.
ReadByte(0x14014B);
170 if (main_palettes.ok()) {
171 out <<
"constexpr bool kGoldenEnableMainPalettes = "
172 << (*main_palettes != 0 ?
"true" :
"false") <<
";" << std::endl;
175 out <<
"constexpr bool kGoldenEnableAreaSpecificBG = "
176 << (*area_bg != 0 ?
"true" :
"false") <<
";" << std::endl;
178 if (subscreen_overlay.ok()) {
179 out <<
"constexpr bool kGoldenEnableSubscreenOverlay = "
180 << (*subscreen_overlay != 0 ?
"true" :
"false") <<
";" << std::endl;
182 if (animated_gfx.ok()) {
183 out <<
"constexpr bool kGoldenEnableAnimatedGFX = "
184 << (*animated_gfx != 0 ?
"true" :
"false") <<
";" << std::endl;
186 if (custom_tiles.ok()) {
187 out <<
"constexpr bool kGoldenEnableCustomTiles = "
188 << (*custom_tiles != 0 ?
"true" :
"false") <<
";" << std::endl;
191 out <<
"constexpr bool kGoldenEnableMosaic = "
192 << (*mosaic != 0 ?
"true" :
"false") <<
";" << std::endl;
199 out <<
"// =============================================================================" << std::endl;
200 out <<
"// Overworld Maps Data" << std::endl;
201 out <<
"// =============================================================================" << std::endl;
205 out <<
"constexpr size_t kGoldenNumOverworldMaps = " << maps.size() <<
";" << std::endl;
209 out <<
"// Map properties for first 20 maps" << std::endl;
210 out <<
"constexpr std::array<uint8_t, 20> kGoldenMapAreaGraphics = {{" << std::endl;
211 for (
int i = 0; i < std::min(20, static_cast<int>(maps.size())); i++) {
212 out <<
" 0x" << std::hex << std::setw(2) << std::setfill(
'0')
213 <<
static_cast<int>(maps[i].area_graphics());
214 if (i < 19) out <<
",";
215 out <<
" // Map " << i << std::endl;
217 out <<
"}};" << std::endl;
220 out <<
"constexpr std::array<uint8_t, 20> kGoldenMapMainPalettes = {{" << std::endl;
221 for (
int i = 0; i < std::min(20, static_cast<int>(maps.size())); i++) {
222 out <<
" 0x" << std::hex << std::setw(2) << std::setfill(
'0')
223 <<
static_cast<int>(maps[i].main_palette());
224 if (i < 19) out <<
",";
225 out <<
" // Map " << i << std::endl;
227 out <<
"}};" << std::endl;
230 out <<
"constexpr std::array<AreaSizeEnum, 20> kGoldenMapAreaSizes = {{" << std::endl;
231 for (
int i = 0; i < std::min(20, static_cast<int>(maps.size())); i++) {
232 out <<
" AreaSizeEnum::";
233 switch (maps[i].area_size()) {
234 case AreaSizeEnum::SmallArea: out <<
"SmallArea";
break;
235 case AreaSizeEnum::LargeArea: out <<
"LargeArea";
break;
236 case AreaSizeEnum::WideArea: out <<
"WideArea";
break;
237 case AreaSizeEnum::TallArea: out <<
"TallArea";
break;
239 if (i < 19) out <<
",";
240 out <<
" // Map " << i << std::endl;
242 out <<
"}};" << std::endl;
247 out <<
"// =============================================================================" << std::endl;
248 out <<
"// Tile Data Information" << std::endl;
249 out <<
"// =============================================================================" << std::endl;
252 out <<
"constexpr bool kGoldenExpandedTile16 = "
253 << (overworld.
expanded_tile16() ?
"true" :
"false") <<
";" << std::endl;
254 out <<
"constexpr bool kGoldenExpandedTile32 = "
255 << (overworld.
expanded_tile32() ?
"true" :
"false") <<
";" << std::endl;
258 const auto& tiles16 = overworld.
tiles16();
261 out <<
"constexpr size_t kGoldenNumTiles16 = " << tiles16.size() <<
";" << std::endl;
262 out <<
"constexpr size_t kGoldenNumTiles32 = " << tiles32.size() <<
";" << std::endl;
266 out <<
"// Sample Tile16 data (first 10 tiles)" << std::endl;
267 out <<
"constexpr std::array<uint32_t, 10> kGoldenTile16Sample = {{" << std::endl;
268 for (
int i = 0; i < std::min(10, static_cast<int>(tiles16.size())); i++) {
270 const auto& tile16 = tiles16[i];
271 uint32_t sample = tile16.tile0_.id_ | (tile16.tile1_.id_ << 8) |
272 (tile16.tile2_.id_ << 16) | (tile16.tile3_.id_ << 24);
273 out <<
" 0x" << std::hex << std::setw(8) << std::setfill(
'0') << sample;
274 if (i < 9) out <<
",";
275 out <<
" // Tile16 " << i << std::endl;
277 out <<
"}};" << std::endl;
282 out <<
"// =============================================================================" << std::endl;
283 out <<
"// Entrance Data" << std::endl;
284 out <<
"// =============================================================================" << std::endl;
287 const auto& entrances = overworld.
entrances();
288 out <<
"constexpr size_t kGoldenNumEntrances = " << entrances.size() <<
";" << std::endl;
292 out <<
"// Sample entrance data (first 10 entrances)" << std::endl;
293 out <<
"constexpr std::array<uint16_t, 10> kGoldenEntranceMapPos = {{" << std::endl;
294 for (
int i = 0; i < std::min(10, static_cast<int>(entrances.size())); i++) {
295 out <<
" 0x" << std::hex << std::setw(4) << std::setfill(
'0')
296 << entrances[i].map_pos_;
297 if (i < 9) out <<
",";
298 out <<
" // Entrance " << i << std::endl;
300 out <<
"}};" << std::endl;
303 out <<
"constexpr std::array<uint16_t, 10> kGoldenEntranceMapId = {{" << std::endl;
304 for (
int i = 0; i < std::min(10, static_cast<int>(entrances.size())); i++) {
305 out <<
" 0x" << std::hex << std::setw(4) << std::setfill(
'0')
306 << entrances[i].map_id_;
307 if (i < 9) out <<
",";
308 out <<
" // Entrance " << i << std::endl;
310 out <<
"}};" << std::endl;
313 out <<
"constexpr std::array<int, 10> kGoldenEntranceX = {{" << std::endl;
314 for (
int i = 0; i < std::min(10, static_cast<int>(entrances.size())); i++) {
315 out <<
" " << std::dec << entrances[i].x_;
316 if (i < 9) out <<
",";
317 out <<
" // Entrance " << i << std::endl;
319 out <<
"}};" << std::endl;
322 out <<
"constexpr std::array<int, 10> kGoldenEntranceY = {{" << std::endl;
323 for (
int i = 0; i < std::min(10, static_cast<int>(entrances.size())); i++) {
324 out <<
" " << std::dec << entrances[i].y_;
325 if (i < 9) out <<
",";
326 out <<
" // Entrance " << i << std::endl;
328 out <<
"}};" << std::endl;
333 out <<
"// =============================================================================" << std::endl;
334 out <<
"// Hole Data" << std::endl;
335 out <<
"// =============================================================================" << std::endl;
338 const auto& holes = overworld.
holes();
339 out <<
"constexpr size_t kGoldenNumHoles = " << holes.size() <<
";" << std::endl;
343 out <<
"// Sample hole data (first 5 holes)" << std::endl;
344 out <<
"constexpr std::array<uint16_t, 5> kGoldenHoleMapPos = {{" << std::endl;
345 for (
int i = 0; i < std::min(5, static_cast<int>(holes.size())); i++) {
346 out <<
" 0x" << std::hex << std::setw(4) << std::setfill(
'0')
347 << holes[i].map_pos_;
348 if (i < 4) out <<
",";
349 out <<
" // Hole " << i << std::endl;
351 out <<
"}};" << std::endl;
356 out <<
"// =============================================================================" << std::endl;
357 out <<
"// Exit Data" << std::endl;
358 out <<
"// =============================================================================" << std::endl;
361 const auto& exits = overworld.
exits();
362 out <<
"constexpr size_t kGoldenNumExits = " << exits->size() <<
";" << std::endl;
366 out <<
"// Sample exit data (first 10 exits)" << std::endl;
367 out <<
"constexpr std::array<uint16_t, 10> kGoldenExitRoomId = {{" << std::endl;
368 for (
int i = 0; i < std::min(10, static_cast<int>(exits->size())); i++) {
369 out <<
" 0x" << std::hex << std::setw(4) << std::setfill(
'0')
370 << (*exits)[i].room_id_;
371 if (i < 9) out <<
",";
372 out <<
" // Exit " << i << std::endl;
374 out <<
"}};" << std::endl;
379 out <<
"// =============================================================================" << std::endl;
380 out <<
"// Item Data" << std::endl;
381 out <<
"// =============================================================================" << std::endl;
384 const auto& items = overworld.
all_items();
385 out <<
"constexpr size_t kGoldenNumItems = " << items.size() <<
";" << std::endl;
389 if (!items.empty()) {
390 out <<
"// Sample item data (first 10 items)" << std::endl;
391 out <<
"constexpr std::array<uint8_t, 10> kGoldenItemIds = {{" << std::endl;
392 for (
int i = 0; i < std::min(10, static_cast<int>(items.size())); i++) {
393 out <<
" 0x" << std::hex << std::setw(2) << std::setfill(
'0')
394 <<
static_cast<int>(items[i].id_);
395 if (i < 9) out <<
",";
396 out <<
" // Item " << i << std::endl;
398 out <<
"}};" << std::endl;
404 out <<
"// =============================================================================" << std::endl;
405 out <<
"// Sprite Data" << std::endl;
406 out <<
"// =============================================================================" << std::endl;
410 out <<
"constexpr size_t kGoldenNumSpriteStates = " << sprites.size() <<
";" << std::endl;
414 out <<
"// Sample sprite data (first 5 sprites from each state)" << std::endl;
415 for (
int state = 0; state < std::min(3, static_cast<int>(sprites.size())); state++) {
416 out <<
"constexpr size_t kGoldenNumSpritesState" << state <<
" = "
417 << sprites[state].size() <<
";" << std::endl;
423 out <<
"// =============================================================================" << std::endl;
424 out <<
"// Map Tiles Data" << std::endl;
425 out <<
"// =============================================================================" << std::endl;
428 const auto& map_tiles = overworld.
map_tiles();
429 out <<
"// Map tile dimensions" << std::endl;
430 out <<
"constexpr size_t kGoldenMapTileWidth = " << map_tiles.light_world[0].size() <<
";" << std::endl;
431 out <<
"constexpr size_t kGoldenMapTileHeight = " << map_tiles.light_world.size() <<
";" << std::endl;
435 out <<
"// Sample map tile data (top-left 10x10 corner of Light World)" << std::endl;
436 out <<
"constexpr std::array<std::array<uint16_t, 10>, 10> kGoldenMapTilesSample = {{" << std::endl;
437 for (
int row = 0; row < 10; row++) {
439 for (
int col = 0; col < 10; col++) {
440 out <<
"0x" << std::hex << std::setw(4) << std::setfill(
'0')
441 << map_tiles.light_world[row][col];
442 if (col < 9) out <<
", ";
445 if (row < 9) out <<
",";
446 out <<
" // Row " << row << std::endl;
448 out <<
"}};" << std::endl;
453 out <<
"// =============================================================================" << std::endl;
454 out <<
"// Palette Data" << std::endl;
455 out <<
"// =============================================================================" << std::endl;
459 out <<
"// Sample palette data (first 10 bytes from overworld palette table)" << std::endl;
460 out <<
"constexpr std::array<uint8_t, 10> kGoldenPaletteSample = {{" << std::endl;
461 for (
int i = 0; i < 10; i++) {
462 auto palette_byte = rom.
ReadByte(0x7D1C + i);
463 if (palette_byte.ok()) {
464 out <<
" 0x" << std::hex << std::setw(2) << std::setfill(
'0')
465 <<
static_cast<int>(*palette_byte);
469 if (i < 9) out <<
",";
470 out <<
" // Palette " << i << std::endl;
472 out <<
"}};" << std::endl;
477 out <<
"// =============================================================================" << std::endl;
478 out <<
"// Music Data" << std::endl;
479 out <<
"// =============================================================================" << std::endl;
483 out <<
"// Sample music data (first 10 bytes from overworld music table)" << std::endl;
484 out <<
"constexpr std::array<uint8_t, 10> kGoldenMusicSample = {{" << std::endl;
485 for (
int i = 0; i < 10; i++) {
486 auto music_byte = rom.
ReadByte(0x14303 + i);
487 if (music_byte.ok()) {
488 out <<
" 0x" << std::hex << std::setw(2) << std::setfill(
'0')
489 <<
static_cast<int>(*music_byte);
493 if (i < 9) out <<
",";
494 out <<
" // Music " << i << std::endl;
496 out <<
"}};" << std::endl;
501 out <<
"// =============================================================================" << std::endl;
502 out <<
"// Overlay Data" << std::endl;
503 out <<
"// =============================================================================" << std::endl;
507 out <<
"// Sample overlay data (first 10 bytes from overlay pointers)" << std::endl;
508 out <<
"constexpr std::array<uint8_t, 10> kGoldenOverlaySample = {{" << std::endl;
509 for (
int i = 0; i < 10; i++) {
510 auto overlay_byte = rom.
ReadByte(0x77664 + i);
511 if (overlay_byte.ok()) {
512 out <<
" 0x" << std::hex << std::setw(2) << std::setfill(
'0')
513 <<
static_cast<int>(*overlay_byte);
517 if (i < 9) out <<
",";
518 out <<
" // Overlay " << i << std::endl;
520 out <<
"}};" << std::endl;
527int main(
int argc,
char* argv[]) {
529 std::cerr <<
"Usage: " << argv[0] <<
" <rom_path> <output_path>" << std::endl;
530 std::cerr <<
"Example: " << argv[0] <<
" zelda3.sfc golden_data.h" << std::endl;
534 std::string rom_path = argv[1];
535 std::string output_path = argv[2];
537 if (!std::filesystem::exists(rom_path)) {
538 std::cerr <<
"Error: ROM file not found: " << rom_path << std::endl;
546 std::cout <<
"Successfully extracted golden data from " << rom_path
547 <<
" to " << output_path << std::endl;
550 std::cerr <<
"Error extracting golden data: " << status.message() << std::endl;
The Rom class is used to load, save, and modify Rom data.
absl::Status LoadFromFile(const std::string &filename, bool z3_load=true)
absl::StatusOr< uint16_t > ReadWord(int offset)
absl::StatusOr< uint8_t > ReadByte(int offset)
Represents the full Overworld data, light and dark world.
absl::Status Load(Rom *rom)
auto expanded_tile32() const
const std::vector< OverworldEntrance > & holes() const
std::vector< gfx::Tile16 > tiles16() const
auto expanded_tile16() const
auto tiles32_unique() const
const std::vector< OverworldEntrance > & entrances() const
auto overworld_maps() const
#define RETURN_IF_ERROR(expression)
Zelda 3 specific classes and functions.
Main namespace for the application.