7.4 KiB
Custom Objects & Minecart System Handoff
Status: Partially Implemented
Created: 2025-12-07
Owner: dungeon-rendering-specialist
Priority: Medium
Overview
This document describes the custom dungeon object system for Oracle of Secrets and similar ROM hacks. Custom objects (IDs 0x31 and 0x32) are loaded from external binary files rather than vanilla ROM tile data.
Current State
What Works
| Component | Status | Notes |
|---|---|---|
| Project configuration | ✅ Complete | custom_objects_folder in .yaze file |
| Feature flag in UI | ✅ Complete | Checkbox in Dungeon Flags menu |
| Feature flag sync | ✅ Complete | Project flags sync to global on load |
| MinecartTrackEditorPanel | ✅ Complete | Loads/saves minecart_tracks.asm |
| CustomObjectManager | ✅ Complete | Loads .bin files from project folder |
| Panel registration | ✅ Complete | Panel available in Dungeon category |
What Doesn't Work
| Component | Status | Issue |
|---|---|---|
| DrawCustomObject | ❌ Not Working | Draw routine not registered; tiles not rendering |
| Object previews | ❌ Not Working | DungeonObjectSelector previews don't load custom objects |
| Graphics editing | ❌ Not Started | No UI to edit custom object graphics |
Architecture
File Structure (Oracle of Secrets)
Oracle-of-Secrets/
├── Oracle-of-Secrets.yaze # Project file
├── Dungeons/Objects/Data/ # Custom object .bin files
│ ├── track_LR.bin
│ ├── track_UD.bin
│ ├── track_corner_TL.bin
│ ├── furnace.bin
│ └── ...
└── Sprites/Objects/data/
└── minecart_tracks.asm # Track starting positions
Project Configuration
[files]
custom_objects_folder=/path/to/Dungeons/Objects/Data
[feature_flags]
enable_custom_objects=true
Key Files
| File | Purpose |
|---|---|
src/core/project.h |
custom_objects_folder field |
src/core/project.cc |
Serialization/parsing of field |
src/core/features.h |
kEnableCustomObjects flag |
src/zelda3/dungeon/custom_object.h |
CustomObject struct, CustomObjectManager |
src/zelda3/dungeon/custom_object.cc |
Binary file loading and parsing |
src/zelda3/dungeon/object_drawer.cc |
DrawCustomObject method |
src/app/editor/dungeon/dungeon_editor_v2.cc |
Panel registration, manager init |
src/app/editor/dungeon/panels/minecart_track_editor_panel.cc |
Track editor UI |
src/app/gui/app/feature_flags_menu.h |
UI checkbox for flag |
Custom Object Binary Format
Based on ZScream's object handler:
Header (2 bytes):
Low 5 bits: Tile count for this row
High byte: Row stride (usually 0x80 = 1 tilemap row)
Tile Data (2 bytes per tile):
Bits 0-9: Tile ID (10 bits)
Bits 10-12: Palette (3 bits)
Bit 13: Priority
Bit 14: Horizontal flip
Bit 15: Vertical flip
Repeat Header + Tiles until Header == 0x0000
Object ID Mapping
| Object ID | Subtype | Filename |
|---|---|---|
| 0x31 | 0 | track_LR.bin |
| 0x31 | 1 | track_UD.bin |
| 0x31 | 2 | track_corner_TL.bin |
| 0x31 | 3 | track_corner_TR.bin |
| 0x31 | 4 | track_corner_BL.bin |
| 0x31 | 5 | track_corner_BR.bin |
| 0x31 | 6-14 | track_floor_*.bin, track_any.bin |
| 0x31 | 15 | small_statue.bin |
| 0x32 | 0 | furnace.bin |
| 0x32 | 1 | firewood.bin |
| 0x32 | 2 | ice_chair.bin |
Issues to Fix
Issue 1: DrawCustomObject Not Registered
Location: src/zelda3/dungeon/object_drawer.cc
Problem: The draw routine for custom objects (routine ID 130+) is defined but not registered in InitializeDrawRoutines(). The object_to_routine_map_ doesn't have entries for 0x31 and 0x32.
Fix Required:
// In InitializeDrawRoutines():
object_to_routine_map_[0x31] = CUSTOM_OBJECT_ROUTINE_ID;
object_to_routine_map_[0x32] = CUSTOM_OBJECT_ROUTINE_ID;
// Also need to register the routine itself:
draw_routines_.push_back([](ObjectDrawer* self, const RoomObject& obj,
gfx::BackgroundBuffer& bg,
std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
self->DrawCustomObject(obj, bg, tiles, state);
});
Also: The tiles passed to DrawCustomObject are from object.tiles() which are loaded from ROM. Custom objects should NOT use ROM tiles - they should use tiles from the .bin file. The current implementation gets tiles from CustomObjectManager but ignores the tiles parameter.
Issue 2: CustomObjectManager Not Initialized Early Enough
Location: src/app/editor/dungeon/dungeon_editor_v2.cc
Problem: CustomObjectManager is initialized in DungeonEditorV2::Load() but objects may be drawn before this happens.
Current Code:
if (!dependencies_.project->custom_objects_folder.empty()) {
zelda3::CustomObjectManager::Get().Initialize(
dependencies_.project->custom_objects_folder);
}
Fix: Ensure initialization happens before any room rendering.
Issue 3: Object Previews in Selector
Location: src/app/editor/dungeon/dungeon_object_selector.cc
Problem: The custom objects section in DrawObjectAssetBrowser() attempts to show previews but:
- Uses
MakePreviewObject()which loads ROM tiles - Doesn't use CustomObjectManager to get the actual custom object data
- Preview rendering fails silently
Fix Required: Create a separate preview path for custom objects that:
- Loads binary data from CustomObjectManager
- Renders tiles using the binary tile data, not ROM tiles
Minecart Track Editor
Status: Complete
The MinecartTrackEditorPanel loads and saves minecart_tracks.asm which defines:
.TrackStartingRooms- Which room each track starts in.TrackStartingX- X position within the room.TrackStartingY- Y position within the room
File Format
.TrackStartingRooms
dw $0098, $0088, $0087, ...
.TrackStartingX
dw $1190, $1160, $1300, ...
.TrackStartingY
dw $1380, $10C9, $1100, ...
Next Steps
Priority 1: Make Custom Objects Render
- Register routine for 0x31/0x32 in
InitializeDrawRoutines() - Verify CustomObjectManager is initialized before room load
- Test with Oracle of Secrets project
Priority 2: Fix Previews
- Add custom preview path in DungeonObjectSelector
- Use CustomObjectManager data instead of ROM tiles
- Handle case where project folder isn't set
Priority 3: Graphics Editing (Future)
- Create UI to view/edit custom object binary files
- Add export functionality for new objects
- Integrate with sprite editor or create dedicated panel
Testing
To Test Custom Objects:
- Open YAZE
- Open Oracle of Secrets project file
- Navigate to Dungeon editor
- Open a room that contains custom objects (e.g., minecart tracks)
- Objects should render (currently: they don't)
To Test Minecart Panel:
- Open Oracle of Secrets project
- Go to Dungeon editor
- View > Panels > Minecart Tracks (or find in panel browser)
- Should show table of track starting positions
- Edit values and click "Save Tracks"
Related Documentation
draw_routine_tracker.md- Draw routine statusdungeon-object-rendering-spec.md- Object rendering details
Contact
For questions about this system, refer to the Oracle of Secrets project structure or check the custom object handler in the ASM source.