5#include <unordered_map>
9#include "absl/status/status.h"
23 if (
rom->size() == 0) {
24 return absl::InvalidArgumentError(
"ROM file not loaded");
44 return absl::OkStatus();
48 for (
int i = 128; i < 145; i++) {
58 std::array<bool, kNumMapsPerWorld> map_checked;
59 std::ranges::fill(map_checked,
false);
64 if (
int i = xx + (yy * 8); map_checked[i] ==
false) {
66 map_checked[i] =
true;
70 map_checked[i + 1] =
true;
74 map_checked[i + 8] =
true;
78 map_checked[i + 9] =
true;
85 map_checked[i] =
true;
101 int index,
int quadrant,
int dimension,
const uint32_t *map32address) {
103 auto arg1,
rom()->ReadByte(map32address[dimension] + quadrant + (index)));
105 rom()->ReadWord(map32address[dimension] + (index) +
106 (quadrant <= 1 ? 4 : 5)));
107 return (uint16_t)(arg1 +
108 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
112 constexpr int kMap32TilesLength = 0x33F0;
113 int num_tile32 = kMap32TilesLength;
114 uint32_t map32address[4] = {
rom()->version_constants().kMap32TileTL,
115 rom()->version_constants().kMap32TileTR,
116 rom()->version_constants().kMap32TileBL,
117 rom()->version_constants().kMap32TileBR};
120 map32address[0] =
rom()->version_constants().kMap32TileTL;
129 for (
int i = 0; i < num_tile32; i += 6) {
131 for (
int k = 0; k < 4; k++) {
155 for (
int i = 0; i < 0x200; i++) {
161 return absl::OkStatus();
174 for (
int i = 0; i < num_tile16; i += 1) {
187 tiles16_.emplace_back(t0, t1, t2, t3);
189 return absl::OkStatus();
194 int position_x1 = (x * 2) + (sx * 32);
195 int position_y1 = (y * 2) + (sy * 32);
196 int position_x2 = (x * 2) + 1 + (sx * 32);
197 int position_y2 = (y * 2) + 1 + (sy * 32);
205 std::vector<uint8_t> &bytes2,
int i,
int sx,
206 int sy,
int &ttpos) {
207 for (
int y = 0; y < 16; y++) {
208 for (
int x = 0; x < 16; x++) {
209 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
225 const auto get_ow_map_gfx_ptr = [
this](
int index, uint32_t map_ptr) {
226 int p = (
rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
227 (
rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
228 (
rom()->data()[map_ptr + (3 * index)]);
232 constexpr uint32_t kBaseLowest = 0x0FFFFF;
233 constexpr uint32_t kBaseHighest = 0x0F8000;
235 uint32_t lowest = kBaseLowest;
236 uint32_t highest = kBaseHighest;
241 auto p1 = get_ow_map_gfx_ptr(
242 i,
rom()->version_constants().kCompressedAllMap32PointersHigh);
243 auto p2 = get_ow_map_gfx_ptr(
244 i,
rom()->version_constants().kCompressedAllMap32PointersLow);
248 if (p1 >= highest) highest = p1;
249 if (p2 >= highest) highest = p2;
251 if (p1 <= lowest && p1 > kBaseHighest) lowest = p1;
252 if (p2 <= lowest && p2 > kBaseHighest) lowest = p2;
276 std::vector<std::future<absl::Status>> futures;
284 auto task_function = [
this, i, size, world_type]() {
288 futures.emplace_back(std::async(std::launch::async, task_function));
292 for (
auto &future : futures) {
296 return absl::OkStatus();
302 rom()->data()[
rom()->version_constants().kOverworldTilesType + i];
310 int num_entrances = 129;
319 for (
int i = 0; i < num_entrances; i++) {
321 rom()->ReadWord(ow_entrance_map_ptr + (i * 2)));
323 rom()->ReadWord(ow_entrance_pos_ptr + (i * 2)));
325 int p = map_pos >> 1;
328 bool deleted =
false;
329 if (map_pos == 0xFFFF) {
333 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
334 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id, map_pos,
338 return absl::OkStatus();
342 constexpr int kNumHoles = 0x13;
343 for (
int i = 0; i < kNumHoles; i++) {
350 int p = (map_pos + 0x400) >> 1;
354 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
355 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id,
356 (uint16_t)(map_pos + 0x400),
true);
358 return absl::OkStatus();
362 const int NumberOfOverworldExits = 0x4F;
363 std::vector<OverworldExit>
exits;
364 for (
int i = 0; i < NumberOfOverworldExits; i++) {
365 auto rom_data =
rom()->data();
367 uint16_t exit_room_id;
368 uint16_t exit_map_id;
370 uint16_t exit_y_scroll;
371 uint16_t exit_x_scroll;
372 uint16_t exit_y_player;
373 uint16_t exit_x_player;
374 uint16_t exit_y_camera;
375 uint16_t exit_x_camera;
376 uint16_t exit_scroll_mod_y;
377 uint16_t exit_scroll_mod_x;
378 uint16_t exit_door_type_1;
379 uint16_t exit_door_type_2;
387 exit_scroll_mod_x,
OWExitUnk2 + i, exit_door_type_1,
391 uint16_t py = (uint16_t)((rom_data[
OWExitYPlayer + (i * 2) + 1] << 8) +
393 uint16_t px = (uint16_t)((rom_data[
OWExitXPlayer + (i * 2) + 1] << 8) +
397 "Exit: %d RoomID: %d MapID: %d VRAM: %d YScroll: %d XScroll: "
398 "%d YPlayer: %d XPlayer: %d YCamera: %d XCamera: %d "
399 "ScrollModY: %d ScrollModX: %d DoorType1: %d DoorType2: %d",
400 i, exit_room_id, exit_map_id, exit_vram, exit_y_scroll, exit_x_scroll,
401 py, px, exit_y_camera, exit_x_camera, exit_scroll_mod_y,
402 exit_scroll_mod_x, exit_door_type_1, exit_door_type_2);
404 exits.emplace_back(exit_room_id, exit_map_id, exit_vram, exit_y_scroll,
405 exit_x_scroll, py, px, exit_y_camera, exit_x_camera,
406 exit_scroll_mod_y, exit_scroll_mod_x, exit_door_type_1,
407 exit_door_type_2, (px & py) == 0xFFFF);
410 return absl::OkStatus();
416 uint32_t pointer_pc =
SnesToPc(pointer);
417 for (
int i = 0; i < 128; i++) {
419 rom()->ReadWord(pointer_pc + i * 2));
420 uint32_t addr = (pointer & 0xFF0000) | word_address;
434 if (b1 == 0xFF && b2 == 0xFF) {
438 int p = (((b2 & 0x1F) << 8) + b1) >> 1;
449 int sx = fakeID - (sy * 8);
451 all_items_.emplace_back(b3, (uint16_t)i, (x * 16) + (sx * 512),
452 (y * 16) + (sy * 512),
false);
460 return absl::OkStatus();
464 std::vector<std::future<absl::Status>> futures;
465 futures.emplace_back(std::async(std::launch::async, [
this]() {
468 futures.emplace_back(std::async(std::launch::async, [
this]() {
471 futures.emplace_back(std::async(std::launch::async, [
this]() {
475 for (
auto &future : futures) {
479 return absl::OkStatus();
483 int num_maps_per_gamestate,
485 for (
int i = 0; i < num_maps_per_gamestate; i++) {
488 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
490 int sprite_address =
SnesToPc((0x09 << 0x10) | word_addr);
495 if (b1 == 0xFF)
break;
497 int editor_map_index = i;
498 if (game_state != 0) {
499 if (editor_map_index >= 128)
500 editor_map_index -= 128;
501 else if (editor_map_index >= 64)
502 editor_map_index -= 64;
504 int mapY = (editor_map_index / 8);
505 int mapX = (editor_map_index % 8);
507 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
508 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
511 (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY);
518 return absl::OkStatus();
530 return absl::OkStatus();
534 util::logf(
"Saving Overworld Maps");
543 std::vector<uint8_t> single_map_1(512);
544 std::vector<uint8_t> single_map_2(512);
548 for (
int y = 0; y < 16; y++) {
549 for (
int x = 0; x < 16; x++) {
551 single_map_1[npos] = packed & 0xFF;
552 single_map_2[npos] = (packed >> 8) & 0xFF;
561 if (a.empty() || b.empty()) {
562 return absl::AbortedError(
"Error compressing map gfx.");
569 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
573 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
574 util::logf(
"Pos set to overflow region for map %s at %s",
579 const auto compare_array = [](
const std::vector<uint8_t> &array1,
580 const std::vector<uint8_t> &array2) ->
bool {
581 if (array1.size() != array2.size()) {
585 for (
size_t i = 0; i < array1.size(); i++) {
586 if (array1[i] != array2[i]) {
594 for (
int j = 0; j < i; j++) {
608 std::copy(a.begin(), a.end(),
map_data_p1[i].begin());
611 util::logf(
"Saving map pointers1 and compressed data for map %s at %s",
614 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
621 util::logf(
"Saving map pointers1 for map %s at %s",
util::HexByte(i),
624 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
628 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
632 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
633 util::logf(
"Pos set to overflow region for map %s at %s",
640 std::copy(b.begin(), b.end(),
map_data_p2[i].begin());
643 util::logf(
"Saving map pointers2 and compressed data for map %s at %s",
646 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
653 util::logf(
"Saving map pointers2 for map %s at %s",
util::HexByte(i),
656 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
664 return absl::AbortedError(
"Too many maps data " + std::to_string(pos));
668 return absl::OkStatus();
672 util::logf(
"Saving Large Maps");
673 std::vector<uint8_t> checked_map;
685 if (std::find(checked_map.begin(), checked_map.end(), i) !=
693 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
694 for (
const auto &offset : large_map_offsets) {
719 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
722 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
726 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
729 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
733 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
736 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
740 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
743 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
747 (parent_x_pos * 0x200)));
749 (parent_y_pos * 0x200)));
753 (parent_x_pos * 0x200)));
756 (parent_y_pos * 0x200)));
761 (parent_x_pos * 0x200)));
764 (parent_y_pos * 0x200)));
768 (parent_x_pos * 0x200)));
771 (parent_y_pos * 0x200)));
780 if (parent_x_pos == 0) {
883 checked_map.emplace_back(i);
884 checked_map.emplace_back((i + 1));
885 checked_map.emplace_back((i + 8));
886 checked_map.emplace_back((i + 9));
908 if (i - 1 >= 0 && parent_x_pos != 0) {
920 if (i + 1 < 64 && parent_x_pos != 7) {
964 (uint16_t)((y_pos * 0x200) - 0xE0)));
966 (uint16_t)((x_pos * 0x200) - 0x100)));
973 checked_map.emplace_back(i);
977 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
980 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
982 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
984 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
986 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
988 return absl::OkStatus();
993 std::vector<uint64_t> all_tile_16;
1008 for (
int y = 0; y < 32; y += 2) {
1009 for (
int x = 0; x < 32; x += 2) {
1011 tiles_used[x + (sx * 32)][y + (sy * 32)],
1012 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
1013 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
1014 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
1043 std::vector<uint64_t> all_tile_16 = GetAllTile16(
map_tiles_);
1046 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
1048 std::vector<uint64_t> unique_tiles(all_tile_16);
1049 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
1052 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
1053 for (
size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
1054 all_tiles_indexed.insert(
1055 {unique_tiles[tile32_id],
static_cast<uint16_t
>(tile32_id)});
1061 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
1065 for (
size_t i = 0; i < unique_tiles.size(); ++i) {
1075 return absl::InternalError(absl::StrFormat(
1076 "Number of unique Tiles32: %d Out of: %d\nUnique Tile32 count exceed "
1077 "the limit\nThe ROM Has not been saved\nYou can fill maps with grass "
1078 "tiles to free some space\nOr use the option Clear DW Tiles in the "
1095 return absl::OkStatus();
1143 return absl::OkStatus();
1147 util::logf(
"Saving Map32 Tiles");
1148 constexpr int kMaxUniqueTiles = 0x4540;
1149 constexpr int kTilesPer32x32Tile = 6;
1151 int unique_tile_index = 0;
1154 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
1155 if (unique_tile_index >= kMaxUniqueTiles) {
1156 return absl::AbortedError(
"Too many unique tile32 definitions.");
1160 auto top_left =
rom()->version_constants().kMap32TileTL;
1188 auto top_right =
rom()->version_constants().kMap32TileTR;
1193 top_right + (i + 1),
1196 top_right + (i + 2),
1199 top_right + (i + 3),
1203 top_right + (i + 4),
1208 top_right + (i + 5),
1268 unique_tile_index += 4;
1269 num_unique_tiles += 2;
1272 return absl::OkStatus();
1350 return absl::OkStatus();
1354 util::logf(
"Saving Map16 Tiles");
1359 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)))
1362 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)))
1365 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)))
1368 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)))
1371 return absl::OkStatus();
1375 util::logf(
"Saving Entrances");
1405 return absl::OkStatus();
1409 util::logf(
"Saving Exits");
1438 return absl::OkStatus();
1443 std::vector<OverworldItem> item_array2) {
1444 if (item_array1.size() != item_array2.size()) {
1449 for (
size_t i = 0; i < item_array1.size(); i++) {
1451 for (
size_t j = 0; j < item_array2.size(); j++) {
1453 if (item_array1[i].x_ == item_array2[j].x_ &&
1454 item_array1[i].y_ == item_array2[j].y_ &&
1455 item_array1[i].id_ == item_array2[j].id_) {
1471 std::vector<std::vector<OverworldItem>> room_items(
1475 room_items[i] = std::vector<OverworldItem>();
1477 if (item.room_map_id_ == i) {
1478 room_items[i].emplace_back(item);
1479 if (item.id_ == 0x86) {
1481 0x16DC5 + (i * 2), (item.game_x_ + (item.game_y_ * 64)) * 2));
1490 int empty_pointer = 0;
1492 item_pointers_reuse[i] = -1;
1493 for (
int ci = 0; ci < i; ci++) {
1494 if (room_items[i].empty()) {
1495 item_pointers_reuse[i] = -2;
1500 if (CompareItemsArrays(
1501 std::vector<OverworldItem>(room_items[i].begin(),
1502 room_items[i].end()),
1503 std::vector<OverworldItem>(room_items[ci].begin(),
1504 room_items[ci].end()))) {
1505 item_pointers_reuse[i] = ci;
1512 if (item_pointers_reuse[i] == -1) {
1513 item_pointers[i] = data_pos;
1516 static_cast<short>(((item.game_y_ << 6) + item.game_x_) << 1);
1518 uint32_t data =
static_cast<uint8_t
>(map_pos & 0xFF) |
1519 static_cast<uint8_t
>(map_pos >> 8) |
1520 static_cast<uint8_t
>(item.id_);
1525 empty_pointer = data_pos;
1528 }
else if (item_pointers_reuse[i] == -2) {
1529 item_pointers[i] = empty_pointer;
1531 item_pointers[i] = item_pointers[item_pointers_reuse[i]];
1534 int snesaddr =
PcToSnes(item_pointers[i]);
1540 return absl::AbortedError(
"Too many items");
1543 util::logf(
"End of Items : %d", data_pos);
1545 return absl::OkStatus();
1549 util::logf(
"Saving Map Properties");
1596 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data.
Tile composition of four 16x16 tiles.
uint64_t GetPackedValue() const
SNES 16-bit tile metadata container.
absl::Status SaveMap32Expanded()
std::vector< uint16_t > tiles32_list_
absl::Status Load(Rom *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)
std::array< int, kNumOverworldMaps > map_pointers1
std::vector< gfx::Tile32 > tiles32_unique_
void DecompressAllMapTiles()
absl::Status SaveMapProperties()
absl::Status SaveMap32Tiles()
std::vector< OverworldEntrance > all_entrances_
OverworldMapTiles map_tiles_
absl::Status SaveMap16Tiles()
absl::Status SaveLargeMaps()
std::array< uint8_t, kNumOverworldMaps > map_parent_
void AssignWorldTiles(int x, int y, int sx, int sy, int tpos, OverworldBlockset &world)
std::array< uint8_t, kNumTileTypes > all_tiles_types_
absl::Status CreateTile32Tilemap()
std::array< int, kNumOverworldMaps > map_pointers1_id
absl::Status SaveEntrances()
absl::Status LoadSprites()
std::vector< OverworldMap > overworld_maps_
absl::Status LoadEntrances()
absl::Status Save(Rom *rom)
absl::Status SaveOverworldMaps()
std::array< std::vector< Sprite >, 3 > all_sprites_
std::array< int, kNumOverworldMaps > map_pointers2_id
absl::Status LoadOverworldMaps()
std::vector< gfx::Tile16 > tiles16_
absl::Status AssembleMap16Tiles()
absl::Status LoadSpritesFromMap(int sprite_start, int sprite_count, int sprite_index)
std::array< std::vector< uint8_t >, kNumOverworldMaps > map_data_p1
absl::Status SaveMap16Expanded()
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 AssembleMap32Tiles()
OverworldBlockset & GetMapTiles(int world_type)
std::vector< OverworldEntrance > all_holes_
#define RETURN_IF_ERROR(expression)
#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)
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)
std::string HexLong(uint32_t dword, HexStringParams params)
bool CompareItemsArrays(std::vector< OverworldItem > item_array1, std::vector< OverworldItem > item_array2)
std::vector< uint64_t > GetAllTile16(OverworldMapTiles &map_tiles_)
Zelda 3 specific classes and functions.
constexpr int OWExitYScroll
constexpr int kAreaGfxIdPtr
constexpr int kOverworldHoleArea
constexpr int kOverworldTransitionPositionY
constexpr int kOverworldEntrancePos
constexpr int kOverworldHoleEntrance
constexpr int kNumMapsPerWorld
constexpr int kOverworldSpriteset
constexpr int kMap16ExpandedFlagPos
constexpr int LimitOfMap32
constexpr int NumberOfMap16Ex
constexpr int kOverworldScreenTileMapChangeByScreen1
constexpr int kOverworldMapDataOverflow
constexpr int kOverworldMapSizeHighByte
constexpr int kOverworldEntranceEntranceIdExpanded
constexpr int kNumTileTypes
constexpr int NumberOfMap32
constexpr int kNumOverworldMapItemPointers
constexpr int kOverworldScreenSize
constexpr int kOverworldScreenTileMapChangeByScreen4
constexpr int kNumTile16Individual
constexpr int kNumOverworldHoles
constexpr int kSpecialWorldMapIdStart
constexpr int OWExitDoorType2
constexpr int kOverworldEntranceEntranceId
constexpr int kOverworldItemsAddress
constexpr int kMap16Tiles
constexpr int kOverworldHolePos
constexpr int kNumOverworldMaps
constexpr int kOverworldEntranceMap
constexpr int kOverworldItemsEndData
constexpr int OWExitYCamera
std::vector< std::vector< uint16_t > > OverworldBlockset
Represents tile32 data for the overworld.
constexpr int kMap32TileBLExpanded
constexpr int kOverworldTransitionPositionX
constexpr int OWExitXScroll
constexpr int OWExitRoomId
constexpr int OWExitXCamera
constexpr int OWExitYPlayer
constexpr int kOverworldScreenSizeForLoading
constexpr int kOverworldSpritePaletteIds
constexpr int kMap32TileBRExpanded
constexpr int kMap32TileCountExpanded
constexpr int OWExitMapId
constexpr int kTransitionTargetWest
constexpr int kOverworldSpritesZelda
constexpr int kOverworldMapParentId
constexpr int kMap32ExpandedFlagPos
constexpr int kOverworldEntrancePosExpanded
constexpr int OWExitDoorType1
constexpr int kOverworldItemsPointers
constexpr int kNumOverworldExits
constexpr int NumberOfMap16
constexpr int kOverworldMapSize
constexpr int kOverworldScreenTileMapChangeByScreen2
constexpr int kOverworldEntranceMapExpanded
constexpr int kDarkWorldMapIdStart
constexpr int kOverworldCompressedMapPos
constexpr int kOverworldSpritesBeginning
constexpr int kOverworldScreenTileMapChangeByScreen3
constexpr int kMap16TilesExpanded
constexpr int kOverworldEntranceExpandedFlagPos
constexpr int kNumOverworldEntrances
constexpr int kOverworldSpritesAgahnim
constexpr int kTransitionTargetNorth
constexpr int kOverworldCompressedOverflowPos
constexpr int kMap32TileTRExpanded
constexpr int OWExitXPlayer
constexpr int kOverworldMapPaletteIds
Main namespace for the application.
uint32_t PcToSnes(uint32_t addr)
uint32_t SnesToPc(uint32_t addr) noexcept
Overworld map tile32 data.
OverworldBlockset dark_world
OverworldBlockset special_world
OverworldBlockset light_world