Files
yaze/docs/internal/agents/archive/large-ref-docs/dungeon-system-reference.md

14 KiB

YAZE Dungeon System - Complete Technical Reference

Comprehensive reference for AI agents working on the YAZE Dungeon editing system.


1. Architecture Overview

File Structure

src/zelda3/dungeon/
├── dungeon.h/cc                # Main Dungeon class
├── room.h/cc                   # Room class (1,337 lines)
├── room_object.h/cc            # RoomObject encoding (633+249 lines)
├── object_drawer.h/cc          # Object rendering (210+972 lines)
├── object_parser.h/cc          # ROM tile parsing (172+387 lines)
├── room_entrance.h             # Entrance data (367 lines)
├── dungeon_rom_addresses.h     # ROM address constants (108 lines)

src/app/editor/dungeon/
├── dungeon_editor_v2.h/cc      # Main editor (card-based)
├── dungeon_room_loader.h/cc    # ROM data loading
├── dungeon_room_selector.h/cc  # Room selection UI
├── dungeon_canvas_viewer.h/cc  # Canvas rendering
├── dungeon_object_selector.h/cc # Object palette
├── dungeon_object_interaction.h/cc # Mouse interactions

Data Model

Dungeon
  └── rooms_[296]
        └── Room
              ├── tile_objects_[] (RoomObject instances)
              ├── sprites_[]
              ├── chests_in_room_[]
              ├── z3_staircases_[]
              ├── bg1_buffer_ (512x512 pixels)
              ├── bg2_buffer_ (512x512 pixels)
              └── current_gfx16_[] (16KB graphics)

2. Room Structure

Room Count & Organization

  • Total Rooms: 296 (indices 0x00-0x127)
  • Canvas Size: 512x512 pixels (64x64 tiles)
  • Layers: BG1, BG2, BG3

Room Properties

// room.h
int room_id_;                    // Room index (0-295)
uint8_t blockset;                // Graphics blockset ID
uint8_t spriteset;               // Sprite set ID
uint8_t palette;                 // Palette ID (0-63)
uint8_t layout;                  // Layout template (0-7)
uint8_t floor1, floor2;          // Floor graphics (nibbles)
uint16_t message_id_;            // Associated message

// Behavioral
CollisionKey collision_type;     // Collision enum
EffectKey effect_type;           // Visual effect enum
TagKey tag1, tag2;               // Special condition tags
LayerMergeType layer_merge;      // BG1/BG2 blend mode

Layer Merge Types

enum LayerMergeType {
  LayerMerge00 = 0x00,  // Off - Layer 2 invisible
  LayerMerge01 = 0x01,  // Parallax scrolling
  LayerMerge02 = 0x02,  // Dark overlay
  LayerMerge03 = 0x03,  // On top (translucent)
  LayerMerge04 = 0x04,  // Translucent blend
  LayerMerge05 = 0x05,  // Addition blend
  LayerMerge06 = 0x06,  // Normal overlay
  LayerMerge07 = 0x07,  // Transparent
  LayerMerge08 = 0x08,  // Dark room effect
};

3. Object Encoding System

3-Byte Object Format

Objects are stored as 3 bytes in ROM with three distinct encoding types:

Type 1: Standard Objects (ID 0x00-0xFF)

Byte format: xxxxxxss | yyyyyyss | iiiiiiii
             b1         b2         b3

Decoding:
  x = (b1 & 0xFC) >> 2        // 6 bits (0-63)
  y = (b2 & 0xFC) >> 2        // 6 bits (0-63)
  size = ((b1 & 0x03) << 2) | (b2 & 0x03)  // 4 bits (0-15)
  id = b3                      // 8 bits

Type 2: Extended Objects (ID 0x100-0x1FF)

Indicator: b1 >= 0xFC

Byte format: 111111xx | xxxxyyyy | yyiiiiii
             b1         b2         b3

Decoding:
  id = (b3 & 0x3F) | 0x100
  x = ((b2 & 0xF0) >> 4) | ((b1 & 0x03) << 4)
  y = ((b2 & 0x0F) << 2) | ((b3 & 0xC0) >> 6)
  size = 0  // No size parameter

Type 3: Rare Objects (ID 0xF00-0xFFF)

Indicator: b3 >= 0xF8

Byte format: xxxxxxii | yyyyyyii | 11111iii
             b1         b2         b3

Decoding:
  id = (b3 << 4) | 0x80 | ((b2 & 0x03) << 2) | (b1 & 0x03)
  x = (b1 & 0xFC) >> 2
  y = (b2 & 0xFC) >> 2
  size = ((b1 & 0x03) << 2) | (b2 & 0x03)

Object Categories

Type ID Range Examples
Type 1 0x00-0xFF Walls, floors, decorations
Type 2 0x100-0x1FF Corners, stairs, furniture
Type 3 0xF00-0xFFF Chests, pipes, special objects

4. ObjectDrawer Rendering System

Class Structure

// object_drawer.h
class ObjectDrawer {
  // Entry point
  absl::Status DrawObject(const RoomObject& object,
                          gfx::BackgroundBuffer& bg1,
                          gfx::BackgroundBuffer& bg2,
                          const gfx::PaletteGroup& palette_group);

  // Data
  Rom* rom_;
  const uint8_t* room_gfx_buffer_;  // current_gfx16_
  std::unordered_map<int16_t, int> object_to_routine_map_;
  std::vector<DrawRoutine> draw_routines_;
};

Draw Routine Status

# Routine Name Status Lines
0 DrawRightwards2x2_1to15or32 COMPLETE 302-321
1 DrawRightwards2x4_1to15or26 COMPLETE 323-348
2 DrawRightwards2x4spaced4_1to16 COMPLETE 350-373
3 DrawRightwards2x4spaced4_BothBG STUB 375-381
4 DrawRightwards2x2_1to16 COMPLETE 383-399
5 DrawDiagonalAcute_1to16 UNCLEAR 401-417
6 DrawDiagonalGrave_1to16 UNCLEAR 419-435
7 DrawDownwards2x2_1to15or32 COMPLETE 689-708
8 DrawDownwards4x2_1to15or26 COMPLETE 710-753
9 DrawDownwards4x2_BothBG STUB 755-761
10 DrawDownwardsDecor4x2spaced4 COMPLETE 763-782
11 DrawDownwards2x2_1to16 COMPLETE 784-799
12 DrawDownwardsHasEdge1x1 COMPLETE 801-813
13 DrawDownwardsEdge1x1 COMPLETE 815-827
14 DrawDownwardsLeftCorners COMPLETE 829-842
15 DrawDownwardsRightCorners COMPLETE 844-857
16 DrawRightwards4x4_1to16 COMPLETE 534-550
- CustomDraw STUB 524-532
- DrawDoorSwitcherer STUB 566-575

INCOMPLETE: BothBG Routines (4 locations)

These routines should draw to BOTH BG1 and BG2 but currently only call single-layer version:

// Line 375-381: DrawRightwards2x4spaced4_1to16_BothBG
// Line 437-442: DrawDiagonalAcute_1to16_BothBG
// Line 444-449: DrawDiagonalGrave_1to16_BothBG
// Line 755-761: DrawDownwards4x2_1to16_BothBG

// Current (WRONG):
void DrawRightwards2x4spaced4_1to16_BothBG(
    const RoomObject& obj, gfx::BackgroundBuffer& bg,  // Only 1 buffer!
    std::span<const gfx::TileInfo> tiles) {
  // Just calls single-layer version - misses BG2
  DrawRightwards2x4spaced4_1to16(obj, bg, tiles);
}

// Should be:
void DrawRightwards2x4spaced4_1to16_BothBG(
    const RoomObject& obj,
    gfx::BackgroundBuffer& bg1,  // Both buffers
    gfx::BackgroundBuffer& bg2,
    std::span<const gfx::TileInfo> tiles) {
  DrawRightwards2x4spaced4_1to16(obj, bg1, tiles);
  DrawRightwards2x4spaced4_1to16(obj, bg2, tiles);
}

UNCLEAR: Diagonal Routines

// Lines 401-417, 419-435
// Issues:
// - Hardcoded +6 and 5 iterations (why?)
// - Coordinate formula may produce negative Y
// - Only uses 4 tiles from larger span
// - No bounds checking

for (int s = 0; s < size + 6; s++) {  // Why +6?
  for (int i = 0; i < 5; i++) {       // Why 5?
    WriteTile8(bg, obj.x_ + s, obj.y_ + (i - s), tiles[i % 4]);
    // ^^ (i - s) can be negative when s > i
  }
}

5. Tile Rendering Pipeline

WriteTile8() - Tile to Pixel Conversion

// object_drawer.cc lines 863-883
void WriteTile8(gfx::BackgroundBuffer& bg, int tile_x, int tile_y,
                const gfx::TileInfo& tile_info) {
  // tile coords → pixel coords: tile_x * 8, tile_y * 8
  DrawTileToBitmap(bitmap, tile_info, tile_x * 8, tile_y * 8, room_gfx_buffer_);
}

DrawTileToBitmap() - Pixel Rendering

// object_drawer.cc lines 890-970
// Key steps:
// 1. Graphics sheet lookup: tile_info.id_ → (sheet_x, sheet_y)
// 2. Palette offset: (palette & 0x0F) * 8
// 3. Per-pixel with mirroring support
// 4. Color 0 = transparent (skipped)

int tile_sheet_x = (tile_info.id_ % 16) * 8;   // 0-127 pixels
int tile_sheet_y = (tile_info.id_ / 16) * 8;   // 0-127 pixels
uint8_t palette_offset = (tile_info.palette_ & 0x0F) * 8;

for (int py = 0; py < 8; py++) {
  for (int px = 0; px < 8; px++) {
    int src_x = tile_info.horizontal_mirror_ ? (7 - px) : px;
    int src_y = tile_info.vertical_mirror_ ? (7 - py) : py;
    // Read pixel, apply palette, write to bitmap
  }
}

Palette Application (CRITICAL)

// object_drawer.cc lines 71-115
// Palette must be applied AFTER drawing, BEFORE SDL sync

// 1. Draw all objects (writes palette indices 0-255)
for (auto& obj : objects) {
  DrawObject(obj, bg1, bg2, palette_group);
}

// 2. Apply dungeon palette to convert indices → RGB
bg1_bmp.SetPalette(dungeon_palette);
bg2_bmp.SetPalette(dungeon_palette);

// 3. Sync to SDL surfaces
SDL_LockSurface(bg1_bmp.surface());
memcpy(bg1_bmp.surface()->pixels, bg1_bmp.mutable_data().data(), ...);
SDL_UnlockSurface(bg1_bmp.surface());

6. ROM Addresses

Room Data

kRoomObjectLayoutPointer = 0x882D   // Layout pointer table
kRoomObjectPointer = 0x874C         // Object data pointer
kRoomHeaderPointer = 0xB5DD         // Room headers (3-byte long)
kRoomHeaderPointerBank = 0xB5E7     // Bank byte

Palette & Graphics

kDungeonsMainBgPalettePointers = 0xDEC4B
kDungeonsPalettes = 0xDD734
kGfxGroupsPointer = 0x6237
kTileAddress = 0x1B52               // Main tile graphics
kTileAddressFloor = 0x1B5A          // Floor tile graphics

Object Subtypes

kRoomObjectSubtype1 = 0x0F8000      // Standard objects
kRoomObjectSubtype2 = 0x0F83F0      // Extended objects
kRoomObjectSubtype3 = 0x0F84F0      // Rare objects
kRoomObjectTileAddress = 0x091B52   // Tile data

Special Objects

kBlocksPointer[1-4] = 0x15AFA-0x15B0F
kChestsDataPointer1 = 0xEBFB
kTorchData = 0x2736A
kPitPointer = 0x394AB
kDoorPointers = 0xF83C0

7. TODOs in room_object.h (30+ items)

Unknown Objects Needing Verification

Line ID Description
234 0x35 "WEIRD DOOR" - needs investigation
252-255 0x49-0x4C "Unknown" Type 1 objects
350-353 0xC4-0xC7 "Diagonal layer 2 mask B" - needs verify
392-395 0xDE-0xE1 "Moving wall flag" - WTF IS THIS?
466-476 Type 2 Multiple "Unknown" objects
480 0x30 "Intraroom stairs north B" - verify layer
486 0x36 "Water ladder (south)" - needs verify
512-584 Type 3 Multiple "Unknown" objects

8. DungeonEditorV2 Architecture

Card-Based Component System

DungeonEditorV2 (Coordinator)
├── DungeonRoomLoader       // ROM data loading
├── DungeonRoomSelector     // Room list/selection
├── DungeonCanvasViewer     // 512x512 canvas
├── DungeonObjectSelector   // Object palette
├── DungeonObjectInteraction // Mouse handling
├── ObjectEditorCard        // Property editing
└── PaletteEditorWidget     // Color editing

Card Types

show_control_panel_   // Room/entrance selection
show_room_selector_   // Room list
show_room_matrix_     // 16x19 visual layout
show_entrances_list_  // Entrance/spawn list
show_room_graphics_   // Blockset/palette
show_object_editor_   // Object placement
show_palette_editor_  // Palette colors
show_debug_controls_  // Debug options

Undo/Redo System

// Per-room object snapshots
std::unordered_map<int, std::vector<std::vector<RoomObject>>> undo_history_;
std::unordered_map<int, std::vector<std::vector<RoomObject>>> redo_history_;

9. Room Loading Flow

LoadRoomFromRom(room_id)
  │
  ├── Resolve room header pointer (0xB5DD + room_id * 3)
  │
  ├── Parse header bytes:
  │   ├── BG2 type, collision, light flag
  │   ├── Palette, blockset, spriteset
  │   ├── Effect type, tags
  │   └── Staircase data
  │
  ├── Load graphics sheets (16 blocks)
  │
  └── LoadObjects()
        │
        ├── Read floor/layout header (2 bytes)
        │
        ├── Parse object stream:
        │   ├── 3 bytes per object
        │   ├── 0xFF 0xFF = layer boundary
        │   └── 0xF0 0xFF = door section
        │
        └── Handle special objects:
            ├── Staircases
            ├── Chests
            ├── Doors
            ├── Torches
            └── Blocks

10. Rendering Pipeline

1. LoadRoomGraphics()
   └── Build graphics sheet list from blockset

2. CopyRoomGraphicsToBuffer()
   └── Copy ROM sheets → current_gfx16_[]

3. RenderRoomGraphics()
   ├── Check dirty flags
   ├── LoadLayoutTilesToBuffer()
   ├── Draw floor to bg1/bg2 buffers
   └── RenderObjectsToBackground()
         └── ObjectDrawer::DrawObjectList()

4. Present (Canvas Viewer)
   ├── Process deferred texture queue
   ├── Create/update GPU textures
   └── Render to ImGui canvas

11. Known Issues Summary

BothBG Support (4 stubs)

  • Line 380: DrawRightwards2x4spaced4_1to16_BothBG
  • Line 441: DrawDiagonalAcute_1to16_BothBG
  • Line 448: DrawDiagonalGrave_1to16_BothBG
  • Line 760: DrawDownwards4x2_1to16_BothBG

Fix: Change signature to accept both bg1 and bg2 buffers.

Diagonal Logic (2 routines)

  • Lines 401-435: Hardcoded constants, potential negative coords
  • Needs: Game verification or ZScream reference

Custom/Door Stubs (2 routines)

  • Line 524-532: CustomDraw - only draws first tile
  • Line 566-575: DrawDoorSwitcherer - only draws first tile

Object Names (30+ unknowns)

  • Multiple objects need in-game verification
  • See section 7 for full list

12. Testing

Run Dungeon Tests

# Unit tests
ctest --test-dir build -R "dungeon\|Dungeon" -V

# E2E tests
ctest --test-dir build -R "DungeonEditor" -V

E2E Test Files

  • test/e2e/dungeon_editor_smoke_test.cc
  • test/e2e/dungeon_canvas_interaction_test.cc
  • test/e2e/dungeon_layer_rendering_test.cc
  • test/e2e/dungeon_object_drawing_test.cc

Test Design Doc

docs/internal/testing/dungeon-gui-test-design.md (1000+ lines)