yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
Overworld Entity System

This document provides a technical overview of the overworld entity system, including critical bug fixes that enable its functionality and the ongoing plan to refactor it for modularity and ZScream feature parity.

1. System Overview

The overworld entity system manages all interactive objects on the overworld map, such as entrances, exits, items, and sprites. The system is undergoing a refactor to move from a monolithic architecture within the Overworld class to a modular design where each entity's save/load logic is handled in dedicated files.

Key Goals of the Refactor:

  • Modularity: Isolate entity logic into testable, self-contained units.
  • ZScream Parity: Achieve feature compatibility with ZScream's entity management, including support for expanded ROM formats.
  • Maintainability: Simplify the Overworld class by delegating I/O responsibilities.

2. Core Components & Bug Fixes

Several critical bugs were fixed to make the entity system functional. Understanding these fixes is key to understanding the system's design.

2.1. Entity Interaction and Hover Detection

File: src/app/editor/overworld/overworld_entity_renderer.cc

  • Problem: Exit entities were not responding to mouse interactions because the hover state was being improperly reset.
  • Fix: The hover state (hovered_entity_) is now reset only once at the beginning of the entity rendering cycle, specifically in DrawExits(), which is the first rendering function called. Subsequent functions (DrawEntrances(), DrawItems(), etc.) can set the hover state without it being cleared, preserving the correct hover priority (last-drawn entity wins).
// In DrawExits(), which is called first:
hovered_entity_ = nullptr; // Reset hover state at the start of the cycle.
// In DrawEntrances() and other subsequent renderers:
// The reset is removed to allow hover state to persist.

2.2. Entity Property Popup Save/Cancel Logic

File: src/app/editor/overworld/entity.cc

  • Problem: The "Done" and "Cancel" buttons in entity property popups had inverted logic, causing changes to be saved on "Cancel" and discarded on "Done".
  • Fix: The set_done flag, which controls the popup's return value, is now correctly managed. The "Done" and "Delete" buttons set set_done = true to signal a save action, while the "Cancel" button does not, correctly discarding changes.
// Corrected logic for the "Done" button in popups
if (ImGui::Button(ICON_MD_DONE)) {
set_done = true; // Save changes
ImGui::CloseCurrentPopup();
}
// Corrected logic for the "Cancel" button
if (ImGui::Button(ICON_MD_CANCEL)) {
// Discard changes (do not set set_done)
ImGui::CloseCurrentPopup();
}
#define ICON_MD_CANCEL
Definition icons.h:364
#define ICON_MD_DONE
Definition icons.h:607

2.3. Exit Entity Coordinate System

File: src/zelda3/overworld/overworld_exit.h

  • Problem: Saving a vanilla ROM would corrupt exit positions, causing them to load at (0,0). This was because the OverworldExit class used uint8_t for player coordinates, truncating 16-bit values.
  • Fix: The coordinate-related members of OverworldExit were changed to uint16_t to match the full 0-4088 coordinate range, achieving parity with ZScream's data structures.
// In OverworldExit class definition:
class OverworldExit : public GameEntity {
public:
// ...
uint16_t y_player_; // Changed from uint8_t
uint16_t x_player_; // Changed from uint8_t
uint16_t y_camera_; // Changed from uint8_t
uint16_t x_camera_; // Changed from uint8_t
// ...
};

2.4. Coordinate Synchronization on Drag

File: src/zelda3/overworld/overworld_exit.h

  • Problem: When dragging an exit, the visual position (x_, y_) would update, but the underlying data used for saving (x_player_, y_player_) would not, leading to a data desync and incorrect saves.
  • Fix: The UpdateMapProperties method now explicitly syncs the base entity coordinates to the player coordinates before recalculating scroll and camera values. This ensures that drag operations correctly persist.
// In OverworldExit::UpdateMapProperties()
void UpdateMapProperties(uint16_t map_id) override {
// Sync player position from the base entity coordinates updated by the drag system.
x_player_ = static_cast<uint16_t>(x_);
y_player_ = static_cast<uint16_t>(y_);
// Proceed with auto-calculation using the now-correct player coordinates.
// ...
}

3. Entity I/O Refactoring Plan

The next phase of development is to extract all entity save and load logic from the monolithic overworld.cc into dedicated files.

3.1. File Structure

New files will be created to handle I/O for each entity type:

3.2. Core Functions

Each new file will implement a standard set of flat functions:

  • LoadAll...(): Reads all entities of a given type from the ROM.
  • SaveAll...(): Writes all entities of a given type to the ROM.
  • Helper functions for coordinate calculation and data manipulation, mirroring ZScream's logic.

3.3. ZScream Parity Goals

The refactor aims to implement key ZScream features:

  • Expanded ROM Support: Correctly read/write from vanilla or expanded ROM addresses for entrances and items.
  • Pointer Deduplication: When saving items, reuse pointers for identical item lists on different maps to conserve space.
  • Automatic Coordinate Calculation: For exits and transports, automatically calculate camera and scroll values based on player position, matching the UpdateMapStuff logic in ZScream.
  • Transport Entity: Add full support for transport entities (whirlpools, birds).

3.4. Overworld Class Role

After the refactor, the Overworld class will act as a coordinator, delegating all entity I/O to the new, modular functions. Its responsibility will be to hold the entity vectors and orchestrate the calls to the LoadAll... and SaveAll... functions.