12#include <unordered_map>
15#include "absl/status/status.h"
16#include "absl/status/statusor.h"
17#include "absl/strings/str_format.h"
39 if (
rom->size() == 0) {
40 return absl::InvalidArgumentError(
"ROM file not loaded");
125 return absl::OkStatus();
145 }
else if (i == parent + 1) {
147 }
else if (i == parent + 8) {
149 }
else if (i == parent + 9) {
160 std::array<bool, kNumOverworldMaps> map_checked{};
161 std::ranges::fill(map_checked,
false);
164 for (
int world_offset = 0; world_offset < 128; world_offset += 64) {
165 for (
int local = 0; local < 64; local++) {
166 int i = world_offset + local;
181 }
else if (i == parent + 1) {
183 }
else if (i == parent + 8) {
185 }
else if (i == parent + 9) {
190 map_checked[i] =
true;
195 std::array<int, 4> siblings = {parent, parent + 1, parent + 8,
197 int world_start = world_offset;
198 int world_end = world_offset + 64;
199 for (
int q = 0; q < 4; q++) {
200 int sibling = siblings[q];
202 if (sibling >= world_start && sibling < world_end &&
203 !map_checked[sibling]) {
205 map_checked[sibling] =
true;
211 map_checked[i] =
true;
229 int i = world + xx + (yy * 8);
231 if (i >=
static_cast<int>(map_checked.size())) {
235 if (!map_checked[i]) {
236 switch (maps[i].area_size()) {
238 map_checked[i] =
true;
243 map_checked[i] =
true;
244 maps[i].SetAsLargeMap(i, 0);
246 if (i + 1 <
static_cast<int>(maps.size())) {
247 map_checked[i + 1] =
true;
248 maps[i + 1].SetAsLargeMap(i, 1);
251 if (i + 8 <
static_cast<int>(maps.size())) {
252 map_checked[i + 8] =
true;
253 maps[i + 8].SetAsLargeMap(i, 2);
256 if (i + 9 <
static_cast<int>(maps.size())) {
257 map_checked[i + 9] =
true;
258 maps[i + 9].SetAsLargeMap(i, 3);
265 map_checked[i] =
true;
268 maps[i].SetParent(i);
271 if (i + 1 <
static_cast<int>(maps.size())) {
272 map_checked[i + 1] =
true;
273 maps[i + 1].SetParent(i);
281 map_checked[i] =
true;
284 maps[i].SetParent(i);
287 if (i + 8 <
static_cast<int>(maps.size())) {
288 map_checked[i + 8] =
true;
289 maps[i + 8].SetParent(i);
312 return absl::InvalidArgumentError(
313 absl::StrFormat(
"Invalid parent index: %d", parent_index));
322 return absl::FailedPreconditionError(
323 "Wide and Tall areas require ZSCustomOverworld v3+");
327 "ConfigureMultiAreaMap: parent=%d, current_size=%d, new_size=%d, "
331 static_cast<int>(size),
335 std::vector<int> old_siblings;
341 old_siblings = {old_parent, old_parent + 1, old_parent + 8,
345 old_siblings = {old_parent, old_parent + 1};
348 old_siblings = {old_parent, old_parent + 8};
351 old_siblings = {parent_index};
356 for (
int old_sibling : old_siblings) {
363 std::vector<int> new_siblings;
370 new_siblings = {parent_index};
374 new_siblings = {parent_index, parent_index + 1, parent_index + 8,
376 for (
size_t i = 0; i < new_siblings.size(); ++i) {
377 int sibling = new_siblings[i];
385 new_siblings = {parent_index, parent_index + 1};
386 for (
int sibling : new_siblings) {
395 new_siblings = {parent_index, parent_index + 8};
396 for (
int sibling : new_siblings) {
406 std::set<int> all_affected;
407 for (
int sibling : old_siblings) {
408 all_affected.insert(sibling);
410 for (
int sibling : new_siblings) {
411 all_affected.insert(sibling);
416 for (
int sibling : all_affected) {
429 for (
int sibling : all_affected) {
441 for (
int sibling : all_affected) {
456 "Configured %s area: parent=%d, old_siblings=%zu, new_siblings=%zu",
461 parent_index, old_siblings.size(), new_siblings.size());
463 return absl::OkStatus();
467 int index,
int quadrant,
int dimension,
const uint32_t* map32address) {
469 auto arg1,
rom()->ReadByte(map32address[dimension] + quadrant + (index)));
471 rom()->ReadWord(map32address[dimension] + (index) +
472 (quadrant <= 1 ? 4 : 5)));
473 return (uint16_t)(arg1 +
474 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
478 constexpr int kMap32TilesLength = 0x33F0;
479 int num_tile32 = kMap32TilesLength;
480 uint32_t map32address[4] = {
488 util::logf(
"Expanded tile32 flag: %d", expanded_flag);
489 if (expanded_flag != 0x04 ||
502 for (
int i = 0; i < num_tile32; i += 6) {
504 for (
int k = 0; k < 4; k++) {
528 for (
int i = 0; i < 0x200; i++) {
534 return absl::OkStatus();
545 util::logf(
"Expanded tile16 flag: %d", expanded_flag);
555 for (
int i = 0; i < num_tile16; i += 1) {
568 tiles16_.emplace_back(t0, t1, t2, t3);
570 return absl::OkStatus();
575 int position_x1 = (x * 2) + (sx * 32);
576 int position_y1 = (y * 2) + (sy * 32);
577 int position_x2 = (x * 2) + 1 + (sx * 32);
578 int position_y2 = (y * 2) + 1 + (sy * 32);
586 switch (world_type) {
605 int local_index = map_index % 64;
606 int sx = local_index % 8;
607 int sy = local_index / 8;
611 for (
int y = 0; y < 32; ++y) {
612 for (
int x = 0; x < 32; ++x) {
613 world[(sx * 32) + x][(sy * 32) + y] = 0;
619 std::vector<uint8_t>& bytes2,
int i,
int sx,
620 int sy,
int& ttpos) {
621 for (
int y = 0; y < 16; y++) {
622 for (
int x = 0; x < 16; x++) {
623 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
639 const auto get_ow_map_gfx_ptr = [
this](
int index, uint32_t map_ptr) {
640 int p = (
rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
641 (
rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
642 (
rom()->data()[map_ptr + (3 * index)]);
646 constexpr uint32_t kBaseLowest = 0x0FFFFF;
647 constexpr uint32_t kBaseHighest = 0x0F8000;
649 uint32_t lowest = kBaseLowest;
650 uint32_t highest = kBaseHighest;
657 const bool allow_special_tail =
663 if (!allow_special_tail &&
680 auto p1 = get_ow_map_gfx_ptr(
682 auto p2 = get_ow_map_gfx_ptr(
687 bool pointers_valid =
688 (p1 > 0 && p2 > 0 && p1 <
rom()->size() && p2 <
rom()->size());
689 if (!pointers_valid) {
711 if (p1 <= lowest && p1 > kBaseHighest)
713 if (p2 <= lowest && p2 > kBaseHighest)
717 size_t max_size_p2 =
rom()->size() - p2;
720 size_t max_size_p1 =
rom()->size() - p1;
725 if (bytes.empty() || bytes2.empty()) {
745 return absl::OkStatus();
755 constexpr int kDarkWorldEssential =
757 constexpr int kSpecialWorldEssential =
759 std::vector<int> essential_map_ids;
763 "Building essential maps only (first %d maps per world) for faster "
773 bool is_essential =
false;
775 if (i < kLightWorldEssential) {
784 essential_map_ids.push_back(i);
799 if (map->is_large_map() &&
801 if (map->parent() != i && !map->is_initialized()) {
804 map->set_sprite_graphics(0, 0x0E);
805 map->set_sprite_graphics(1, 0x0E);
806 map->set_sprite_graphics(2, 0x0E);
807 map->set_area_graphics(
811 }
else if (i == 0x88) {
812 map->set_area_graphics(0x51);
813 map->set_area_palette(0x00);
817 map->set_area_palette(
827 const std::vector<uint8_t>* cached_tileset =
832 if (!cached_tileset) {
842 std::vector<std::future<absl::Status>> futures;
846 bool is_essential =
false;
849 if (i < kLightWorldEssential) {
865 auto task_function = [
this, i, size, world_type]() {
869 futures.emplace_back(std::async(std::launch::async, task_function));
877 for (
auto& future : futures) {
883 for (
int map_index : essential_map_ids) {
888 util::logf(
"Essential maps built. Remaining maps will be built on-demand.");
889 return absl::OkStatus();
894 return absl::InvalidArgumentError(
"Invalid map index");
900 const bool allow_special_tail =
903 if (!allow_special_tail &&
909 return absl::OkStatus();
921 return absl::OkStatus();
953 if (map->parent() != map_index && !map->is_initialized()) {
959 map->set_sprite_graphics(0, 0x0E);
960 map->set_sprite_graphics(1, 0x0E);
961 map->set_sprite_graphics(2, 0x0E);
962 map->set_area_graphics(
966 }
else if (map_index == 0x88) {
967 map->set_area_graphics(0x51);
968 map->set_area_palette(0x00);
991 if (!cached_tileset) {
1022 hash ^=
static_cast<uint64_t
>(world_type) << 62;
1023 hash *= 0x517cc1b727220a95ULL;
1028 for (
int i = 0; i < 12; ++i) {
1029 hash ^=
static_cast<uint64_t
>(map->static_graphics(i)) << ((i % 8) * 8);
1030 hash *= 0x517cc1b727220a95ULL;
1037 hash *= 0x517cc1b727220a95ULL;
1041 for (
int i = 0; i < 3; ++i) {
1042 hash ^=
static_cast<uint64_t
>(map->sprite_graphics(i)) << (52 + i * 4);
1043 hash *= 0x517cc1b727220a95ULL;
1047 hash ^=
static_cast<uint64_t
>(map->area_graphics()) << 48;
1048 hash *= 0x517cc1b727220a95ULL;
1052 hash ^=
static_cast<uint64_t
>(map->main_gfx_id()) << 56;
1053 hash *= 0x517cc1b727220a95ULL;
1056 hash ^=
static_cast<uint64_t
>(map->parent()) << 40;
1057 hash *= 0x517cc1b727220a95ULL;
1063 hash ^=
static_cast<uint64_t
>(map_index) << 8;
1064 hash *= 0x517cc1b727220a95ULL;
1067 hash ^=
static_cast<uint64_t
>(map->main_palette()) << 24;
1068 hash *= 0x517cc1b727220a95ULL;
1071 hash ^=
static_cast<uint64_t
>(map->animated_gfx()) << 16;
1072 hash *= 0x517cc1b727220a95ULL;
1075 hash ^=
static_cast<uint64_t
>(map->area_palette()) << 32;
1076 hash *= 0x517cc1b727220a95ULL;
1080 hash ^=
static_cast<uint64_t
>(map->subscreen_overlay());
1081 hash *= 0x517cc1b727220a95ULL;
1089 it->second.reference_count++;
1090 return &it->second.current_gfx;
1096 const std::vector<uint8_t>& tileset) {
1103 if (it->second.reference_count < min_it->second.reference_count) {
1139 int parent_id = map->parent();
1140 std::vector<int> siblings;
1146 switch (map->area_size()) {
1148 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1151 siblings = {parent_id, parent_id + 1};
1154 siblings = {parent_id, parent_id + 8};
1157 siblings = {map_index};
1162 if (map->is_large_map()) {
1163 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1165 siblings = {map_index};
1170 for (
int sibling : siblings) {
1180#ifdef __EMSCRIPTEN__
1195 std::vector<std::future<absl::Status>> futures;
1199 futures.emplace_back(std::async(std::launch::async, [
this]() {
1202 futures.emplace_back(std::async(std::launch::async, [
this]() {
1205 futures.emplace_back(std::async(std::launch::async, [
this]() {
1210 futures.emplace_back(std::async(std::launch::async, [
this]() {
1213 futures.emplace_back(std::async(std::launch::async, [
this]() {
1216 futures.emplace_back(std::async(std::launch::async, [
this]() {
1221 for (
auto& future : futures) {
1226 return absl::OkStatus();
1230 int num_maps_per_gamestate,
1232 for (
int i = 0; i < num_maps_per_gamestate; i++) {
1236 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
1238 int sprite_address =
SnesToPc((0x09 << 0x10) | word_addr);
1246 int editor_map_index = i;
1247 if (game_state != 0) {
1248 if (editor_map_index >= 128)
1249 editor_map_index -= 128;
1250 else if (editor_map_index >= 64)
1251 editor_map_index -= 64;
1253 int mapY = (editor_map_index / 8);
1254 int mapX = (editor_map_index % 8);
1256 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
1257 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
1260 (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY);
1263 sprite_address += 3;
1267 return absl::OkStatus();
1293 return absl::OkStatus();
1310 std::vector<uint8_t> single_map_1(512);
1311 std::vector<uint8_t> single_map_2(512);
1315 for (
int y = 0; y < 16; y++) {
1316 for (
int x = 0; x < 16; x++) {
1318 single_map_1[npos] = packed & 0xFF;
1319 single_map_2[npos] = (packed >> 8) & 0xFF;
1328 if (a.empty() || b.empty()) {
1329 return absl::AbortedError(
"Error compressing map gfx.");
1336 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
1340 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
1341 util::logf(
"Pos set to overflow region for map %s at %s",
1346 const auto compare_array = [](
const std::vector<uint8_t>& array1,
1347 const std::vector<uint8_t>& array2) ->
bool {
1348 if (array1.size() != array2.size()) {
1352 for (
size_t i = 0; i < array1.size(); i++) {
1353 if (array1[i] != array2[i]) {
1361 for (
int j = 0; j < i; j++) {
1375 std::copy(a.begin(), a.end(),
map_data_p1[i].begin());
1378 util::logf(
"Saving map pointers1 and compressed data for map %s at %s",
1395 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
1399 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
1400 util::logf(
"Pos set to overflow region for map %s at %s",
1407 std::copy(b.begin(), b.end(),
map_data_p2[i].begin());
1410 util::logf(
"Saving map pointers2 and compressed data for map %s at %s",
1431 return absl::AbortedError(
"Too many maps data " + std::to_string(pos));
1435 return absl::OkStatus();
1440 std::vector<std::pair<uint32_t, uint32_t>> ranges;
1443 uint32_t map32address[4] = {
1446 int map32_len = 0x33F0;
1457 for (
int i = 0; i < 4; ++i) {
1458 if (map32address[i] > 0) {
1459 ranges.emplace_back(map32address[i], map32address[i] + map32_len);
1470 ranges.emplace_back(map16_addr, map16_addr + map16_len);
1476 constexpr uint32_t kCompressedBank0bEnd = 0x5FE70;
1477 constexpr uint32_t kCompressedBank0cStart = 0x60000;
1478 constexpr uint32_t kCompressedBank0cEnd = 0x6411F;
1486 kCompressedBank0bEnd);
1487 ranges.emplace_back(kCompressedBank0cStart, kCompressedBank0cEnd);
1498 bool use_expanded_transitions =
1501 if (use_expanded_transitions) {
1507 std::vector<uint8_t> checked_map;
1519 if (std::find(checked_map.begin(), checked_map.end(), i) !=
1520 checked_map.end()) {
1527 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
1528 for (
const auto& offset : large_map_offsets) {
1553 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1556 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1560 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1563 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1567 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1570 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1574 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1577 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1581 (parent_x_pos * 0x200)));
1583 (parent_y_pos * 0x200)));
1587 (parent_x_pos * 0x200)));
1590 (parent_y_pos * 0x200)));
1594 (parent_x_pos * 0x200)));
1597 (parent_y_pos * 0x200)));
1601 (parent_x_pos * 0x200)));
1604 (parent_y_pos * 0x200)));
1613 if (parent_x_pos == 0) {
1716 checked_map.emplace_back(i);
1717 checked_map.emplace_back((i + 1));
1718 checked_map.emplace_back((i + 8));
1719 checked_map.emplace_back((i + 9));
1741 if (i - 1 >= 0 && parent_x_pos != 0) {
1753 if (i + 1 < 64 && parent_x_pos != 7) {
1797 (uint16_t)((y_pos * 0x200) - 0xE0)));
1799 (uint16_t)((x_pos * 0x200) - 0x100)));
1806 checked_map.emplace_back(i);
1810 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
1813 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
1815 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
1817 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
1819 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
1821 return absl::OkStatus();
1825 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
1826 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
1827 int screen_change_1,
int screen_change_2,
int screen_change_3,
1828 int screen_change_4) {
1831 rom()->WriteShort(transition_target_north + (i * 2),
1832 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
1834 rom()->WriteShort(transition_target_west + (i * 2),
1835 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
1838 rom()->WriteShort(transition_pos_x + (i * 2), parent_x_pos * 0x0200));
1840 rom()->WriteShort(transition_pos_y + (i * 2), parent_y_pos * 0x0200));
1843 uint16_t by_screen1_small = 0x0060;
1846 if ((i % 0x40) - 1 >= 0) {
1851 west_neighbor.large_index() == 3) {
1852 by_screen1_small = 0xF060;
1856 west_neighbor.large_index() == 2) {
1857 by_screen1_small = 0xF060;
1862 rom()->WriteShort(screen_change_1 + (i * 2), by_screen1_small));
1865 uint16_t by_screen2_small = 0x0040;
1873 east_neighbor.large_index() == 2) {
1874 by_screen2_small = 0xF040;
1878 east_neighbor.large_index() == 2) {
1879 by_screen2_small = 0xF040;
1884 rom()->WriteShort(screen_change_2 + (i * 2), by_screen2_small));
1887 uint16_t by_screen3_small = 0x1800;
1890 if ((i % 0x40) - 8 >= 0) {
1895 north_neighbor.large_index() == 3) {
1896 by_screen3_small = 0x17C0;
1900 north_neighbor.large_index() == 1) {
1901 by_screen3_small = 0x17C0;
1906 rom()->WriteShort(screen_change_3 + (i * 2), by_screen3_small));
1909 uint16_t by_screen4_small = 0x1000;
1917 south_neighbor.large_index() == 1) {
1918 by_screen4_small = 0x0FC0;
1922 south_neighbor.large_index() == 1) {
1923 by_screen4_small = 0x0FC0;
1928 rom()->WriteShort(screen_change_4 + (i * 2), by_screen4_small));
1930 return absl::OkStatus();
1934 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
1935 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
1936 int screen_change_1,
int screen_change_2,
int screen_change_3,
1937 int screen_change_4) {
1939 const uint16_t offsets[] = {0, 2, 16, 18};
1940 for (
auto offset : offsets) {
1942 rom()->WriteShort(transition_target_north + (i * 2) + offset,
1943 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
1945 rom()->WriteShort(transition_target_west + (i * 2) + offset,
1946 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
1948 parent_x_pos * 0x0200));
1950 parent_y_pos * 0x0200));
1955 std::array<uint16_t, 4> by_screen1_large = {0x0060, 0x0060, 0x1060, 0x1060};
1958 if ((i % 0x40) - 1 >= 0) {
1962 switch (west_neighbor.large_index()) {
1964 by_screen1_large[2] = 0x0060;
1967 by_screen1_large[0] = 0xF060;
1971 switch (west_neighbor.large_index()) {
1973 by_screen1_large[2] = 0x0060;
1976 by_screen1_large[0] = 0xF060;
1982 for (
int j = 0; j < 4; j++) {
1984 by_screen1_large[j]));
1988 std::array<uint16_t, 4> by_screen2_large = {0x0080, 0x0080, 0x1080, 0x1080};
1995 switch (east_neighbor.large_index()) {
1997 by_screen2_large[3] = 0x0080;
2000 by_screen2_large[1] = 0xF080;
2004 switch (east_neighbor.large_index()) {
2006 by_screen2_large[3] = 0x0080;
2009 by_screen2_large[1] = 0xF080;
2015 for (
int j = 0; j < 4; j++) {
2017 by_screen2_large[j]));
2021 std::array<uint16_t, 4> by_screen3_large = {0x1800, 0x1840, 0x1800, 0x1840};
2024 if ((i % 0x40) - 8 >= 0) {
2028 switch (north_neighbor.large_index()) {
2030 by_screen3_large[1] = 0x1800;
2033 by_screen3_large[0] = 0x17C0;
2037 switch (north_neighbor.large_index()) {
2039 by_screen3_large[1] = 0x1800;
2042 by_screen3_large[0] = 0x17C0;
2048 for (
int j = 0; j < 4; j++) {
2050 by_screen3_large[j]));
2054 std::array<uint16_t, 4> by_screen4_large = {0x2000, 0x2040, 0x2000, 0x2040};
2061 switch (south_neighbor.large_index()) {
2063 by_screen4_large[3] = 0x2000;
2066 by_screen4_large[2] = 0x1FC0;
2070 switch (south_neighbor.large_index()) {
2072 by_screen4_large[3] = 0x2000;
2075 by_screen4_large[2] = 0x1FC0;
2081 for (
int j = 0; j < 4; j++) {
2083 by_screen4_large[j]));
2086 return absl::OkStatus();
2090 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
2091 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
2092 int screen_change_1,
int screen_change_2,
int screen_change_3,
2093 int screen_change_4) {
2095 const uint16_t offsets[] = {0, 2};
2096 for (
auto offset : offsets) {
2098 rom()->WriteShort(transition_target_north + (i * 2) + offset,
2099 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
2101 rom()->WriteShort(transition_target_west + (i * 2) + offset,
2102 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
2104 parent_x_pos * 0x0200));
2106 parent_y_pos * 0x0200));
2110 std::array<uint16_t, 2> by_screen1_wide = {0x0060, 0x0060};
2113 if ((i % 0x40) - 1 >= 0) {
2118 west_neighbor.large_index() == 3) {
2119 by_screen1_wide[0] = 0xF060;
2123 west_neighbor.large_index() == 2) {
2124 by_screen1_wide[0] = 0xF060;
2128 for (
int j = 0; j < 2; j++) {
2130 by_screen1_wide[j]));
2134 std::array<uint16_t, 2> by_screen2_wide = {0x0080, 0x0080};
2142 east_neighbor.large_index() == 2) {
2143 by_screen2_wide[1] = 0xF080;
2147 east_neighbor.large_index() == 2) {
2148 by_screen2_wide[1] = 0xF080;
2152 for (
int j = 0; j < 2; j++) {
2154 by_screen2_wide[j]));
2158 std::array<uint16_t, 2> by_screen3_wide = {0x1800, 0x1840};
2161 if ((i % 0x40) - 8 >= 0) {
2165 switch (north_neighbor.large_index()) {
2167 by_screen3_wide[1] = 0x1800;
2170 by_screen3_wide[0] = 0x17C0;
2174 switch (north_neighbor.large_index()) {
2176 by_screen3_wide[1] = 0x1800;
2179 by_screen3_wide[0] = 0x07C0;
2185 for (
int j = 0; j < 2; j++) {
2187 by_screen3_wide[j]));
2191 std::array<uint16_t, 2> by_screen4_wide = {0x1000, 0x1040};
2198 switch (south_neighbor.large_index()) {
2200 by_screen4_wide[1] = 0x1000;
2203 by_screen4_wide[0] = 0x0FC0;
2207 if (south_neighbor.large_index() == 1) {
2208 by_screen4_wide[0] = 0x0FC0;
2210 switch (south_neighbor.large_index()) {
2212 by_screen4_wide[1] = 0x1000;
2215 by_screen4_wide[0] = 0x0FC0;
2221 for (
int j = 0; j < 2; j++) {
2223 by_screen4_wide[j]));
2226 return absl::OkStatus();
2230 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
2231 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
2232 int screen_change_1,
int screen_change_2,
int screen_change_3,
2233 int screen_change_4) {
2235 const uint16_t offsets[] = {0, 16};
2236 for (
auto offset : offsets) {
2238 rom()->WriteShort(transition_target_north + (i * 2) + offset,
2239 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
2241 rom()->WriteShort(transition_target_west + (i * 2) + offset,
2242 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
2244 parent_x_pos * 0x0200));
2246 parent_y_pos * 0x0200));
2250 std::array<uint16_t, 2> by_screen1_tall = {0x0060, 0x1060};
2253 if ((i % 0x40) - 1 >= 0) {
2257 switch (west_neighbor.large_index()) {
2259 by_screen1_tall[1] = 0x0060;
2262 by_screen1_tall[0] = 0xF060;
2266 switch (west_neighbor.large_index()) {
2268 by_screen1_tall[1] = 0x0060;
2271 by_screen1_tall[0] = 0xF060;
2277 for (
int j = 0; j < 2; j++) {
2279 by_screen1_tall[j]));
2283 std::array<uint16_t, 2> by_screen2_tall = {0x0040, 0x1040};
2290 switch (east_neighbor.large_index()) {
2292 by_screen2_tall[1] = 0x0040;
2295 by_screen2_tall[0] = 0xF040;
2299 switch (east_neighbor.large_index()) {
2301 by_screen2_tall[1] = 0x0040;
2304 by_screen2_tall[0] = 0xF040;
2310 for (
int j = 0; j < 2; j++) {
2312 by_screen2_tall[j]));
2316 std::array<uint16_t, 2> by_screen3_tall = {0x1800, 0x1800};
2319 if ((i % 0x40) - 8 >= 0) {
2324 north_neighbor.large_index() == 3) {
2325 by_screen3_tall[0] = 0x17C0;
2329 north_neighbor.large_index() == 1) {
2330 by_screen3_tall[0] = 0x17C0;
2334 for (
int j = 0; j < 2; j++) {
2336 by_screen3_tall[j]));
2340 std::array<uint16_t, 2> by_screen4_tall = {0x2000, 0x2000};
2348 south_neighbor.large_index() == 1) {
2349 by_screen4_tall[1] = 0x1FC0;
2353 south_neighbor.large_index() == 1) {
2354 by_screen4_tall[1] = 0x1FC0;
2358 for (
int j = 0; j < 2; j++) {
2360 by_screen4_tall[j]));
2363 return absl::OkStatus();
2367 util::logf(
"Saving Large Maps (v3+ Expanded)");
2379 std::vector<uint8_t> checked_map;
2384 if (std::find(checked_map.begin(), checked_map.end(), i) !=
2385 checked_map.end()) {
2401 i, parent_x_pos, parent_y_pos, transition_target_north,
2402 transition_target_west, transition_pos_x, transition_pos_y,
2403 screen_change_1, screen_change_2, screen_change_3,
2405 checked_map.emplace_back(i);
2410 i, parent_x_pos, parent_y_pos, transition_target_north,
2411 transition_target_west, transition_pos_x, transition_pos_y,
2412 screen_change_1, screen_change_2, screen_change_3,
2415 checked_map.emplace_back(i);
2416 checked_map.emplace_back(i + 1);
2417 checked_map.emplace_back(i + 8);
2418 checked_map.emplace_back(i + 9);
2423 i, parent_x_pos, parent_y_pos, transition_target_north,
2424 transition_target_west, transition_pos_x, transition_pos_y,
2425 screen_change_1, screen_change_2, screen_change_3,
2428 checked_map.emplace_back(i);
2429 checked_map.emplace_back(i + 1);
2434 i, parent_x_pos, parent_y_pos, transition_target_north,
2435 transition_target_west, transition_pos_x, transition_pos_y,
2436 screen_change_1, screen_change_2, screen_change_3,
2439 checked_map.emplace_back(i);
2440 checked_map.emplace_back(i + 8);
2445 return absl::OkStatus();
2450 std::vector<uint64_t> all_tile_16;
2465 for (
int y = 0; y < 32; y += 2) {
2466 for (
int x = 0; x < 32; x += 2) {
2468 tiles_used[x + (sx * 32)][y + (sy * 32)],
2469 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
2470 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
2471 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
2500 std::vector<uint64_t> all_tile_16 = GetAllTile16(
map_tiles_);
2503 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
2505 std::vector<uint64_t> unique_tiles(all_tile_16);
2506 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
2509 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
2510 for (
size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
2511 all_tiles_indexed.insert(
2512 {unique_tiles[tile32_id],
static_cast<uint16_t
>(tile32_id)});
2518 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
2522 for (
size_t i = 0; i < unique_tiles.size(); ++i) {
2532 return absl::InternalError(absl::StrFormat(
2533 "Number of unique Tiles32: %d Out of: %d\nUnique Tile32 count exceed "
2534 "the limit\nThe ROM Has not been saved\nYou can fill maps with grass "
2535 "tiles to free some space\nOr use the option Clear DW Tiles in the "
2552 return absl::OkStatus();
2586 constexpr int kTilesPer32x32Tile = 6;
2587 int unique_tile_index = 0;
2590 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
2591 if (unique_tile_index >= limit) {
2592 return absl::AbortedError(
"Too many unique tile32 definitions.");
2623 auto top_right = topRight;
2628 top_right + (i + 1),
2631 top_right + (i + 2),
2634 top_right + (i + 3),
2638 top_right + (i + 4),
2643 top_right + (i + 5),
2650 auto bottom_left = bottomLeft;
2655 bottom_left + (i + 1),
2658 bottom_left + (i + 2),
2661 bottom_left + (i + 3),
2665 bottom_left + (i + 4),
2670 bottom_left + (i + 5),
2677 auto bottom_right = bottomRight;
2682 bottom_right + (i + 1),
2685 bottom_right + (i + 2),
2688 bottom_right + (i + 3),
2692 bottom_right + (i + 4),
2697 bottom_right + (i + 5),
2703 unique_tile_index += 4;
2706 return absl::OkStatus();
2711 constexpr int kMaxUniqueTiles = 0x4540;
2712 constexpr int kTilesPer32x32Tile = 6;
2714 int unique_tile_index = 0;
2717 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
2718 if (unique_tile_index >= kMaxUniqueTiles) {
2719 return absl::AbortedError(
"Too many unique tile32 definitions.");
2756 top_right + (i + 1),
2759 top_right + (i + 2),
2762 top_right + (i + 3),
2766 top_right + (i + 4),
2771 top_right + (i + 5),
2831 unique_tile_index += 4;
2832 num_unique_tiles += 2;
2835 return absl::OkStatus();
2909 static_cast<uint8_t
>(
PcToSnes(map16_expanded) >> 16)));
2912 static_cast<uint8_t
>(
PcToSnes(map16_expanded) >> 16)));
2914 int tpos = map16_expanded;
2918 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)));
2921 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)));
2924 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)));
2927 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)));
2931 return absl::OkStatus();
2940 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)))
2943 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)))
2946 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)))
2949 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)))
2952 return absl::OkStatus();
2959 return absl::OkStatus();
2964 return absl::OkStatus();
2977 return absl::OkStatus();
2984 std::vector<uint8_t> new_overlay_code = {
2990 0xBF, 0x00, 0x00, 0x00,
2992 0xBF, 0x00, 0x00, 0x00,
3008 int snes_ptr_start =
PcToSnes(ptr_start);
3018 constexpr int kExpandedOverlaySpace = 0x120000;
3019 int pos = kExpandedOverlaySpace;
3030 for (
size_t t = 0; t < overlay_data.size(); t += 3) {
3031 if (t + 2 < overlay_data.size()) {
3035 pos + 1, overlay_data[t] | (overlay_data[t + 1] << 8)));
3049 return absl::OkStatus();
3060 return absl::OkStatus();
3070 if (enable_flag != 0x00 && enable_flag != 0xFF) {
3072 std::array<uint8_t, kDiggableTilesBitfieldSize> bitfield;
3083 return absl::OkStatus();
3091 return absl::OkStatus();
3106 return absl::OkStatus();
3115 for (uint16_t tile_id = 0; tile_id < static_cast<uint16_t>(
tiles16_.size()) &&
3123 util::logf(
"Auto-detected %d diggable tiles",
3125 return absl::OkStatus();
3129 bool enable_main_palette,
3131 bool enable_gfx_groups,
3132 bool enable_subscreen_overlay,
3133 bool enable_animated) {
3137 return absl::OkStatus();
3144 uint8_t enable_value = enable_bg_color ? 0xFF : 0x00;
3148 enable_value = enable_main_palette ? 0xFF : 0x00;
3161 uint8_t enable_value = enable_mosaic ? 0xFF : 0x00;
3165 enable_value = enable_gfx_groups ? 0xFF : 0x00;
3169 enable_value = enable_animated ? 0xFF : 0x00;
3173 enable_value = enable_subscreen_overlay ? 0xFF : 0x00;
3181 uint8_t mosaic_byte = (mosaic[0] ? 0x08 : 0x00) |
3182 (mosaic[1] ? 0x04 : 0x00) |
3183 (mosaic[2] ? 0x02 : 0x00) |
3184 (mosaic[3] ? 0x01 : 0x00);
3192 for (
int j = 0; j < 8; j++) {
3209 return absl::OkStatus();
3215 return absl::OkStatus();
3218 util::logf(
"Saving Area Specific Background Colors");
3227 return absl::OkStatus();
3278 return absl::OkStatus();
3303 return absl::OkStatus();
3311 if (asm_version < 3 || asm_version == 0xFF) {
3312 return absl::OkStatus();
3317 uint8_t area_size_byte =
3329 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 bool SupportsExpandedSpace(OverworldVersion version)
Check if ROM uses expanded ROM space for overworld data.
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.
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_
#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_)
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 LimitOfMap32
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
constexpr int kOverworldMapSizeHighByte
absl::StatusOr< std::vector< OverworldItem > > LoadItems(Rom *rom, std::vector< OverworldMap > &overworld_maps)
constexpr int overworldSpritesBeginingExpanded
constexpr int kNumTileTypes
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 OverworldCustomMainPaletteEnabled
constexpr int kNumOverworldMaps
constexpr int OverworldCustomMainPaletteArray
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
int GetOverworldTransitionPositionXExpanded()
@ kZSCustomV1
Basic features, expanded pointers.
@ kVanilla
0xFF in ROM, no ZScream ASM applied
constexpr int kOverworldMusicMasterSword
constexpr int kOverworldMusicZelda
constexpr int transition_target_northExpanded
constexpr int NumberOfMap16
constexpr int kOverworldMapSize
constexpr int kOverworldScreenTileMapChangeByScreen2
constexpr int OverworldCustomAnimatedGFXArray
constexpr int kDarkWorldMapIdStart
absl::Status SaveHoles(Rom *rom, const std::vector< OverworldEntrance > &holes)
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 kOverworldScreenTileMapChangeByScreen3
constexpr int OverworldCustomTileGFXGroupArray
constexpr int OverworldCustomSubscreenOverlayEnabled
constexpr int OverworldCustomAreaSpecificBGPalette
int GetOverworldMessagesExpanded()
constexpr int kOverworldSpritesAgahnim
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)
bool kEnableSpecialWorldExpansion
struct yaze::core::FeatureFlags::Flags::Overworld overworld
Overworld map tile32 data.
OverworldBlockset dark_world
OverworldBlockset special_world
OverworldBlockset light_world
uint32_t kOverworldTilesType
uint32_t kCompressedAllMap32PointersHigh
uint32_t kCompressedAllMap32PointersLow