7#include <unordered_map>
10#include "absl/status/status.h"
31 const bool load_custom_overworld =
flags()->overworld.kLoadCustomOverworld;
43 return absl::OkStatus();
47 for (
int i = 128; i < 145; i++) {
57 std::vector<bool> map_checked;
58 map_checked.reserve(0x40);
59 for (
int i = 0; i < 64; i++) {
60 map_checked[i] =
false;
65 if (
int i = xx + (yy * 8); map_checked[i] ==
false) {
67 map_checked[i] =
true;
71 map_checked[i + 1] =
true;
75 map_checked[i + 8] =
true;
79 map_checked[i + 9] =
true;
86 map_checked[i] =
true;
108 rom_.
ReadByte(map32address[dimension] + quadrant + (index)));
110 (quadrant <= 1 ? 4 : 5)));
111 return (uint16_t)(arg1 +
112 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
121 for (
int k = 0; k < 4; k++) {
141 for (
int i = 0; i < 0x200; i++) {
147 return absl::OkStatus();
161 tiles16_.emplace_back(t0, t1, t2, t3);
167 int position_x1 = (x * 2) + (sx * 32);
168 int position_y1 = (y * 2) + (sy * 32);
169 int position_x2 = (x * 2) + 1 + (sx * 32);
170 int position_y2 = (y * 2) + 1 + (sy * 32);
178 std::vector<uint8_t> &bytes2,
int i,
int sx,
179 int sy,
int &ttpos) {
180 for (
int y = 0; y < 16; y++) {
181 for (
int x = 0; x < 16; x++) {
182 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
186 }
else if (i < 128 && i >= 64) {
198 const auto get_ow_map_gfx_ptr = [
this](
int index, uint32_t map_ptr) {
199 int p = (
rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
200 (
rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
201 (
rom()->data()[map_ptr + (3 * index)]);
205 uint32_t lowest = 0x0FFFFF;
206 uint32_t highest = 0x0F8000;
210 for (
int i = 0; i < 160; i++) {
211 auto p1 = get_ow_map_gfx_ptr(
212 i,
rom()->version_constants().kCompressedAllMap32PointersHigh);
213 auto p2 = get_ow_map_gfx_ptr(
214 i,
rom()->version_constants().kCompressedAllMap32PointersLow);
218 if (p1 >= highest) highest = p1;
219 if (p2 >= highest) highest = p2;
221 if (p1 <= lowest && p1 > 0x0F8000) lowest = p1;
222 if (p2 <= lowest && p2 > 0x0F8000) lowest = p2;
224 std::vector<uint8_t> bytes, bytes2;
228 for (
int j = 0; j < size1; j++) {
229 bytes[j] = decomp[j];
233 bytes2.resize(size2);
234 for (
int j = 0; j < size2; j++) {
235 bytes2[j] = decomp[j];
254 return absl::OkStatus();
259 std::vector<std::future<absl::Status>> futures;
262 if (i >= 64 && i < 0x80) {
264 }
else if (i >= 0x80) {
267 auto task_function = [
this, i, size, world_type]() {
271 futures.emplace_back(std::async(std::launch::async, task_function));
275 for (
auto &future : futures) {
276 absl::Status status = future.get();
281 return absl::OkStatus();
285 for (
int i = 0; i < 0x200; i++) {
287 rom()->data()[
rom()->version_constants().overworldTilesType + i];
292 for (
int i = 0; i < 129; i++) {
296 int p = map_pos >> 1;
299 bool deleted =
false;
300 if (map_pos == 0xFFFF) {
304 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
305 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id, map_pos,
309 for (
int i = 0; i < 0x13; i++) {
312 auto map_pos = (short)((
rom_[
OWHolePos + (i * 2) + 1] << 8) +
315 int p = (map_pos + 0x400) >> 1;
319 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
320 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id,
321 (uint16_t)(map_pos + 0x400),
true);
326 const int NumberOfOverworldExits = 0x4F;
327 std::vector<OverworldExit>
exits;
328 for (
int i = 0; i < NumberOfOverworldExits; i++) {
329 auto rom_data =
rom()->data();
331 uint16_t exit_room_id;
332 uint16_t exit_map_id;
334 uint16_t exit_y_scroll;
335 uint16_t exit_x_scroll;
336 uint16_t exit_y_player;
337 uint16_t exit_x_player;
338 uint16_t exit_y_camera;
339 uint16_t exit_x_camera;
340 uint16_t exit_scroll_mod_y;
341 uint16_t exit_scroll_mod_x;
342 uint16_t exit_door_type_1;
343 uint16_t exit_door_type_2;
351 exit_scroll_mod_x,
OWExitUnk2 + i, exit_door_type_1,
355 uint16_t py = (uint16_t)((rom_data[
OWExitYPlayer + (i * 2) + 1] << 8) +
357 uint16_t px = (uint16_t)((rom_data[
OWExitXPlayer + (i * 2) + 1] << 8) +
360 if (
rom()->
flags()->kLogToConsole) {
361 std::cout <<
"Exit: " << i <<
" RoomID: " << exit_room_id
362 <<
" MapID: " << exit_map_id <<
" VRAM: " << exit_vram
363 <<
" YScroll: " << exit_y_scroll
364 <<
" XScroll: " << exit_x_scroll <<
" YPlayer: " << py
365 <<
" XPlayer: " << px <<
" YCamera: " << exit_y_camera
366 <<
" XCamera: " << exit_x_camera
367 <<
" ScrollModY: " << exit_scroll_mod_y
368 <<
" ScrollModX: " << exit_scroll_mod_x
369 <<
" DoorType1: " << exit_door_type_1
370 <<
" DoorType2: " << exit_door_type_2 << std::endl;
373 exits.emplace_back(exit_room_id, exit_map_id, exit_vram, exit_y_scroll,
374 exit_x_scroll, py, px, exit_y_camera, exit_x_camera,
375 exit_scroll_mod_y, exit_scroll_mod_x, exit_door_type_1,
376 exit_door_type_2, (px & py) == 0xFFFF);
379 return absl::OkStatus();
386 for (
int i = 0; i < 128; i++) {
388 rom()->ReadWord(pointer_pc + i * 2));
389 uint32_t addr = (pointer & 0xFF0000) | word_address;
403 if (b1 == 0xFF && b2 == 0xFF) {
407 int p = (((b2 & 0x1F) << 8) + b1) >> 1;
418 int sx = fakeID - (sy * 8);
420 all_items_.emplace_back(b3, (uint16_t)i, (x * 16) + (sx * 512),
421 (y * 16) + (sy * 512),
false);
429 return absl::OkStatus();
433 for (
int i = 0; i < 3; i++) {
440 return absl::OkStatus();
444 int num_maps_per_gamestate,
446 for (
int i = 0; i < num_maps_per_gamestate; i++) {
449 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
456 if (b1 == 0xFF)
break;
458 int editor_map_index = i;
459 if (game_state != 0) {
460 if (editor_map_index >= 128)
461 editor_map_index -= 128;
462 else if (editor_map_index >= 64)
463 editor_map_index -= 64;
465 int mapY = (editor_map_index / 8);
466 int mapX = (editor_map_index % 8);
468 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
469 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
472 (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY);
479 return absl::OkStatus();
493 return absl::OkStatus();
505 for (
int i = 0; i < 160; i++) {
506 std::vector<uint8_t> single_map_1(512);
507 std::vector<uint8_t> single_map_2(512);
511 for (
int y = 0; y < 16; y++) {
512 for (
int x = 0; x < 16; x++) {
514 single_map_1[npos] = packed & 0xFF;
515 single_map_2[npos] = (packed >> 8) & 0xFF;
520 std::vector<uint8_t> a, b;
525 if (a_char ==
nullptr || b_char ==
nullptr) {
526 return absl::AbortedError(
"Error compressing map gfx.");
532 for (
int k = 0; k < size_a; k++) {
535 for (
int k = 0; k < size_b; k++) {
543 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
547 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
549 std::to_string(i) +
" at " +
554 auto compareArray = [](
const std::vector<uint8_t> &array1,
555 const std::vector<uint8_t> &array2) ->
bool {
556 if (array1.size() != array2.size()) {
560 for (
size_t i = 0; i < array1.size(); i++) {
561 if (array1[i] != array2[i]) {
569 for (
int j = 0; j < i; j++) {
583 std::copy(a.begin(), a.end(),
map_data_p1[i].begin());
590 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
601 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
605 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
609 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
618 std::copy(b.begin(), b.end(),
map_data_p2[i].begin());
625 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
636 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
642 if (pos > 0x137FFF) {
643 std::cerr <<
"Too many maps data " << std::hex << pos << std::endl;
644 return absl::AbortedError(
"Too many maps data " + std::to_string(pos));
650 return absl::OkStatus();
655 std::vector<uint8_t> checked_map;
657 for (
int i = 0; i < 0x40; i++) {
667 if (std::find(checked_map.begin(), checked_map.end(), i) !=
675 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
676 for (
const auto &offset : large_map_offsets) {
699 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
702 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
706 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
709 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
713 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
716 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
720 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
723 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
727 (parent_x_pos * 0x200)));
729 (parent_y_pos * 0x200)));
754 if (parent_x_pos == 0) {
857 checked_map.emplace_back(i);
858 checked_map.emplace_back((i + 1));
859 checked_map.emplace_back((i + 8));
860 checked_map.emplace_back((i + 9));
882 if (i - 1 >= 0 && parent_x_pos != 0) {
894 if (i + 1 < 64 && parent_x_pos != 7) {
938 (uint16_t)((y_pos * 0x200) - 0xE0)));
940 (uint16_t)((x_pos * 0x200) - 0x100)));
947 checked_map.emplace_back(i);
951 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
954 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
956 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
958 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
960 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
962 return absl::OkStatus();
967 std::vector<uint64_t> all_tile_16;
976 }
else if (i < 128 && i >= 64) {
982 for (
int y = 0; y < 32; y += 2) {
983 for (
int x = 0; x < 32; x += 2) {
985 tiles_used[x + (sx * 32)][y + (sy * 32)],
986 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
987 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
988 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
1017 std::vector<uint64_t> all_tile_16 = GetAllTile16(
map_tiles_);
1020 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
1022 std::vector<uint64_t> unique_tiles(all_tile_16);
1023 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
1026 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
1027 for (
size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
1028 all_tiles_indexed.insert(
1029 {unique_tiles[tile32_id],
static_cast<uint16_t
>(tile32_id)});
1035 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
1039 for (
size_t i = 0; i < unique_tiles.size(); ++i) {
1049 return absl::InternalError(absl::StrFormat(
1050 "Number of unique Tiles32: %d Out of: %d\nUnique Tile32 count exceed "
1051 "the limit\nThe ROM Has not been saved\nYou can fill maps with grass "
1052 "tiles to free some space\nOr use the option Clear DW Tiles in the "
1057 if (
flags()->kLogToConsole) {
1069 return absl::OkStatus();
1074 constexpr int kMaxUniqueTiles = 0x4540;
1075 constexpr int kTilesPer32x32Tile = 6;
1077 int unique_tile_index = 0;
1080 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
1081 if (unique_tile_index >= kMaxUniqueTiles) {
1082 return absl::AbortedError(
"Too many unique tile32 definitions.");
1086 auto top_left =
rom()->version_constants().kMap32TileTL;
1114 auto top_right =
rom()->version_constants().kMap32TileTR;
1119 top_right + (i + 1),
1122 top_right + (i + 2),
1125 top_right + (i + 3),
1129 top_right + (i + 4),
1134 top_right + (i + 5),
1194 unique_tile_index += 4;
1195 num_unique_tiles += 2;
1198 return absl::OkStatus();
1207 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)))
1210 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)))
1213 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)))
1216 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)))
1219 return absl::OkStatus();
1224 for (
int i = 0; i < 129; i++) {
1233 for (
int i = 0; i < 0x13; i++) {
1242 return absl::OkStatus();
1247 for (
int i = 0; i < 0x4F; i++) {
1275 return absl::OkStatus();
1281 std::vector<OverworldItem> itemArray2) {
1282 if (itemArray1.size() != itemArray2.size()) {
1287 for (
size_t i = 0; i < itemArray1.size(); i++) {
1289 for (
size_t j = 0; j < itemArray2.size(); j++) {
1291 if (itemArray1[i].x_ == itemArray2[j].x_ &&
1292 itemArray1[i].y_ == itemArray2[j].y_ &&
1293 itemArray1[i].id_ == itemArray2[j].id_) {
1310 std::vector<std::vector<OverworldItem>> room_items(128);
1312 for (
int i = 0; i < 128; i++) {
1313 room_items[i] = std::vector<OverworldItem>();
1315 if (item.room_map_id_ == i) {
1316 room_items[i].emplace_back(item);
1317 if (item.id_ == 0x86) {
1319 0x16DC5 + (i * 2), (item.game_x_ + (item.game_y_ * 64)) * 2));
1327 int item_pointers[128];
1328 int item_pointers_reuse[128];
1329 int empty_pointer = 0;
1331 for (
int i = 0; i < 128; i++) {
1332 item_pointers_reuse[i] = -1;
1333 for (
int ci = 0; ci < i; ci++) {
1334 if (room_items[i].empty()) {
1335 item_pointers_reuse[i] = -2;
1340 if (compareItemsArrays(
1341 std::vector<OverworldItem>(room_items[i].begin(),
1342 room_items[i].end()),
1343 std::vector<OverworldItem>(room_items[ci].begin(),
1344 room_items[ci].end()))) {
1345 item_pointers_reuse[i] = ci;
1351 for (
int i = 0; i < 128; i++) {
1352 if (item_pointers_reuse[i] == -1) {
1353 item_pointers[i] = data_pos;
1356 static_cast<short>(((item.game_y_ << 6) + item.game_x_) << 1);
1358 uint32_t data =
static_cast<uint8_t
>(map_pos & 0xFF) |
1359 static_cast<uint8_t
>(map_pos >> 8) |
1360 static_cast<uint8_t
>(item.id_);
1365 empty_pointer = data_pos;
1368 }
else if (item_pointers_reuse[i] == -2) {
1369 item_pointers[i] = empty_pointer;
1371 item_pointers[i] = item_pointers[item_pointers_reuse[i]];
1380 return absl::AbortedError(
"Too many items");
1383 if (
flags()->kLogToConsole) {
1384 std::cout <<
"End of Items : " << data_pos << std::endl;
1387 return absl::OkStatus();
1392 for (
int i = 0; i < 64; i++) {
1411 for (
int i = 64; i < 128; i++) {
1430 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data.
VersionConstants version_constants() const
absl::StatusOr< uint16_t > ReadWord(int offset)
absl::StatusOr< uint8_t > ReadByte(int offset)
static void log(std::string message)
Tile composition of four 16x16 tiles.
uint64_t GetPackedValue() const
SNES 16-bit tile metadata container.
std::vector< std::vector< Sprite > > all_sprites_
absl::Status AssembleMap32Tiles()
absl::Status SaveMap32Tiles()
auto current_graphics() const
absl::Status DecompressAllMapTiles()
absl::Status CreateTile32Tilemap()
OWBlockset & GetMapTiles(int world_type)
std::vector< OverworldItem > all_items_
std::vector< OverworldEntrance > all_entrances_
absl::Status SaveLargeMaps()
absl::Status SaveMap16Tiles()
absl::Status SaveOverworldMaps()
std::vector< int > map_pointers2_id
absl::Status LoadSprites()
std::vector< gfx::Tile32 > tiles32_unique_
std::vector< int > map_pointers1
std::vector< OverworldExit > all_exits_
absl::Status SaveEntrances()
void OrganizeMapTiles(std::vector< uint8_t > &bytes, std::vector< uint8_t > &bytes2, int i, int sx, int sy, int &ttpos)
absl::StatusOr< uint16_t > GetTile16ForTile32(int index, int quadrant, int dimension)
std::vector< gfx::Tile16 > tiles16_
void AssignWorldTiles(int x, int y, int sx, int sy, int tpos, OWBlockset &world)
std::vector< int > map_pointers1_id
absl::Status Load(Rom &rom)
uint8_t all_tiles_types_[0x200]
std::vector< int > map_pointers2
std::vector< OverworldEntrance > all_holes_
std::vector< OverworldMap > overworld_maps_
absl::Status LoadOverworldMaps()
absl::Status Save(Rom &rom)
std::vector< std::vector< uint8_t > > map_data_p2
std::vector< std::vector< uint8_t > > map_data_p1
absl::Status LoadSpritesFromMap(int spriteStart, int spriteCount, int spriteIndex)
void AssembleMap16Tiles()
std::vector< uint16_t > tiles32_list_
absl::Status SaveMapProperties()
#define RETURN_IF_ERROR(expression)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
uint32_t PcToSnes(uint32_t addr)
std::string UppercaseHexLong(uint32_t dword)
uint32_t SnesToPc(uint32_t addr) noexcept
std::string UppercaseHexByte(uint8_t byte, bool leading)
uint8_t * Uncompress(uint8_t const *src, int *const size, int const p_big_endian)
uint8_t * Compress(uint8_t const *const src, int const oldsize, int *const size, int const flag)
TileInfo GetTilesInfo(uint16_t tile)
bool compareItemsArrays(std::vector< OverworldItem > itemArray1, std::vector< OverworldItem > itemArray2)
std::vector< uint64_t > GetAllTile16(OWMapTiles &map_tiles_)
constexpr int overworldTransitionPositionY
constexpr int OWHoleEntrance
constexpr int OWExitYScroll
constexpr int kOverworldItemsAddress
constexpr int overworldMapParentId
constexpr int OWEntrancePos
constexpr int OWExitXScroll
constexpr int OWExitXCamera
constexpr int OWExitYCamera
constexpr int overworldSpriteset
constexpr int kAreaGfxIdPtr
constexpr int overworldItemsEndData
constexpr int OverworldScreenSizeForLoading
constexpr int OWExitMapId
constexpr int OWEntranceMap
constexpr int OWExitYPlayer
constexpr int kMap16Tiles
constexpr int OverworldScreenTileMapChangeByScreen2
constexpr int kOverworldMapPaletteIds
constexpr int overworldSpritesZelda
constexpr int OverworldMapDataOverflow
constexpr int OWEntranceEntranceId
constexpr int kNumTile16Individual
constexpr int kMap32TilesLength
constexpr int NumberOfMap32
constexpr int kNumOverworldMaps
constexpr int overworldMapSize
constexpr int overworldScreenSize
constexpr int NumberOfMap16
constexpr int OWExitDoorType2
constexpr int kOverworldSpritePaletteIds
constexpr int LimitOfMap32
constexpr int OWExitXPlayer
constexpr int OverworldScreenTileMapChangeByScreen3
constexpr int OWExitRoomId
constexpr int transition_target_north
constexpr int overworldMapSizeHighByte
constexpr int overworldSpritesBegining
constexpr int transition_target_west
constexpr int OverworldScreenTileMapChangeByScreen4
constexpr int overworldTransitionPositionX
constexpr int overworldSpritesAgahnim
constexpr int OverworldScreenTileMapChangeByScreen1
constexpr int OWExitDoorType1
constexpr int overworldItemsPointers
std::vector< std::vector< uint16_t > > OWBlockset
Represents tile32 data for the overworld.
Overworld map tile32 data.