5#include <unordered_map>
8#include "absl/status/status.h"
22 if (
rom->size() == 0) {
23 return absl::InvalidArgumentError(
"ROM file not loaded");
43 return absl::OkStatus();
47 for (
int i = 128; i < 145; i++) {
57 std::array<bool, kNumMapsPerWorld> map_checked;
58 std::fill(map_checked.begin(), map_checked.end(),
false);
63 if (
int i = xx + (yy * 8); map_checked[i] ==
false) {
65 map_checked[i] =
true;
69 map_checked[i + 1] =
true;
73 map_checked[i + 8] =
true;
77 map_checked[i + 9] =
true;
84 map_checked[i] =
true;
100 int index,
int quadrant,
int dimension,
const uint32_t *map32address) {
102 auto arg1,
rom()->ReadByte(map32address[dimension] + quadrant + (index)));
104 rom()->ReadWord(map32address[dimension] + (index) +
105 (quadrant <= 1 ? 4 : 5)));
106 return (uint16_t)(arg1 +
107 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
111 constexpr int kMap32TilesLength = 0x33F0;
112 int num_tile32 = kMap32TilesLength;
113 uint32_t map32address[4] = {
rom()->version_constants().kMap32TileTL,
114 rom()->version_constants().kMap32TileTR,
115 rom()->version_constants().kMap32TileBL,
116 rom()->version_constants().kMap32TileBR};
119 map32address[0] =
rom()->version_constants().kMap32TileTL;
128 for (
int i = 0; i < num_tile32; i += 6) {
130 for (
int k = 0; k < 4; k++) {
154 for (
int i = 0; i < 0x200; i++) {
160 return absl::OkStatus();
173 for (
int i = 0; i < num_tile16; i += 1) {
186 tiles16_.emplace_back(t0, t1, t2, t3);
188 return absl::OkStatus();
193 int position_x1 = (x * 2) + (sx * 32);
194 int position_y1 = (y * 2) + (sy * 32);
195 int position_x2 = (x * 2) + 1 + (sx * 32);
196 int position_y2 = (y * 2) + 1 + (sy * 32);
204 std::vector<uint8_t> &bytes2,
int i,
int sx,
205 int sy,
int &ttpos) {
206 for (
int y = 0; y < 16; y++) {
207 for (
int x = 0; x < 16; x++) {
208 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
224 const auto get_ow_map_gfx_ptr = [
this](
int index, uint32_t map_ptr) {
225 int p = (
rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
226 (
rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
227 (
rom()->data()[map_ptr + (3 * index)]);
231 constexpr uint32_t kBaseLowest = 0x0FFFFF;
232 constexpr uint32_t kBaseHighest = 0x0F8000;
234 uint32_t lowest = kBaseLowest;
235 uint32_t highest = kBaseHighest;
240 auto p1 = get_ow_map_gfx_ptr(
241 i,
rom()->version_constants().kCompressedAllMap32PointersHigh);
242 auto p2 = get_ow_map_gfx_ptr(
243 i,
rom()->version_constants().kCompressedAllMap32PointersLow);
247 if (p1 >= highest) highest = p1;
248 if (p2 >= highest) highest = p2;
250 if (p1 <= lowest && p1 > kBaseHighest) lowest = p1;
251 if (p2 <= lowest && p2 > kBaseHighest) lowest = p2;
275 std::vector<std::future<absl::Status>> futures;
283 auto task_function = [
this, i, size, world_type]() {
287 futures.emplace_back(std::async(std::launch::async, task_function));
291 for (
auto &future : futures) {
295 return absl::OkStatus();
301 rom()->data()[
rom()->version_constants().kOverworldTilesType + i];
309 int num_entrances = 129;
318 for (
int i = 0; i < num_entrances; i++) {
320 rom()->ReadWord(ow_entrance_map_ptr + (i * 2)));
322 rom()->ReadWord(ow_entrance_pos_ptr + (i * 2)));
324 int p = map_pos >> 1;
327 bool deleted =
false;
328 if (map_pos == 0xFFFF) {
332 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
333 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id, map_pos,
337 return absl::OkStatus();
341 constexpr int kNumHoles = 0x13;
342 for (
int i = 0; i < kNumHoles; i++) {
349 int p = (map_pos + 0x400) >> 1;
353 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
354 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id,
355 (uint16_t)(map_pos + 0x400),
true);
357 return absl::OkStatus();
361 const int NumberOfOverworldExits = 0x4F;
362 std::vector<OverworldExit>
exits;
363 for (
int i = 0; i < NumberOfOverworldExits; i++) {
364 auto rom_data =
rom()->data();
366 uint16_t exit_room_id;
367 uint16_t exit_map_id;
369 uint16_t exit_y_scroll;
370 uint16_t exit_x_scroll;
371 uint16_t exit_y_player;
372 uint16_t exit_x_player;
373 uint16_t exit_y_camera;
374 uint16_t exit_x_camera;
375 uint16_t exit_scroll_mod_y;
376 uint16_t exit_scroll_mod_x;
377 uint16_t exit_door_type_1;
378 uint16_t exit_door_type_2;
386 exit_scroll_mod_x,
OWExitUnk2 + i, exit_door_type_1,
390 uint16_t py = (uint16_t)((rom_data[
OWExitYPlayer + (i * 2) + 1] << 8) +
392 uint16_t px = (uint16_t)((rom_data[
OWExitXPlayer + (i * 2) + 1] << 8) +
396 "Exit: %d RoomID: %d MapID: %d VRAM: %d YScroll: %d XScroll: "
397 "%d YPlayer: %d XPlayer: %d YCamera: %d XCamera: %d "
398 "ScrollModY: %d ScrollModX: %d DoorType1: %d DoorType2: %d",
399 i, exit_room_id, exit_map_id, exit_vram, exit_y_scroll, exit_x_scroll,
400 py, px, exit_y_camera, exit_x_camera, exit_scroll_mod_y,
401 exit_scroll_mod_x, exit_door_type_1, exit_door_type_2);
403 exits.emplace_back(exit_room_id, exit_map_id, exit_vram, exit_y_scroll,
404 exit_x_scroll, py, px, exit_y_camera, exit_x_camera,
405 exit_scroll_mod_y, exit_scroll_mod_x, exit_door_type_1,
406 exit_door_type_2, (px & py) == 0xFFFF);
409 return absl::OkStatus();
415 uint32_t pointer_pc =
SnesToPc(pointer);
416 for (
int i = 0; i < 128; i++) {
418 rom()->ReadWord(pointer_pc + i * 2));
419 uint32_t addr = (pointer & 0xFF0000) | word_address;
433 if (b1 == 0xFF && b2 == 0xFF) {
437 int p = (((b2 & 0x1F) << 8) + b1) >> 1;
448 int sx = fakeID - (sy * 8);
450 all_items_.emplace_back(b3, (uint16_t)i, (x * 16) + (sx * 512),
451 (y * 16) + (sy * 512),
false);
459 return absl::OkStatus();
463 std::vector<std::future<absl::Status>> futures;
464 futures.emplace_back(std::async(std::launch::async, [
this]() {
467 futures.emplace_back(std::async(std::launch::async, [
this]() {
470 futures.emplace_back(std::async(std::launch::async, [
this]() {
474 for (
auto &future : futures) {
478 return absl::OkStatus();
482 int num_maps_per_gamestate,
484 for (
int i = 0; i < num_maps_per_gamestate; i++) {
487 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
489 int sprite_address =
SnesToPc((0x09 << 0x10) | word_addr);
494 if (b1 == 0xFF)
break;
496 int editor_map_index = i;
497 if (game_state != 0) {
498 if (editor_map_index >= 128)
499 editor_map_index -= 128;
500 else if (editor_map_index >= 64)
501 editor_map_index -= 64;
503 int mapY = (editor_map_index / 8);
504 int mapX = (editor_map_index % 8);
506 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
507 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
510 (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY);
517 return absl::OkStatus();
529 return absl::OkStatus();
533 util::logf(
"Saving Overworld Maps");
542 std::vector<uint8_t> single_map_1(512);
543 std::vector<uint8_t> single_map_2(512);
547 for (
int y = 0; y < 16; y++) {
548 for (
int x = 0; x < 16; x++) {
550 single_map_1[npos] = packed & 0xFF;
551 single_map_2[npos] = (packed >> 8) & 0xFF;
560 if (a.empty() || b.empty()) {
561 return absl::AbortedError(
"Error compressing map gfx.");
568 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
572 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
573 util::logf(
"Pos set to overflow region for map %s at %s",
578 const auto compare_array = [](
const std::vector<uint8_t> &array1,
579 const std::vector<uint8_t> &array2) ->
bool {
580 if (array1.size() != array2.size()) {
584 for (
size_t i = 0; i < array1.size(); i++) {
585 if (array1[i] != array2[i]) {
593 for (
int j = 0; j < i; j++) {
607 std::copy(a.begin(), a.end(),
map_data_p1[i].begin());
610 util::logf(
"Saving map pointers1 and compressed data for map %s at %s",
613 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
620 util::logf(
"Saving map pointers1 for map %s at %s",
util::HexByte(i),
623 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
627 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
631 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
632 util::logf(
"Pos set to overflow region for map %s at %s",
639 std::copy(b.begin(), b.end(),
map_data_p2[i].begin());
642 util::logf(
"Saving map pointers2 and compressed data for map %s at %s",
645 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
652 util::logf(
"Saving map pointers2 for map %s at %s",
util::HexByte(i),
655 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
663 return absl::AbortedError(
"Too many maps data " + std::to_string(pos));
667 return absl::OkStatus();
671 util::logf(
"Saving Large Maps");
672 std::vector<uint8_t> checked_map;
684 if (std::find(checked_map.begin(), checked_map.end(), i) !=
692 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
693 for (
const auto &offset : large_map_offsets) {
718 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
721 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
725 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
728 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
732 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
735 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
739 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
742 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
746 (parent_x_pos * 0x200)));
748 (parent_y_pos * 0x200)));
752 (parent_x_pos * 0x200)));
755 (parent_y_pos * 0x200)));
760 (parent_x_pos * 0x200)));
763 (parent_y_pos * 0x200)));
767 (parent_x_pos * 0x200)));
770 (parent_y_pos * 0x200)));
779 if (parent_x_pos == 0) {
882 checked_map.emplace_back(i);
883 checked_map.emplace_back((i + 1));
884 checked_map.emplace_back((i + 8));
885 checked_map.emplace_back((i + 9));
907 if (i - 1 >= 0 && parent_x_pos != 0) {
919 if (i + 1 < 64 && parent_x_pos != 7) {
963 (uint16_t)((y_pos * 0x200) - 0xE0)));
965 (uint16_t)((x_pos * 0x200) - 0x100)));
972 checked_map.emplace_back(i);
976 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
979 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
981 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
983 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
985 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
987 return absl::OkStatus();
992 std::vector<uint64_t> all_tile_16;
1007 for (
int y = 0; y < 32; y += 2) {
1008 for (
int x = 0; x < 32; x += 2) {
1010 tiles_used[x + (sx * 32)][y + (sy * 32)],
1011 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
1012 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
1013 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
1042 std::vector<uint64_t> all_tile_16 = GetAllTile16(
map_tiles_);
1045 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
1047 std::vector<uint64_t> unique_tiles(all_tile_16);
1048 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
1051 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
1052 for (
size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
1053 all_tiles_indexed.insert(
1054 {unique_tiles[tile32_id],
static_cast<uint16_t
>(tile32_id)});
1060 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
1064 for (
size_t i = 0; i < unique_tiles.size(); ++i) {
1074 return absl::InternalError(absl::StrFormat(
1075 "Number of unique Tiles32: %d Out of: %d\nUnique Tile32 count exceed "
1076 "the limit\nThe ROM Has not been saved\nYou can fill maps with grass "
1077 "tiles to free some space\nOr use the option Clear DW Tiles in the "
1094 return absl::OkStatus();
1142 return absl::OkStatus();
1146 util::logf(
"Saving Map32 Tiles");
1147 constexpr int kMaxUniqueTiles = 0x4540;
1148 constexpr int kTilesPer32x32Tile = 6;
1150 int unique_tile_index = 0;
1153 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
1154 if (unique_tile_index >= kMaxUniqueTiles) {
1155 return absl::AbortedError(
"Too many unique tile32 definitions.");
1159 auto top_left =
rom()->version_constants().kMap32TileTL;
1187 auto top_right =
rom()->version_constants().kMap32TileTR;
1192 top_right + (i + 1),
1195 top_right + (i + 2),
1198 top_right + (i + 3),
1202 top_right + (i + 4),
1207 top_right + (i + 5),
1267 unique_tile_index += 4;
1268 num_unique_tiles += 2;
1271 return absl::OkStatus();
1349 return absl::OkStatus();
1353 util::logf(
"Saving Map16 Tiles");
1358 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)))
1361 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)))
1364 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)))
1367 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)))
1370 return absl::OkStatus();
1374 util::logf(
"Saving Entrances");
1404 return absl::OkStatus();
1408 util::logf(
"Saving Exits");
1437 return absl::OkStatus();
1442 std::vector<OverworldItem> item_array2) {
1443 if (item_array1.size() != item_array2.size()) {
1448 for (
size_t i = 0; i < item_array1.size(); i++) {
1450 for (
size_t j = 0; j < item_array2.size(); j++) {
1452 if (item_array1[i].x_ == item_array2[j].x_ &&
1453 item_array1[i].y_ == item_array2[j].y_ &&
1454 item_array1[i].id_ == item_array2[j].id_) {
1470 std::vector<std::vector<OverworldItem>> room_items(
1474 room_items[i] = std::vector<OverworldItem>();
1476 if (item.room_map_id_ == i) {
1477 room_items[i].emplace_back(item);
1478 if (item.id_ == 0x86) {
1480 0x16DC5 + (i * 2), (item.game_x_ + (item.game_y_ * 64)) * 2));
1489 int empty_pointer = 0;
1491 item_pointers_reuse[i] = -1;
1492 for (
int ci = 0; ci < i; ci++) {
1493 if (room_items[i].empty()) {
1494 item_pointers_reuse[i] = -2;
1499 if (CompareItemsArrays(
1500 std::vector<OverworldItem>(room_items[i].begin(),
1501 room_items[i].end()),
1502 std::vector<OverworldItem>(room_items[ci].begin(),
1503 room_items[ci].end()))) {
1504 item_pointers_reuse[i] = ci;
1511 if (item_pointers_reuse[i] == -1) {
1512 item_pointers[i] = data_pos;
1515 static_cast<short>(((item.game_y_ << 6) + item.game_x_) << 1);
1517 uint32_t data =
static_cast<uint8_t
>(map_pos & 0xFF) |
1518 static_cast<uint8_t
>(map_pos >> 8) |
1519 static_cast<uint8_t
>(item.id_);
1524 empty_pointer = data_pos;
1527 }
else if (item_pointers_reuse[i] == -2) {
1528 item_pointers[i] = empty_pointer;
1530 item_pointers[i] = item_pointers[item_pointers_reuse[i]];
1533 int snesaddr =
PcToSnes(item_pointers[i]);
1539 return absl::AbortedError(
"Too many items");
1542 util::logf(
"End of Items : %d", data_pos);
1544 return absl::OkStatus();
1548 util::logf(
"Saving Map Properties");
1595 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