5#include <unordered_map>
8#include "absl/status/status.h"
21 if (
rom.size() == 0) {
22 return absl::InvalidArgumentError(
"ROM file not loaded");
42 return absl::OkStatus();
46 for (
int i = 128; i < 145; i++) {
56 std::array<bool, kNumMapsPerWorld> map_checked;
57 std::fill(map_checked.begin(), map_checked.end(),
false);
62 if (
int i = xx + (yy * 8); map_checked[i] ==
false) {
64 map_checked[i] =
true;
68 map_checked[i + 1] =
true;
72 map_checked[i + 8] =
true;
76 map_checked[i + 9] =
true;
83 map_checked[i] =
true;
99 int index,
int quadrant,
int dimension,
const uint32_t *map32address) {
101 rom_.ReadByte(map32address[dimension] + quadrant + (index)));
103 (quadrant <= 1 ? 4 : 5)));
104 return (uint16_t)(arg1 +
105 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
109 constexpr int kMap32TilesLength = 0x33F0;
110 int num_tile32 = kMap32TilesLength;
111 uint32_t map32address[4] = {
rom_.version_constants().kMap32TileTL,
112 rom_.version_constants().kMap32TileTR,
113 rom_.version_constants().kMap32TileBL,
114 rom_.version_constants().kMap32TileBR};
117 map32address[0] =
rom_.version_constants().kMap32TileTL;
126 for (
int i = 0; i < num_tile32; i += 6) {
128 for (
int k = 0; k < 4; k++) {
152 for (
int i = 0; i < 0x200; i++) {
158 return absl::OkStatus();
171 for (
int i = 0; i < num_tile16; i += 1) {
184 tiles16_.emplace_back(t0, t1, t2, t3);
186 return absl::OkStatus();
191 int position_x1 = (x * 2) + (sx * 32);
192 int position_y1 = (y * 2) + (sy * 32);
193 int position_x2 = (x * 2) + 1 + (sx * 32);
194 int position_y2 = (y * 2) + 1 + (sy * 32);
202 std::vector<uint8_t> &bytes2,
int i,
int sx,
203 int sy,
int &ttpos) {
204 for (
int y = 0; y < 16; y++) {
205 for (
int x = 0; x < 16; x++) {
206 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
222 const auto get_ow_map_gfx_ptr = [
this](
int index, uint32_t map_ptr) {
223 int p = (
rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
224 (
rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
225 (
rom()->data()[map_ptr + (3 * index)]);
229 constexpr uint32_t kBaseLowest = 0x0FFFFF;
230 constexpr uint32_t kBaseHighest = 0x0F8000;
232 uint32_t lowest = kBaseLowest;
233 uint32_t highest = kBaseHighest;
238 auto p1 = get_ow_map_gfx_ptr(
239 i,
rom()->version_constants().kCompressedAllMap32PointersHigh);
240 auto p2 = get_ow_map_gfx_ptr(
241 i,
rom()->version_constants().kCompressedAllMap32PointersLow);
245 if (p1 >= highest) highest = p1;
246 if (p2 >= highest) highest = p2;
248 if (p1 <= lowest && p1 > kBaseHighest) lowest = p1;
249 if (p2 <= lowest && p2 > kBaseHighest) lowest = p2;
273 std::vector<std::future<absl::Status>> futures;
281 auto task_function = [
this, i, size, world_type]() {
285 futures.emplace_back(std::async(std::launch::async, task_function));
289 for (
auto &future : futures) {
293 return absl::OkStatus();
299 rom()->data()[
rom()->version_constants().kOverworldTilesType + i];
307 int num_entrances = 129;
316 for (
int i = 0; i < num_entrances; i++) {
318 rom()->ReadWord(ow_entrance_map_ptr + (i * 2)));
320 rom()->ReadWord(ow_entrance_pos_ptr + (i * 2)));
322 int p = map_pos >> 1;
325 bool deleted =
false;
326 if (map_pos == 0xFFFF) {
330 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
331 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id, map_pos,
335 return absl::OkStatus();
339 constexpr int kNumHoles = 0x13;
340 for (
int i = 0; i < kNumHoles; i++) {
347 int p = (map_pos + 0x400) >> 1;
351 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
352 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id,
353 (uint16_t)(map_pos + 0x400),
true);
355 return absl::OkStatus();
359 const int NumberOfOverworldExits = 0x4F;
360 std::vector<OverworldExit>
exits;
361 for (
int i = 0; i < NumberOfOverworldExits; i++) {
362 auto rom_data =
rom()->data();
364 uint16_t exit_room_id;
365 uint16_t exit_map_id;
367 uint16_t exit_y_scroll;
368 uint16_t exit_x_scroll;
369 uint16_t exit_y_player;
370 uint16_t exit_x_player;
371 uint16_t exit_y_camera;
372 uint16_t exit_x_camera;
373 uint16_t exit_scroll_mod_y;
374 uint16_t exit_scroll_mod_x;
375 uint16_t exit_door_type_1;
376 uint16_t exit_door_type_2;
384 exit_scroll_mod_x,
OWExitUnk2 + i, exit_door_type_1,
388 uint16_t py = (uint16_t)((rom_data[
OWExitYPlayer + (i * 2) + 1] << 8) +
390 uint16_t px = (uint16_t)((rom_data[
OWExitXPlayer + (i * 2) + 1] << 8) +
394 "Exit: %d RoomID: %d MapID: %d VRAM: %d YScroll: %d XScroll: "
395 "%d YPlayer: %d XPlayer: %d YCamera: %d XCamera: %d "
396 "ScrollModY: %d ScrollModX: %d DoorType1: %d DoorType2: %d",
397 i, exit_room_id, exit_map_id, exit_vram, exit_y_scroll, exit_x_scroll,
398 py, px, exit_y_camera, exit_x_camera, exit_scroll_mod_y,
399 exit_scroll_mod_x, exit_door_type_1, exit_door_type_2);
401 exits.emplace_back(exit_room_id, exit_map_id, exit_vram, exit_y_scroll,
402 exit_x_scroll, py, px, exit_y_camera, exit_x_camera,
403 exit_scroll_mod_y, exit_scroll_mod_x, exit_door_type_1,
404 exit_door_type_2, (px & py) == 0xFFFF);
407 return absl::OkStatus();
413 uint32_t pointer_pc =
SnesToPc(pointer);
414 for (
int i = 0; i < 128; i++) {
416 rom()->ReadWord(pointer_pc + i * 2));
417 uint32_t addr = (pointer & 0xFF0000) | word_address;
431 if (b1 == 0xFF && b2 == 0xFF) {
435 int p = (((b2 & 0x1F) << 8) + b1) >> 1;
446 int sx = fakeID - (sy * 8);
448 all_items_.emplace_back(b3, (uint16_t)i, (x * 16) + (sx * 512),
449 (y * 16) + (sy * 512),
false);
457 return absl::OkStatus();
461 std::vector<std::future<absl::Status>> futures;
462 futures.emplace_back(std::async(std::launch::async, [
this]() {
465 futures.emplace_back(std::async(std::launch::async, [
this]() {
468 futures.emplace_back(std::async(std::launch::async, [
this]() {
472 for (
auto &future : futures) {
476 return absl::OkStatus();
480 int num_maps_per_gamestate,
482 for (
int i = 0; i < num_maps_per_gamestate; i++) {
485 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
487 int sprite_address =
SnesToPc((0x09 << 0x10) | word_addr);
492 if (b1 == 0xFF)
break;
494 int editor_map_index = i;
495 if (game_state != 0) {
496 if (editor_map_index >= 128)
497 editor_map_index -= 128;
498 else if (editor_map_index >= 64)
499 editor_map_index -= 64;
501 int mapY = (editor_map_index / 8);
502 int mapX = (editor_map_index % 8);
504 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
505 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
508 (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY);
515 return absl::OkStatus();
527 return absl::OkStatus();
531 util::logf(
"Saving Overworld Maps");
540 std::vector<uint8_t> single_map_1(512);
541 std::vector<uint8_t> single_map_2(512);
545 for (
int y = 0; y < 16; y++) {
546 for (
int x = 0; x < 16; x++) {
548 single_map_1[npos] = packed & 0xFF;
549 single_map_2[npos] = (packed >> 8) & 0xFF;
558 if (a.empty() || b.empty()) {
559 return absl::AbortedError(
"Error compressing map gfx.");
566 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
570 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
571 util::logf(
"Pos set to overflow region for map %s at %s",
576 const auto compare_array = [](
const std::vector<uint8_t> &array1,
577 const std::vector<uint8_t> &array2) ->
bool {
578 if (array1.size() != array2.size()) {
582 for (
size_t i = 0; i < array1.size(); i++) {
583 if (array1[i] != array2[i]) {
591 for (
int j = 0; j < i; j++) {
605 std::copy(a.begin(), a.end(),
map_data_p1[i].begin());
608 util::logf(
"Saving map pointers1 and compressed data for map %s at %s",
611 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
618 util::logf(
"Saving map pointers1 for map %s at %s",
util::HexByte(i),
621 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
625 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
629 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
630 util::logf(
"Pos set to overflow region for map %s at %s",
637 std::copy(b.begin(), b.end(),
map_data_p2[i].begin());
640 util::logf(
"Saving map pointers2 and compressed data for map %s at %s",
643 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
650 util::logf(
"Saving map pointers2 for map %s at %s",
util::HexByte(i),
653 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
661 return absl::AbortedError(
"Too many maps data " + std::to_string(pos));
665 return absl::OkStatus();
669 util::logf(
"Saving Large Maps");
670 std::vector<uint8_t> checked_map;
682 if (std::find(checked_map.begin(), checked_map.end(), i) !=
690 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
691 for (
const auto &offset : large_map_offsets) {
716 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
719 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
723 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
726 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
730 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
733 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
737 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
740 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
744 (parent_x_pos * 0x200)));
746 (parent_y_pos * 0x200)));
750 (parent_x_pos * 0x200)));
753 (parent_y_pos * 0x200)));
758 (parent_x_pos * 0x200)));
761 (parent_y_pos * 0x200)));
765 (parent_x_pos * 0x200)));
768 (parent_y_pos * 0x200)));
777 if (parent_x_pos == 0) {
880 checked_map.emplace_back(i);
881 checked_map.emplace_back((i + 1));
882 checked_map.emplace_back((i + 8));
883 checked_map.emplace_back((i + 9));
905 if (i - 1 >= 0 && parent_x_pos != 0) {
917 if (i + 1 < 64 && parent_x_pos != 7) {
961 (uint16_t)((y_pos * 0x200) - 0xE0)));
963 (uint16_t)((x_pos * 0x200) - 0x100)));
970 checked_map.emplace_back(i);
974 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
977 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
979 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
981 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
983 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
985 return absl::OkStatus();
990 std::vector<uint64_t> all_tile_16;
1005 for (
int y = 0; y < 32; y += 2) {
1006 for (
int x = 0; x < 32; x += 2) {
1008 tiles_used[x + (sx * 32)][y + (sy * 32)],
1009 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
1010 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
1011 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
1040 std::vector<uint64_t> all_tile_16 = GetAllTile16(
map_tiles_);
1043 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
1045 std::vector<uint64_t> unique_tiles(all_tile_16);
1046 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
1049 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
1050 for (
size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
1051 all_tiles_indexed.insert(
1052 {unique_tiles[tile32_id],
static_cast<uint16_t
>(tile32_id)});
1058 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
1062 for (
size_t i = 0; i < unique_tiles.size(); ++i) {
1072 return absl::InternalError(absl::StrFormat(
1073 "Number of unique Tiles32: %d Out of: %d\nUnique Tile32 count exceed "
1074 "the limit\nThe ROM Has not been saved\nYou can fill maps with grass "
1075 "tiles to free some space\nOr use the option Clear DW Tiles in the "
1092 return absl::OkStatus();
1140 return absl::OkStatus();
1144 util::logf(
"Saving Map32 Tiles");
1145 constexpr int kMaxUniqueTiles = 0x4540;
1146 constexpr int kTilesPer32x32Tile = 6;
1148 int unique_tile_index = 0;
1151 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
1152 if (unique_tile_index >= kMaxUniqueTiles) {
1153 return absl::AbortedError(
"Too many unique tile32 definitions.");
1157 auto top_left =
rom()->version_constants().kMap32TileTL;
1185 auto top_right =
rom()->version_constants().kMap32TileTR;
1190 top_right + (i + 1),
1193 top_right + (i + 2),
1196 top_right + (i + 3),
1200 top_right + (i + 4),
1205 top_right + (i + 5),
1265 unique_tile_index += 4;
1266 num_unique_tiles += 2;
1269 return absl::OkStatus();
1347 return absl::OkStatus();
1351 util::logf(
"Saving Map16 Tiles");
1356 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)))
1359 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)))
1362 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)))
1365 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)))
1368 return absl::OkStatus();
1372 util::logf(
"Saving Entrances");
1402 return absl::OkStatus();
1406 util::logf(
"Saving Exits");
1435 return absl::OkStatus();
1440 std::vector<OverworldItem> item_array2) {
1441 if (item_array1.size() != item_array2.size()) {
1446 for (
size_t i = 0; i < item_array1.size(); i++) {
1448 for (
size_t j = 0; j < item_array2.size(); j++) {
1450 if (item_array1[i].x_ == item_array2[j].x_ &&
1451 item_array1[i].y_ == item_array2[j].y_ &&
1452 item_array1[i].id_ == item_array2[j].id_) {
1468 std::vector<std::vector<OverworldItem>> room_items(
1472 room_items[i] = std::vector<OverworldItem>();
1474 if (item.room_map_id_ == i) {
1475 room_items[i].emplace_back(item);
1476 if (item.id_ == 0x86) {
1478 0x16DC5 + (i * 2), (item.game_x_ + (item.game_y_ * 64)) * 2));
1487 int empty_pointer = 0;
1489 item_pointers_reuse[i] = -1;
1490 for (
int ci = 0; ci < i; ci++) {
1491 if (room_items[i].empty()) {
1492 item_pointers_reuse[i] = -2;
1497 if (CompareItemsArrays(
1498 std::vector<OverworldItem>(room_items[i].begin(),
1499 room_items[i].end()),
1500 std::vector<OverworldItem>(room_items[ci].begin(),
1501 room_items[ci].end()))) {
1502 item_pointers_reuse[i] = ci;
1509 if (item_pointers_reuse[i] == -1) {
1510 item_pointers[i] = data_pos;
1513 static_cast<short>(((item.game_y_ << 6) + item.game_x_) << 1);
1515 uint32_t data =
static_cast<uint8_t
>(map_pos & 0xFF) |
1516 static_cast<uint8_t
>(map_pos >> 8) |
1517 static_cast<uint8_t
>(item.id_);
1522 empty_pointer = data_pos;
1525 }
else if (item_pointers_reuse[i] == -2) {
1526 item_pointers[i] = empty_pointer;
1528 item_pointers[i] = item_pointers[item_pointers_reuse[i]];
1531 int snesaddr =
PcToSnes(item_pointers[i]);
1537 return absl::AbortedError(
"Too many items");
1540 util::logf(
"End of Items : %d", data_pos);
1542 return absl::OkStatus();
1546 util::logf(
"Saving Map Properties");
1593 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 Save(Rom &rom)
absl::Status SaveEntrances()
absl::Status LoadSprites()
std::vector< OverworldMap > overworld_maps_
absl::Status LoadEntrances()
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