13#include <unordered_map>
16#include "absl/status/status.h"
17#include "absl/status/statusor.h"
18#include "absl/strings/str_format.h"
40 std::array<int, 4> destinations{};
41 int storage_bytes_per_quadrant = 0;
42 int definition_capacity = 0;
43 bool expanded =
false;
51 layout.
expanded = profile.has_expanded_tile32;
65 return absl::OutOfRangeError(absl::StrFormat(
66 "Tile32 destination 0x%06X is outside the ROM",
destination));
69 usable_bytes = std::min(usable_bytes,
70 static_cast<int>(std::min<size_t>(
71 available, std::numeric_limits<int>::max())));
78 std::sort(ordered_destinations.begin(), ordered_destinations.end());
79 for (
size_t i = 1; i < ordered_destinations.size(); ++i) {
80 const int span = ordered_destinations[i] - ordered_destinations[i - 1];
82 return absl::FailedPreconditionError(
83 "Tile32 destinations overlap or share the same address");
85 usable_bytes = std::min(usable_bytes, span);
90 if (usable_bytes <= 0) {
91 return absl::ResourceExhaustedError(
92 "Tile32 destinations have no usable packed storage");
104 return absl::InvalidArgumentError(absl::StrFormat(
105 "Tile32 definition count %zu is not aligned to a packed group of %d",
109 return absl::ResourceExhaustedError(absl::StrFormat(
110 "Number of unique Tiles32: %zu Out of: %d\n"
111 "Unique Tile32 count exceeds the %s destination capacity; the ROM has "
114 layout.
expanded ?
"expanded" :
"vanilla"));
117 const size_t required_bytes =
121 return absl::ResourceExhaustedError(absl::StrFormat(
122 "Tile32 definitions require %zu bytes per quadrant; destination "
123 "capacity is %d bytes",
126 return absl::OkStatus();
134 if (
rom->size() == 0) {
135 return absl::InvalidArgumentError(
"ROM file not loaded");
222 return absl::OkStatus();
242 }
else if (i == parent + 1) {
244 }
else if (i == parent + 8) {
246 }
else if (i == parent + 9) {
257 std::array<bool, kNumOverworldMaps> map_checked{};
258 std::ranges::fill(map_checked,
false);
261 for (
int world_offset = 0; world_offset < 128; world_offset += 64) {
262 for (
int local = 0; local < 64; local++) {
263 int i = world_offset + local;
278 }
else if (i == parent + 1) {
280 }
else if (i == parent + 8) {
282 }
else if (i == parent + 9) {
287 map_checked[i] =
true;
292 std::array<int, 4> siblings = {parent, parent + 1, parent + 8,
294 int world_start = world_offset;
295 int world_end = world_offset + 64;
296 for (
int q = 0; q < 4; q++) {
297 int sibling = siblings[q];
299 if (sibling >= world_start && sibling < world_end &&
300 !map_checked[sibling]) {
302 map_checked[sibling] =
true;
308 map_checked[i] =
true;
326 int i = world + xx + (yy * 8);
328 if (i >=
static_cast<int>(map_checked.size())) {
332 if (!map_checked[i]) {
333 switch (maps[i].area_size()) {
335 map_checked[i] =
true;
340 map_checked[i] =
true;
341 maps[i].SetAsLargeMap(i, 0);
343 if (i + 1 <
static_cast<int>(maps.size())) {
344 map_checked[i + 1] =
true;
345 maps[i + 1].SetAsLargeMap(i, 1);
348 if (i + 8 <
static_cast<int>(maps.size())) {
349 map_checked[i + 8] =
true;
350 maps[i + 8].SetAsLargeMap(i, 2);
353 if (i + 9 <
static_cast<int>(maps.size())) {
354 map_checked[i + 9] =
true;
355 maps[i + 9].SetAsLargeMap(i, 3);
362 map_checked[i] =
true;
365 maps[i].SetParent(i);
368 if (i + 1 <
static_cast<int>(maps.size())) {
369 map_checked[i + 1] =
true;
370 maps[i + 1].SetParent(i);
378 map_checked[i] =
true;
381 maps[i].SetParent(i);
384 if (i + 8 <
static_cast<int>(maps.size())) {
385 map_checked[i + 8] =
true;
386 maps[i + 8].SetParent(i);
409 return absl::InvalidArgumentError(
410 absl::StrFormat(
"Invalid parent index: %d", parent_index));
419 return absl::FailedPreconditionError(
420 "Wide and Tall areas require ZSCustomOverworld v3+");
424 return absl::FailedPreconditionError(
425 "Special World multi-area changes require ZSCustomOverworld v3+");
429 "ConfigureMultiAreaMap: parent=%d, current_size=%d, new_size=%d, "
433 static_cast<int>(size),
437 std::vector<int> old_siblings;
443 old_siblings = {old_parent, old_parent + 1, old_parent + 8,
447 old_siblings = {old_parent, old_parent + 1};
450 old_siblings = {old_parent, old_parent + 8};
453 old_siblings = {parent_index};
459 std::vector<int> new_siblings;
462 new_siblings = {parent_index};
465 new_siblings = {parent_index, parent_index + 1, parent_index + 8,
469 new_siblings = {parent_index, parent_index + 1};
472 new_siblings = {parent_index, parent_index + 8};
475 for (
int sibling : new_siblings) {
478 return absl::FailedPreconditionError(
479 absl::StrFormat(
"Area size crosses an overworld boundary: parent=%d "
481 parent_index, sibling));
486 for (
int old_sibling : old_siblings) {
500 for (
size_t i = 0; i < new_siblings.size(); ++i) {
506 for (
int sibling : new_siblings) {
513 for (
int sibling : new_siblings) {
521 std::set<int> all_affected;
522 for (
int sibling : old_siblings) {
523 all_affected.insert(sibling);
525 for (
int sibling : new_siblings) {
526 all_affected.insert(sibling);
531 for (
int sibling : all_affected) {
547 for (
int sibling : all_affected) {
568 "Configured %s area: parent=%d, old_siblings=%zu, new_siblings=%zu",
573 parent_index, old_siblings.size(), new_siblings.size());
575 return absl::OkStatus();
579 int index,
int quadrant,
int dimension,
const uint32_t* map32address) {
581 auto arg1,
rom()->ReadByte(map32address[dimension] + quadrant + (index)));
583 rom()->ReadWord(map32address[dimension] + (index) +
584 (quadrant <= 1 ? 4 : 5)));
585 return (uint16_t)(arg1 +
586 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
590 constexpr int kMap32TilesLength = 0x33F0;
591 int num_tile32 = kMap32TilesLength;
592 uint32_t map32address[4] = {
601 util::logf(
"Expanded tile32 flag: %d", expanded_flag);
602 if (profile.has_expanded_tile32) {
614 for (
int i = 0; i < num_tile32; i += 6) {
616 for (
int k = 0; k < 4; k++) {
640 for (
int i = 0; i < 0x200; i++) {
646 return absl::OkStatus();
658 util::logf(
"Expanded tile16 flag: %d", expanded_flag);
659 if (profile.has_expanded_tile16) {
667 for (
int i = 0; i < num_tile16; i += 1) {
680 tiles16_.emplace_back(t0, t1, t2, t3);
682 return absl::OkStatus();
687 int position_x1 = (x * 2) + (sx * 32);
688 int position_y1 = (y * 2) + (sy * 32);
689 int position_x2 = (x * 2) + 1 + (sx * 32);
690 int position_y2 = (y * 2) + 1 + (sy * 32);
698 switch (world_type) {
717 int local_index = map_index % 64;
718 int sx = local_index % 8;
719 int sy = local_index / 8;
723 for (
int y = 0; y < 32; ++y) {
724 for (
int x = 0; x < 32; ++x) {
725 world[(sx * 32) + x][(sy * 32) + y] = 0;
731 std::vector<uint8_t>& bytes2,
int i,
int sx,
732 int sy,
int& ttpos) {
733 for (
int y = 0; y < 16; y++) {
734 for (
int x = 0; x < 16; x++) {
735 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
751 const auto get_ow_map_gfx_ptr = [
this](
int index, uint32_t map_ptr) {
752 int p = (
rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
753 (
rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
754 (
rom()->data()[map_ptr + (3 * index)]);
758 constexpr uint32_t kBaseLowest = 0x0FFFFF;
759 constexpr uint32_t kBaseHighest = 0x0F8000;
761 uint32_t lowest = kBaseLowest;
762 uint32_t highest = kBaseHighest;
769 const bool allow_special_tail =
775 if (!allow_special_tail &&
792 auto p1 = get_ow_map_gfx_ptr(
794 auto p2 = get_ow_map_gfx_ptr(
799 bool pointers_valid =
800 (p1 > 0 && p2 > 0 && p1 <
rom()->size() && p2 <
rom()->size());
801 if (!pointers_valid) {
823 if (p1 <= lowest && p1 > kBaseHighest)
825 if (p2 <= lowest && p2 > kBaseHighest)
829 size_t max_size_p2 =
rom()->size() - p2;
832 size_t max_size_p1 =
rom()->size() - p1;
837 if (bytes.empty() || bytes2.empty()) {
857 return absl::OkStatus();
867 constexpr int kDarkWorldEssential =
869 constexpr int kSpecialWorldEssential =
871 std::vector<int> essential_map_ids;
875 "Building essential maps only (first %d maps per world) for faster "
885 bool is_essential =
false;
887 if (i < kLightWorldEssential) {
896 essential_map_ids.push_back(i);
911 if (map->is_large_map() &&
913 if (map->parent() != i && !map->is_initialized()) {
916 map->set_sprite_graphics(0, 0x0E);
917 map->set_sprite_graphics(1, 0x0E);
918 map->set_sprite_graphics(2, 0x0E);
919 map->set_area_graphics(
923 }
else if (i == 0x88) {
924 map->set_area_graphics(0x51);
925 map->set_area_palette(0x00);
929 map->set_area_palette(
939 const std::vector<uint8_t>* cached_tileset =
944 if (!cached_tileset) {
954 std::vector<std::future<absl::Status>> futures;
958 bool is_essential =
false;
961 if (i < kLightWorldEssential) {
977 auto task_function = [
this, i, size, world_type]() {
981 futures.emplace_back(std::async(std::launch::async, task_function));
989 for (
auto& future : futures) {
995 for (
int map_index : essential_map_ids) {
1000 util::logf(
"Essential maps built. Remaining maps will be built on-demand.");
1001 return absl::OkStatus();
1006 return absl::InvalidArgumentError(
"Invalid map index");
1012 const bool allow_special_tail =
1015 if (!allow_special_tail &&
1021 return absl::OkStatus();
1033 return absl::OkStatus();
1065 if (map->parent() != map_index && !map->is_initialized()) {
1069 map_index != 0x88) {
1071 map->set_sprite_graphics(0, 0x0E);
1072 map->set_sprite_graphics(1, 0x0E);
1073 map->set_sprite_graphics(2, 0x0E);
1074 map->set_area_graphics(
1078 }
else if (map_index == 0x88) {
1079 map->set_area_graphics(0x51);
1080 map->set_area_palette(0x00);
1095 const std::vector<uint8_t>* cached_tileset =
GetCachedTileset(config_hash);
1103 if (!cached_tileset) {
1134 hash ^=
static_cast<uint64_t
>(world_type) << 62;
1135 hash *= 0x517cc1b727220a95ULL;
1140 for (
int i = 0; i < 12; ++i) {
1141 hash ^=
static_cast<uint64_t
>(map->static_graphics(i)) << ((i % 8) * 8);
1142 hash *= 0x517cc1b727220a95ULL;
1149 hash *= 0x517cc1b727220a95ULL;
1153 for (
int i = 0; i < 3; ++i) {
1154 hash ^=
static_cast<uint64_t
>(map->sprite_graphics(i)) << (52 + i * 4);
1155 hash *= 0x517cc1b727220a95ULL;
1159 hash ^=
static_cast<uint64_t
>(map->area_graphics()) << 48;
1160 hash *= 0x517cc1b727220a95ULL;
1164 hash ^=
static_cast<uint64_t
>(map->main_gfx_id()) << 56;
1165 hash *= 0x517cc1b727220a95ULL;
1168 hash ^=
static_cast<uint64_t
>(map->parent()) << 40;
1169 hash *= 0x517cc1b727220a95ULL;
1175 hash ^=
static_cast<uint64_t
>(map_index) << 8;
1176 hash *= 0x517cc1b727220a95ULL;
1179 hash ^=
static_cast<uint64_t
>(map->main_palette()) << 24;
1180 hash *= 0x517cc1b727220a95ULL;
1183 hash ^=
static_cast<uint64_t
>(map->animated_gfx()) << 16;
1184 hash *= 0x517cc1b727220a95ULL;
1187 hash ^=
static_cast<uint64_t
>(map->area_palette()) << 32;
1188 hash *= 0x517cc1b727220a95ULL;
1192 hash ^=
static_cast<uint64_t
>(map->subscreen_overlay());
1193 hash *= 0x517cc1b727220a95ULL;
1201 it->second.reference_count++;
1202 return &it->second.current_gfx;
1208 const std::vector<uint8_t>& tileset) {
1215 if (it->second.reference_count < min_it->second.reference_count) {
1251 int parent_id = map->parent();
1252 std::vector<int> siblings;
1258 switch (map->area_size()) {
1260 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1263 siblings = {parent_id, parent_id + 1};
1266 siblings = {parent_id, parent_id + 8};
1269 siblings = {map_index};
1274 if (map->is_large_map()) {
1275 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1277 siblings = {map_index};
1282 for (
int sibling : siblings) {
1292#ifdef __EMSCRIPTEN__
1307 std::vector<std::future<absl::Status>> futures;
1311 futures.emplace_back(std::async(std::launch::async, [
this]() {
1314 futures.emplace_back(std::async(std::launch::async, [
this]() {
1317 futures.emplace_back(std::async(std::launch::async, [
this]() {
1322 futures.emplace_back(std::async(std::launch::async, [
this]() {
1325 futures.emplace_back(std::async(std::launch::async, [
this]() {
1328 futures.emplace_back(std::async(std::launch::async, [
this]() {
1333 for (
auto& future : futures) {
1338 return absl::OkStatus();
1342 int num_maps_per_gamestate,
1344 for (
int i = 0; i < num_maps_per_gamestate; i++) {
1348 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
1350 int sprite_address =
SnesToPc((0x09 << 0x10) | word_addr);
1358 int editor_map_index = i;
1359 if (game_state != 0) {
1360 if (editor_map_index >= 128)
1361 editor_map_index -= 128;
1362 else if (editor_map_index >= 64)
1363 editor_map_index -= 64;
1365 int mapY = (editor_map_index / 8);
1366 int mapX = (editor_map_index % 8);
1368 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
1369 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
1372 (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY);
1375 sprite_address += 3;
1379 return absl::OkStatus();
1404 return absl::OkStatus();
1421 std::vector<uint8_t> single_map_1(512);
1422 std::vector<uint8_t> single_map_2(512);
1426 for (
int y = 0; y < 16; y++) {
1427 for (
int x = 0; x < 16; x++) {
1429 single_map_1[npos] = packed & 0xFF;
1430 single_map_2[npos] = (packed >> 8) & 0xFF;
1439 if (a.empty() || b.empty()) {
1440 return absl::AbortedError(
"Error compressing map gfx.");
1447 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
1451 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
1452 util::logf(
"Pos set to overflow region for map %s at %s",
1457 const auto compare_array = [](
const std::vector<uint8_t>& array1,
1458 const std::vector<uint8_t>& array2) ->
bool {
1459 if (array1.size() != array2.size()) {
1463 for (
size_t i = 0; i < array1.size(); i++) {
1464 if (array1[i] != array2[i]) {
1472 for (
int j = 0; j < i; j++) {
1486 std::copy(a.begin(), a.end(),
map_data_p1[i].begin());
1489 util::logf(
"Saving map pointers1 and compressed data for map %s at %s",
1506 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
1510 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
1511 util::logf(
"Pos set to overflow region for map %s at %s",
1518 std::copy(b.begin(), b.end(),
map_data_p2[i].begin());
1521 util::logf(
"Saving map pointers2 and compressed data for map %s at %s",
1542 return absl::AbortedError(
"Too many maps data " + std::to_string(pos));
1546 return absl::OkStatus();
1551 std::vector<std::pair<uint32_t, uint32_t>> ranges;
1554 uint32_t map32address[4] = {
1557 int map32_len = 0x33F0;
1568 for (
int i = 0; i < 4; ++i) {
1569 if (map32address[i] > 0) {
1570 ranges.emplace_back(map32address[i], map32address[i] + map32_len);
1581 ranges.emplace_back(map16_addr, map16_addr + map16_len);
1587 constexpr uint32_t kCompressedBank0bEnd = 0x5FE70;
1588 constexpr uint32_t kCompressedBank0cStart = 0x60000;
1589 constexpr uint32_t kCompressedBank0cEnd = 0x6411F;
1597 kCompressedBank0bEnd);
1598 ranges.emplace_back(kCompressedBank0cStart, kCompressedBank0cEnd);
1609 bool use_expanded_transitions =
1612 if (use_expanded_transitions) {
1618 std::vector<uint8_t> checked_map;
1630 if (std::find(checked_map.begin(), checked_map.end(), i) !=
1631 checked_map.end()) {
1638 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
1639 for (
const auto& offset : large_map_offsets) {
1664 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1667 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1671 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1674 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1678 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1681 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1685 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1688 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1692 (parent_x_pos * 0x200)));
1694 (parent_y_pos * 0x200)));
1698 (parent_x_pos * 0x200)));
1701 (parent_y_pos * 0x200)));
1705 (parent_x_pos * 0x200)));
1708 (parent_y_pos * 0x200)));
1712 (parent_x_pos * 0x200)));
1715 (parent_y_pos * 0x200)));
1724 if (parent_x_pos == 0) {
1827 checked_map.emplace_back(i);
1828 checked_map.emplace_back((i + 1));
1829 checked_map.emplace_back((i + 8));
1830 checked_map.emplace_back((i + 9));
1852 if (i - 1 >= 0 && parent_x_pos != 0) {
1864 if (i + 1 < 64 && parent_x_pos != 7) {
1908 (uint16_t)((y_pos * 0x200) - 0xE0)));
1910 (uint16_t)((x_pos * 0x200) - 0x100)));
1917 checked_map.emplace_back(i);
1926 const auto legacy_size_byte = [
this](
int map_index) -> uint8_t {
1929 const auto legacy_loading_size_byte = [
this](
int map_index) -> uint8_t {
1935 legacy_size_byte(map_index)));
1937 legacy_loading_size_byte(map_index)));
1943 legacy_loading_size_byte(map_index)));
1946 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
1949 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
1951 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
1953 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
1955 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
1957 return absl::OkStatus();
1961 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
1962 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
1963 int screen_change_1,
int screen_change_2,
int screen_change_3,
1964 int screen_change_4) {
1967 rom()->WriteShort(transition_target_north + (i * 2),
1968 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
1970 rom()->WriteShort(transition_target_west + (i * 2),
1971 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
1974 rom()->WriteShort(transition_pos_x + (i * 2), parent_x_pos * 0x0200));
1976 rom()->WriteShort(transition_pos_y + (i * 2), parent_y_pos * 0x0200));
1979 uint16_t by_screen1_small = 0x0060;
1982 if ((i % 0x40) - 1 >= 0) {
1987 west_neighbor.large_index() == 3) {
1988 by_screen1_small = 0xF060;
1992 west_neighbor.large_index() == 2) {
1993 by_screen1_small = 0xF060;
1998 rom()->WriteShort(screen_change_1 + (i * 2), by_screen1_small));
2001 uint16_t by_screen2_small = 0x0040;
2009 east_neighbor.large_index() == 2) {
2010 by_screen2_small = 0xF040;
2014 east_neighbor.large_index() == 2) {
2015 by_screen2_small = 0xF040;
2020 rom()->WriteShort(screen_change_2 + (i * 2), by_screen2_small));
2023 uint16_t by_screen3_small = 0x1800;
2026 if ((i % 0x40) - 8 >= 0) {
2031 north_neighbor.large_index() == 3) {
2032 by_screen3_small = 0x17C0;
2036 north_neighbor.large_index() == 1) {
2037 by_screen3_small = 0x17C0;
2042 rom()->WriteShort(screen_change_3 + (i * 2), by_screen3_small));
2045 uint16_t by_screen4_small = 0x1000;
2053 south_neighbor.large_index() == 1) {
2054 by_screen4_small = 0x0FC0;
2058 south_neighbor.large_index() == 1) {
2059 by_screen4_small = 0x0FC0;
2064 rom()->WriteShort(screen_change_4 + (i * 2), by_screen4_small));
2066 return absl::OkStatus();
2070 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
2071 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
2072 int screen_change_1,
int screen_change_2,
int screen_change_3,
2073 int screen_change_4) {
2075 const uint16_t offsets[] = {0, 2, 16, 18};
2076 for (
auto offset : offsets) {
2078 rom()->WriteShort(transition_target_north + (i * 2) + offset,
2079 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
2081 rom()->WriteShort(transition_target_west + (i * 2) + offset,
2082 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
2084 parent_x_pos * 0x0200));
2086 parent_y_pos * 0x0200));
2091 std::array<uint16_t, 4> by_screen1_large = {0x0060, 0x0060, 0x1060, 0x1060};
2094 if ((i % 0x40) - 1 >= 0) {
2098 switch (west_neighbor.large_index()) {
2100 by_screen1_large[2] = 0x0060;
2103 by_screen1_large[0] = 0xF060;
2107 switch (west_neighbor.large_index()) {
2109 by_screen1_large[2] = 0x0060;
2112 by_screen1_large[0] = 0xF060;
2118 for (
int j = 0; j < 4; j++) {
2120 by_screen1_large[j]));
2124 std::array<uint16_t, 4> by_screen2_large = {0x0080, 0x0080, 0x1080, 0x1080};
2131 switch (east_neighbor.large_index()) {
2133 by_screen2_large[3] = 0x0080;
2136 by_screen2_large[1] = 0xF080;
2140 switch (east_neighbor.large_index()) {
2142 by_screen2_large[3] = 0x0080;
2145 by_screen2_large[1] = 0xF080;
2151 for (
int j = 0; j < 4; j++) {
2153 by_screen2_large[j]));
2157 std::array<uint16_t, 4> by_screen3_large = {0x1800, 0x1840, 0x1800, 0x1840};
2160 if ((i % 0x40) - 8 >= 0) {
2164 switch (north_neighbor.large_index()) {
2166 by_screen3_large[1] = 0x1800;
2169 by_screen3_large[0] = 0x17C0;
2173 switch (north_neighbor.large_index()) {
2175 by_screen3_large[1] = 0x1800;
2178 by_screen3_large[0] = 0x17C0;
2184 for (
int j = 0; j < 4; j++) {
2186 by_screen3_large[j]));
2190 std::array<uint16_t, 4> by_screen4_large = {0x2000, 0x2040, 0x2000, 0x2040};
2197 switch (south_neighbor.large_index()) {
2199 by_screen4_large[3] = 0x2000;
2202 by_screen4_large[2] = 0x1FC0;
2206 switch (south_neighbor.large_index()) {
2208 by_screen4_large[3] = 0x2000;
2211 by_screen4_large[2] = 0x1FC0;
2217 for (
int j = 0; j < 4; j++) {
2219 by_screen4_large[j]));
2222 return absl::OkStatus();
2226 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
2227 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
2228 int screen_change_1,
int screen_change_2,
int screen_change_3,
2229 int screen_change_4) {
2231 const uint16_t offsets[] = {0, 2};
2232 for (
auto offset : offsets) {
2234 rom()->WriteShort(transition_target_north + (i * 2) + offset,
2235 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
2237 rom()->WriteShort(transition_target_west + (i * 2) + offset,
2238 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
2240 parent_x_pos * 0x0200));
2242 parent_y_pos * 0x0200));
2246 std::array<uint16_t, 2> by_screen1_wide = {0x0060, 0x0060};
2249 if ((i % 0x40) - 1 >= 0) {
2254 west_neighbor.large_index() == 3) {
2255 by_screen1_wide[0] = 0xF060;
2259 west_neighbor.large_index() == 2) {
2260 by_screen1_wide[0] = 0xF060;
2264 for (
int j = 0; j < 2; j++) {
2266 by_screen1_wide[j]));
2270 std::array<uint16_t, 2> by_screen2_wide = {0x0080, 0x0080};
2278 east_neighbor.large_index() == 2) {
2279 by_screen2_wide[1] = 0xF080;
2283 east_neighbor.large_index() == 2) {
2284 by_screen2_wide[1] = 0xF080;
2288 for (
int j = 0; j < 2; j++) {
2290 by_screen2_wide[j]));
2294 std::array<uint16_t, 2> by_screen3_wide = {0x1800, 0x1840};
2297 if ((i % 0x40) - 8 >= 0) {
2301 switch (north_neighbor.large_index()) {
2303 by_screen3_wide[1] = 0x1800;
2306 by_screen3_wide[0] = 0x17C0;
2310 switch (north_neighbor.large_index()) {
2312 by_screen3_wide[1] = 0x1800;
2315 by_screen3_wide[0] = 0x07C0;
2321 for (
int j = 0; j < 2; j++) {
2323 by_screen3_wide[j]));
2327 std::array<uint16_t, 2> by_screen4_wide = {0x1000, 0x1040};
2334 switch (south_neighbor.large_index()) {
2336 by_screen4_wide[1] = 0x1000;
2339 by_screen4_wide[0] = 0x0FC0;
2343 if (south_neighbor.large_index() == 1) {
2344 by_screen4_wide[0] = 0x0FC0;
2346 switch (south_neighbor.large_index()) {
2348 by_screen4_wide[1] = 0x1000;
2351 by_screen4_wide[0] = 0x0FC0;
2357 for (
int j = 0; j < 2; j++) {
2359 by_screen4_wide[j]));
2362 return absl::OkStatus();
2366 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
2367 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
2368 int screen_change_1,
int screen_change_2,
int screen_change_3,
2369 int screen_change_4) {
2371 const uint16_t offsets[] = {0, 16};
2372 for (
auto offset : offsets) {
2374 rom()->WriteShort(transition_target_north + (i * 2) + offset,
2375 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
2377 rom()->WriteShort(transition_target_west + (i * 2) + offset,
2378 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
2380 parent_x_pos * 0x0200));
2382 parent_y_pos * 0x0200));
2386 std::array<uint16_t, 2> by_screen1_tall = {0x0060, 0x1060};
2389 if ((i % 0x40) - 1 >= 0) {
2393 switch (west_neighbor.large_index()) {
2395 by_screen1_tall[1] = 0x0060;
2398 by_screen1_tall[0] = 0xF060;
2402 switch (west_neighbor.large_index()) {
2404 by_screen1_tall[1] = 0x0060;
2407 by_screen1_tall[0] = 0xF060;
2413 for (
int j = 0; j < 2; j++) {
2415 by_screen1_tall[j]));
2419 std::array<uint16_t, 2> by_screen2_tall = {0x0040, 0x1040};
2426 switch (east_neighbor.large_index()) {
2428 by_screen2_tall[1] = 0x0040;
2431 by_screen2_tall[0] = 0xF040;
2435 switch (east_neighbor.large_index()) {
2437 by_screen2_tall[1] = 0x0040;
2440 by_screen2_tall[0] = 0xF040;
2446 for (
int j = 0; j < 2; j++) {
2448 by_screen2_tall[j]));
2452 std::array<uint16_t, 2> by_screen3_tall = {0x1800, 0x1800};
2455 if ((i % 0x40) - 8 >= 0) {
2460 north_neighbor.large_index() == 3) {
2461 by_screen3_tall[0] = 0x17C0;
2465 north_neighbor.large_index() == 1) {
2466 by_screen3_tall[0] = 0x17C0;
2470 for (
int j = 0; j < 2; j++) {
2472 by_screen3_tall[j]));
2476 std::array<uint16_t, 2> by_screen4_tall = {0x2000, 0x2000};
2484 south_neighbor.large_index() == 1) {
2485 by_screen4_tall[1] = 0x1FC0;
2489 south_neighbor.large_index() == 1) {
2490 by_screen4_tall[1] = 0x1FC0;
2494 for (
int j = 0; j < 2; j++) {
2496 by_screen4_tall[j]));
2499 return absl::OkStatus();
2503 util::logf(
"Saving Large Maps (v3+ Expanded)");
2515 std::vector<uint8_t> checked_map;
2520 if (std::find(checked_map.begin(), checked_map.end(), i) !=
2521 checked_map.end()) {
2537 i, parent_x_pos, parent_y_pos, transition_target_north,
2538 transition_target_west, transition_pos_x, transition_pos_y,
2539 screen_change_1, screen_change_2, screen_change_3,
2541 checked_map.emplace_back(i);
2546 i, parent_x_pos, parent_y_pos, transition_target_north,
2547 transition_target_west, transition_pos_x, transition_pos_y,
2548 screen_change_1, screen_change_2, screen_change_3,
2551 checked_map.emplace_back(i);
2552 checked_map.emplace_back(i + 1);
2553 checked_map.emplace_back(i + 8);
2554 checked_map.emplace_back(i + 9);
2559 i, parent_x_pos, parent_y_pos, transition_target_north,
2560 transition_target_west, transition_pos_x, transition_pos_y,
2561 screen_change_1, screen_change_2, screen_change_3,
2564 checked_map.emplace_back(i);
2565 checked_map.emplace_back(i + 1);
2570 i, parent_x_pos, parent_y_pos, transition_target_north,
2571 transition_target_west, transition_pos_x, transition_pos_y,
2572 screen_change_1, screen_change_2, screen_change_3,
2575 checked_map.emplace_back(i);
2576 checked_map.emplace_back(i + 8);
2581 return absl::OkStatus();
2586 std::vector<uint64_t> all_tile_16;
2601 for (
int y = 0; y < 32; y += 2) {
2602 for (
int x = 0; x < 32; x += 2) {
2604 tiles_used[x + (sx * 32)][y + (sy * 32)],
2605 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
2606 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
2607 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
2639 std::vector<uint64_t> all_tile_16 = GetAllTile16(
map_tiles_);
2642 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
2644 std::vector<uint64_t> unique_tiles(all_tile_16);
2645 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
2648 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
2649 for (
size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
2650 all_tiles_indexed.insert(
2651 {unique_tiles[tile32_id],
static_cast<uint16_t
>(tile32_id)});
2657 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
2661 for (
size_t i = 0; i < unique_tiles.size(); ++i) {
2671 ValidateMap32DefinitionCount(
tiles32_unique_.size(), storage_layout));
2676 <<
" Out of: " << storage_layout.definition_capacity << std::endl;
2679 return absl::OkStatus();
2685 if (!storage_layout.expanded) {
2686 return absl::FailedPreconditionError(
2687 "Expanded Tile32 save requested for a vanilla Tile32 layout");
2692 ValidateMap32DefinitionCount(
tiles32_unique_.size(), storage_layout));
2723 int unique_tile_index = 0;
2757 auto top_right = topRight;
2762 top_right + (i + 1),
2765 top_right + (i + 2),
2768 top_right + (i + 3),
2772 top_right + (i + 4),
2777 top_right + (i + 5),
2784 auto bottom_left = bottomLeft;
2789 bottom_left + (i + 1),
2792 bottom_left + (i + 2),
2795 bottom_left + (i + 3),
2799 bottom_left + (i + 4),
2804 bottom_left + (i + 5),
2811 auto bottom_right = bottomRight;
2816 bottom_right + (i + 1),
2819 bottom_right + (i + 2),
2822 bottom_right + (i + 3),
2826 bottom_right + (i + 4),
2831 bottom_right + (i + 5),
2837 unique_tile_index += 4;
2840 return absl::OkStatus();
2847 if (storage_layout.expanded) {
2848 return absl::FailedPreconditionError(
2849 "Vanilla Tile32 save requested for an expanded Tile32 layout");
2852 ValidateMap32DefinitionCount(
tiles32_unique_.size(), storage_layout));
2854 int unique_tile_index = 0;
2894 top_right + (i + 1),
2897 top_right + (i + 2),
2900 top_right + (i + 3),
2904 top_right + (i + 4),
2909 top_right + (i + 5),
2969 unique_tile_index += 4;
2972 return absl::OkStatus();
3046 static_cast<uint8_t
>(
PcToSnes(map16_expanded) >> 16)));
3049 static_cast<uint8_t
>(
PcToSnes(map16_expanded) >> 16)));
3051 int tpos = map16_expanded;
3055 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)));
3058 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)));
3061 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)));
3064 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)));
3068 return absl::OkStatus();
3077 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)))
3080 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)))
3083 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)))
3086 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)))
3089 return absl::OkStatus();
3096 return absl::OkStatus();
3101 return absl::OkStatus();
3114 return absl::OkStatus();
3121 std::vector<uint8_t> new_overlay_code = {
3127 0xBF, 0x00, 0x00, 0x00,
3129 0xBF, 0x00, 0x00, 0x00,
3145 int snes_ptr_start =
PcToSnes(ptr_start);
3155 constexpr int kExpandedOverlaySpace = 0x120000;
3156 int pos = kExpandedOverlaySpace;
3167 for (
size_t t = 0; t < overlay_data.size(); t += 3) {
3168 if (t + 2 < overlay_data.size()) {
3172 pos + 1, overlay_data[t] | (overlay_data[t + 1] << 8)));
3186 return absl::OkStatus();
3197 return absl::OkStatus();
3207 if (enable_flag != 0x00 && enable_flag != 0xFF) {
3209 std::array<uint8_t, kDiggableTilesBitfieldSize> bitfield;
3220 return absl::OkStatus();
3228 return absl::OkStatus();
3243 return absl::OkStatus();
3252 for (uint16_t tile_id = 0; tile_id < static_cast<uint16_t>(
tiles16_.size()) &&
3260 util::logf(
"Auto-detected %d diggable tiles",
3262 return absl::OkStatus();
3266 bool enable_main_palette,
3268 bool enable_gfx_groups,
3269 bool enable_subscreen_overlay,
3270 bool enable_animated) {
3274 return absl::OkStatus();
3279 const auto write_enable_flag = [
this](
int address,
3280 bool enabled) -> absl::Status {
3282 if ((current != 0x00) == enabled) {
3283 return absl::OkStatus();
3285 return rom()->WriteByte(address, enabled ? 0xFF : 0x00);
3293 enable_main_palette));
3296 if (enable_main_palette) {
3309 enable_gfx_groups));
3313 enable_subscreen_overlay));
3316 if (enable_mosaic) {
3320 uint8_t mosaic_byte = (mosaic[0] ? 0x08 : 0x00) |
3321 (mosaic[1] ? 0x04 : 0x00) |
3322 (mosaic[2] ? 0x02 : 0x00) |
3323 (mosaic[3] ? 0x01 : 0x00);
3330 if (enable_gfx_groups) {
3332 for (
int j = 0; j < 8; j++) {
3339 if (enable_animated) {
3347 if (enable_subscreen_overlay) {
3356 return absl::OkStatus();
3362 return absl::OkStatus();
3365 util::logf(
"Saving Area Specific Background Colors");
3374 return absl::OkStatus();
3379 return absl::FailedPreconditionError(
"ROM not loaded");
3385 return absl::OkStatus();
3388 const auto enabled = [
this](
int address) {
3395 const bool subscreen_overlay_enabled =
3399 bg_color_enabled, main_palette_enabled, mosaic_enabled,
3400 gfx_groups_enabled, subscreen_overlay_enabled, animated_enabled));
3401 if (bg_color_enabled) {
3405 return absl::OkStatus();
3411 const bool use_zscustom_palette_table =
3413 const bool use_zscustom_special_tables =
3415 const int palette_table = use_zscustom_palette_table
3457 if (use_zscustom_special_tables) {
3461 if (use_zscustom_palette_table) {
3467 const int sprite_gfx_table =
3468 use_zscustom_special_tables
3471 const int sprite_palette_table =
3480 return absl::OkStatus();
3505 return absl::OkStatus();
3513 if (asm_version < 3 || asm_version == 0xFF) {
3514 return absl::OkStatus();
3519 uint8_t area_size_byte =
3531 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
RAII timer for automatic timing management.
Tile composition of four 16x16 tiles.
uint64_t GetPackedValue() const
SNES 16-bit tile metadata container.
int GetDiggableCount() const
Get the count of tiles marked as diggable.
void SetVanillaDefaults()
Reset to vanilla diggable tiles.
void FromBytes(const uint8_t *data)
Load bitfield from raw bytes (64 bytes).
void SetDiggable(uint16_t tile_id, bool diggable)
Set or clear the diggable bit for a Map16 tile ID.
static bool IsTile16Diggable(const gfx::Tile16 &tile16, const std::array< uint8_t, 0x200 > &all_tiles_types)
Check if a Tile16 should be diggable based on its component tiles.
const std::array< uint8_t, kDiggableTilesBitfieldSize > & GetRawData() const
Get raw bitfield data for direct ROM writing.
void Clear()
Clear all diggable bits.
static bool SupportsCustomBGColors(OverworldVersion version)
Check if ROM supports custom background colors per area (v2+)
static OverworldVersion GetVersion(const Rom &rom)
Detect ROM version from ASM marker byte.
static bool SupportsAreaEnum(OverworldVersion version)
Check if ROM supports area enum system (v3+ only)
static const char * GetVersionName(OverworldVersion version)
Get human-readable version name for display/logging.
absl::Status SaveMap32Expanded()
Save expanded tile32 definitions (v1+ ROMs)
absl::Status DecompressAllMapTilesParallel()
std::vector< uint16_t > tiles32_list_
absl::Status Load(Rom *rom)
Load all overworld data from ROM.
std::vector< OverworldItem > all_items_
void OrganizeMapTiles(std::vector< uint8_t > &bytes, std::vector< uint8_t > &bytes2, int i, int sx, int sy, int &ttpos)
zelda3_version_pointers version_constants() const
Get version-specific ROM addresses.
std::array< int, kNumOverworldMaps > map_pointers1
std::vector< gfx::Tile32 > tiles32_unique_
const std::vector< uint8_t > & current_graphics() const
absl::Status SaveMapProperties()
Save per-area graphics, palettes, and messages.
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.
std::vector< OverworldEntrance > all_entrances_
absl::Status SaveTallAreaTransitions(int i, int parent_x_pos, int parent_y_pos, int transition_target_north, int transition_target_west, int transition_pos_x, int transition_pos_y, int screen_change_1, int screen_change_2, int screen_change_3, int screen_change_4)
Save screen transition data for tall (1x2) areas (v3+ only)
OverworldMapTiles map_tiles_
absl::Status SaveMap16Tiles()
Save tile16 definitions to ROM.
absl::Status SaveAreaSizes()
Save area size enum data (v3+ only)
void InvalidateSiblingMapCaches(int map_index)
Invalidate cached tilesets for a map and all its siblings.
absl::Status SaveLargeMaps()
Save large map parent/sibling relationships.
std::array< uint8_t, kNumOverworldMaps > map_parent_
void AssignWorldTiles(int x, int y, int sx, int sy, int tpos, OverworldBlockset &world)
absl::Status SaveDiggableTiles()
void InvalidateMapCache(int map_index)
Invalidate cached tileset for a specific map.
std::array< uint8_t, kNumTileTypes > all_tiles_types_
std::unordered_map< uint64_t, GraphicsConfigCache > gfx_config_cache_
void LoadTileTypes()
Load tile type collision data.
absl::Status CreateTile32Tilemap()
Build tile32 tilemap from current tile16 data.
std::array< int, kNumOverworldMaps > map_pointers1_id
const std::vector< uint8_t > * GetCachedTileset(uint64_t config_hash)
Try to get cached tileset data for a graphics configuration.
absl::Status SaveLargeAreaTransitions(int i, int parent_x_pos, int parent_y_pos, int transition_target_north, int transition_target_west, int transition_pos_x, int transition_pos_y, int screen_change_1, int screen_change_2, int screen_change_3, int screen_change_4)
Save screen transition data for large (2x2) areas.
OverworldBlockset & SelectWorldBlockset(int world_type)
bool HasExpandedPointerTables() const
Check if the ROM has expanded pointer tables for tail maps.
static constexpr int kMaxCachedConfigs
absl::Status SaveCustomOverworldASM(bool enable_bg_color, bool enable_main_palette, bool enable_mosaic, bool enable_gfx_groups, bool enable_subscreen_overlay, bool enable_animated)
Save custom ASM feature enable flags.
absl::Status SaveCustomOverworldData()
Save all v2/v3 property tables using the ROM's current feature flags.
void FillBlankMapTiles(int map_index)
auto mutable_overworld_map(int i)
absl::Status SaveEntrances()
Save entrance warp points to ROM.
absl::Status SaveExits()
Save exit return points to ROM.
absl::Status LoadSprites()
Load sprite data for all game states.
absl::Status EnsureMapBuilt(int map_index)
Build a map on-demand if it hasn't been built yet.
uint64_t ComputeGraphicsConfigHash(int map_index)
Compute hash of graphics configuration for cache lookup.
std::vector< OverworldMap > overworld_maps_
void CacheTileset(uint64_t config_hash, const std::vector< uint8_t > &tileset)
Cache tileset data for future reuse.
absl::Status SaveItems()
Save hidden overworld items to ROM.
absl::Status SaveAreaSpecificBGColors()
Save per-area background colors (v2+)
absl::Status LoadDiggableTiles()
absl::Status Save(Rom *rom)
Master save method (calls sub-methods in correct order)
absl::Status SaveWideAreaTransitions(int i, int parent_x_pos, int parent_y_pos, int transition_target_north, int transition_target_west, int transition_pos_x, int transition_pos_y, int screen_change_1, int screen_change_2, int screen_change_3, int screen_change_4)
Save screen transition data for wide (2x1) areas (v3+ only)
absl::Status SaveOverworldMaps()
Save compressed map tile data to ROM.
std::array< std::vector< Sprite >, 3 > all_sprites_
OverworldVersion cached_version_
std::array< int, kNumOverworldMaps > map_pointers2_id
absl::Status LoadOverworldMaps()
Load overworld map tile data.
std::vector< gfx::Tile16 > tiles16_
absl::Status AutoDetectDiggableTiles()
absl::Status AssembleMap16Tiles()
absl::Status LoadSpritesFromMap(int sprite_start, int sprite_count, int sprite_index)
Load sprites from a specific map range.
std::array< std::vector< uint8_t >, kNumOverworldMaps > map_data_p1
absl::Status SaveLargeMapsExpanded()
Save expanded large map data (v1+ ROMs)
void AssignMapSizes(std::vector< OverworldMap > &maps)
Assign map sizes based on area size enum (v3+)
absl::Status SaveMap16Expanded()
Save expanded tile16 definitions (v1+ ROMs)
std::vector< OverworldExit > all_exits_
std::array< int, kNumOverworldMaps > map_pointers2
absl::StatusOr< uint16_t > GetTile16ForTile32(int index, int quadrant, int dimension, const uint32_t *map32address)
std::array< std::vector< uint8_t >, kNumOverworldMaps > map_data_p2
absl::Status SaveSmallAreaTransitions(int i, int parent_x_pos, int parent_y_pos, int transition_target_north, int transition_target_west, int transition_pos_x, int transition_pos_y, int screen_change_1, int screen_change_2, int screen_change_3, int screen_change_4)
Save screen transition data for small (1x1) areas.
std::deque< int > built_map_lru_
absl::Status SaveMapOverlays()
Save interactive overlay data to ROM.
absl::Status AssembleMap32Tiles()
DiggableTiles diggable_tiles_
static constexpr int kMaxBuiltMaps
OverworldBlockset & GetMapTiles(int world_type)
absl::Status SaveOverworldTilesType()
Save tile type collision data to ROM.
absl::Status SaveMusic()
Save per-area music IDs.
absl::Status ConfigureMultiAreaMap(int parent_index, AreaSizeEnum size)
Configure a multi-area map structure (Large/Wide/Tall)
std::vector< OverworldEntrance > all_holes_
struct destination destination
Room transition destination.
#define LOG_DEBUG(category, format,...)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
std::vector< uint8_t > HyruleMagicDecompress(uint8_t const *src, int *const size, int const p_big_endian, size_t max_src_size)
TileInfo GetTilesInfo(uint16_t tile)
std::vector< uint8_t > HyruleMagicCompress(uint8_t const *const src, int const oldsize, int *const size, int const flag)
std::string HexByte(uint8_t byte, HexStringParams params)
void logf(const absl::FormatSpec< Args... > &format, Args &&... args)
std::string HexLong(uint32_t dword, HexStringParams params)
std::vector< uint64_t > GetAllTile16(OverworldMapTiles &map_tiles_)
absl::StatusOr< Map32StorageLayout > ResolveMap32StorageLayout(const Rom &rom, const zelda3_version_pointers &version_constants)
absl::Status ValidateMap32DefinitionCount(size_t definition_count, const Map32StorageLayout &layout)
Zelda 3 specific classes and functions.
constexpr int kDiggableTilesBitfieldSize
constexpr int kAreaGfxIdPtr
int GetOverworldMapParentIdExpanded()
absl::Status SaveEntrances(Rom *rom, const std::vector< OverworldEntrance > &entrances, bool expanded_entrances)
constexpr int OverworldCustomTileGFXGroupEnabled
constexpr int OverworldCustomAreaSpecificBGEnabled
constexpr int kOverworldTransitionPositionY
constexpr int kNumMapsPerWorld
constexpr int kOverworldSpriteset
int GetMap32TileBRExpanded()
int GetOverworldScreenChange3Expanded()
constexpr int kMap16ExpandedFlagPos
constexpr int NumberOfMap16Ex
int GetOverworldScreenChange4Expanded()
absl::StatusOr< std::vector< OverworldEntrance > > LoadEntrances(Rom *rom)
absl::Status SaveItems(Rom *rom, const std::vector< OverworldItem > &items)
constexpr int kOverworldScreenTileMapChangeByScreen1
constexpr int kOverworldMapDataOverflow
int LegacyParentTableIndexForMap(int map_index)
constexpr int kMap32BytesPerPackedGroup
constexpr int kOverworldMapSizeHighByte
absl::StatusOr< std::vector< OverworldItem > > LoadItems(Rom *rom, std::vector< OverworldMap > &overworld_maps)
constexpr int overworldSpritesBeginingExpanded
constexpr int kNumTileTypes
uint8_t ReadRomByteOr(const Rom &rom, int address, uint8_t fallback)
constexpr int NumberOfMap32
constexpr int kOverworldScreenSize
constexpr int kOverworldScreenTileMapChangeByScreen4
constexpr int kNumTile16Individual
int GetMap32TileTRExpanded()
constexpr int kSpecialWorldMapIdStart
constexpr int OverworldCustomMosaicArray
constexpr int kOverworldCustomDiggableTilesEnabled
constexpr int kMap16Tiles
constexpr int overworldSpritesAgahnimExpanded
int GetMap32TileBLExpanded()
constexpr int OverworldCustomAnimatedGFXEnabled
constexpr int Map32DefinitionCapacityForStorageBytes(int storage_bytes)
constexpr int OverworldCustomMainPaletteEnabled
constexpr int kNumOverworldMaps
constexpr int OverworldCustomMainPaletteArray
constexpr int kOverworldSpecialSpritePaletteExpandedTemp
constexpr int kOverworldSpecialSpriteGfxGroupExpandedTemp
constexpr int kOverworldMusicBeginning
std::vector< std::vector< uint16_t > > OverworldBlockset
Represents tile32 data for the overworld.
AreaSizeEnum
Area size enumeration for v3+ ROMs.
constexpr int kOverworldTransitionPositionX
constexpr int kOverworldMusicDarkWorld
constexpr int kOverworldSpecialPalGroup
constexpr int kOverworldScreenSizeForLoading
constexpr int kOverworldSpritePaletteIds
constexpr int overworldTilesType
constexpr int transition_target_westExpanded
int GetOverworldScreenChange1Expanded()
absl::StatusOr< std::vector< OverworldExit > > LoadExits(Rom *rom)
constexpr int kMap32TileCountExpanded
constexpr int kTransitionTargetWest
constexpr int OverworldCustomASMHasBeenApplied
constexpr int kOverworldMusicAgahnim
constexpr int kOverworldSpritesZelda
constexpr int kOverworldMapParentId
constexpr int kOverworldCustomDiggableTilesArray
constexpr int kMap32ExpandedFlagPos
constexpr int kMap32DefinitionsPerPackedGroup
int GetOverworldTransitionPositionXExpanded()
@ kZSCustomV1
Basic features, expanded pointers.
@ kVanilla
0xFF in ROM, no ZScream ASM applied
bool IsSameOverworldWorld(int a, int b)
constexpr int kOverworldPalettesScreenToSetNew
constexpr int kOverworldMusicMasterSword
constexpr int kOverworldMusicZelda
constexpr int transition_target_northExpanded
constexpr int NumberOfMap16
constexpr int kOverworldMapSize
constexpr int kOverworldScreenTileMapChangeByScreen2
constexpr int kOverworldSpecialSpritePalette
constexpr int OverworldCustomAnimatedGFXArray
constexpr int kDarkWorldMapIdStart
OverworldRomProfile DetectOverworldRomProfile(const Rom &rom)
absl::Status SaveHoles(Rom *rom, const std::vector< OverworldEntrance > &holes)
bool CanPersistLegacyScreenSize(int map_index)
absl::StatusOr< std::vector< OverworldEntrance > > LoadHoles(Rom *rom)
constexpr int OverworldCustomMosaicEnabled
constexpr int kEssentialMapsPerWorld
constexpr int kOverworldCompressedMapPos
constexpr int kMaxDiggableTileId
constexpr int kOverworldSpritesBeginning
constexpr int kOverworldSpecialSpriteGFXGroup
constexpr int kOverworldScreenTileMapChangeByScreen3
constexpr int OverworldCustomTileGFXGroupArray
bool CanPersistLegacyMultiAreaMap(int map_index)
uint8_t LegacyParentTableValueForMap(int parent_index)
int Map32StorageBytesForProfile(const OverworldRomProfile &profile)
constexpr int OverworldCustomSubscreenOverlayEnabled
constexpr int OverworldCustomAreaSpecificBGPalette
int GetOverworldMessagesExpanded()
constexpr int kOverworldSpritesAgahnim
int LegacyScreenSizeTableIndexForMap(int map_index)
constexpr int kTransitionTargetNorth
constexpr int overworldSpritesZeldaExpanded
constexpr int kOverworldCompressedOverflowPos
int GetOverworldScreenChange2Expanded()
constexpr int kOverlayCodeStart
absl::Status SaveExits(Rom *rom, const std::vector< OverworldExit > &exits)
int GetMap16TilesExpanded()
constexpr int kOverworldMapPaletteIds
int GetOverworldTransitionPositionYExpanded()
constexpr int kOverworldSpecialGfxGroup
constexpr int OverworldCustomSubscreenOverlayArray
uint32_t PcToSnes(uint32_t addr)
uint32_t SnesToPc(uint32_t addr) noexcept
#define RETURN_IF_ERROR(expr)
Room transition destination.
bool kEnableSpecialWorldExpansion
struct yaze::core::FeatureFlags::Flags::Overworld overworld
Overworld map tile32 data.
OverworldBlockset dark_world
OverworldBlockset special_world
OverworldBlockset light_world
std::array< int, 4 > destinations
int storage_bytes_per_quadrant
ROM data pointers for different game versions.
uint32_t kOverworldTilesType
uint32_t kCompressedAllMap32PointersHigh
uint32_t kCompressedAllMap32PointersLow