refactor: enhance overworld entity properties and version handling

- Updated `UpdateMapProperties` methods across various entities (entrances, exits, items, sprites) to include an optional context parameter for improved area size detection.
- Introduced `OverworldVersionHelper` for centralized ROM version detection and feature gating, replacing scattered inline checks.
- Refactored coordinate calculations to utilize normalized map IDs, ensuring consistency and preventing data corruption.
- Enhanced exit properties to sync player positions and calculate scroll/camera values based on the overworld context.

Benefits:
- Streamlines entity property updates and improves compatibility with different ROM versions.
- Reduces code duplication and enhances maintainability by centralizing version checks.
- Ensures accurate coordinate calculations for overworld entities, improving overall functionality.
This commit is contained in:
scawful
2025-10-18 00:09:09 -04:00
parent 9f56728f80
commit 1e39df88a3
15 changed files with 546 additions and 282 deletions

View File

@@ -3,7 +3,10 @@
#include "app/gui/core/icons.h"
#include "app/gui/core/input.h"
#include "app/gui/core/style.h"
#include "imgui.h"
#include "util/hex.h"
#include "zelda3/common.h"
#include "zelda3/overworld/overworld_item.h"
namespace yaze {
namespace editor {
@@ -26,11 +29,8 @@ bool IsMouseHoveringOverEntity(const zelda3::GameEntity &entity,
const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
// Check if the mouse is hovering over the entity
if (mouse_pos.x >= entity.x_ && mouse_pos.x <= entity.x_ + 16 &&
mouse_pos.y >= entity.y_ && mouse_pos.y <= entity.y_ + 16) {
return true;
}
return false;
return mouse_pos.x >= entity.x_ && mouse_pos.x <= entity.x_ + 16 &&
mouse_pos.y >= entity.y_ && mouse_pos.y <= entity.y_ + 16;
}
void MoveEntityOnGrid(zelda3::GameEntity *entity, ImVec2 canvas_p0,
@@ -154,6 +154,7 @@ bool DrawExitEditorPopup(zelda3::OverworldExit &exit) {
static bool set_done = false;
if (set_done) {
set_done = false;
return true;
}
if (ImGui::BeginPopupModal("Exit editor", NULL,
ImGuiWindowFlags_AlwaysAutoResize)) {
@@ -207,7 +208,9 @@ bool DrawExitEditorPopup(zelda3::OverworldExit &exit) {
if (show_properties) {
Text("Deleted? %s", exit.deleted_ ? "true" : "false");
Text("Hole? %s", exit.is_hole_ ? "true" : "false");
Text("Large Map? %s", exit.large_map_ ? "true" : "false");
Text("Auto-calc scroll/camera? %s", exit.is_automatic_ ? "true" : "false");
Text("Map ID: 0x%02X", exit.map_id_);
Text("Game coords: (%d, %d)", exit.game_x_, exit.game_y_);
}
gui::TextWithSeparators("Unimplemented below");
@@ -260,19 +263,21 @@ bool DrawExitEditorPopup(zelda3::OverworldExit &exit) {
}
if (Button(ICON_MD_DONE)) {
set_done = true; // FIX: Save changes when Done is clicked
ImGui::CloseCurrentPopup();
}
SameLine();
if (Button(ICON_MD_CANCEL)) {
set_done = true;
// FIX: Discard changes - don't set set_done
ImGui::CloseCurrentPopup();
}
SameLine();
if (Button(ICON_MD_DELETE)) {
exit.deleted_ = true;
set_done = true; // FIX: Save deletion when Delete is clicked
ImGui::CloseCurrentPopup();
}
@@ -316,6 +321,7 @@ bool DrawItemEditorPopup(zelda3::OverworldItem &item) {
static bool set_done = false;
if (set_done) {
set_done = false;
return true;
}
if (ImGui::BeginPopupModal("Item editor", NULL,
ImGuiWindowFlags_AlwaysAutoResize)) {
@@ -325,20 +331,26 @@ bool DrawItemEditorPopup(zelda3::OverworldItem &item) {
for (size_t i = 0; i < zelda3::kSecretItemNames.size(); i++) {
if (Selectable(zelda3::kSecretItemNames[i].c_str(), item.id_ == i)) {
item.id_ = i;
item.entity_id_ = i;
item.UpdateMapProperties(item.map_id_, nullptr);
}
}
ImGui::EndGroup();
EndChild();
if (Button(ICON_MD_DONE)) ImGui::CloseCurrentPopup();
if (Button(ICON_MD_DONE)) {
set_done = true; // FIX: Save changes when Done is clicked
ImGui::CloseCurrentPopup();
}
SameLine();
if (Button(ICON_MD_CLOSE)) {
set_done = true;
// FIX: Discard changes - don't set set_done
ImGui::CloseCurrentPopup();
}
SameLine();
if (Button(ICON_MD_DELETE)) {
item.deleted = true;
set_done = true; // FIX: Save deletion when Delete is clicked
ImGui::CloseCurrentPopup();
}
@@ -437,6 +449,7 @@ bool DrawSpriteEditorPopup(zelda3::Sprite &sprite) {
static bool set_done = false;
if (set_done) {
set_done = false;
return true;
}
if (ImGui::BeginPopupModal("Sprite editor", NULL,
ImGuiWindowFlags_AlwaysAutoResize)) {
@@ -447,20 +460,24 @@ bool DrawSpriteEditorPopup(zelda3::Sprite &sprite) {
DrawSpriteTable([&sprite](int selected_id) {
sprite.set_id(selected_id);
sprite.UpdateMapProperties(sprite.map_id());
sprite.UpdateMapProperties(sprite.map_id(), nullptr);
});
ImGui::EndGroup();
EndChild();
if (Button(ICON_MD_DONE)) ImGui::CloseCurrentPopup();
if (Button(ICON_MD_DONE)) {
set_done = true; // FIX: Save changes when Done is clicked
ImGui::CloseCurrentPopup();
}
SameLine();
if (Button(ICON_MD_CLOSE)) {
set_done = true;
// FIX: Discard changes - don't set set_done
ImGui::CloseCurrentPopup();
}
SameLine();
if (Button(ICON_MD_DELETE)) {
sprite.set_deleted(true);
set_done = true; // FIX: Save deletion when Delete is clicked
ImGui::CloseCurrentPopup();
}

View File

@@ -34,33 +34,33 @@ absl::StatusOr<zelda3::OverworldEntrance*> InsertEntrance(
holes[i].entrance_id_ = 0; // Default, user configures in popup
holes[i].is_hole_ = true;
// Update map properties (ZScream: EntranceMode.cs:90)
holes[i].UpdateMapProperties(map_id);
LOG_DEBUG("EntityOps", "Inserted hole at slot %zu: pos=(%d,%d) map=0x%02X",
i, holes[i].x_, holes[i].y_, map_id);
return &holes[i];
}
// Update map properties (ZScream: EntranceMode.cs:90)
holes[i].UpdateMapProperties(map_id, overworld);
LOG_DEBUG("EntityOps", "Inserted hole at slot %zu: pos=(%d,%d) map=0x%02X",
i, holes[i].x_, holes[i].y_, map_id);
return &holes[i];
}
return absl::ResourceExhaustedError(
"No space available for new hole. Delete one first.");
} else {
// Search for first deleted entrance slot (ZScream: EntranceMode.cs:104-130)
auto* entrances = overworld->mutable_entrances();
for (size_t i = 0; i < entrances->size(); ++i) {
if (entrances->at(i).deleted) {
// Reuse deleted slot
entrances->at(i).deleted = false;
entrances->at(i).map_id_ = map_id;
entrances->at(i).x_ = static_cast<int>(snapped_pos.x);
entrances->at(i).y_ = static_cast<int>(snapped_pos.y);
entrances->at(i).entrance_id_ = 0; // Default, user configures in popup
entrances->at(i).is_hole_ = false;
// Update map properties (ZScream: EntranceMode.cs:120)
entrances->at(i).UpdateMapProperties(map_id);
}
return absl::ResourceExhaustedError(
"No space available for new hole. Delete one first.");
} else {
// Search for first deleted entrance slot (ZScream: EntranceMode.cs:104-130)
auto* entrances = overworld->mutable_entrances();
for (size_t i = 0; i < entrances->size(); ++i) {
if (entrances->at(i).deleted) {
// Reuse deleted slot
entrances->at(i).deleted = false;
entrances->at(i).map_id_ = map_id;
entrances->at(i).x_ = static_cast<int>(snapped_pos.x);
entrances->at(i).y_ = static_cast<int>(snapped_pos.y);
entrances->at(i).entrance_id_ = 0; // Default, user configures in popup
entrances->at(i).is_hole_ = false;
// Update map properties (ZScream: EntranceMode.cs:120)
entrances->at(i).UpdateMapProperties(map_id, overworld);
LOG_DEBUG("EntityOps", "Inserted entrance at slot %zu: pos=(%d,%d) map=0x%02X",
i, entrances->at(i).x_, entrances->at(i).y_, map_id);
@@ -111,8 +111,8 @@ absl::StatusOr<zelda3::OverworldExit*> InsertExit(
exits[i].door_type_1_ = 0;
exits[i].door_type_2_ = 0;
// Update map properties
exits[i].UpdateMapProperties(map_id);
// Update map properties with overworld context for area size detection
exits[i].UpdateMapProperties(map_id, overworld);
LOG_DEBUG("EntityOps", "Inserted exit at slot %zu: pos=(%d,%d) map=0x%02X",
i, exits[i].x_, exits[i].y_, map_id);

View File

@@ -9,6 +9,7 @@
#include "app/gui/core/input.h"
#include "app/gui/core/layout_helpers.h"
#include "zelda3/overworld/overworld_map.h"
#include "zelda3/overworld/overworld_version_helper.h"
#include "imgui/imgui.h"
namespace yaze {
@@ -60,15 +61,15 @@ void MapPropertiesSystem::DrawSimplifiedMapSettings(
ImGui::Text("%d (0x%02X)", current_map, current_map);
TableNextColumn();
// IMPORTANT: Don't cache - read fresh to reflect ROM upgrades
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
// Use centralized version detection
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
// ALL ROMs support Small/Large. Only v3+ supports Wide/Tall.
int current_area_size =
static_cast<int>(overworld_->overworld_map(current_map)->area_size());
ImGui::SetNextItemWidth(kComboAreaSizeWidth);
if (asm_version >= 3 && asm_version != 0xFF) {
if (zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version)) {
// v3+ ROM: Show all 4 area size options
if (ImGui::Combo("##AreaSize", &current_area_size, kAreaSizeNames, 4)) {
auto status = overworld_->ConfigureMultiAreaMap(
@@ -95,7 +96,8 @@ void MapPropertiesSystem::DrawSimplifiedMapSettings(
}
}
if (asm_version == 0xFF || asm_version < 3) {
if (rom_version == zelda3::OverworldVersion::kVanilla ||
!zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version)) {
HOVER_HINT("Small (1x1) and Large (2x2) maps. Wide/Tall require v3+");
}
}
@@ -223,9 +225,9 @@ void MapPropertiesSystem::DrawMapPropertiesPanel(
}
// Custom Overworld Features Tab
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
if (asm_version != 0xFF && ImGui::BeginTabItem("Custom Features")) {
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
if (rom_version != zelda3::OverworldVersion::kVanilla &&
ImGui::BeginTabItem("Custom Features")) {
DrawCustomFeaturesTab(current_map);
ImGui::EndTabItem();
}
@@ -254,9 +256,8 @@ void MapPropertiesSystem::DrawCustomBackgroundColorEditor(
return;
}
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
if (asm_version < 2) {
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
if (!zelda3::OverworldVersionHelper::SupportsCustomBGColors(rom_version)) {
Text("Custom background colors require ZSCustomOverworld v2+");
return;
}
@@ -309,15 +310,14 @@ void MapPropertiesSystem::DrawOverlayEditor(int current_map,
return;
}
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
ICON_MD_LAYERS " Visual Effects Configuration");
ImGui::Text("Map: 0x%02X", current_map);
Separator();
if (asm_version < 1) {
if (rom_version == zelda3::OverworldVersion::kVanilla) {
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.4f, 1.0f),
ICON_MD_WARNING " Subscreen overlays require ZSCustomOverworld v1+");
ImGui::Separator();
@@ -491,9 +491,8 @@ void MapPropertiesSystem::SetupCanvasContextMenu(
canvas.AddContextMenuItem(properties_item);
// Custom overworld features (only show if v3+)
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
if (asm_version >= 3 && asm_version != 0xFF) {
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
if (zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version)) {
// Custom Background Color
gui::CanvasMenuItem bg_color_item;
bg_color_item.label = ICON_MD_FORMAT_COLOR_FILL " Custom Background Color";
@@ -589,9 +588,8 @@ void MapPropertiesSystem::DrawGraphicsPopup(int current_map, int game_state) {
}
HOVER_HINT("Sprite graphics sheet for current game state");
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
if (asm_version >= 3) {
auto rom_version_gfx = zelda3::OverworldVersionHelper::GetVersion(*rom_);
if (zelda3::OverworldVersionHelper::SupportsAnimatedGFX(rom_version_gfx)) {
if (gui::InputHexByte(ICON_MD_ANIMATION " Animated GFX",
overworld_->mutable_overworld_map(current_map)
->mutable_animated_gfx(),
@@ -605,7 +603,7 @@ void MapPropertiesSystem::DrawGraphicsPopup(int current_map, int game_state) {
}
// Custom Tile Graphics - Only available for v1+ ROMs
if (asm_version >= 1 && asm_version != 0xFF) {
if (zelda3::OverworldVersionHelper::SupportsExpandedSpace(rom_version_gfx)) {
ImGui::Separator();
ImGui::Text(ICON_MD_GRID_VIEW " Custom Tile Graphics");
ImGui::Separator();
@@ -631,7 +629,7 @@ void MapPropertiesSystem::DrawGraphicsPopup(int current_map, int game_state) {
}
ImGui::EndTable();
}
} else if (asm_version == 0xFF) {
} else if (rom_version_gfx == zelda3::OverworldVersion::kVanilla) {
ImGui::Separator();
ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f),
ICON_MD_INFO " Custom Tile Graphics");
@@ -672,8 +670,8 @@ void MapPropertiesSystem::DrawPalettesPopup(int current_map, int game_state,
HOVER_HINT("Main color palette for background tiles");
// Read fresh to reflect ROM upgrades
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
if (asm_version >= 2) {
auto rom_version_pal = zelda3::OverworldVersionHelper::GetVersion(*rom_);
if (zelda3::OverworldVersionHelper::SupportsCustomBGColors(rom_version_pal)) {
if (gui::InputHexByte(ICON_MD_COLOR_LENS " Main Palette",
overworld_->mutable_overworld_map(current_map)
->mutable_main_palette(),
@@ -1037,14 +1035,13 @@ void MapPropertiesSystem::DrawCustomFeaturesTab(int current_map) {
ImGui::Text(ICON_MD_PHOTO_SIZE_SELECT_LARGE " Area Size");
TableNextColumn();
// ALL ROMs support Small/Large. Only v3+ supports Wide/Tall.
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
auto rom_version_basic = zelda3::OverworldVersionHelper::GetVersion(*rom_);
int current_area_size =
static_cast<int>(overworld_->overworld_map(current_map)->area_size());
ImGui::SetNextItemWidth(130.f);
if (asm_version >= 3 && asm_version != 0xFF) {
if (zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version_basic)) {
// v3+ ROM: Show all 4 area size options
static const char* all_sizes[] = {"Small (1x1)", "Large (2x2)",
"Wide (2x1)", "Tall (1x2)"};
@@ -1079,7 +1076,7 @@ void MapPropertiesSystem::DrawCustomFeaturesTab(int current_map) {
}
}
if (asm_version >= 2) {
if (zelda3::OverworldVersionHelper::SupportsCustomBGColors(rom_version_basic)) {
TableNextColumn();
ImGui::Text(ICON_MD_COLOR_LENS " Main Palette");
TableNextColumn();
@@ -1096,7 +1093,7 @@ void MapPropertiesSystem::DrawCustomFeaturesTab(int current_map) {
}
}
if (asm_version >= 3) {
if (zelda3::OverworldVersionHelper::SupportsAnimatedGFX(rom_version_basic)) {
TableNextColumn();
ImGui::Text(ICON_MD_ANIMATION " Animated GFX");
TableNextColumn();
@@ -1131,10 +1128,10 @@ void MapPropertiesSystem::DrawCustomFeaturesTab(int current_map) {
}
void MapPropertiesSystem::DrawTileGraphicsTab(int current_map) {
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
// Only show custom tile graphics for v1+ ROMs
if (asm_version >= 1 && asm_version != 0xFF) {
if (zelda3::OverworldVersionHelper::SupportsExpandedSpace(rom_version)) {
ImGui::Text(ICON_MD_GRID_VIEW " Custom Tile Graphics (8 sheets)");
Separator();
@@ -1350,9 +1347,8 @@ void MapPropertiesSystem::RefreshSiblingMapGraphics(int map_index, bool include_
}
void MapPropertiesSystem::DrawMosaicControls(int current_map) {
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
if (asm_version >= 2) {
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
if (zelda3::OverworldVersionHelper::SupportsCustomBGColors(rom_version)) {
ImGui::Separator();
ImGui::Text("Mosaic Effects (per direction):");
@@ -1379,8 +1375,7 @@ void MapPropertiesSystem::DrawMosaicControls(int current_map) {
void MapPropertiesSystem::DrawOverlayControls(int current_map,
bool& show_overlay_preview) {
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
// Determine if this is a special overworld map (0x80-0x9F)
bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
@@ -1491,7 +1486,7 @@ void MapPropertiesSystem::DrawOverlayControls(int current_map,
ImGui::Separator();
// Interactive/Dynamic Map Overlay Section (for vanilla ROMs)
if (asm_version == 0xFF) {
if (rom_version == zelda3::OverworldVersion::kVanilla) {
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.4f, 1.0f),
ICON_MD_EDIT_NOTE " Map Overlay (Interactive)");
ImGui::SameLine();
@@ -1537,16 +1532,17 @@ void MapPropertiesSystem::DrawOverlayControls(int current_map,
// Show version and capability info
ImGui::Separator();
if (asm_version == 0xFF) {
if (rom_version == zelda3::OverworldVersion::kVanilla) {
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
ICON_MD_INFO " Vanilla ROM");
ImGui::BulletText("Visual effects use maps 0x80-0x9F");
ImGui::BulletText("Map overlays are read-only");
} else {
const char* version_name = zelda3::OverworldVersionHelper::GetVersionName(rom_version);
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
ICON_MD_UPGRADE " ZSCustomOverworld v%d", asm_version);
ICON_MD_UPGRADE " %s", version_name);
ImGui::BulletText("Enhanced visual effect control");
if (asm_version >= 3) {
if (zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version)) {
ImGui::BulletText("Extended overlay system");
ImGui::BulletText("Custom area sizes support");
}
@@ -1592,8 +1588,6 @@ void MapPropertiesSystem::DrawOverlayPreviewOnMap(int current_map,
uint16_t overlay_id = 0x00FF;
bool has_subscreen_overlay = false;
uint8_t asm_version =
(*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
bool is_special_overworld_map = (current_map >= 0x80 && current_map < 0xA0);
if (is_special_overworld_map) {

View File

@@ -56,6 +56,7 @@
#include "zelda3/overworld/overworld_exit.h"
#include "zelda3/overworld/overworld_item.h"
#include "zelda3/overworld/overworld_map.h"
#include "zelda3/overworld/overworld_version_helper.h"
#include "zelda3/sprite/sprite.h"
namespace yaze::editor {
@@ -491,8 +492,9 @@ void OverworldEditor::DrawToolset() {
// Modern adaptive toolbar with inline mode switching and properties
static gui::Toolset toolbar;
// IMPORTANT: Don't make asm_version static - it needs to update after ROM upgrade
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
// IMPORTANT: Don't cache version - it needs to update after ROM upgrade
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied]; // Still needed for badge display
// Don't use WidgetIdScope here - it conflicts with ImGui::Begin/End ID stack in cards
// Widgets register themselves individually instead
@@ -1256,9 +1258,9 @@ absl::Status OverworldEditor::CheckForCurrentMap() {
const int current_highlighted_map = current_map_;
// Check if ZSCustomOverworld v3 is present
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
bool use_v3_area_sizes = (asm_version >= 3);
// Use centralized version detection
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
bool use_v3_area_sizes = zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version);
// Get area size for v3+ ROMs, otherwise use legacy logic
if (use_v3_area_sizes) {
@@ -1622,7 +1624,8 @@ void OverworldEditor::DrawOverworldCanvas() {
MoveEntityOnGrid(dragged_entity_, ow_map_canvas_.zero_point(),
ow_map_canvas_.scrolling(),
dragged_entity_free_movement_);
dragged_entity_->UpdateMapProperties(dragged_entity_->map_id_);
// Pass overworld context for proper area size detection
dragged_entity_->UpdateMapProperties(dragged_entity_->map_id_, &overworld_);
rom_->set_dirty(true);
}
is_dragging_entity_ = false;
@@ -2118,9 +2121,9 @@ void OverworldEditor::RefreshChildMapOnDemand(int map_index) {
}
// Handle multi-area maps (large, wide, tall) with safe coordination
// Check if ZSCustomOverworld v3 is present
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
bool use_v3_area_sizes = (asm_version >= 3 && asm_version != 0xFF);
// Use centralized version detection
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
bool use_v3_area_sizes = zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version);
if (use_v3_area_sizes) {
// Use v3 multi-area coordination
@@ -2302,9 +2305,9 @@ absl::Status OverworldEditor::RefreshMapPalette() {
overworld_.mutable_overworld_map(current_map_)->LoadPalette());
const auto current_map_palette = overworld_.current_area_palette();
// Check if ZSCustomOverworld v3 is present
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
bool use_v3_area_sizes = (asm_version >= 3 && asm_version != 0xFF);
// Use centralized version detection
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
bool use_v3_area_sizes = zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version);
if (use_v3_area_sizes) {
// Use v3 area size system
@@ -2444,9 +2447,9 @@ void OverworldEditor::RefreshSiblingMapGraphics(int map_index,
void OverworldEditor::RefreshMapProperties() {
const auto& current_ow_map = *overworld_.mutable_overworld_map(current_map_);
// Check if ZSCustomOverworld v3 is present
uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied];
bool use_v3_area_sizes = (asm_version >= 3);
// Use centralized version detection
auto rom_version = zelda3::OverworldVersionHelper::GetVersion(*rom_);
bool use_v3_area_sizes = zelda3::OverworldVersionHelper::SupportsAreaEnum(rom_version);
if (use_v3_area_sizes) {
// Use v3 area size system

View File

@@ -1,4 +1,5 @@
#include "overworld_entity_renderer.h"
#include <string>
#include "absl/strings/str_format.h"
#include "core/features.h"
@@ -7,6 +8,7 @@
#include "zelda3/common.h"
#include "util/hex.h"
#include "imgui/imgui.h"
#include "zelda3/overworld/overworld_item.h"
namespace yaze {
namespace editor {
@@ -24,7 +26,7 @@ ImVec4 GetSpriteColor() { return ImVec4{1.0f, 0.0f, 1.0f, 1.0f}; } // So
void OverworldEntityRenderer::DrawEntrances(ImVec2 canvas_p0, ImVec2 scrolling,
int current_world,
int current_mode) {
hovered_entity_ = nullptr;
// Don't reset hovered_entity_ here - DrawExits resets it (called first)
int i = 0;
for (auto& each : overworld_->entrances()) {
if (each.map_id_ < 0x40 + (current_world * 0x40) &&
@@ -56,11 +58,15 @@ void OverworldEntityRenderer::DrawEntrances(ImVec2 canvas_p0, ImVec2 scrolling,
void OverworldEntityRenderer::DrawExits(ImVec2 canvas_p0, ImVec2 scrolling,
int current_world,
int current_mode) {
// Reset hover state at the start of entity rendering (DrawExits is called first)
hovered_entity_ = nullptr;
int i = 0;
for (auto& each : *overworld_->mutable_exits()) {
if (each.map_id_ < 0x40 + (current_world * 0x40) &&
each.map_id_ >= (current_world * 0x40) && !each.deleted_) {
canvas_->DrawRect(each.x_, each.y_, 16, 16, GetExitColor());
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling)) {
hovered_entity_ = &each;
}
@@ -91,7 +97,7 @@ void OverworldEntityRenderer::DrawItems(int current_world, int current_mode) {
}
std::string item_name = "";
std::string item_name = "";
if (item.id_ < zelda3::kSecretItemNames.size()) {
item_name = zelda3::kSecretItemNames[item.id_];
} else {