From 6791fa03e5b29361eec7692f37ebd5f61faadc4e Mon Sep 17 00:00:00 2001 From: scawful Date: Mon, 29 Jan 2024 22:58:39 -0500 Subject: [PATCH] Overworld updates, Tile16 and large map fixes --- src/app/editor/master_editor.cc | 20 +- src/app/editor/overworld_editor.cc | 69 +++---- src/app/gui/canvas.cc | 101 ++++++---- src/app/gui/canvas.h | 6 +- src/app/zelda3/overworld.cc | 304 ++++++++++++++--------------- src/app/zelda3/overworld.h | 14 +- src/app/zelda3/overworld_map.cc | 10 +- src/app/zelda3/overworld_map.h | 12 +- 8 files changed, 282 insertions(+), 254 deletions(-) diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index 5187a218..541f2d1d 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -571,18 +571,14 @@ void MasterEditor::SaveRom() { RETURN_VOID_IF_ERROR(status_); } if (flags()->overworld.kSaveOverworldMaps) { - if (!overworld_editor_.overworld()->CreateTile32Tilemap()) { - status_ = overworld_editor_.overworld()->SaveMap32Tiles(); - RETURN_VOID_IF_ERROR(status_); - status_ = overworld_editor_.overworld()->SaveMap16Tiles(); - RETURN_VOID_IF_ERROR(status_); - status_ = overworld_editor_.overworld()->SaveOverworldMaps(); - RETURN_VOID_IF_ERROR(status_); - } else { - status_ = absl::InternalError( - "Failed to save Overworld maps, aborting ROM save."); - return; - } + RETURN_VOID_IF_ERROR( + status_ = overworld_editor_.overworld()->CreateTile32Tilemap()); + status_ = overworld_editor_.overworld()->SaveMap32Tiles(); + RETURN_VOID_IF_ERROR(status_); + status_ = overworld_editor_.overworld()->SaveMap16Tiles(); + RETURN_VOID_IF_ERROR(status_); + status_ = overworld_editor_.overworld()->SaveOverworldMaps(); + RETURN_VOID_IF_ERROR(status_); } if (flags()->overworld.kSaveOverworldEntrances) { status_ = overworld_editor_.overworld()->SaveEntrances(); diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index d3b1e954..0466021e 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -485,9 +485,8 @@ void OverworldEditor::DrawOverworldMaps() { } void OverworldEditor::DrawOverworldEdits() { - auto mouse_position = ow_map_canvas_.drawn_tile_position(); - // Determine which overworld map the user is currently editing. + auto mouse_position = ow_map_canvas_.drawn_tile_position(); constexpr int small_map_size = 512; int map_x = mouse_position.x / small_map_size; int map_y = mouse_position.y / small_map_size; @@ -511,12 +510,7 @@ void OverworldEditor::DrawOverworldEdits() { int tile16_x = (mouse_x % small_map_size) / (small_map_size / 32); int tile16_y = (mouse_y % small_map_size) / (small_map_size / 32); - // Update the overworld_.map_tiles() data (word) based on tile16 ID and - // current world - uint16_t tile_value = current_tile16_; - uint8_t low_byte = tile_value & 0xFF; - uint8_t high_byte = (tile_value >> 8) & 0xFF; - + // Update the overworld_.map_tiles() based on tile16 ID and current world auto &selected_world = (current_world_ == 0) ? overworld_.mutable_map_tiles()->light_world : (current_world_ == 1) ? overworld_.mutable_map_tiles()->dark_world @@ -525,7 +519,7 @@ void OverworldEditor::DrawOverworldEdits() { int index_x = superX * 32 + tile16_x; int index_y = superY * 32 + tile16_y; - selected_world[index_x][index_y] = tile_value; + selected_world[index_x][index_y] = current_tile16_; } void OverworldEditor::RenderUpdatedMapBitmap(const ImVec2 &click_position, @@ -557,12 +551,14 @@ void OverworldEditor::RenderUpdatedMapBitmap(const ImVec2 &click_position, } void OverworldEditor::CheckForOverworldEdits() { + // User has selected a tile they want to draw from the blockset. if (!blockset_canvas_.points().empty() && current_mode == EditingMode::DRAW_TILE) { - // User has selected a tile they want to draw from the blockset. - int x = blockset_canvas_.points().front().x / 32; - int y = blockset_canvas_.points().front().y / 32; - current_tile16_ = x + (y * 8); + // int x = blockset_canvas_.points().front().x / 32; + // int y = blockset_canvas_.points().front().y / 32; + // current_tile16_ = x + (y * 8); + CheckForSelectRectangle(); + if (ow_map_canvas_.DrawTilePainter(tile16_individual_[current_tile16_], 16)) { // Update the overworld map. @@ -571,6 +567,28 @@ void OverworldEditor::CheckForOverworldEdits() { } } +void OverworldEditor::CheckForSelectRectangle() { + ow_map_canvas_.DrawSelectRectTile16(current_map_); + + static std::vector tile16_ids; + if (ow_map_canvas_.selected_tiles().size() != 0) { + // Get the tile16 IDs from the selected tile ID positions + // if (tile16_ids.size() != 0) { + // tile16_ids.clear(); + // } + // for (auto &each : ow_map_canvas_.selected_tiles()) { + // tile16_ids.push_back(overworld_.GetTile16Id(each)); + // } + if (ow_map_canvas_.selected_tiles().size() == 1) { + current_tile16_ = + overworld_.GetTile16Id(ow_map_canvas_.selected_tiles().at(0)); + } + ow_map_canvas_.mutable_selected_tiles()->clear(); + } + // Create a composite image of all the tile16s selected + // ow_map_canvas_.DrawBitmapGroup(tile16_ids, tile16_individual_, 0x10); +} + void OverworldEditor::CheckForCurrentMap() { // 4096x4096, 512x512 maps and some are larges maps 1024x1024 auto mouse_position = ImGui::GetIO().MousePos; @@ -618,26 +636,6 @@ void OverworldEditor::CheckForCurrentMap() { } } -void OverworldEditor::CheckForSelectRectangle() { - if (current_mode == EditingMode::DRAW_TILE) { - ow_map_canvas_.DrawSelectRect(0x10); - static std::vector tile16_ids; - if (ow_map_canvas_.selected_tiles().size() != 0) { - // Get the tile16 IDs from the selected tile ID positions - if (tile16_ids.size() != 0) { - tile16_ids.clear(); - } - for (auto &each : ow_map_canvas_.selected_tiles()) { - int tile16_id = overworld_.GetTile16Id(each); - tile16_ids.push_back(tile16_id); - } - ow_map_canvas_.mutable_selected_tiles()->clear(); - } - // Create a composite image of all the tile16s selected - ow_map_canvas_.DrawBitmapGroup(tile16_ids, tile16_individual_, 0x10); - } -} - // Overworld Editor canvas // Allows the user to make changes to the overworld map. void OverworldEditor::DrawOverworldCanvas() { @@ -686,6 +684,11 @@ void OverworldEditor::DrawTile16Selector() { tile16_editor_.set_tile16(id); show_tile16_editor_ = true; } + if (ImGui::IsItemClicked() && !blockset_canvas_.points().empty()) { + int x = blockset_canvas_.points().front().x / 32; + int y = blockset_canvas_.points().front().y / 32; + current_tile16_ = x + (y * 8); + } blockset_canvas_.DrawGrid(); blockset_canvas_.DrawOverlay(); ImGui::EndChild(); diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index 376286da..80f43ab0 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -384,7 +384,6 @@ void Canvas::DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color) { IM_COL32(color.x, color.y, color.z, color.w)); } - void Canvas::DrawOutlineWithColor(int x, int y, int w, int h, uint32_t color) { ImVec2 origin(canvas_p0_.x + scrolling_.x + x, canvas_p0_.y + scrolling_.y + y); @@ -420,47 +419,81 @@ void Canvas::DrawSelectRect(int tile_size, float scale) { if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { // Start dragging and snap the start position to the nearest grid point - drag_start_pos.x = - std::floor(io.MousePos.x / (tile_size * scale)) * tile_size * scale; - drag_start_pos.y = - std::floor(io.MousePos.y / (tile_size * scale)) * tile_size * scale; + drag_start_pos = { + std::floor(io.MousePos.x / (tile_size * scale)) * tile_size * scale, + std::floor(io.MousePos.y / (tile_size * scale)) * tile_size * scale}; dragging = true; } + if (dragging) { + ImVec2 current_pos = io.MousePos; + // Snap current position to the nearest grid point + ImVec2 snapped_current_pos{ + std::floor(current_pos.x / (tile_size * scale)) * tile_size * scale, + std::floor(current_pos.y / (tile_size * scale)) * tile_size * scale}; - ImVec2 current_pos = io.MousePos; - // Snap current position to the nearest grid point - ImVec2 snapped_current_pos; - snapped_current_pos.x = - std::floor(current_pos.x / (tile_size * scale)) * tile_size * scale; - snapped_current_pos.y = - std::floor(current_pos.y / (tile_size * scale)) * tile_size * scale; - // Calculate rect_min and rect_max considering the drag direction - ImVec2 rect_min = ImVec2(std::min(drag_start_pos.x, snapped_current_pos.x), - std::min(drag_start_pos.y, snapped_current_pos.y)); - ImVec2 rect_max = ImVec2( - std::max(drag_start_pos.x, snapped_current_pos.x) + tile_size * scale, - std::max(drag_start_pos.y, snapped_current_pos.y) + tile_size * scale); + // Calculate rect_min and rect_max considering the drag direction + ImVec2 rect_min = ImVec2(std::min(drag_start_pos.x, snapped_current_pos.x), + std::min(drag_start_pos.y, snapped_current_pos.y)); + ImVec2 rect_max = ImVec2( + std::max(drag_start_pos.x, snapped_current_pos.x) + tile_size * scale, + std::max(drag_start_pos.y, snapped_current_pos.y) + tile_size * scale); - if (dragging && ImGui::IsMouseDragging(ImGuiMouseButton_Right)) { - draw_list_->AddRect(rect_min, rect_max, kRectangleBorder); + if (ImGui::IsMouseDragging(ImGuiMouseButton_Right)) { + draw_list_->AddRect(rect_min, rect_max, kRectangleBorder); + } + + if (!ImGui::IsMouseDown(ImGuiMouseButton_Right)) { + dragging = false; + ImVec2 scaled_rect_min = + ImVec2(drag_start_pos.x / scale, drag_start_pos.y / scale); + ImVec2 scaled_rect_max = ImVec2(rect_max.x / scale, rect_max.y / scale); + + // Calculate the bounds of the rectangle in terms of 16x16 tile indices + constexpr int tile16_size = 16; + int start_x = scaled_rect_min.x / tile16_size; + int start_y = scaled_rect_min.y / tile16_size; + int end_x = scaled_rect_max.x / tile16_size; + int end_y = scaled_rect_max.y / tile16_size; + + // Loop through the tiles in the rectangle and store their positions + selected_tiles_.clear(); + for (int y = start_y; y < end_y; ++y) { + for (int x = start_x; x < end_x; ++x) { + selected_tiles_.push_back(ImVec2(x * tile16_size, y * tile16_size)); + } + } + + // Clear and add the calculated rectangle points + points_.clear(); + points_.push_back(scaled_rect_min); + points_.push_back(scaled_rect_max); + } } +} - if (dragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) { - dragging = false; - ImVec2 scaled_rect_min = - ImVec2(drag_start_pos.x / scale, drag_start_pos.y / scale); - ImVec2 scaled_rect_max = ImVec2(rect_max.x / scale, rect_max.y / scale); +void Canvas::DrawSelectRectTile16(int current_map) { + const ImGuiIO &io = ImGui::GetIO(); + const ImVec2 origin(canvas_p0_.x + scrolling_.x, canvas_p0_.y + scrolling_.y); + const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y); - // Here, calculate and store the tile16 IDs within the rectangle - selected_tiles_ = - GetTileIDsInGrid(scaled_rect_min.x, scaled_rect_min.y, - scaled_rect_max.x - scaled_rect_min.x, - scaled_rect_max.y - scaled_rect_min.y, tile_size); + if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { + // Calculate the coordinates of the mouse + ImVec2 painter_pos; + painter_pos.x = std::floor((double)mouse_pos.x / 16) * 16; + painter_pos.y = std::floor((double)mouse_pos.y / 16) * 16; + int painter_x = painter_pos.x; + int painter_y = painter_pos.y; + constexpr int small_map_size = 0x200; - // Clear and add the calculated rectangle points - points_.clear(); - points_.push_back(scaled_rect_min); - points_.push_back(scaled_rect_max); + auto tile16_x = (painter_x % small_map_size) / (small_map_size / 0x20); + auto tile16_y = (painter_y % small_map_size) / (small_map_size / 0x20); + + int superY = current_map / 8; + int superX = current_map % 8; + + int index_x = superX * 0x20 + tile16_x; + int index_y = superY * 0x20 + tile16_y; + selected_tiles_.push_back(ImVec2(index_x, index_y)); } } diff --git a/src/app/gui/canvas.h b/src/app/gui/canvas.h index a583f261..1ec6921a 100644 --- a/src/app/gui/canvas.h +++ b/src/app/gui/canvas.h @@ -98,8 +98,12 @@ class Canvas { void DrawOutline(int x, int y, int w, int h); void DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color); void DrawOutlineWithColor(int x, int y, int w, int h, uint32_t color); + void DrawSelectRect(int tile_size, float scale = 1.0f); + void DrawSelectRectTile16(int current_map); + void DrawRect(int x, int y, int w, int h, ImVec4 color); + void DrawText(std::string text, int x, int y); void DrawGridLines(float grid_step); void DrawGrid(float grid_step = 64.0f, int tile_id_offset = 8); @@ -184,7 +188,7 @@ class Canvas { ImVec2 mouse_pos_in_canvas_; ImVec2 drawn_tile_pos_; - std::vector selected_tiles_; + std::vector selected_tiles_; }; } // namespace gui diff --git a/src/app/zelda3/overworld.cc b/src/app/zelda3/overworld.cc index 6af80872..96f6b6a1 100644 --- a/src/app/zelda3/overworld.cc +++ b/src/app/zelda3/overworld.cc @@ -99,33 +99,6 @@ absl::Status Overworld::Load(ROM &rom) { return absl::OkStatus(); } -absl::Status Overworld::LoadOverworldMaps() { - auto size = tiles16_.size(); - std::vector> futures; - for (int i = 0; i < kNumOverworldMaps; ++i) { - int world_type = 0; - if (i >= 64 && i < 0x80) { - world_type = 1; - } else if (i >= 0x80) { - world_type = 2; - } - futures.emplace_back(std::async(std::launch::async, [this, i, size, - world_type]() { - return overworld_maps_[i].BuildMap(size, game_state_, world_type, - map_parent_, GetMapTiles(world_type)); - })); - } - - // Wait for all tasks to complete and check their results - for (auto &future : futures) { - absl::Status status = future.get(); - if (!status.ok()) { - return status; - } - } - return absl::OkStatus(); -} - void Overworld::FetchLargeMaps() { for (int i = 128; i < 145; i++) { map_parent_[i] = 0; @@ -171,7 +144,7 @@ void Overworld::FetchLargeMaps() { map_parent_[i + 8] = (uchar)i; map_parent_[i + 72] = (uchar)(i + 64); overworld_maps_[i + 8].SetAsLargeMap(i, 2); - overworld_maps_[i + 64].SetAsLargeMap(i + 64, 2); + overworld_maps_[i + 72].SetAsLargeMap(i + 64, 2); mapChecked[i + 9] = true; map_parent_[i + 9] = (uchar)i; @@ -199,40 +172,36 @@ void Overworld::FetchLargeMaps() { } } -uint16_t Overworld::GenerateTile32(int index, int quadrant, int dimension) { - // The addresses of the four 32x32 pixel tiles in the rom()-> - const uint32_t map32address[4] = {rom()->version_constants().kMap32TileTL, - rom()->version_constants().kMap32TileTR, - rom()->version_constants().kMap32TileBL, - rom()->version_constants().kMap32TileBR}; - - return (ushort)(rom_[map32address[dimension] + quadrant + (index)] + - (((rom_[map32address[dimension] + (index) + - (quadrant <= 1 ? 4 : 5)] >> - (quadrant % 2 == 0 ? 4 : 0)) & - 0x0F) * - 256)); -} - void Overworld::AssembleMap32Tiles() { + auto get_tile16_for_tile32 = [this](int index, int quadrant, int dimension) { + const uint32_t map32address[4] = {rom()->version_constants().kMap32TileTL, + rom()->version_constants().kMap32TileTR, + rom()->version_constants().kMap32TileBL, + rom()->version_constants().kMap32TileBR}; + return (uint16_t)(rom_[map32address[dimension] + quadrant + (index)] + + (((rom_[map32address[dimension] + (index) + + (quadrant <= 1 ? 4 : 5)] >> + (quadrant % 2 == 0 ? 4 : 0)) & + 0x0F) * + 256)); + }; + // Loop through each 32x32 pixel tile in the rom()-> for (int i = 0; i < 0x33F0; i += 6) { // Loop through each quadrant of the 32x32 pixel tile. for (int k = 0; k < 4; k++) { // Generate the 16-bit tile for the current quadrant of the current // 32x32 pixel tile. - uint16_t tl = GenerateTile32(i, k, (int)Dimension::map32TilesTL); - uint16_t tr = GenerateTile32(i, k, (int)Dimension::map32TilesTR); - uint16_t bl = GenerateTile32(i, k, (int)Dimension::map32TilesBL); - uint16_t br = GenerateTile32(i, k, (int)Dimension::map32TilesBR); + uint16_t tl = get_tile16_for_tile32(i, k, (int)Dimension::map32TilesTL); + uint16_t tr = get_tile16_for_tile32(i, k, (int)Dimension::map32TilesTR); + uint16_t bl = get_tile16_for_tile32(i, k, (int)Dimension::map32TilesBL); + uint16_t br = get_tile16_for_tile32(i, k, (int)Dimension::map32TilesBR); // Add the generated 16-bit tiles to the tiles32 vector. tiles32_unique_.emplace_back(gfx::Tile32(tl, tr, bl, br)); } } - // Initialize the light_world, dark_world, and special_world vectors with - // the appropriate number of tiles. map_tiles_.light_world.resize(0x200); map_tiles_.dark_world.resize(0x200); map_tiles_.special_world.resize(0x200); @@ -289,55 +258,46 @@ void Overworld::OrganizeMapTiles(Bytes &bytes, Bytes &bytes2, int i, int sx, } } -namespace { -uint GetOwMapGfxHighPtr(const uchar *rom, int index, uint32_t map_high_ptr) { - int p1 = (rom[map_high_ptr + 2 + (3 * index)] << 16) + - (rom[map_high_ptr + 1 + (3 * index)] << 8) + - (rom[map_high_ptr + (3 * index)]); - return core::SnesToPc(p1); -} - -uint GetOwMapGfxLowPtr(const uchar *rom, int index, uint32_t map_low_ptr) { - int p2 = (rom[map_low_ptr + 2 + (3 * index)] << 16) + - (rom[map_low_ptr + 1 + (3 * index)] << 8) + - (rom[map_low_ptr + (3 * index)]); - return core::SnesToPc(p2); -} -} // namespace - absl::Status Overworld::DecompressAllMapTiles() { + const auto get_ow_map_gfx_ptr = [this](int index, uint32_t map_ptr) { + int p = (rom()->data()[map_ptr + 2 + (3 * index)] << 16) + + (rom()->data()[map_ptr + 1 + (3 * index)] << 8) + + (rom()->data()[map_ptr + (3 * index)]); + return core::SnesToPc(p); + }; + int lowest = 0x0FFFFF; int highest = 0x0F8000; int sx = 0; int sy = 0; int c = 0; for (int i = 0; i < 160; i++) { - auto p1 = GetOwMapGfxHighPtr( - rom()->data(), i, - rom()->version_constants().kCompressedAllMap32PointersHigh); - auto p2 = GetOwMapGfxLowPtr( - rom()->data(), i, - rom()->version_constants().kCompressedAllMap32PointersLow); + auto p1 = get_ow_map_gfx_ptr( + i, rom()->version_constants().kCompressedAllMap32PointersHigh); + auto p2 = get_ow_map_gfx_ptr( + i, rom()->version_constants().kCompressedAllMap32PointersLow); + int ttpos = 0; - if (p1 >= highest) { - highest = p1; + if (p1 >= highest) highest = p1; + if (p2 >= highest) highest = p2; + + if (p1 <= lowest && p1 > 0x0F8000) lowest = p1; + if (p2 <= lowest && p2 > 0x0F8000) lowest = p2; + + std::vector bytes, bytes2; + int size1, size2; + auto decomp = gfx::lc_lz2::Uncompress(rom()->data() + p2, &size1, 1); + bytes.resize(size1); + for (int i = 0; i < size1; i++) { + bytes[i] = decomp[i]; } - if (p2 >= highest) { - highest = p2; + decomp = gfx::lc_lz2::Uncompress(rom()->data() + p1, &size2, 1); + bytes2.resize(size2); + for (int i = 0; i < size2; i++) { + bytes2[i] = decomp[i]; } - if (p1 <= lowest && p1 > 0x0F8000) { - lowest = p1; - } - if (p2 <= lowest && p2 > 0x0F8000) { - lowest = p2; - } - - ASSIGN_OR_RETURN( - auto bytes, gfx::lc_lz2::DecompressOverworld(rom()->data(), p2, 0x1000)) - ASSIGN_OR_RETURN(auto bytes2, gfx::lc_lz2::DecompressOverworld( - rom()->data(), p1, 0x1000)) OrganizeMapTiles(bytes, bytes2, i, sx, sy, ttpos); sx++; @@ -356,6 +316,33 @@ absl::Status Overworld::DecompressAllMapTiles() { return absl::OkStatus(); } +absl::Status Overworld::LoadOverworldMaps() { + auto size = tiles16_.size(); + std::vector> futures; + for (int i = 0; i < kNumOverworldMaps; ++i) { + int world_type = 0; + if (i >= 64 && i < 0x80) { + world_type = 1; + } else if (i >= 0x80) { + world_type = 2; + } + futures.emplace_back(std::async(std::launch::async, [this, i, size, + world_type]() { + return overworld_maps_[i].BuildMap(size, game_state_, world_type, + map_parent_, GetMapTiles(world_type)); + })); + } + + // Wait for all tasks to complete and check their results + for (auto &future : futures) { + absl::Status status = future.get(); + if (!status.ok()) { + return status; + } + } + return absl::OkStatus(); +} + void Overworld::LoadTileTypes() { for (int i = 0; i < 0x200; i++) { all_tiles_types_[i] = rom()->data()[overworldTilesType + i]; @@ -454,12 +441,13 @@ absl::Status Overworld::LoadExits() { } absl::Status Overworld::LoadItems() { - ASSIGN_OR_RETURN(int pointer, rom()->ReadLong(zelda3::overworldItemsAddress)); - int pointer_pc = core::SnesToPc(pointer); // 1BC2F9 -> 0DC2F9 + ASSIGN_OR_RETURN(uint32_t pointer, + rom()->ReadLong(zelda3::overworldItemsAddress)); + uint32_t pointer_pc = core::SnesToPc(pointer); // 1BC2F9 -> 0DC2F9 for (int i = 0; i < 128; i++) { ASSIGN_OR_RETURN(uint16_t word_address, rom()->ReadWord(pointer_pc + i * 2)); - int addr = (pointer & 0xFF0000) | word_address; // 1B F9 3C + uint32_t addr = (pointer & 0xFF0000) | word_address; // 1B F9 3C addr = core::SnesToPc(addr); if (overworld_maps_[i].IsLargeMap()) { @@ -551,6 +539,8 @@ absl::Status Overworld::LoadSpritesFromMap(int sprite_start, int sprite_count, return absl::OkStatus(); } +// --------------------------------------------------------------------------- + absl::Status Overworld::Save(ROM &rom) { rom_ = rom; @@ -590,24 +580,17 @@ absl::Status Overworld::SaveOverworldMaps() { std::vector a, b; int size_a, size_b; // Compress single_map_1 and single_map_2 - if (flags()->kUseClassicCompression) { - auto a_char = gfx::lc_lz2::Compress(single_map_1.data(), 256, &size_a, 1); - auto b_char = gfx::lc_lz2::Compress(single_map_2.data(), 256, &size_b, 1); - // Copy the compressed data to a and b - a.resize(size_a); - b.resize(size_b); - // Copy the arrays manually - for (int k = 0; k < size_a; k++) { - a[k] = a_char[k]; - } - for (int k = 0; k < size_b; k++) { - b[k] = b_char[k]; - } - } else { - ASSIGN_OR_RETURN( - a, gfx::lc_lz2::CompressOverworld(single_map_1.data(), 0, 256)) - ASSIGN_OR_RETURN( - b, gfx::lc_lz2::CompressOverworld(single_map_2.data(), 0, 256)) + auto a_char = gfx::lc_lz2::Compress(single_map_1.data(), 256, &size_a, 1); + auto b_char = gfx::lc_lz2::Compress(single_map_2.data(), 256, &size_b, 1); + // Copy the compressed data to a and b + a.resize(size_a); + b.resize(size_b); + // Copy the arrays manually + for (int k = 0; k < size_a; k++) { + a[k] = a_char[k]; + } + for (int k = 0; k < size_b; k++) { + b[k] = b_char[k]; } if (a.empty() || b.empty()) { return absl::AbortedError("Error compressing map gfx."); @@ -775,38 +758,42 @@ absl::Status Overworld::SaveLargeMaps() { const int large_map_offsets[] = {0, 1, 8, 9}; for (const auto &offset : large_map_offsets) { // Check 1 - RETURN_IF_ERROR(rom()->Write(overworldMapSize + i + offset, 0x20)); + RETURN_IF_ERROR(rom()->WriteByte(overworldMapSize + i + offset, 0x20)); // Check 2 RETURN_IF_ERROR( - rom()->Write(overworldMapSizeHighByte + i + offset, 0x03)); + rom()->WriteByte(overworldMapSizeHighByte + i + offset, 0x03)); // Check 3 - RETURN_IF_ERROR(rom()->Write(overworldScreenSize + i + offset, 0x00)); RETURN_IF_ERROR( - rom()->Write(overworldScreenSize + i + offset + 64, 0x00)); + rom()->WriteByte(overworldScreenSize + i + offset, 0x00)); + RETURN_IF_ERROR( + rom()->WriteByte(overworldScreenSize + i + offset + 64, 0x00)); // Check 4 RETURN_IF_ERROR( - rom()->Write(OverworldScreenSizeForLoading + i + offset, 0x04)); - RETURN_IF_ERROR(rom()->Write( + rom()->WriteByte(OverworldScreenSizeForLoading + i + offset, 0x04)); + RETURN_IF_ERROR(rom()->WriteByte( OverworldScreenSizeForLoading + i + offset + 64, 0x04)); - RETURN_IF_ERROR(rom()->Write( + RETURN_IF_ERROR(rom()->WriteByte( OverworldScreenSizeForLoading + i + offset + 128, 0x04)); } // Check 5 and 6 RETURN_IF_ERROR(rom()->WriteShort(transition_target_north + (i * 2) + 2, - (short)((parentyPos * 0x200) - 0xE0))); - RETURN_IF_ERROR(rom()->WriteShort(transition_target_west + (i * 2) + 2, - (short)((parentxPos * 0x200) - 0x100))); + (ushort)((parentyPos * 0x200) - 0xE0))); + RETURN_IF_ERROR( + rom()->WriteShort(transition_target_west + (i * 2) + 2, + (ushort)((parentxPos * 0x200) - 0x100))); RETURN_IF_ERROR(rom()->WriteShort(transition_target_north + (i * 2) + 16, - (short)((parentyPos * 0x200) - 0xE0))); - RETURN_IF_ERROR(rom()->WriteShort(transition_target_west + (i * 2) + 16, - (short)((parentxPos * 0x200) - 0x100))); + (ushort)((parentyPos * 0x200) - 0xE0))); + RETURN_IF_ERROR( + rom()->WriteShort(transition_target_west + (i * 2) + 16, + (ushort)((parentxPos * 0x200) - 0x100))); RETURN_IF_ERROR(rom()->WriteShort(transition_target_north + (i * 2) + 18, - (short)((parentyPos * 0x200) - 0xE0))); - RETURN_IF_ERROR(rom()->WriteShort(transition_target_west + (i * 2) + 18, - (short)((parentxPos * 0x200) - 0x100))); + (ushort)((parentyPos * 0x200) - 0xE0))); + RETURN_IF_ERROR( + rom()->WriteShort(transition_target_west + (i * 2) + 18, + (ushort)((parentxPos * 0x200) - 0x100))); RETURN_IF_ERROR(rom()->WriteShort(overworldTransitionPositionX + (i * 2), (parentxPos * 0x200))); @@ -884,8 +871,7 @@ absl::Status Overworld::SaveLargeMaps() { // If the area to the right is the top left of a large area. if (overworld_maps_[i + 2].ParentIndex() == 0) { RETURN_IF_ERROR(rom()->WriteShort( - OverworldScreenTileMapChangeByScreen2 + (i * 2) + 18, - 0x0080)); // Always 0x1080. + OverworldScreenTileMapChangeByScreen2 + (i * 2) + 18, 0x0080)); } } } @@ -968,24 +954,26 @@ absl::Status Overworld::SaveLargeMaps() { if (i - 1 >= 0 && parentxPos != 0) { if (overworld_maps_[i - 1].IsLargeMap()) { if (overworld_maps_[i - 1].ParentIndex() == 3) { - rom()->WriteShort(OverworldScreenTileMapChangeByScreen1 + (i * 2), - 0xF060); + RETURN_IF_ERROR(rom()->WriteShort( + OverworldScreenTileMapChangeByScreen1 + (i * 2), 0xF060)); } } } - rom()->WriteShort(OverworldScreenTileMapChangeByScreen2 + (i * 2) + 128, - 0x0040); + RETURN_IF_ERROR(rom()->WriteShort( + OverworldScreenTileMapChangeByScreen2 + (i * 2) + 128, 0x0040)); if (i + 1 < 64 && parentxPos != 7) { if (overworld_maps_[i + 1].IsLargeMap()) { if (overworld_maps_[i + 1].ParentIndex() == 1) { - rom()->WriteShort(OverworldScreenTileMapChangeByScreen2 + (i * 2), - 0x1060); + RETURN_IF_ERROR(rom()->WriteShort( + OverworldScreenTileMapChangeByScreen2 + (i * 2), 0xF040)); } } } - rom()->WriteShort(OverworldScreenTileMapChangeByScreen3 + (i * 2) + 256, - 0x1800); + + RETURN_IF_ERROR(rom()->WriteShort( + OverworldScreenTileMapChangeByScreen3 + (i * 2) + 256, 0x1800)); + // If the area above is a large map, we don't need to add an offset to it. // otherwise leave it the same. // Just to make sure where don't try to read outside of the array. @@ -994,13 +982,15 @@ absl::Status Overworld::SaveLargeMaps() { if (overworld_maps_[i - 8].IsLargeMap()) { // If we are under the bottom right of the large area. if (overworld_maps_[i - 8].ParentIndex() == 3) { - rom()->WriteShort(OverworldScreenTileMapChangeByScreen3 + (i * 2), - 0x17C0); + RETURN_IF_ERROR(rom()->WriteShort( + OverworldScreenTileMapChangeByScreen3 + (i * 2), 0x17C0)); } } } - rom()->WriteShort(OverworldScreenTileMapChangeByScreen4 + (i * 2) + 384, - 0x1000); + + RETURN_IF_ERROR(rom()->WriteShort( + OverworldScreenTileMapChangeByScreen4 + (i * 2) + 384, 0x1000)); + // If the area below is a large map, we don't need to add an offset to it. // otherwise leave it the same. // Just to make sure where don't try to read outside of the array. @@ -1009,16 +999,16 @@ absl::Status Overworld::SaveLargeMaps() { if (overworld_maps_[i + 8].IsLargeMap()) { // If we are on top of the top right of the large area. if (overworld_maps_[i + 8].ParentIndex() == 1) { - rom()->WriteShort(OverworldScreenTileMapChangeByScreen4 + (i * 2), - 0x0FC0); + RETURN_IF_ERROR(rom()->WriteShort( + OverworldScreenTileMapChangeByScreen4 + (i * 2), 0x0FC0)); } } } RETURN_IF_ERROR(rom()->WriteShort(transition_target_north + (i * 2), - (short)((yPos * 0x200) - 0xE0))); + (ushort)((yPos * 0x200) - 0xE0))); RETURN_IF_ERROR(rom()->WriteShort(transition_target_west + (i * 2), - (short)((xPos * 0x200) - 0x100))); + (ushort)((xPos * 0x200) - 0x100))); RETURN_IF_ERROR(rom()->WriteShort(overworldTransitionPositionX + (i * 2), (xPos * 0x200))); @@ -1078,7 +1068,7 @@ std::vector GetAllTile16(OWMapTiles &map_tiles_) { } } // namespace -bool Overworld::CreateTile32Tilemap(bool only_show) { +absl::Status Overworld::CreateTile32Tilemap() { tiles32_unique_.clear(); tiles32_list_.clear(); @@ -1090,7 +1080,6 @@ bool Overworld::CreateTile32Tilemap(bool only_show) { std::vector unique_tiles(all_tile_16); unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end()); - std::cout << "Number of unique Tiles16: " << unique_tiles.size() << std::endl; // Create the indexed tiles list std::unordered_map all_tiles_indexed; @@ -1116,23 +1105,20 @@ bool Overworld::CreateTile32Tilemap(bool only_show) { tiles32_unique_.emplace_back(padding_tile.GetPackedValue()); } - if (only_show) { - std::cout << "Number of unique Tiles32: " << unique_tiles.size() - << " Out of: " << LimitOfMap32 << std::endl; - } else if (tiles32_unique_.size() > LimitOfMap32) { - std::cerr << "Number of unique Tiles32: " << unique_tiles.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; + if (tiles32_unique_.size() > LimitOfMap32) { + return absl::InternalError(absl::StrFormat( + "Number of unique Tiles32: %d Out of: %d\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", + unique_tiles.size(), LimitOfMap32)); } - std::cout << "Number of unique Tiles32: " << tiles32_unique_.size() - << " Saved:" << tiles32_unique_.size() - << " Out of: " << LimitOfMap32 << std::endl; + if (flags()->kLogToConsole) { + std::cout << "Number of unique Tiles32: " << tiles32_unique_.size() + << " Saved:" << tiles32_unique_.size() + << " Out of: " << LimitOfMap32 << std::endl; + } int v = tiles32_unique_.size(); for (int i = v; i < LimitOfMap32; i++) { @@ -1140,7 +1126,7 @@ bool Overworld::CreateTile32Tilemap(bool only_show) { tiles32_unique_.emplace_back(padding_tile.GetPackedValue()); } - return false; + return absl::OkStatus(); } absl::Status Overworld::SaveMap32Tiles() { diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index 023e9b90..7483cd9d 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -462,15 +462,22 @@ class Overworld : public SharedROM, public core::ExperimentFlags { absl::Status SaveExits(); absl::Status SaveItems(); - bool CreateTile32Tilemap(bool onlyShow = false); + absl::Status CreateTile32Tilemap(); absl::Status SaveMap16Tiles(); absl::Status SaveMap32Tiles(); absl::Status SaveMapProperties(); absl::Status LoadPrototype(ROM &rom_, const std::string &tilemap_filename); - int GetTile16Id(int grid_id) const { - return map_tiles_.light_world[game_state_][grid_id]; + int current_world_ = 0; + int GetTile16Id(ImVec2 position) const { + if (current_world_ == 0) { + return map_tiles_.light_world[position.x][position.y]; + } else if (current_world_ == 1) { + return map_tiles_.dark_world[position.x][position.y]; + } else { + return map_tiles_.special_world[position.x][position.y]; + } } auto overworld_maps() const { return overworld_maps_; } @@ -519,7 +526,6 @@ class Overworld : public SharedROM, public core::ExperimentFlags { }; void FetchLargeMaps(); - uint16_t GenerateTile32(int index, int quadrant, int dimension); void AssembleMap32Tiles(); void AssembleMap16Tiles(); void AssignWorldTiles(int x, int y, int sx, int sy, int tpos, diff --git a/src/app/zelda3/overworld_map.cc b/src/app/zelda3/overworld_map.cc index eb1e5d6b..f95a8866 100644 --- a/src/app/zelda3/overworld_map.cc +++ b/src/app/zelda3/overworld_map.cc @@ -30,8 +30,8 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world, OWBlockset& world_blockset) { game_state_ = game_state; world_ = world; + parent_ = map_parent[index_]; if (large_map_) { - parent_ = map_parent[index_]; if (parent_ != index_ && !initialized_) { if (index_ >= 0x80 && index_ <= 0x8A && index_ != 0x88) { area_graphics_ = rom_[overworldSpecialGFXGroup + (parent_ - 0x80)]; @@ -60,7 +60,7 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world, void OverworldMap::LoadAreaInfo() { if (index_ != 0x80) { if (index_ <= 150) - large_map_ = rom_[overworldMapSize + (index_ & 0x3F)] != 0; + large_map_ = (rom_[overworldMapSize + (index_ & 0x3F)] != 0); else { large_map_ = index_ == 129 || index_ == 130 || index_ == 137 || index_ == 138; @@ -119,8 +119,10 @@ void OverworldMap::LoadAreaInfo() { parent_ = 129; } + message_id_ = rom_[overworldMessages + parent_]; + area_palette_ = rom_[overworldSpecialPALGroup + parent_ - 0x80]; - if (index_ >= 0x80 && index_ <= 0x8A && index_ != 0x88) { + if ((index_ >= 0x80 && index_ <= 0x8A && index_ != 0x88) || index_ == 0x94) { area_graphics_ = rom_[overworldSpecialGFXGroup + (parent_ - 0x80)]; area_palette_ = rom_[overworldSpecialPALGroup + 1]; } else if (index_ == 0x88) { @@ -132,8 +134,6 @@ void OverworldMap::LoadAreaInfo() { area_palette_ = rom_[overworldMapPalette + parent_]; } - message_id_ = rom_[overworldMessages + parent_]; - sprite_graphics_[0] = rom_[overworldSpriteset + parent_ + 0x80]; sprite_graphics_[1] = rom_[overworldSpriteset + parent_ + 0x80]; sprite_graphics_[2] = rom_[overworldSpriteset + parent_ + 0x80]; diff --git a/src/app/zelda3/overworld_map.h b/src/app/zelda3/overworld_map.h index 38b97f5c..07f52734 100644 --- a/src/app/zelda3/overworld_map.h +++ b/src/app/zelda3/overworld_map.h @@ -107,12 +107,12 @@ class OverworldMap : public GfxContext { bool large_map_ = false; bool initialized_ = false; - int parent_ = 0; - int index_ = 0; - int parent_index_ = 0; - int world_ = 0; - int game_state_ = 0; - int world_index_ = 0; + int index_ = 0; // Map index + int parent_ = 0; // Parent map index + int parent_index_ = 0; // Quadrant ID [0-3] + int world_ = 0; // World ID [0-2] + int game_state_ = 0; // Game state [0-2] + int world_index_ = 0; // Spr Pal Modifier uint16_t message_id_ = 0; uint8_t area_graphics_ = 0;