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;
102 int index,
int quadrant,
int dimension,
const uint32_t *map32address) {
104 rom_.
ReadByte(map32address[dimension] + quadrant + (index)));
106 (quadrant <= 1 ? 4 : 5)));
107 return (uint16_t)(arg1 +
108 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
119 if (
rom()->data()[0x01772E] != 0x04) {
131 for (
int k = 0; k < 4; k++) {
155 for (
int i = 0; i < 0x200; i++) {
161 return absl::OkStatus();
167 if (
rom()->data()[0x02FD28] != 0x0F) {
173 for (
int i = 0; i < num_tile16; i += 1) {
182 tiles16_.emplace_back(t0, t1, t2, t3);
188 int position_x1 = (x * 2) + (sx * 32);
189 int position_y1 = (y * 2) + (sy * 32);
190 int position_x2 = (x * 2) + 1 + (sx * 32);
191 int position_y2 = (y * 2) + 1 + (sy * 32);
199 std::vector<uint8_t> &bytes2,
int i,
int sx,
200 int sy,
int &ttpos) {
201 for (
int y = 0; y < 16; y++) {
202 for (
int x = 0; x < 16; x++) {
203 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
207 }
else if (i < 128 && i >= 64) {
219 const auto get_ow_map_gfx_ptr = [
this](
int index, uint32_t map_ptr) {
220 int p = (
rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
221 (
rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
222 (
rom()->data()[map_ptr + (3 * index)]);
226 uint32_t lowest = 0x0FFFFF;
227 uint32_t highest = 0x0F8000;
231 for (
int i = 0; i < 160; i++) {
232 auto p1 = get_ow_map_gfx_ptr(
233 i,
rom()->version_constants().kCompressedAllMap32PointersHigh);
234 auto p2 = get_ow_map_gfx_ptr(
235 i,
rom()->version_constants().kCompressedAllMap32PointersLow);
239 if (p1 >= highest) highest = p1;
240 if (p2 >= highest) highest = p2;
242 if (p1 <= lowest && p1 > 0x0F8000) lowest = p1;
243 if (p2 <= lowest && p2 > 0x0F8000) lowest = p2;
245 std::vector<uint8_t> bytes, bytes2;
249 for (
int j = 0; j < size1; j++) {
250 bytes[j] = decomp[j];
254 bytes2.resize(size2);
255 for (
int j = 0; j < size2; j++) {
256 bytes2[j] = decomp[j];
275 return absl::OkStatus();
280 std::vector<std::future<absl::Status>> futures;
283 if (i >= 64 && i < 0x80) {
285 }
else if (i >= 0x80) {
288 auto task_function = [
this, i, size, world_type]() {
292 futures.emplace_back(std::async(std::launch::async, task_function));
296 for (
auto &future : futures) {
297 absl::Status status = future.get();
302 return absl::OkStatus();
306 for (
int i = 0; i < 0x200; i++) {
308 rom()->data()[
rom()->version_constants().overworldTilesType + i];
316 int num_entrances = 129;
317 if (
rom()->data()[0x0DB895] != 0xB8) {
318 ow_entrance_map_ptr = 0x0DB55F;
319 ow_entrance_pos_ptr = 0x0DB35F;
320 ow_entrance_id_ptr = 0x0DB75F;
324 for (
int i = 0; i < num_entrances; i++) {
325 short map_id =
rom()->toint16(ow_entrance_map_ptr + (i * 2));
326 uint16_t map_pos =
rom()->toint16(ow_entrance_pos_ptr + (i * 2));
327 uint8_t entrance_id =
rom_[ow_entrance_id_ptr + i];
328 int p = map_pos >> 1;
331 bool deleted =
false;
332 if (map_pos == 0xFFFF) {
336 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
337 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id, map_pos,
341 for (
int i = 0; i < 0x13; i++) {
344 auto map_pos = (short)((
rom_[
OWHolePos + (i * 2) + 1] << 8) +
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);
358 const int NumberOfOverworldExits = 0x4F;
359 std::vector<OverworldExit>
exits;
360 for (
int i = 0; i < NumberOfOverworldExits; i++) {
361 auto rom_data =
rom()->data();
363 uint16_t exit_room_id;
364 uint16_t exit_map_id;
366 uint16_t exit_y_scroll;
367 uint16_t exit_x_scroll;
368 uint16_t exit_y_player;
369 uint16_t exit_x_player;
370 uint16_t exit_y_camera;
371 uint16_t exit_x_camera;
372 uint16_t exit_scroll_mod_y;
373 uint16_t exit_scroll_mod_x;
374 uint16_t exit_door_type_1;
375 uint16_t exit_door_type_2;
383 exit_scroll_mod_x,
OWExitUnk2 + i, exit_door_type_1,
387 uint16_t py = (uint16_t)((rom_data[
OWExitYPlayer + (i * 2) + 1] << 8) +
389 uint16_t px = (uint16_t)((rom_data[
OWExitXPlayer + (i * 2) + 1] << 8) +
392 if (
rom()->
flags()->kLogToConsole) {
393 std::cout <<
"Exit: " << i <<
" RoomID: " << exit_room_id
394 <<
" MapID: " << exit_map_id <<
" VRAM: " << exit_vram
395 <<
" YScroll: " << exit_y_scroll
396 <<
" XScroll: " << exit_x_scroll <<
" YPlayer: " << py
397 <<
" XPlayer: " << px <<
" YCamera: " << exit_y_camera
398 <<
" XCamera: " << exit_x_camera
399 <<
" ScrollModY: " << exit_scroll_mod_y
400 <<
" ScrollModX: " << exit_scroll_mod_x
401 <<
" DoorType1: " << exit_door_type_1
402 <<
" DoorType2: " << exit_door_type_2 << std::endl;
405 exits.emplace_back(exit_room_id, exit_map_id, exit_vram, exit_y_scroll,
406 exit_x_scroll, py, px, exit_y_camera, exit_x_camera,
407 exit_scroll_mod_y, exit_scroll_mod_x, exit_door_type_1,
408 exit_door_type_2, (px & py) == 0xFFFF);
411 return absl::OkStatus();
418 for (
int i = 0; i < 128; i++) {
420 rom()->ReadWord(pointer_pc + i * 2));
421 uint32_t addr = (pointer & 0xFF0000) | word_address;
435 if (b1 == 0xFF && b2 == 0xFF) {
439 int p = (((b2 & 0x1F) << 8) + b1) >> 1;
450 int sx = fakeID - (sy * 8);
452 all_items_.emplace_back(b3, (uint16_t)i, (x * 16) + (sx * 512),
453 (y * 16) + (sy * 512),
false);
461 return absl::OkStatus();
465 for (
int i = 0; i < 3; i++) {
472 return absl::OkStatus();
476 int num_maps_per_gamestate,
478 for (
int i = 0; i < num_maps_per_gamestate; i++) {
481 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
488 if (b1 == 0xFF)
break;
490 int editor_map_index = i;
491 if (game_state != 0) {
492 if (editor_map_index >= 128)
493 editor_map_index -= 128;
494 else if (editor_map_index >= 64)
495 editor_map_index -= 64;
497 int mapY = (editor_map_index / 8);
498 int mapX = (editor_map_index % 8);
500 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
501 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
503 all_sprites_[game_state].emplace_back(current_gfx, (uint8_t)i, b3,
504 (uint8_t)(b2 & 0x3F),
505 (uint8_t)(b1 & 0x3F), realX, realY);
512 return absl::OkStatus();
526 return absl::OkStatus();
538 for (
int i = 0; i < 160; i++) {
539 std::vector<uint8_t> single_map_1(512);
540 std::vector<uint8_t> single_map_2(512);
544 for (
int y = 0; y < 16; y++) {
545 for (
int x = 0; x < 16; x++) {
547 single_map_1[npos] = packed & 0xFF;
548 single_map_2[npos] = (packed >> 8) & 0xFF;
553 std::vector<uint8_t> a, b;
558 if (a_char ==
nullptr || b_char ==
nullptr) {
559 return absl::AbortedError(
"Error compressing map gfx.");
565 for (
int k = 0; k < size_a; k++) {
568 for (
int k = 0; k < size_b; k++) {
576 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
580 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
582 std::to_string(i) +
" at " +
587 auto compareArray = [](
const std::vector<uint8_t> &array1,
588 const std::vector<uint8_t> &array2) ->
bool {
589 if (array1.size() != array2.size()) {
593 for (
size_t i = 0; i < array1.size(); i++) {
594 if (array1[i] != array2[i]) {
602 for (
int j = 0; j < i; j++) {
616 std::copy(a.begin(), a.end(),
map_data_p1[i].begin());
623 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
634 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
638 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
642 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
651 std::copy(b.begin(), b.end(),
map_data_p2[i].begin());
658 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
669 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
675 if (pos > 0x137FFF) {
676 std::cerr <<
"Too many maps data " << std::hex << pos << std::endl;
677 return absl::AbortedError(
"Too many maps data " + std::to_string(pos));
683 return absl::OkStatus();
688 std::vector<uint8_t> checked_map;
690 for (
int i = 0; i < 0x40; i++) {
700 if (std::find(checked_map.begin(), checked_map.end(), i) !=
708 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
709 for (
const auto &offset : large_map_offsets) {
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 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
749 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
753 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
756 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
760 (parent_x_pos * 0x200)));
762 (parent_y_pos * 0x200)));
787 if (parent_x_pos == 0) {
890 checked_map.emplace_back(i);
891 checked_map.emplace_back((i + 1));
892 checked_map.emplace_back((i + 8));
893 checked_map.emplace_back((i + 9));
915 if (i - 1 >= 0 && parent_x_pos != 0) {
927 if (i + 1 < 64 && parent_x_pos != 7) {
971 (uint16_t)((y_pos * 0x200) - 0xE0)));
973 (uint16_t)((x_pos * 0x200) - 0x100)));
980 checked_map.emplace_back(i);
984 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
987 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
989 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
991 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
993 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
995 return absl::OkStatus();
1000 std::vector<uint64_t> all_tile_16;
1009 }
else if (i < 128 && i >= 64) {
1015 for (
int y = 0; y < 32; y += 2) {
1016 for (
int x = 0; x < 32; x += 2) {
1018 tiles_used[x + (sx * 32)][y + (sy * 32)],
1019 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
1020 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
1021 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
1050 std::vector<uint64_t> all_tile_16 = GetAllTile16(
map_tiles_);
1053 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
1055 std::vector<uint64_t> unique_tiles(all_tile_16);
1056 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
1059 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
1060 for (
size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
1061 all_tiles_indexed.insert(
1062 {unique_tiles[tile32_id],
static_cast<uint16_t
>(tile32_id)});
1068 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
1072 for (
size_t i = 0; i < unique_tiles.size(); ++i) {
1082 return absl::InternalError(absl::StrFormat(
1083 "Number of unique Tiles32: %d Out of: %d\nUnique Tile32 count exceed "
1084 "the limit\nThe ROM Has not been saved\nYou can fill maps with grass "
1085 "tiles to free some space\nOr use the option Clear DW Tiles in the "
1090 if (
flags()->kLogToConsole) {
1102 return absl::OkStatus();
1153 return absl::OkStatus();
1158 constexpr int kMaxUniqueTiles = 0x4540;
1159 constexpr int kTilesPer32x32Tile = 6;
1161 int unique_tile_index = 0;
1164 for (
int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
1165 if (unique_tile_index >= kMaxUniqueTiles) {
1166 return absl::AbortedError(
"Too many unique tile32 definitions.");
1170 auto top_left =
rom()->version_constants().kMap32TileTL;
1198 auto top_right =
rom()->version_constants().kMap32TileTR;
1203 top_right + (i + 1),
1206 top_right + (i + 2),
1209 top_right + (i + 3),
1213 top_right + (i + 4),
1218 top_right + (i + 5),
1278 unique_tile_index += 4;
1279 num_unique_tiles += 2;
1282 return absl::OkStatus();
1360 return absl::OkStatus();
1369 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile0_)))
1372 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile1_)))
1375 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile2_)))
1378 rom()->WriteShort(tpos, TileInfoToShort(
tiles16_[i].tile3_)))
1381 return absl::OkStatus();
1386 for (
int i = 0; i < 129; i++) {
1395 for (
int i = 0; i < 0x13; i++) {
1404 return absl::OkStatus();
1409 for (
int i = 0; i < 0x4F; i++) {
1437 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_) {
1472 std::vector<std::vector<OverworldItem>> room_items(128);
1474 for (
int i = 0; i < 128; i++) {
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));
1489 int item_pointers[128];
1490 int item_pointers_reuse[128];
1491 int empty_pointer = 0;
1493 for (
int i = 0; i < 128; i++) {
1494 item_pointers_reuse[i] = -1;
1495 for (
int ci = 0; ci < i; ci++) {
1496 if (room_items[i].empty()) {
1497 item_pointers_reuse[i] = -2;
1502 if (compareItemsArrays(
1503 std::vector<OverworldItem>(room_items[i].begin(),
1504 room_items[i].end()),
1505 std::vector<OverworldItem>(room_items[ci].begin(),
1506 room_items[ci].end()))) {
1507 item_pointers_reuse[i] = ci;
1513 for (
int i = 0; i < 128; i++) {
1514 if (item_pointers_reuse[i] == -1) {
1515 item_pointers[i] = data_pos;
1518 static_cast<short>(((item.game_y_ << 6) + item.game_x_) << 1);
1520 uint32_t data =
static_cast<uint8_t
>(map_pos & 0xFF) |
1521 static_cast<uint8_t
>(map_pos >> 8) |
1522 static_cast<uint8_t
>(item.id_);
1527 empty_pointer = data_pos;
1530 }
else if (item_pointers_reuse[i] == -2) {
1531 item_pointers[i] = empty_pointer;
1533 item_pointers[i] = item_pointers[item_pointers_reuse[i]];
1542 return absl::AbortedError(
"Too many items");
1545 if (
flags()->kLogToConsole) {
1546 std::cout <<
"End of Items : " << data_pos << std::endl;
1549 return absl::OkStatus();
1554 for (
int i = 0; i < 64; i++) {
1573 for (
int i = 64; i < 128; i++) {
1592 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()
absl::Status DecompressAllMapTiles()
absl::Status CreateTile32Tilemap()
absl::Status SaveMap16Expanded()
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)
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)
absl::StatusOr< uint16_t > GetTile16ForTile32(int index, int quadrant, int dimension, const uint32_t *map32address)
uint8_t all_tiles_types_[0x200]
std::vector< int > map_pointers2
absl::Status SaveMap32Expanded()
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 > item_array1, std::vector< OverworldItem > item_array2)
std::vector< uint64_t > GetAllTile16(OWMapTiles &map_tiles_)
constexpr int overworldTransitionPositionY
constexpr int OWHoleEntrance
constexpr int kMap32TileCountExpanded
constexpr int OWExitYScroll
constexpr int kOverworldItemsAddress
constexpr int overworldMapParentId
constexpr int OWEntrancePos
constexpr int kMap32TileBLExpanded
constexpr int OWExitXScroll
constexpr int OWExitXCamera
constexpr int OWExitYCamera
constexpr int overworldSpriteset
constexpr int kAreaGfxIdPtr
constexpr int kMap32TileTRExpanded
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 NumberOfMap16Ex
constexpr int kNumOverworldMaps
constexpr int overworldMapSize
constexpr int overworldScreenSize
constexpr int kMap16TilesExpanded
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 kMap32TileBRExpanded
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.