From 168030ee316acb78046f21e1bb8c1a634e768a3f Mon Sep 17 00:00:00 2001 From: scawful Date: Sat, 26 Aug 2023 17:06:30 -0400 Subject: [PATCH] Start Overworld save --- src/app/editor/overworld_editor.cc | 7 + src/app/gfx/snes_tile.h | 46 ++- src/app/rom.cc | 2 +- src/app/rom.h | 6 + src/app/zelda3/overworld.cc | 582 +++++++++++++++++++++-------- src/app/zelda3/overworld.h | 18 +- 6 files changed, 490 insertions(+), 171 deletions(-) diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 80fcd47c..494cb10b 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -245,6 +245,13 @@ void OverworldEditor::RenderUpdatedMapBitmap(const ImVec2 &click_position, void OverworldEditor::QueueROMChanges(int index, ushort new_tile16) { // Store the changes made by the user to the ROM (or project file) + overworld_.SaveOverworldMaps(); + if (!overworld_.CreateTile32Tilemap()) { + // overworld_.SaveMap16Tiles(); + overworld_.SaveMap32Tiles(); + } else { + std::cout << "Failed to create tile32 tilemap" << std::endl; + } } void OverworldEditor::DetermineActiveMap(const ImVec2 &mouse_position) { diff --git a/src/app/gfx/snes_tile.h b/src/app/gfx/snes_tile.h index 92cceb65..64467d2b 100644 --- a/src/app/gfx/snes_tile.h +++ b/src/app/gfx/snes_tile.h @@ -60,13 +60,49 @@ TileInfo GetTilesInfo(ushort tile); class Tile32 { public: - ushort tile0_; - ushort tile1_; - ushort tile2_; - ushort tile3_; + uint16_t tile0_; + uint16_t tile1_; + uint16_t tile2_; + uint16_t tile3_; - Tile32(ushort t0, ushort t1, ushort t2, ushort t3) + // Default constructor + Tile32() : tile0_(0), tile1_(0), tile2_(0), tile3_(0) {} + + // Parameterized constructor + Tile32(uint16_t t0, uint16_t t1, uint16_t t2, uint16_t t3) : tile0_(t0), tile1_(t1), tile2_(t2), tile3_(t3) {} + + // Copy constructor + Tile32(const Tile32& other) + : tile0_(other.tile0_), + tile1_(other.tile1_), + tile2_(other.tile2_), + tile3_(other.tile3_) {} + + // Constructor from packed value + Tile32(uint64_t packedVal) { + tile0_ = (packedVal >> 48) & 0xFFFF; + tile1_ = (packedVal >> 32) & 0xFFFF; + tile2_ = (packedVal >> 16) & 0xFFFF; + tile3_ = packedVal & 0xFFFF; + } + + // Equality operator + bool operator==(const Tile32& other) const { + return tile0_ == other.tile0_ && tile1_ == other.tile1_ && + tile2_ == other.tile2_ && tile3_ == other.tile3_; + } + + // Inequality operator + bool operator!=(const Tile32& other) const { return !(*this == other); } + + // Get packed uint64_t representation + uint64_t GetPackedValue() const { + return (static_cast(tile0_) << 48) | + (static_cast(tile1_) << 32) | + (static_cast(tile2_) << 16) | + static_cast(tile3_); + } }; class Tile16 { diff --git a/src/app/rom.cc b/src/app/rom.cc index 8a3c399f..96d85fc0 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -323,7 +323,7 @@ absl::Status ROM::SaveToFile(bool backup, absl::string_view filename) { } // Run the other save functions - SaveAllPalettes(); + // SaveAllPalettes(); // Open the file that we know exists for writing std::fstream file(filename.data(), std::ios::binary | std::ios::out); diff --git a/src/app/rom.h b/src/app/rom.h index 36393c37..973c6204 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -182,6 +182,12 @@ class ROM { rom_data_[addr + 1] = (uint16_t)((value >> 8) & 0xFF); } + void WriteVector(int addr, std::vector data) { + for (int i = 0; i < data.size(); i++) { + rom_data_[addr + i] = data[i]; + } + } + void WriteColor(uint32_t address, const gfx::SNESColor& color) { uint16_t bgr = ((color.GetSNES() >> 10) & 0x1F) | ((color.GetSNES() & 0x1F) << 10) | diff --git a/src/app/zelda3/overworld.cc b/src/app/zelda3/overworld.cc index f946bcca..ebcb7362 100644 --- a/src/app/zelda3/overworld.cc +++ b/src/app/zelda3/overworld.cc @@ -135,189 +135,340 @@ absl::Status Overworld::Load(ROM &rom) { return absl::OkStatus(); } +absl::Status Overworld::SaveOverworldMaps() { + for (int i = 0; i < 160; i++) { + mapPointers1id[i] = -1; + mapPointers2id[i] = -1; + } + + int pos = 0x058000; + for (int i = 0; i < 160; i++) { + int npos = 0; + std::vector singleMap1(512); + std::vector singleMap2(512); + + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) { + auto packed1 = tiles32[npos + (i * 256)].GetPackedValue(); + auto packed2 = tiles32[npos + (i * 256) + 16].GetPackedValue(); + singleMap1[npos] = static_cast(packed1 & 0xFF); + singleMap2[npos] = static_cast(packed2 & 0xFF); + npos++; + } + } + ASSIGN_OR_RETURN(auto a, + gfx::lc_lz2::CompressOverworld(singleMap1.data(), 0, 256)); + ASSIGN_OR_RETURN(auto b, + gfx::lc_lz2::CompressOverworld(singleMap2.data(), 0, 256)); + + if (a.empty() || b.empty()) { + return absl::AbortedError("Error compressing map gfx."); + } + + mapDatap1[i] = a; + mapDatap2[i] = b; + + int snesPos = core::PcToSnes(pos); + mapPointers1[i] = snesPos; + + // Handle the special case for debugging + if (i == 0x54) { + // Here, if you need to print the values, use the appropriate logging or + // output method. std::cout << std::hex << (pos + a.size()) << std::endl; + // std::cout << std::hex << (pos + b.size()) << std::endl; + } + + // Handle specific memory regions + if ((pos + a.size()) >= 0x5FE70 && (pos + a.size()) <= 0x60000) { + pos = 0x60000; + } + + if ((pos + a.size()) >= 0x6411F && (pos + a.size()) <= 0x70000) { + pos = OverworldMapDataOverflow; // Assuming you've defined + // Constants in C++ as well. + } + + for (int j = 0; j < i; j++) { + if (a == mapDatap1[j]) { + mapPointers1id[i] = j; + } + + if (b == mapDatap2[j]) { + mapPointers2id[i] = j; + } + } + + if (mapPointers1id[i] == -1) { + std::copy(a.begin(), a.end(), mapDatap1[i].begin()); + + int snesPos = core::PcToSnes(pos); + mapPointers1[i] = snesPos; + + // Assuming ROM is a class/namespace and Write is a function in it + rom()->Write(compressedAllMap32PointersLow + 0 + 3 * i, + static_cast(snesPos & 0xFF)); + rom()->Write(compressedAllMap32PointersLow + 1 + 3 * i, + static_cast((snesPos >> 8) & 0xFF)); + rom()->Write(compressedAllMap32PointersLow + 2 + 3 * i, + static_cast((snesPos >> 16) & 0xFF)); + + rom()->WriteVector(pos, a); + + pos += a.size(); + } else { + int snesPos = mapPointers1[mapPointers1id[i]]; + rom()->Write(compressedAllMap32PointersLow + 0 + 3 * i, + static_cast(snesPos & 0xFF)); + rom()->Write(compressedAllMap32PointersLow + 1 + 3 * i, + static_cast((snesPos >> 8) & 0xFF)); + rom()->Write(compressedAllMap32PointersLow + 2 + 3 * i, + static_cast((snesPos >> 16) & 0xFF)); + } + + if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) { + pos = 0x60000; + } + if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) { + pos = OverworldMapDataOverflow; + } + + // Map2 + if (mapPointers2id[i] == -1) { + std::copy(b.begin(), b.end(), mapDatap2[i].begin()); + + int snesPos = core::PcToSnes(pos); + mapPointers2[i] = snesPos; + + rom()->Write(compressedAllMap32PointersHigh + 0 + 3 * i, + static_cast(snesPos & 0xFF)); + rom()->Write(compressedAllMap32PointersHigh + 1 + 3 * i, + static_cast((snesPos >> 8) & 0xFF)); + rom()->Write(compressedAllMap32PointersHigh + 2 + 3 * i, + static_cast((snesPos >> 16) & 0xFF)); + + rom()->WriteVector(pos, b); + + pos += b.size(); + } else { + int snesPos = mapPointers2[mapPointers2id[i]]; + rom()->Write(compressedAllMap32PointersHigh + 0 + 3 * i, + static_cast(snesPos & 0xFF)); + rom()->Write(compressedAllMap32PointersHigh + 1 + 3 * i, + static_cast((snesPos >> 8) & 0xFF)); + rom()->Write(compressedAllMap32PointersHigh + 2 + 3 * i, + static_cast((snesPos >> 16) & 0xFF)); + } + } + + if (pos > 0x137FFF) { + std::cerr << "Too many maps data " << std::hex << pos << std::endl; + return absl::AbortedError("Too many maps data"); + } + + RETURN_IF_ERROR(SaveLargeMaps()); // Assuming this function exists and + // returns an absl::Status + + return absl::OkStatus(); +} + // ---------------------------------------------------------------------------- -absl::Status Overworld::SaveOverworldMaps() { +absl::Status Overworld::SaveLargeMaps() { for (int i = 0; i < 0x40; i++) { int yPos = i / 8; int xPos = i % 8; int parentyPos = overworld_maps_[i].Parent() / 8; int parentxPos = overworld_maps_[i].Parent() % 8; + std::unordered_map checkedMap; + // Always write the map parent since it should not matter - rom_.Write(overworldMapParentId + i, overworld_maps_[i].Parent()); + rom()->Write(overworldMapParentId + i, overworld_maps_[i].Parent()); + + if (checkedMap.count(overworld_maps_[i].Parent()) > 0) { + continue; + } // If it's large then save parent pos * // 0x200 otherwise pos * 0x200 if (overworld_maps_[i].IsLargeMap()) { // Check 1 - rom_.Write(overworldMapSize + i, 0x20); - rom_.Write(overworldMapSize + i + 1, 0x20); - rom_.Write(overworldMapSize + i + 8, 0x20); - rom_.Write(overworldMapSize + i + 9, 0x20); + rom()->Write(overworldMapSize + i, 0x20); + rom()->Write(overworldMapSize + i + 1, 0x20); + rom()->Write(overworldMapSize + i + 8, 0x20); + rom()->Write(overworldMapSize + i + 9, 0x20); // Check 2 - rom_.Write(overworldMapSizeHighByte + i, 0x03); - rom_.Write(overworldMapSizeHighByte + i + 1, 0x03); - rom_.Write(overworldMapSizeHighByte + i + 8, 0x03); - rom_.Write(overworldMapSizeHighByte + i + 9, 0x03); + rom()->Write(overworldMapSizeHighByte + i, 0x03); + rom()->Write(overworldMapSizeHighByte + i + 1, 0x03); + rom()->Write(overworldMapSizeHighByte + i + 8, 0x03); + rom()->Write(overworldMapSizeHighByte + i + 9, 0x03); // Check 3 - rom_.Write(overworldScreenSize + i, 0x00); - rom_.Write(overworldScreenSize + i + 64, 0x00); + rom()->Write(overworldScreenSize + i, 0x00); + rom()->Write(overworldScreenSize + i + 64, 0x00); - rom_.Write(overworldScreenSize + i + 1, 0x00); - rom_.Write(overworldScreenSize + i + 1 + 64, 0x00); + rom()->Write(overworldScreenSize + i + 1, 0x00); + rom()->Write(overworldScreenSize + i + 1 + 64, 0x00); - rom_.Write(overworldScreenSize + i + 8, 0x00); - rom_.Write(overworldScreenSize + i + 8 + 64, 0x00); + rom()->Write(overworldScreenSize + i + 8, 0x00); + rom()->Write(overworldScreenSize + i + 8 + 64, 0x00); - rom_.Write(overworldScreenSize + i + 9, 0x00); - rom_.Write(overworldScreenSize + i + 9 + 64, 0x00); + rom()->Write(overworldScreenSize + i + 9, 0x00); + rom()->Write(overworldScreenSize + i + 9 + 64, 0x00); // Check 4 - rom_.Write(OverworldScreenSizeForLoading + i, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 64, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 128, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 64, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 128, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 1, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 1 + 64, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 1 + 128, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 1, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 1 + 64, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 1 + 128, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 8, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 8 + 64, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 8 + 128, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 8, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 8 + 64, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 8 + 128, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 9, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 9 + 64, 0x04); - rom_.Write(OverworldScreenSizeForLoading + i + 9 + 128, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 9, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 9 + 64, 0x04); + rom()->Write(OverworldScreenSizeForLoading + i + 9 + 128, 0x04); // Check 5 and 6 - rom_.WriteShort( + rom()->WriteShort( transition_target_north + (i * 2) + 2, (short)((parentyPos * 0x200) - 0xE0)); // (short) is placed to reduce the int to 2 bytes. - rom_.WriteShort(transition_target_west + (i * 2) + 2, - (short)((parentxPos * 0x200) - 0x100)); + rom()->WriteShort(transition_target_west + (i * 2) + 2, + (short)((parentxPos * 0x200) - 0x100)); - rom_.WriteShort( + rom()->WriteShort( transition_target_north + (i * 2) + 16, (short)((parentyPos * 0x200) - 0xE0)); // (short) is placed to reduce the int to 2 bytes. - rom_.WriteShort(transition_target_west + (i * 2) + 16, - (short)((parentxPos * 0x200) - 0x100)); + rom()->WriteShort(transition_target_west + (i * 2) + 16, + (short)((parentxPos * 0x200) - 0x100)); - rom_.WriteShort( + rom()->WriteShort( transition_target_north + (i * 2) + 18, (short)((parentyPos * 0x200) - 0xE0)); // (short) is placed to reduce the int to 2 bytes. - rom_.WriteShort(transition_target_west + (i * 2) + 18, - (short)((parentxPos * 0x200) - 0x100)); + rom()->WriteShort(transition_target_west + (i * 2) + 18, + (short)((parentxPos * 0x200) - 0x100)); // Check 7 and 8 - rom_.WriteShort(overworldTransitionPositionX + (i * 2), - (parentxPos * 0x200)); - rom_.WriteShort(overworldTransitionPositionY + (i * 2), - (parentyPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionX + (i * 2), + (parentxPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionY + (i * 2), + (parentyPos * 0x200)); - rom_.WriteShort(overworldTransitionPositionX + (i * 2) + 2, - (parentxPos * 0x200)); - rom_.WriteShort(overworldTransitionPositionY + (i * 2) + 2, - (parentyPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionX + (i * 2) + 2, + (parentxPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionY + (i * 2) + 2, + (parentyPos * 0x200)); - rom_.WriteShort(overworldTransitionPositionX + (i * 2) + 16, - (parentxPos * 0x200)); - rom_.WriteShort(overworldTransitionPositionY + (i * 2) + 16, - (parentyPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionX + (i * 2) + 16, + (parentxPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionY + (i * 2) + 16, + (parentyPos * 0x200)); - rom_.WriteShort(overworldTransitionPositionX + (i * 2) + 18, - (parentxPos * 0x200)); - rom_.WriteShort(overworldTransitionPositionY + (i * 2) + 18, - (parentyPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionX + (i * 2) + 18, + (parentxPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionY + (i * 2) + 18, + (parentyPos * 0x200)); // Check 9 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2), - 0x0060); // Always 0x0060 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 2, - 0x0060); // Always 0x0060 + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2), + 0x0060); // Always 0x0060 + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 2, + 0x0060); // Always 0x0060 // If parentX == 0 then lower submaps == 0x0060 too if (parentxPos == 0) { - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 16, - 0x0060); - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 18, - 0x0060); + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 16, + 0x0060); + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 18, + 0x0060); } else { // Otherwise lower submaps == 0x1060 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 16, - 0x1060); - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 18, - 0x1060); + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 16, + 0x1060); + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 18, + 0x1060); } - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 128, - 0x0080); // Always 0x0080 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 2 + 128, - 0x0080); // Always 0x0080 - // Lower are always 8010 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 16 + 128, - 0x1080); // Always 0x1080 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 18 + 128, - 0x1080); // Always 0x1080 + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 128, + 0x0080); // Always 0x0080 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 2 + 128, + 0x0080); // Always 0x0080 + // Lower are always 8010 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 16 + 128, + 0x1080); // Always 0x1080 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 18 + 128, + 0x1080); // Always 0x1080 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 256, - 0x1800); // Always 0x1800 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 16 + 256, - 0x1800); // Always 0x1800 - // Right side is always 1840 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 2 + 256, - 0x1840); // Always 0x1840 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 18 + 256, - 0x1840); // Always 0x1840 + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 256, + 0x1800); // Always 0x1800 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 16 + 256, + 0x1800); // Always 0x1800 + // Right side is always 1840 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 2 + 256, + 0x1840); // Always 0x1840 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 18 + 256, + 0x1840); // Always 0x1840 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 384, - 0x2000); // Always 0x2000 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 16 + 384, - 0x2000); // Always 0x2000 - // Right side is always 0x2040 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 2 + 384, - 0x2040); // Always 0x2000 - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 18 + 384, - 0x2040); // Always 0x2000 + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 384, + 0x2000); // Always 0x2000 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 16 + 384, + 0x2000); // Always 0x2000 + // Right side is always 0x2040 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 2 + 384, + 0x2040); // Always 0x2000 + rom()->WriteShort( + OverworldScreenTileMapChangeByScreen + (i * 2) + 18 + 384, + 0x2040); // Always 0x2000 - // checkedMap.Add((uchar)i); - // checkedMap.Add((uchar)(i + 1)); - // checkedMap.Add((uchar)(i + 8)); - // checkedMap.Add((uchar)(i + 9)); + checkedMap.emplace(i, 1); + checkedMap.emplace((i + 1), 1); + checkedMap.emplace((i + 8), 1); + checkedMap.emplace((i + 9), 1); } else { - rom_.Write(overworldMapSize + i, 0x00); - rom_.Write(overworldMapSizeHighByte + i, 0x01); + rom()->Write(overworldMapSize + i, 0x00); + rom()->Write(overworldMapSizeHighByte + i, 0x01); - rom_.Write(overworldScreenSize + i, 0x01); - rom_.Write(overworldScreenSize + i + 64, 0x01); + rom()->Write(overworldScreenSize + i, 0x01); + rom()->Write(overworldScreenSize + i + 64, 0x01); - rom_.Write(OverworldScreenSizeForLoading + i, 0x02); - rom_.Write(OverworldScreenSizeForLoading + i + 64, 0x02); - rom_.Write(OverworldScreenSizeForLoading + i + 128, 0x02); + rom()->Write(OverworldScreenSizeForLoading + i, 0x02); + rom()->Write(OverworldScreenSizeForLoading + i + 64, 0x02); + rom()->Write(OverworldScreenSizeForLoading + i + 128, 0x02); - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2), 0x0060); - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 128, - 0x0040); - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 256, - 0x1800); - rom_.WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 384, - 0x1000); + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2), 0x0060); + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 128, + 0x0040); + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 256, + 0x1800); + rom()->WriteShort(OverworldScreenTileMapChangeByScreen + (i * 2) + 384, + 0x1000); - rom_.WriteShort(transition_target_north + (i * 2), - (short)((yPos * 0x200) - 0xE0)); - rom_.WriteShort(transition_target_west + (i * 2), - (short)((xPos * 0x200) - 0x100)); + rom()->WriteShort(transition_target_north + (i * 2), + (short)((yPos * 0x200) - 0xE0)); + rom()->WriteShort(transition_target_west + (i * 2), + (short)((xPos * 0x200) - 0x100)); - rom_.WriteShort(overworldTransitionPositionX + (i * 2), (xPos * 0x200)); - rom_.WriteShort(overworldTransitionPositionY + (i * 2), (yPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionX + (i * 2), (xPos * 0x200)); + rom()->WriteShort(overworldTransitionPositionY + (i * 2), (yPos * 0x200)); - // checkedMap.Add((uchar)i); + checkedMap.emplace(i, 1); } } return absl::OkStatus(); @@ -325,60 +476,163 @@ absl::Status Overworld::SaveOverworldMaps() { // ---------------------------------------------------------------------------- +bool Overworld::CreateTile32Tilemap(bool onlyShow) { + tiles32_unique_.clear(); + tiles32.clear(); + + std::vector allTile16; // Ensure it's 64 bits + + int sx = 0; + int sy = 0; + int c = 0; + for (int i = 0; i < kNumOverworldMaps; i++) { + OWBlockset *tilesused; + if (i < 64) { + tilesused = &map_tiles_.light_world; + } else if (i < 128 && i >= 64) { + tilesused = &map_tiles_.dark_world; + } else { + tilesused = &map_tiles_.special_world; + } + + for (int y = 0; y < 32; y += 2) { + for (int x = 0; x < 32; x += 2) { + gfx::Tile32 currentTile( + (*tilesused)[x + (sx * 32)][y + (sy * 32)], + (*tilesused)[x + 1 + (sx * 32)][y + (sy * 32)], + (*tilesused)[x + (sx * 32)][y + 1 + (sy * 32)], + (*tilesused)[x + 1 + (sx * 32)][y + 1 + (sy * 32)]); + + allTile16.push_back(currentTile.GetPackedValue()); + } + } + + sx++; + if (sx >= 8) { + sy++; + sx = 0; + } + + c++; + if (c >= 64) { + sx = 0; + sy = 0; + c = 0; + } + } + + std::vector uniqueTiles(allTile16); // Ensure it's 64 bits + std::sort(uniqueTiles.begin(), uniqueTiles.end()); + uniqueTiles.erase(std::unique(uniqueTiles.begin(), uniqueTiles.end()), + uniqueTiles.end()); + + std::unordered_map alltilesIndexed; // Ensure it's 64 bits + for (size_t i = 0; i < uniqueTiles.size(); i++) { + alltilesIndexed.insert({uniqueTiles[i], static_cast(i)}); + } + + for (int i = 0; i < NumberOfMap32; i++) { + this->tiles32.push_back(alltilesIndexed[allTile16[i]]); + } + + for (const auto &tile : uniqueTiles) { + this->tiles32_unique_.push_back(static_cast(tile)); + } + + while (this->tiles32_unique_.size() % 4 != 0) { + gfx::Tile32 paddingTile(420, 420, 420, 420); + this->tiles32_unique_.push_back(paddingTile.GetPackedValue()); + } + + if (onlyShow) { + std::cout << "Number of unique Tiles32: " << uniqueTiles.size() + << " Out of: " << LimitOfMap32 << std::endl; + } else if (this->tiles32_unique_.size() > LimitOfMap32) { + std::cerr << "Number of unique Tiles32: " << uniqueTiles.size() + << " Out of: " << LimitOfMap32 + << "\nUnique Tile32 count exceed the limit" + << "\nThe ROM Has not been saved" + << "\nYou can fill maps with grass tiles to free some space" + << "\nOr use the option Clear DW Tiles in the Overworld Menu" + << std::endl; + return true; + } + + std::cout << "Number of unique Tiles32: " << uniqueTiles.size() + << " Saved:" << this->tiles32_unique_.size() + << " Out of: " << LimitOfMap32 << std::endl; + + int v = this->tiles32_unique_.size(); + for (int i = v; i < LimitOfMap32; i++) { + gfx::Tile32 paddingTile(420, 420, 420, 420); + this->tiles32_unique_.push_back(paddingTile.GetPackedValue()); + } + + return false; +} + +// ---------------------------------------------------------------------------- + void Overworld::SaveMap16Tiles() { int tpos = kMap16Tiles; // 3760 for (int i = 0; i < NumberOfMap16; i += 1) { - rom_.WriteShort(tpos, TileInfoToShort(tiles16[i].tile0_)); + rom()->WriteShort(tpos, TileInfoToShort(tiles16[i].tile0_)); tpos += 2; - rom_.WriteShort(tpos, TileInfoToShort(tiles16[i].tile1_)); + rom()->WriteShort(tpos, TileInfoToShort(tiles16[i].tile1_)); tpos += 2; - rom_.WriteShort(tpos, TileInfoToShort(tiles16[i].tile2_)); + rom()->WriteShort(tpos, TileInfoToShort(tiles16[i].tile2_)); tpos += 2; - rom_.WriteShort(tpos, TileInfoToShort(tiles16[i].tile3_)); + rom()->WriteShort(tpos, TileInfoToShort(tiles16[i].tile3_)); tpos += 2; } } -// ---------------------------------------------------------------------------- - void Overworld::SaveMap32Tiles() { - const int max_tiles = 0x4540; - const int unique_size = tiles32_unique_.size(); + int index = 0; + int c = tiles32_unique_.size(); - auto write_tiles = [&](int address, auto get_tile) { - for (int i = 0; i < unique_size && i < max_tiles; i += 4) { - for (int j = 0; j < 4; ++j) { - rom_.Write(address + i + j, (uchar)(get_tile(i + j) & 0xFF)); - } - rom_.Write(address + i + 4, (uchar)(((get_tile(i) >> 4) & 0xF0) | - ((get_tile(i + 1) >> 8) & 0x0F))); - rom_.Write(address + i + 5, (uchar)(((get_tile(i + 2) >> 4) & 0xF0) | - ((get_tile(i + 3) >> 8) & 0x0F))); + for (int i = 0; i < c; i += 6) { + if (index >= 0x4540) { + std::cout << "Too many unique tiles!" << std::endl; + break; } - }; - write_tiles(rom_.GetVersionConstants().kMap32TileTL, - [&](int i) { return tiles32_unique_[i].tile0_; }); - write_tiles(rom_.GetVersionConstants().kMap32TileTR, - [&](int i) { return tiles32_unique_[i].tile1_; }); - write_tiles(rom_.GetVersionConstants().kMap32TileBL, - [&](int i) { return tiles32_unique_[i].tile2_; }); - write_tiles(rom_.GetVersionConstants().kMap32TileBR, - [&](int i) { return tiles32_unique_[i].tile3_; }); + // Helper lambda to avoid code repetition + auto writeTilesToRom = [&](int base_addr, auto get_tile) { + for (int j = 0; j < 4; ++j) { + rom()->Write(base_addr + i + j, + get_tile(tiles32_unique_[index + j]) & 0xFF); + } + rom()->Write(base_addr + i + 4, + ((get_tile(tiles32_unique_[index]) >> 4) & 0xF0) | + ((get_tile(tiles32_unique_[index + 1]) >> 8) & 0x0F)); + rom()->Write(base_addr + i + 5, + ((get_tile(tiles32_unique_[index + 2]) >> 4) & 0xF0) | + ((get_tile(tiles32_unique_[index + 3]) >> 8) & 0x0F)); + }; - if (unique_size > max_tiles) { - std::cout << "Too many unique tiles!" << std::endl; + writeTilesToRom(rom()->GetVersionConstants().kMap32TileTL, + [](const gfx::Tile32 &t) { return t.tile0_; }); + writeTilesToRom(rom()->GetVersionConstants().kMap32TileTR, + [](const gfx::Tile32 &t) { return t.tile1_; }); + writeTilesToRom(rom()->GetVersionConstants().kMap32TileBL, + [](const gfx::Tile32 &t) { return t.tile2_; }); + writeTilesToRom(rom()->GetVersionConstants().kMap32TileBR, + [](const gfx::Tile32 &t) { return t.tile3_; }); + + index += 4; + c += 2; } } // ---------------------------------------------------------------------------- ushort Overworld::GenerateTile32(int i, int k, int dimension) { - const uint32_t map32address[4] = {rom_.GetVersionConstants().kMap32TileTL, - rom_.GetVersionConstants().kMap32TileTR, - rom_.GetVersionConstants().kMap32TileBL, - rom_.GetVersionConstants().kMap32TileBR}; + const uint32_t map32address[4] = {rom()->GetVersionConstants().kMap32TileTL, + rom()->GetVersionConstants().kMap32TileTR, + rom()->GetVersionConstants().kMap32TileBL, + rom()->GetVersionConstants().kMap32TileBR}; return (ushort)(rom_[map32address[dimension] + k + (i)] + (((rom_[map32address[dimension] + (i) + (k <= 1 ? 4 : 5)] >> @@ -414,13 +668,13 @@ void Overworld::AssembleMap32Tiles() { void Overworld::AssembleMap16Tiles() { int tpos = kMap16Tiles; for (int i = 0; i < 4096; i += 1) { - auto t0 = gfx::GetTilesInfo(rom_.toint16(tpos)); + auto t0 = gfx::GetTilesInfo(rom()->toint16(tpos)); tpos += 2; - auto t1 = gfx::GetTilesInfo(rom_.toint16(tpos)); + auto t1 = gfx::GetTilesInfo(rom()->toint16(tpos)); tpos += 2; - auto t2 = gfx::GetTilesInfo(rom_.toint16(tpos)); + auto t2 = gfx::GetTilesInfo(rom()->toint16(tpos)); tpos += 2; - auto t3 = gfx::GetTilesInfo(rom_.toint16(tpos)); + auto t3 = gfx::GetTilesInfo(rom()->toint16(tpos)); tpos += 2; tiles16.emplace_back(t0, t1, t2, t3); } @@ -471,11 +725,11 @@ absl::Status Overworld::DecompressAllMapTiles() { int c = 0; for (int i = 0; i < 160; i++) { auto p1 = GetOwMapGfxHighPtr( - rom_.data(), i, - rom_.GetVersionConstants().compressedAllMap32PointersHigh); + rom()->data(), i, + rom()->GetVersionConstants().compressedAllMap32PointersHigh); auto p2 = GetOwMapGfxLowPtr( - rom_.data(), i, - rom_.GetVersionConstants().compressedAllMap32PointersLow); + rom()->data(), i, + rom()->GetVersionConstants().compressedAllMap32PointersLow); int ttpos = 0; if (p1 >= highest) { @@ -493,9 +747,9 @@ absl::Status Overworld::DecompressAllMapTiles() { } ASSIGN_OR_RETURN(auto bytes, - gfx::lc_lz2::DecompressOverworld(rom_.data(), p2, 1000)) + gfx::lc_lz2::DecompressOverworld(rom()->data(), p2, 1000)) ASSIGN_OR_RETURN(auto bytes2, - gfx::lc_lz2::DecompressOverworld(rom_.data(), p1, 1000)) + gfx::lc_lz2::DecompressOverworld(rom()->data(), p1, 1000)) OrganizeMapTiles(bytes, bytes2, i, sx, sy, ttpos); sx++; @@ -613,8 +867,8 @@ void Overworld::FetchLargeMaps() { void Overworld::LoadEntrances() { for (int i = 0; i < 129; i++) { - short mapId = rom_.toint16(OWEntranceMap + (i * 2)); - ushort mapPos = rom_.toint16(OWEntrancePos + (i * 2)); + short mapId = rom()->toint16(OWEntranceMap + (i * 2)); + ushort mapPos = rom()->toint16(OWEntrancePos + (i * 2)); uchar entranceId = (rom_[OWEntranceEntranceId + i]); int p = mapPos >> 1; int x = (p % 64); @@ -677,7 +931,7 @@ void Overworld::LoadSpritesFromMap(int spriteStart, int spriteCount, if (map_parent_[i] != i) continue; int ptrPos = spriteStart + (i * 2); - int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos)); + int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom()->toint16(ptrPos)); while (true) { uchar b1 = rom_[spriteAddress]; uchar b2 = rom_[spriteAddress + 1]; diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index f48f9f6f..a7c5c6b5 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -120,6 +120,7 @@ constexpr int overworldMapPaletteGroup = 0x75504; constexpr int overworldSpritePaletteGroup = 0x75580; constexpr int overworldSpriteset = 0x7A41; constexpr int overworldSpecialGFXGroup = 0x16821; +constexpr int OverworldMapDataOverflow = 0x130000; constexpr int overworldSpecialPALGroup = 0x16831; constexpr int overworldSpritesBegining = 0x4C881; constexpr int overworldSpritesAgahnim = 0x4CA21; @@ -177,10 +178,14 @@ struct MapData { std::vector lowData; }; -class Overworld { +class Overworld : public SharedROM { public: absl::Status Load(ROM &rom); + absl::Status SaveOverworldMaps(); + absl::Status SaveLargeMaps(); + + bool CreateTile32Tilemap(bool onlyShow = false); void SaveMap16Tiles(); void SaveMap32Tiles(); @@ -247,6 +252,17 @@ class Overworld { std::vector> all_sprites_; absl::flat_hash_map proto_map_data_; + + std::vector> mapDatap1 = + std::vector>(kNumOverworldMaps); + std::vector> mapDatap2 = + std::vector>(kNumOverworldMaps); + + std::vector mapPointers1id = std::vector(kNumOverworldMaps); + std::vector mapPointers2id = std::vector(kNumOverworldMaps); + + std::vector mapPointers1 = std::vector(kNumOverworldMaps); + std::vector mapPointers2 = std::vector(kNumOverworldMaps); }; } // namespace zelda3