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) {
428 for (
int sibling : all_affected) {
440 for (
int sibling : all_affected) {
455 "Configured %s area: parent=%d, old_siblings=%zu, new_siblings=%zu",
460 parent_index, old_siblings.size(), new_siblings.size());
462 return absl::OkStatus();
466 int index,
int quadrant,
int dimension,
const uint32_t* map32address) {
468 auto arg1,
rom()->ReadByte(map32address[dimension] + quadrant + (index)));
470 rom()->ReadWord(map32address[dimension] + (index) +
471 (quadrant <= 1 ? 4 : 5)));
472 return (uint16_t)(arg1 +
473 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
477 constexpr int kMap32TilesLength = 0x33F0;
478 int num_tile32 = kMap32TilesLength;
479 uint32_t map32address[4] = {
487 util::logf(
"Expanded tile32 flag: %d", expanded_flag);
488 if (expanded_flag != 0x04 ||
501 for (
int i = 0; i < num_tile32; i += 6) {
503 for (
int k = 0; k < 4; k++) {
527 for (
int i = 0; i < 0x200; i++) {
533 return absl::OkStatus();
544 util::logf(
"Expanded tile16 flag: %d", expanded_flag);
554 for (
int i = 0; i < num_tile16; i += 1) {
567 tiles16_.emplace_back(t0, t1, t2, t3);
569 return absl::OkStatus();
574 int position_x1 = (x * 2) + (sx * 32);
575 int position_y1 = (y * 2) + (sy * 32);
576 int position_x2 = (x * 2) + 1 + (sx * 32);
577 int position_y2 = (y * 2) + 1 + (sy * 32);
585 switch (world_type) {
604 int local_index = map_index % 64;
605 int sx = local_index % 8;
606 int sy = local_index / 8;
610 for (
int y = 0; y < 32; ++y) {
611 for (
int x = 0; x < 32; ++x) {
612 world[(sx * 32) + x][(sy * 32) + y] = 0;
618 std::vector<uint8_t>& bytes2,
int i,
int sx,
619 int sy,
int& ttpos) {
620 for (
int y = 0; y < 16; y++) {
621 for (
int x = 0; x < 16; x++) {
622 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
638 const auto get_ow_map_gfx_ptr = [
this](
int index, uint32_t map_ptr) {
639 int p = (
rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
640 (
rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
641 (
rom()->data()[map_ptr + (3 * index)]);
645 constexpr uint32_t kBaseLowest = 0x0FFFFF;
646 constexpr uint32_t kBaseHighest = 0x0F8000;
648 uint32_t lowest = kBaseLowest;
649 uint32_t highest = kBaseHighest;
656 const bool allow_special_tail =
662 if (!allow_special_tail &&
679 auto p1 = get_ow_map_gfx_ptr(
681 auto p2 = get_ow_map_gfx_ptr(
686 bool pointers_valid =
687 (p1 > 0 && p2 > 0 && p1 <
rom()->size() && p2 <
rom()->size());
688 if (!pointers_valid) {
710 if (p1 <= lowest && p1 > kBaseHighest)
712 if (p2 <= lowest && p2 > kBaseHighest)
716 size_t max_size_p2 =
rom()->size() - p2;
719 size_t max_size_p1 =
rom()->size() - p1;
724 if (bytes.empty() || bytes2.empty()) {
744 return absl::OkStatus();
755 constexpr int kEssentialMapsPerWorld = 4;
757 constexpr int kEssentialMapsPerWorld = 16;
759 constexpr int kLightWorldEssential = kEssentialMapsPerWorld;
760 constexpr int kDarkWorldEssential =
762 constexpr int kSpecialWorldEssential =
766 "Building essential maps only (first %d maps per world) for faster "
768 kEssentialMapsPerWorld);
776 bool is_essential =
false;
778 if (i < kLightWorldEssential) {
801 if (map->is_large_map() &&
803 if (map->parent() != i && !map->is_initialized()) {
806 map->set_sprite_graphics(0, 0x0E);
807 map->set_sprite_graphics(1, 0x0E);
808 map->set_sprite_graphics(2, 0x0E);
809 map->set_area_graphics(
813 }
else if (i == 0x88) {
814 map->set_area_graphics(0x51);
815 map->set_area_palette(0x00);
819 map->set_area_palette(
829 const std::vector<uint8_t>* cached_tileset =
834 if (!cached_tileset) {
843 std::vector<std::future<absl::Status>> futures;
847 bool is_essential =
false;
850 if (i < kLightWorldEssential) {
866 auto task_function = [
this, i, size, world_type]() {
870 futures.emplace_back(std::async(std::launch::async, task_function));
878 for (
auto& future : futures) {
884 util::logf(
"Essential maps built. Remaining maps will be built on-demand.");
885 return absl::OkStatus();
890 return absl::InvalidArgumentError(
"Invalid map index");
896 const bool allow_special_tail =
899 if (!allow_special_tail &&
905 return absl::OkStatus();
917 return absl::OkStatus();
949 if (map->parent() != map_index && !map->is_initialized()) {
955 map->set_sprite_graphics(0, 0x0E);
956 map->set_sprite_graphics(1, 0x0E);
957 map->set_sprite_graphics(2, 0x0E);
958 map->set_area_graphics(
962 }
else if (map_index == 0x88) {
963 map->set_area_graphics(0x51);
964 map->set_area_palette(0x00);
987 if (!cached_tileset) {
1018 hash ^=
static_cast<uint64_t
>(world_type) << 62;
1019 hash *= 0x517cc1b727220a95ULL;
1024 for (
int i = 0; i < 12; ++i) {
1025 hash ^=
static_cast<uint64_t
>(map->static_graphics(i)) << ((i % 8) * 8);
1026 hash *= 0x517cc1b727220a95ULL;
1033 hash *= 0x517cc1b727220a95ULL;
1037 for (
int i = 0; i < 3; ++i) {
1038 hash ^=
static_cast<uint64_t
>(map->sprite_graphics(i)) << (52 + i * 4);
1039 hash *= 0x517cc1b727220a95ULL;
1043 hash ^=
static_cast<uint64_t
>(map->area_graphics()) << 48;
1044 hash *= 0x517cc1b727220a95ULL;
1048 hash ^=
static_cast<uint64_t
>(map->main_gfx_id()) << 56;
1049 hash *= 0x517cc1b727220a95ULL;
1052 hash ^=
static_cast<uint64_t
>(map->parent()) << 40;
1053 hash *= 0x517cc1b727220a95ULL;
1059 hash ^=
static_cast<uint64_t
>(map_index) << 8;
1060 hash *= 0x517cc1b727220a95ULL;
1063 hash ^=
static_cast<uint64_t
>(map->main_palette()) << 24;
1064 hash *= 0x517cc1b727220a95ULL;
1067 hash ^=
static_cast<uint64_t
>(map->animated_gfx()) << 16;
1068 hash *= 0x517cc1b727220a95ULL;
1071 hash ^=
static_cast<uint64_t
>(map->area_palette()) << 32;
1072 hash *= 0x517cc1b727220a95ULL;
1076 hash ^=
static_cast<uint64_t
>(map->subscreen_overlay());
1077 hash *= 0x517cc1b727220a95ULL;
1085 it->second.reference_count++;
1086 return &it->second.current_gfx;
1092 const std::vector<uint8_t>& tileset) {
1099 if (it->second.reference_count < min_it->second.reference_count) {
1135 int parent_id = map->parent();
1136 std::vector<int> siblings;
1142 switch (map->area_size()) {
1144 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1147 siblings = {parent_id, parent_id + 1};
1150 siblings = {parent_id, parent_id + 8};
1153 siblings = {map_index};
1158 if (map->is_large_map()) {
1159 siblings = {parent_id, parent_id + 1, parent_id + 8, parent_id + 9};
1161 siblings = {map_index};
1166 for (
int sibling : siblings) {
1176#ifdef __EMSCRIPTEN__
1191 std::vector<std::future<absl::Status>> futures;
1195 futures.emplace_back(std::async(std::launch::async, [
this]() {
1198 futures.emplace_back(std::async(std::launch::async, [
this]() {
1201 futures.emplace_back(std::async(std::launch::async, [
this]() {
1206 futures.emplace_back(std::async(std::launch::async, [
this]() {
1209 futures.emplace_back(std::async(std::launch::async, [
this]() {
1212 futures.emplace_back(std::async(std::launch::async, [
this]() {
1217 for (
auto& future : futures) {
1222 return absl::OkStatus();
1226 int num_maps_per_gamestate,
1228 for (
int i = 0; i < num_maps_per_gamestate; i++) {
1232 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
1234 int sprite_address =
SnesToPc((0x09 << 0x10) | word_addr);
1242 int editor_map_index = i;
1243 if (game_state != 0) {
1244 if (editor_map_index >= 128)
1245 editor_map_index -= 128;
1246 else if (editor_map_index >= 64)
1247 editor_map_index -= 64;
1249 int mapY = (editor_map_index / 8);
1250 int mapX = (editor_map_index % 8);
1252 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
1253 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
1256 (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY);
1259 sprite_address += 3;
1263 return absl::OkStatus();
1289 return absl::OkStatus();
1306 std::vector<uint8_t> single_map_1(512);
1307 std::vector<uint8_t> single_map_2(512);
1311 for (
int y = 0; y < 16; y++) {
1312 for (
int x = 0; x < 16; x++) {
1314 single_map_1[npos] = packed & 0xFF;
1315 single_map_2[npos] = (packed >> 8) & 0xFF;
1324 if (a.empty() || b.empty()) {
1325 return absl::AbortedError(
"Error compressing map gfx.");
1332 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
1336 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
1337 util::logf(
"Pos set to overflow region for map %s at %s",
1342 const auto compare_array = [](
const std::vector<uint8_t>& array1,
1343 const std::vector<uint8_t>& array2) ->
bool {
1344 if (array1.size() != array2.size()) {
1348 for (
size_t i = 0; i < array1.size(); i++) {
1349 if (array1[i] != array2[i]) {
1357 for (
int j = 0; j < i; j++) {
1371 std::copy(a.begin(), a.end(),
map_data_p1[i].begin());
1374 util::logf(
"Saving map pointers1 and compressed data for map %s at %s",
1391 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
1395 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
1396 util::logf(
"Pos set to overflow region for map %s at %s",
1403 std::copy(b.begin(), b.end(),
map_data_p2[i].begin());
1406 util::logf(
"Saving map pointers2 and compressed data for map %s at %s",
1427 return absl::AbortedError(
"Too many maps data " + std::to_string(pos));
1431 return absl::OkStatus();
1436 std::vector<std::pair<uint32_t, uint32_t>> ranges;
1439 uint32_t map32address[4] = {
1442 int map32_len = 0x33F0;
1453 for (
int i = 0; i < 4; ++i) {
1454 if (map32address[i] > 0) {
1455 ranges.emplace_back(map32address[i], map32address[i] + map32_len);
1466 ranges.emplace_back(map16_addr, map16_addr + map16_len);
1472 constexpr uint32_t kCompressedBank0bEnd = 0x5FE70;
1473 constexpr uint32_t kCompressedBank0cStart = 0x60000;
1474 constexpr uint32_t kCompressedBank0cEnd = 0x6411F;
1482 ranges.emplace_back(kCompressedBank0cStart, kCompressedBank0cEnd);
1493 bool use_expanded_transitions =
1496 if (use_expanded_transitions) {
1502 std::vector<uint8_t> checked_map;
1514 if (std::find(checked_map.begin(), checked_map.end(), i) !=
1515 checked_map.end()) {
1522 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
1523 for (
const auto& offset : large_map_offsets) {
1548 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1551 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1555 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1558 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1562 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1565 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1569 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
1572 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
1576 (parent_x_pos * 0x200)));
1578 (parent_y_pos * 0x200)));
1582 (parent_x_pos * 0x200)));
1585 (parent_y_pos * 0x200)));
1589 (parent_x_pos * 0x200)));
1592 (parent_y_pos * 0x200)));
1596 (parent_x_pos * 0x200)));
1599 (parent_y_pos * 0x200)));
1608 if (parent_x_pos == 0) {
1711 checked_map.emplace_back(i);
1712 checked_map.emplace_back((i + 1));
1713 checked_map.emplace_back((i + 8));
1714 checked_map.emplace_back((i + 9));
1736 if (i - 1 >= 0 && parent_x_pos != 0) {
1748 if (i + 1 < 64 && parent_x_pos != 7) {
1792 (uint16_t)((y_pos * 0x200) - 0xE0)));
1794 (uint16_t)((x_pos * 0x200) - 0x100)));
1801 checked_map.emplace_back(i);
1805 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
1808 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
1810 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
1812 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
1814 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
1816 return absl::OkStatus();
1820 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
1821 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
1822 int screen_change_1,
int screen_change_2,
int screen_change_3,
1823 int screen_change_4) {
1826 rom()->WriteShort(transition_target_north + (i * 2),
1827 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
1829 rom()->WriteShort(transition_target_west + (i * 2),
1830 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
1833 rom()->WriteShort(transition_pos_x + (i * 2), parent_x_pos * 0x0200));
1835 rom()->WriteShort(transition_pos_y + (i * 2), parent_y_pos * 0x0200));
1838 uint16_t by_screen1_small = 0x0060;
1841 if ((i % 0x40) - 1 >= 0) {
1846 west_neighbor.large_index() == 3) {
1847 by_screen1_small = 0xF060;
1851 west_neighbor.large_index() == 2) {
1852 by_screen1_small = 0xF060;
1857 rom()->WriteShort(screen_change_1 + (i * 2), by_screen1_small));
1860 uint16_t by_screen2_small = 0x0040;
1868 east_neighbor.large_index() == 2) {
1869 by_screen2_small = 0xF040;
1873 east_neighbor.large_index() == 2) {
1874 by_screen2_small = 0xF040;
1879 rom()->WriteShort(screen_change_2 + (i * 2), by_screen2_small));
1882 uint16_t by_screen3_small = 0x1800;
1885 if ((i % 0x40) - 8 >= 0) {
1890 north_neighbor.large_index() == 3) {
1891 by_screen3_small = 0x17C0;
1895 north_neighbor.large_index() == 1) {
1896 by_screen3_small = 0x17C0;
1901 rom()->WriteShort(screen_change_3 + (i * 2), by_screen3_small));
1904 uint16_t by_screen4_small = 0x1000;
1912 south_neighbor.large_index() == 1) {
1913 by_screen4_small = 0x0FC0;
1917 south_neighbor.large_index() == 1) {
1918 by_screen4_small = 0x0FC0;
1923 rom()->WriteShort(screen_change_4 + (i * 2), by_screen4_small));
1925 return absl::OkStatus();
1929 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
1930 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
1931 int screen_change_1,
int screen_change_2,
int screen_change_3,
1932 int screen_change_4) {
1934 const uint16_t offsets[] = {0, 2, 16, 18};
1935 for (
auto offset : offsets) {
1937 rom()->WriteShort(transition_target_north + (i * 2) + offset,
1938 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
1940 rom()->WriteShort(transition_target_west + (i * 2) + offset,
1941 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
1943 parent_x_pos * 0x0200));
1945 parent_y_pos * 0x0200));
1950 std::array<uint16_t, 4> by_screen1_large = {0x0060, 0x0060, 0x1060, 0x1060};
1953 if ((i % 0x40) - 1 >= 0) {
1957 switch (west_neighbor.large_index()) {
1959 by_screen1_large[2] = 0x0060;
1962 by_screen1_large[0] = 0xF060;
1966 switch (west_neighbor.large_index()) {
1968 by_screen1_large[2] = 0x0060;
1971 by_screen1_large[0] = 0xF060;
1977 for (
int j = 0; j < 4; j++) {
1979 by_screen1_large[j]));
1983 std::array<uint16_t, 4> by_screen2_large = {0x0080, 0x0080, 0x1080, 0x1080};
1990 switch (east_neighbor.large_index()) {
1992 by_screen2_large[3] = 0x0080;
1995 by_screen2_large[1] = 0xF080;
1999 switch (east_neighbor.large_index()) {
2001 by_screen2_large[3] = 0x0080;
2004 by_screen2_large[1] = 0xF080;
2010 for (
int j = 0; j < 4; j++) {
2012 by_screen2_large[j]));
2016 std::array<uint16_t, 4> by_screen3_large = {0x1800, 0x1840, 0x1800, 0x1840};
2019 if ((i % 0x40) - 8 >= 0) {
2023 switch (north_neighbor.large_index()) {
2025 by_screen3_large[1] = 0x1800;
2028 by_screen3_large[0] = 0x17C0;
2032 switch (north_neighbor.large_index()) {
2034 by_screen3_large[1] = 0x1800;
2037 by_screen3_large[0] = 0x17C0;
2043 for (
int j = 0; j < 4; j++) {
2045 by_screen3_large[j]));
2049 std::array<uint16_t, 4> by_screen4_large = {0x2000, 0x2040, 0x2000, 0x2040};
2056 switch (south_neighbor.large_index()) {
2058 by_screen4_large[3] = 0x2000;
2061 by_screen4_large[2] = 0x1FC0;
2065 switch (south_neighbor.large_index()) {
2067 by_screen4_large[3] = 0x2000;
2070 by_screen4_large[2] = 0x1FC0;
2076 for (
int j = 0; j < 4; j++) {
2078 by_screen4_large[j]));
2081 return absl::OkStatus();
2085 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
2086 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
2087 int screen_change_1,
int screen_change_2,
int screen_change_3,
2088 int screen_change_4) {
2090 const uint16_t offsets[] = {0, 2};
2091 for (
auto offset : offsets) {
2093 rom()->WriteShort(transition_target_north + (i * 2) + offset,
2094 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
2096 rom()->WriteShort(transition_target_west + (i * 2) + offset,
2097 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
2099 parent_x_pos * 0x0200));
2101 parent_y_pos * 0x0200));
2105 std::array<uint16_t, 2> by_screen1_wide = {0x0060, 0x0060};
2108 if ((i % 0x40) - 1 >= 0) {
2113 west_neighbor.large_index() == 3) {
2114 by_screen1_wide[0] = 0xF060;
2118 west_neighbor.large_index() == 2) {
2119 by_screen1_wide[0] = 0xF060;
2123 for (
int j = 0; j < 2; j++) {
2125 by_screen1_wide[j]));
2129 std::array<uint16_t, 2> by_screen2_wide = {0x0080, 0x0080};
2137 east_neighbor.large_index() == 2) {
2138 by_screen2_wide[1] = 0xF080;
2142 east_neighbor.large_index() == 2) {
2143 by_screen2_wide[1] = 0xF080;
2147 for (
int j = 0; j < 2; j++) {
2149 by_screen2_wide[j]));
2153 std::array<uint16_t, 2> by_screen3_wide = {0x1800, 0x1840};
2156 if ((i % 0x40) - 8 >= 0) {
2160 switch (north_neighbor.large_index()) {
2162 by_screen3_wide[1] = 0x1800;
2165 by_screen3_wide[0] = 0x17C0;
2169 switch (north_neighbor.large_index()) {
2171 by_screen3_wide[1] = 0x1800;
2174 by_screen3_wide[0] = 0x07C0;
2180 for (
int j = 0; j < 2; j++) {
2182 by_screen3_wide[j]));
2186 std::array<uint16_t, 2> by_screen4_wide = {0x1000, 0x1040};
2193 switch (south_neighbor.large_index()) {
2195 by_screen4_wide[1] = 0x1000;
2198 by_screen4_wide[0] = 0x0FC0;
2202 if (south_neighbor.large_index() == 1) {
2203 by_screen4_wide[0] = 0x0FC0;
2205 switch (south_neighbor.large_index()) {
2207 by_screen4_wide[1] = 0x1000;
2210 by_screen4_wide[0] = 0x0FC0;
2216 for (
int j = 0; j < 2; j++) {
2218 by_screen4_wide[j]));
2221 return absl::OkStatus();
2225 int i,
int parent_x_pos,
int parent_y_pos,
int transition_target_north,
2226 int transition_target_west,
int transition_pos_x,
int transition_pos_y,
2227 int screen_change_1,
int screen_change_2,
int screen_change_3,
2228 int screen_change_4) {
2230 const uint16_t offsets[] = {0, 16};
2231 for (
auto offset : offsets) {
2233 rom()->WriteShort(transition_target_north + (i * 2) + offset,
2234 (uint16_t)((parent_y_pos * 0x0200) - 0x00E0)));
2236 rom()->WriteShort(transition_target_west + (i * 2) + offset,
2237 (uint16_t)((parent_x_pos * 0x0200) - 0x0100)));
2239 parent_x_pos * 0x0200));
2241 parent_y_pos * 0x0200));
2245 std::array<uint16_t, 2> by_screen1_tall = {0x0060, 0x1060};
2248 if ((i % 0x40) - 1 >= 0) {
2252 switch (west_neighbor.large_index()) {
2254 by_screen1_tall[1] = 0x0060;
2257 by_screen1_tall[0] = 0xF060;
2261 switch (west_neighbor.large_index()) {
2263 by_screen1_tall[1] = 0x0060;
2266 by_screen1_tall[0] = 0xF060;
2272 for (
int j = 0; j < 2; j++) {
2274 by_screen1_tall[j]));
2278 std::array<uint16_t, 2> by_screen2_tall = {0x0040, 0x1040};
2285 switch (east_neighbor.large_index()) {
2287 by_screen2_tall[1] = 0x0040;
2290 by_screen2_tall[0] = 0xF040;
2294 switch (east_neighbor.large_index()) {
2296 by_screen2_tall[1] = 0x0040;
2299 by_screen2_tall[0] = 0xF040;
2305 for (
int j = 0; j < 2; j++) {
2307 by_screen2_tall[j]));
2311 std::array<uint16_t, 2> by_screen3_tall = {0x1800, 0x1800};
2314 if ((i % 0x40) - 8 >= 0) {
2319 north_neighbor.large_index() == 3) {
2320 by_screen3_tall[0] = 0x17C0;
2324 north_neighbor.large_index() == 1) {
2325 by_screen3_tall[0] = 0x17C0;
2329 for (
int j = 0; j < 2; j++) {
2331 by_screen3_tall[j]));
2335 std::array<uint16_t, 2> by_screen4_tall = {0x2000, 0x2000};
2343 south_neighbor.large_index() == 1) {
2344 by_screen4_tall[1] = 0x1FC0;
2348 south_neighbor.large_index() == 1) {
2349 by_screen4_tall[1] = 0x1FC0;
2353 for (
int j = 0; j < 2; j++) {
2355 by_screen4_tall[j]));
2358 return absl::OkStatus();
2362 util::logf(
"Saving Large Maps (v3+ Expanded)");
2374 std::vector<uint8_t> checked_map;
2379 if (std::find(checked_map.begin(), checked_map.end(), i) !=
2380 checked_map.end()) {
2395 i, parent_x_pos, parent_y_pos, transition_target_north,
2396 transition_target_west, transition_pos_x, transition_pos_y,
2397 screen_change_1, screen_change_2, screen_change_3,
2399 checked_map.emplace_back(i);
2404 i, parent_x_pos, parent_y_pos, transition_target_north,
2405 transition_target_west, transition_pos_x, transition_pos_y,
2406 screen_change_1, screen_change_2, screen_change_3,
2409 checked_map.emplace_back(i);
2410 checked_map.emplace_back(i + 1);
2411 checked_map.emplace_back(i + 8);
2412 checked_map.emplace_back(i + 9);
2417 i, parent_x_pos, parent_y_pos, transition_target_north,
2418 transition_target_west, transition_pos_x, transition_pos_y,
2419 screen_change_1, screen_change_2, screen_change_3,
2422 checked_map.emplace_back(i);
2423 checked_map.emplace_back(i + 1);
2428 i, parent_x_pos, parent_y_pos, transition_target_north,
2429 transition_target_west, transition_pos_x, transition_pos_y,
2430 screen_change_1, screen_change_2, screen_change_3,
2433 checked_map.emplace_back(i);
2434 checked_map.emplace_back(i + 8);
2439 return absl::OkStatus();
2444 std::vector<uint64_t> all_tile_16;
2459 for (
int y = 0; y < 32; y += 2) {
2460 for (
int x = 0; x < 32; x += 2) {
2462 tiles_used[x + (sx * 32)][y + (sy * 32)],
2463 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
2464 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
2465 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
2494 std::vector<uint64_t> all_tile_16 = GetAllTile16(
map_tiles_);
2497 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
2499 std::vector<uint64_t> unique_tiles(all_tile_16);
2500 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
2503 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
2504 for (
size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
2505 all_tiles_indexed.insert(
2506 {unique_tiles[tile32_id],
static_cast<uint16_t
>(tile32_id)});
2512 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
2516 for (
size_t i = 0; i < unique_tiles.size(); ++i) {
2526 return absl::InternalError(absl::StrFormat(
2527 "Number of unique Tiles32: %d Out of: %d\nUnique Tile32 count exceed "
2528 "the limit\nThe ROM Has not been saved\nYou can fill maps with grass "
2529 "tiles to free some space\nOr use the option Clear DW Tiles in the "
2546 return absl::OkStatus();
2580 constexpr int kTilesPer32x32Tile = 6;
2581 int unique_tile_index = 0;
2584 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
2585 if (unique_tile_index >= limit) {
2586 return absl::AbortedError(
"Too many unique tile32 definitions.");
2617 auto top_right = topRight;
2622 top_right + (i + 1),
2625 top_right + (i + 2),
2628 top_right + (i + 3),
2632 top_right + (i + 4),
2637 top_right + (i + 5),
2644 auto bottom_left = bottomLeft;
2649 bottom_left + (i + 1),
2652 bottom_left + (i + 2),
2655 bottom_left + (i + 3),
2659 bottom_left + (i + 4),
2664 bottom_left + (i + 5),
2671 auto bottom_right = bottomRight;
2676 bottom_right + (i + 1),
2679 bottom_right + (i + 2),
2682 bottom_right + (i + 3),
2686 bottom_right + (i + 4),
2691 bottom_right + (i + 5),
2697 unique_tile_index += 4;
2700 return absl::OkStatus();
2705 constexpr int kMaxUniqueTiles = 0x4540;
2706 constexpr int kTilesPer32x32Tile = 6;
2708 int unique_tile_index = 0;
2711 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
2712 if (unique_tile_index >= kMaxUniqueTiles) {
2713 return absl::AbortedError(
"Too many unique tile32 definitions.");
2750 top_right + (i + 1),
2753 top_right + (i + 2),
2756 top_right + (i + 3),
2760 top_right + (i + 4),
2765 top_right + (i + 5),
2825 unique_tile_index += 4;
2826 num_unique_tiles += 2;
2829 return absl::OkStatus();
2903 static_cast<uint8_t
>(
PcToSnes(map16_expanded) >> 16)));
2906 static_cast<uint8_t
>(
PcToSnes(map16_expanded) >> 16)));
2908 int tpos = map16_expanded;
2912 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)));
2915 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)));
2918 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)));
2921 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)));
2925 return absl::OkStatus();
2934 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)))
2937 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)))
2940 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)))
2943 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)))
2946 return absl::OkStatus();
2953 return absl::OkStatus();
2958 return absl::OkStatus();
2963 return absl::OkStatus();
2970 std::vector<uint8_t> new_overlay_code = {
2976 0xBF, 0x00, 0x00, 0x00,
2978 0xBF, 0x00, 0x00, 0x00,
2994 int snes_ptr_start =
PcToSnes(ptr_start);
3004 constexpr int kExpandedOverlaySpace = 0x120000;
3005 int pos = kExpandedOverlaySpace;
3016 for (
size_t t = 0; t < overlay_data.size(); t += 3) {
3017 if (t + 2 < overlay_data.size()) {
3021 pos + 1, overlay_data[t] | (overlay_data[t + 1] << 8)));
3035 return absl::OkStatus();
3046 return absl::OkStatus();
3056 if (enable_flag != 0x00 && enable_flag != 0xFF) {
3058 std::array<uint8_t, kDiggableTilesBitfieldSize> bitfield;
3069 return absl::OkStatus();
3077 return absl::OkStatus();
3092 return absl::OkStatus();
3101 for (uint16_t tile_id = 0; tile_id < static_cast<uint16_t>(
tiles16_.size()) &&
3109 util::logf(
"Auto-detected %d diggable tiles",
3111 return absl::OkStatus();
3115 bool enable_main_palette,
3117 bool enable_gfx_groups,
3118 bool enable_subscreen_overlay,
3119 bool enable_animated) {
3123 return absl::OkStatus();
3130 uint8_t enable_value = enable_bg_color ? 0xFF : 0x00;
3134 enable_value = enable_main_palette ? 0xFF : 0x00;
3147 uint8_t enable_value = enable_mosaic ? 0xFF : 0x00;
3151 enable_value = enable_gfx_groups ? 0xFF : 0x00;
3155 enable_value = enable_animated ? 0xFF : 0x00;
3159 enable_value = enable_subscreen_overlay ? 0xFF : 0x00;
3167 uint8_t mosaic_byte = (mosaic[0] ? 0x08 : 0x00) |
3168 (mosaic[1] ? 0x04 : 0x00) |
3169 (mosaic[2] ? 0x02 : 0x00) |
3170 (mosaic[3] ? 0x01 : 0x00);
3178 for (
int j = 0; j < 8; j++) {
3195 return absl::OkStatus();
3201 return absl::OkStatus();
3204 util::logf(
"Saving Area Specific Background Colors");
3213 return absl::OkStatus();
3264 return absl::OkStatus();
3289 return absl::OkStatus();
3297 if (asm_version < 3 || asm_version == 0xFF) {
3298 return absl::OkStatus();
3303 uint8_t area_size_byte =
3315 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_
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_
auto current_graphics() const
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 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