Files
yaze/docs/internal/zelda3/dungeon-spec.md

778 lines
22 KiB
Markdown

# Zelda 3 (Link to the Past) Dungeon System Specification
**Purpose:** This document provides a comprehensive specification for the ALTTP dungeon/underworld system based on analysis of:
- **yaze** - C++ dungeon editor implementation (partial)
- **ZScream** - C# reference implementation (complete)
- **usdasm** - Assembly disassembly of bank_01.asm (ground truth)
**Goal:** Close the gaps in yaze's dungeon editor to achieve correct room rendering.
---
## Table of Contents
1. [Room Data Structure](#1-room-data-structure)
2. [Room Header Format](#2-room-header-format)
3. [Object System](#3-object-system)
4. [Layer System](#4-layer-system)
5. [Door System](#5-door-system)
6. [Sprites](#6-sprites)
7. [Items and Chests](#7-items-and-chests)
8. [Graphics and Tilesets](#8-graphics-and-tilesets)
9. [Implementation Gaps in yaze](#9-implementation-gaps-in-yaze)
10. [ROM Address Reference](#10-rom-address-reference)
---
## 1. Room Data Structure
### 1.1 Overview
A dungeon room in ALTTP consists of:
- **Room Header** (14 bytes) - Metadata, properties, warp destinations
- **Object Data** - Tile objects for walls, floors, decorations
- **Sprite Data** - Enemies, NPCs, interactive entities
- **Item Data** - Chest contents, pot items, key drops
- **Door Data** - Connections between rooms
### 1.2 Total Rooms
```
Total Rooms: 296 (0x00 - 0x127)
Room Size: 512x512 pixels (64x64 tiles at 8x8 pixels each)
```
### 1.3 Room Memory Layout
```
Room Object Data:
+0x00: Floor nibbles (floor2 << 4 | floor1)
+0x01: Layout byte ((value >> 2) & 0x07)
+0x02+: Object stream (3 bytes per object)
Layer Separators:
- 0xFF 0xFF: Marks transition to next layer
- 0xF0 0xFF: Begin door list
- Layer 3 reached or 0xFF 0xFF at boundary: End of data
```
---
## 2. Room Header Format
### 2.1 Header Structure (14 bytes)
| Offset | Bits | Field | Description |
|--------|------|-------|-------------|
| 0x00 | 7-5 | bg2 | Background 2 / Layer merge type (0-7) |
| 0x00 | 4-2 | collision | Collision type (0-4) |
| 0x00 | 0 | light | Light flag (if set, bg2 = 0x08 Dark Room) |
| 0x01 | 5-0 | palette | Palette ID (0-63, masked 0x3F) |
| 0x02 | 7-0 | blockset | Tileset/Blockset ID (0-23) |
| 0x03 | 7-0 | spriteset | Spriteset ID (0-64) |
| 0x04 | 7-0 | effect | Room effect (0-7) |
| 0x05 | 7-0 | tag1 | Tag 1 trigger (0-64) |
| 0x06 | 7-0 | tag2 | Tag 2 trigger (0-64) |
| 0x07 | 1-0 | holewarp_plane | Pit warp plane (0-3) |
| 0x07 | 3-2 | staircase_plane[0] | Staircase 1 plane (0-3) |
| 0x07 | 5-4 | staircase_plane[1] | Staircase 2 plane (0-3) |
| 0x07 | 7-6 | staircase_plane[2] | Staircase 3 plane (0-3) |
| 0x08 | 1-0 | staircase_plane[3] | Staircase 4 plane (0-3) |
| 0x09 | 7-0 | holewarp | Hole warp destination room (0-255) |
| 0x0A | 7-0 | staircase_rooms[0] | Staircase 1 destination room |
| 0x0B | 7-0 | staircase_rooms[1] | Staircase 2 destination room |
| 0x0C | 7-0 | staircase_rooms[2] | Staircase 3 destination room |
| 0x0D | 7-0 | staircase_rooms[3] | Staircase 4 destination room |
### 2.2 Header Address Calculation
```cpp
// Step 1: Get master pointer
int header_pointer = ROM[kRoomHeaderPointer, 3]; // 24-bit
header_pointer = SNEStoPC(header_pointer);
// Step 2: Index into pointer table
int table_offset = header_pointer + (room_id * 2);
int address = (ROM[kRoomHeaderPointerBank] << 16) | ROM[table_offset, 2];
// Step 3: Convert to PC address
int header_location = SNEStoPC(address);
```
### 2.3 Layer Merge Types (bg2 field)
| ID | Name | Layer2OnTop | Layer2Translucent | Layer2Visible |
|----|------|-------------|-------------------|---------------|
| 0x00 | Off | true | false | false |
| 0x01 | Parallax | true | false | false |
| 0x02 | Dark | true | true | true |
| 0x03 | On top | true | true | false |
| 0x04 | Translucent | true | true | true |
| 0x05 | Addition | true | true | true |
| 0x06 | Normal | true | false | false |
| 0x07 | Transparent | true | true | true |
| 0x08 | Dark room | true | true | true |
**Note:** When `light` flag is set, bg2 is overridden to 0x08 (Dark room).
### 2.4 Collision Types
| ID | Name |
|----|------|
| 0 | One_Collision |
| 1 | Both |
| 2 | Both_With_Scroll |
| 3 | Moving_Floor_Collision |
| 4 | Moving_Water_Collision |
### 2.5 Room Effects
| ID | Name | Description |
|----|------|-------------|
| 0 | Nothing | No effect |
| 1 | One | Effect 1 |
| 2 | Moving_Floor | Animated floor tiles |
| 3 | Moving_Water | Animated water tiles |
| 4 | Four | Effect 4 |
| 5 | Red_Flashes | Red screen flashes |
| 6 | Torch_Show_Floor | Floor revealed by torches |
| 7 | Ganon_Room | Final boss room effect |
### 2.6 Room Tags (65 types)
Key tags include:
- `NW_Kill_Enemy_to_Open` (1) - Kill all enemies in NW quadrant
- `Clear_Quadrant_to_Open` (various) - Quadrant-based triggers
- `Push_Block_to_Open` (various) - Block puzzle triggers
- `Water_Gate` - Water level control
- `Agahnim_Room` - Boss room setup
- `Holes_0` through `Holes_2` - Pit configurations
---
## 3. Object System
### 3.1 Object Subtypes
ALTTP uses three object subtypes with different encoding and capabilities:
| Subtype | ID Range | Count | Scalable | Description |
|---------|----------|-------|----------|-------------|
| 1 | 0x00-0xF7 | 248 | Yes | Standard room objects |
| 2 | 0x100-0x13F | 64 | No | Fixed-size objects |
| 3 | 0xF80-0xFFF | 128 | No | Special/complex objects |
### 3.2 Object Encoding (3 bytes)
**Subtype 1 (b3 < 0xF8):**
```
Byte 1: xxxxxxss (x = X position bits 7-2, s = size X bits 1-0)
Byte 2: yyyyyyss (y = Y position bits 7-2, s = size Y bits 1-0)
Byte 3: iiiiiiii (object ID 0x00-0xF7)
Decoding:
posX = (b1 & 0xFC) >> 2
posY = (b2 & 0xFC) >> 2
sizeX = b1 & 0x03
sizeY = b2 & 0x03
sizeXY = (sizeX << 2) + sizeY
object_id = b3
```
**Subtype 2 (b1 >= 0xFC):**
```
Byte 1: 111111xx (x = X position bits 5-4)
Byte 2: xxxxyyyy (x = X position bits 3-0, y = Y position bits 5-2)
Byte 3: yyiiiiii (y = Y position bits 1-0, i = object ID low 6 bits)
Decoding:
posX = ((b2 & 0xF0) >> 4) + ((b1 & 0x03) << 4)
posY = ((b2 & 0x0F) << 2) + ((b3 & 0xC0) >> 6)
object_id = (b3 & 0x3F) | 0x100
```
**Subtype 3 (b3 >= 0xF8):**
```
Byte 1: xxxxxxii (x = X position bits 7-2, i = size/ID bits 1-0)
Byte 2: yyyyyyii (y = Y position bits 7-2, i = size/ID bits 3-2)
Byte 3: 11111iii (i = ID bits 6-4, marker 0xF8-0xFF)
Decoding:
posX = (b1 & 0xFC) >> 2
posY = (b2 & 0xFC) >> 2
object_id = ((b3 << 4) | 0x80 + (((b2 & 0x03) << 2) + (b1 & 0x03))) - 0xD80
// Results in 0x200-0x27E range
```
### 3.3 Object Data Tables (bank_01.asm)
```
Address | Size | Content
---------------|-------|------------------------------------------
$018000-$0181FE| 512B | Subtype 1 data offsets (256 entries x 2)
$018200-$0183EE| 494B | Subtype 1 routine pointers (256 entries)
$0183F0-$01846E| 128B | Subtype 2 data offsets (64 entries x 2)
$018470-$0184EE| 128B | Subtype 2 routine pointers (64 entries)
$0184F0-$0185EE| 256B | Subtype 3 data offsets (128 entries x 2)
$0185F0-$0186EE| 256B | Subtype 3 routine pointers (128 entries)
```
### 3.4 Drawing Routines
There are 24+ unique drawing patterns used by objects:
| Routine | Pattern | Multiplier | Objects Using |
|---------|---------|------------|---------------|
| Rightwards2x2_1to15or32 | 2x2 horizontal | s*2 | Walls, floors |
| Rightwards2x4_1to15or26 | 2x4 horizontal | s*2 | Taller walls |
| Downwards2x2_1to15or32 | 2x2 vertical | s*2 | Vertical features |
| Downwards4x2_1to15or26 | 4x2 vertical | s*2 | Wide columns |
| DiagonalAcute_1to16 | Diagonal / | +1,+1 | Stairs up-right |
| DiagonalGrave_1to16 | Diagonal \ | +1,-1 | Stairs down-right |
| 4x4 | Fixed 4x4 | none | Type 2 objects |
| 3x4 | Fixed 3x4 | none | Doors, decorations |
| Single2x2 | Single 2x2 | none | Small decorations |
| Single2x3Pillar | Single 2x3 | none | Pillars |
### 3.5 Size Handling
```cpp
// Default size when size byte is 0
if (size == 0) {
size = 32; // For most subtype 1 objects
}
// Some objects use size + 1 for iteration count
for (int s = 0; s < size + 1; s++) { ... }
// Size masking for some routines
int effective_size = size & 0x0F; // Use lower 4 bits only
```
### 3.6 Layer Assignment
Objects are assigned to layers via the object stream:
- Objects before first `0xFF 0xFF` marker: Layer 0 (BG1)
- Objects after first `0xFF 0xFF` marker: Layer 1 (BG2)
- Objects after second `0xFF 0xFF` marker: Layer 2 (BG3/Sprites)
Some objects have `allBgs = true` flag and draw to both BG1 and BG2.
### 3.7 Common Object IDs
**Subtype 1 (Scalable):**
| ID | Name |
|----|------|
| 0x00-0x07 | Wall segments (N/S/E/W) |
| 0x08-0x0B | Pit edges |
| 0x0C-0x20 | Diagonal walls |
| 0x21-0x30 | Rails and supports |
| 0x31-0x40 | Carpets and trim |
| 0xD0-0xD7 | Floor types (8 patterns) |
| 0xE0-0xE7 | Ceiling types |
| 0xF0-0xF3 | Conveyor belts (4 directions) |
**Subtype 2 (Fixed):**
| ID | Name |
|----|------|
| 0x100-0x107 | Corners (concave/convex) |
| 0x108-0x10F | Braziers and statues |
| 0x110-0x117 | Star tiles |
| 0x118-0x11F | Torches and furniture |
| 0x120-0x127 | Stairs (inter/intra room) |
| 0x128-0x12F | Blocks and platforms |
**Subtype 3 (Special):**
| ID | Name |
|----|------|
| 0x200-0x207 | Waterfall faces |
| 0x208-0x20F | Somaria paths |
| 0x210-0x217 | Item piles (rupees) |
| 0x218-0x21F | Chests (various) |
| 0x220-0x227 | Pipes and conveyors |
| 0x228-0x22F | Pegs and switches |
---
## 4. Layer System
### 4.1 Layer Architecture
ALTTP uses a 3-layer system matching SNES hardware:
| Layer | SNES Name | Memory | Purpose |
|-------|-----------|--------|---------|
| BG1 | Background 1 | $7E2000 | Main room layout |
| BG2 | Background 2 | $7E4000 | Overlay layer |
| BG3 | Background 3 | Sprites | Sprites/effects |
### 4.2 Tilemap Memory Layout
```
Upper Layer (BG1/BG2): $7E2000-$7E27FF (2KB per layer)
Lower Layer (BG3): $7E4000-$7E47FF (2KB per layer)
Grid Structure: 4 columns x 3 rows of 32x32 blocks
Offset: $100 bytes per block horizontally
$1C0 bytes per block vertically
Each tilemap entry: 16-bit word
Bits [9:0]: Tile index (0-1023)
Bit [10]: Priority bit
Bits [13:11]: Palette select (0-7)
Bit [14]: Horizontal flip
Bit [15]: Vertical flip
```
### 4.3 Layer Merge Behavior
The `bg2` field controls how layers are composited:
```cpp
switch (bg2) {
case 0x00: // Off - BG2 hidden
case 0x01: // Parallax - BG2 scrolls differently
case 0x02: // Dark - Dark room effect
case 0x03: // On top - BG2 overlays BG1
case 0x04: // Translucent - BG2 semi-transparent
case 0x05: // Addition - Additive blending
case 0x06: // Normal - Standard display
case 0x07: // Transparent - BG2 transparent
case 0x08: // Dark room - Special dark room
}
```
### 4.4 Floor Rendering
Floor tiles are specified by the first byte of room object data:
```cpp
uint8_t floor_byte = ROM[object_data_ptr];
uint8_t floor1 = floor_byte & 0x0F; // Low nibble
uint8_t floor2 = floor_byte >> 4; // High nibble
```
Floor patterns (0-15) reference tile graphics at `tile_address_floor`.
---
## 5. Door System
### 5.1 Door Data Format
Doors are encoded as 2-byte entries after the `0xF0 0xFF` marker:
```
Byte 1: Door position (0-255)
Byte 2: Door type and direction
Bits [3:0]: Direction (0=North, 1=South, 2=West, 3=East)
Bits [7:4]: Door type/subtype
```
### 5.2 Door Types
| Type | Name | Description |
|------|------|-------------|
| 0x00 | Regular | Standard door |
| 0x02 | Regular2 | Standard door variant |
| 0x06 | EntranceDoor | Entrance from overworld |
| 0x08 | WaterfallTunnel | Behind waterfall |
| 0x0A | EntranceLarge | Large entrance |
| 0x0C | EntranceLarge2 | Large entrance variant |
| 0x0E | EntranceCave | Cave entrance |
| 0x12 | ExitToOW | Exit to overworld |
| 0x14 | ThroneRoom | Throne room door |
| 0x16 | PlayerBgChange | Layer toggle door |
| 0x18 | ShuttersTwoWay | Two-way shutter |
| 0x1A | InvisibleDoor | Hidden door |
| 0x1C | SmallKeyDoor | Requires small key |
| 0x20-0x26 | StairMaskLocked | Locked stair doors |
| 0x28 | BreakableWall | Bomb-able wall |
| 0x30 | LgExplosion | Large explosion door |
| 0x32 | Slashable | Sword-cuttable |
| 0x40 | RegularDoor33 | Regular variant |
| 0x44 | Shutter | One-way shutter |
| 0x46 | WarpRoomDoor | Warp tile door |
| 0x48-0x4A | ShutterTrap | Trap shutter doors |
### 5.3 Door Graphics Addresses
```
Direction | Graphics Pointer
----------|------------------
North | $014D9E (kDoorGfxUp)
South | $014E06 (kDoorGfxDown)
West | $014E66 (kDoorGfxLeft)
East | $014EC6 (kDoorGfxRight)
```
### 5.4 Door Rendering Dimensions
| Direction | Width | Height |
|-----------|-------|--------|
| North/South | 4 tiles | 3 tiles |
| East/West | 3 tiles | 4 tiles |
---
## 6. Sprites
### 6.1 Sprite Data Structure
```cpp
struct Sprite {
uint8_t id; // Sprite type (0x00-0xF3)
uint8_t x; // X position (0-63)
uint8_t y; // Y position (0-63)
uint8_t subtype; // Subtype flags
uint8_t layer; // Layer (0-2)
uint8_t key_drop; // Key drop (0=none, 1=small, 2=big)
bool overlord; // Is overlord sprite
};
```
### 6.2 Sprite Encoding
Sprites are stored as 3-byte entries:
```
Byte 1: Y position (bits 7-1), Layer flag (bit 0)
Byte 2: X position (bits 7-1), Subtype high (bit 0)
Byte 3: Sprite ID (0x00-0xFF)
Special handling:
- Overlord check: (subtype & 0x07) == 0x07
- Key drop at sprite ID 0xE4:
- Position (0x00, 0x1E) = small key drop
- Position (0x00, 0x1D) = big key drop
```
### 6.3 Overlord Sprites
When `(subtype & 7) == 7`, the sprite is an "overlord" with special behavior.
Overlord IDs 0x01-0x1A have separate name tables.
### 6.4 Key Drop Mechanics
```cpp
// Detection during sprite loading
if (sprite_id == 0xE4) {
if (x == 0x00 && y == 0x1E) {
key_drop = 1; // Small key
} else if (x == 0x00 && y == 0x1D) {
key_drop = 2; // Big key
}
}
```
---
## 7. Items and Chests
### 7.1 Chest Data
Chests are stored separately from room objects:
```cpp
struct ChestData {
uint16_t room_id; // Room containing chest
uint8_t x; // X position
uint8_t y; // Y position
uint8_t item_id; // Item contained
bool is_big; // Big chest flag
};
```
### 7.2 Item Types (Pot Items)
| ID | Item | ID | Item |
|----|------|----|------|
| 0 | Nothing | 14 | Small magic |
| 1 | Rupee (green) | 15 | Big magic |
| 2 | Rock crab | 16 | Bomb refill |
| 3 | Bee | 17 | Arrow refill |
| 4 | Random | 18 | Fairy |
| 5 | Bomb | 19 | Key |
| 6 | Heart | 20 | Fairy*8 |
| 7 | Blue rupee | 21-22 | Various |
| 8 | Key*8 | 23 | Hole |
| 9 | Arrow | 24 | Warp |
| 10 | 1 bomb | 25 | Staircase |
| 11 | Heart | 26 | Bombable |
| 12 | Rupee (blue) | 27 | Switch |
| 13 | Heart variant | | |
### 7.3 Item Encoding
Items with ID >= 0x80 use special encoding:
```cpp
if (id & 0x80) {
int actual_id = ((id - 0x80) / 2) + 23;
}
```
### 7.4 Item ROM Addresses
```
Chest Pointers: $01EBF6 (kChestsLengthPointer)
Chest Data: $01EBFB (kChestsDataPointer1)
Room Items: $01DB69 (kRoomItemsPointers)
```
---
## 8. Graphics and Tilesets
### 8.1 Graphics Organization
```
Sheet Count: 223 sheets
Uncompressed Size: 2048 bytes (0x800) per sheet
3BPP Size: 1536 bytes (0x600) per sheet
```
### 8.2 Key Graphics Addresses
```
Tile Address: $009B52 (kTileAddress)
Tile Address Floor: $009B5A (kTileAddressFloor)
Subtype 1 Tiles: $018000 (kRoomObjectSubtype1)
Subtype 2 Tiles: $0183F0 (kRoomObjectSubtype2)
Subtype 3 Tiles: $0184F0 (kRoomObjectSubtype3)
GFX Groups: $006237 (kGfxGroupsPointer)
```
### 8.3 Palette Configuration
```
Palettes Per Group: 16
Colors Per Palette: 16
Total Palette Size: 256 colors
Half Palette Size: 8 colors
Dungeon Main BG: $0DEC4B (kDungeonsMainBgPalettePointers)
Dungeon Palettes: $0DD734 (kDungeonsPalettes)
```
### 8.4 Tile Info Format
```cpp
struct TileInfo {
uint16_t id; // Tile index (10 bits)
uint8_t palette; // Palette (3 bits)
bool h_flip; // Horizontal mirror
bool v_flip; // Vertical mirror
bool priority; // Priority bit
};
// Decode from 16-bit word
TileInfo decode(uint16_t word) {
TileInfo t;
t.id = word & 0x03FF;
t.priority = (word >> 10) & 1;
t.palette = (word >> 11) & 0x07;
t.h_flip = (word >> 14) & 1;
t.v_flip = (word >> 15) & 1;
return t;
}
```
---
## 9. Implementation Gaps in yaze
### 9.1 Critical Gaps (Must Fix for Correct Rendering)
| Gap | Severity | Description | ZScream Reference |
|-----|----------|-------------|-------------------|
| **Type 3 Objects** | Critical | Stub implementation, simplified drawing | Subtype3_Draw.cs |
| **Door Rendering** | Critical | LoadDoors() is stub, no type handling | Doors_Draw.cs |
| **all_bgs Flag Ignored** | Critical | Uses hardcoded routine IDs (3,9,17,18) instead | Room_Object.cs allBgs |
| **Floor Rendering** | High | Floor values loaded but not rendered | Room.cs floor1/floor2 |
| **Type 2 Complex Layouts** | High | Missing column, bed, spiral stair handling | Subtype2_Multiple.cs |
| **Layer Merge Effects** | High | Flags exist but not applied during render | LayerMergeType.cs |
### 9.2 Missing Systems
| System | Status in yaze | ZScream Implementation |
|--------|----------------|----------------------|
| Pot Items | Not implemented | Items_Draw.cs (28 types) |
| Key Drop Visualization | Detection only, no draw | Sprite.cs DrawKey() |
| Door Graphics | Generic object render | Doors_Draw.cs (40+ types) |
| Item-Sprite Linking | Not implemented | PotItem.cs |
| Selection State | Not tracked | Room_Object.cs selected |
| Unique Sprite IDs | Not tracked | ROM.uniqueSpriteID |
### 9.3 Architectural Differences
| Aspect | yaze Approach | ZScream Approach | Recommendation |
|--------|---------------|------------------|----------------|
| Object Classes | Single RoomObject class | Per-ID classes (object_00, etc.) | Keep unified, add type handlers |
| Draw Routines | 38 shared lambdas | 256+ override methods | Keep yaze approach |
| Tile Loading | On-demand parser | Pre-loaded static arrays | Keep yaze approach |
| Layer Selection | Binary choice (BG1/BG2) | Enum with BG3 | Add BG3 support |
### 9.4 Fix Priority List
**Phase 1: Core Rendering**
1. Fix `all_bgs_` flag usage instead of hardcoded routine IDs
2. Implement proper floor rendering from floor1/floor2 values
3. Complete Type 3 object drawing (Somaria paths, etc.)
4. Add missing Type 2 object patterns
**Phase 2: Doors**
5. Implement door type classification system
6. Add special door graphics (caves, holes, hidden walls)
7. Mirror effect for bidirectional doors
8. Layer-specific door rendering
**Phase 3: Items & Sprites**
9. Implement PotItem system (28 types)
10. Add key drop visualization
11. Link items to sprites for drops
12. Selection state tracking
**Phase 4: Polish**
13. Layer merge effect application
14. BG3 layer support
15. Complete bounds checking
16. Dimension calculation for complex objects
---
## 10. ROM Address Reference
### 10.1 Room Data
```cpp
constexpr int kRoomObjectLayoutPointer = 0x882D;
constexpr int kRoomObjectPointer = 0x874C;
constexpr int kRoomHeaderPointer = 0xB5DD;
constexpr int kRoomHeaderPointerBank = 0xB5E7;
constexpr int kNumberOfRooms = 296;
```
### 10.2 Graphics
```cpp
constexpr int kTileAddress = 0x001B52;
constexpr int kTileAddressFloor = 0x001B5A;
constexpr int kRoomObjectSubtype1 = 0x8000;
constexpr int kRoomObjectSubtype2 = 0x83F0;
constexpr int kRoomObjectSubtype3 = 0x84F0;
constexpr int kGfxGroupsPointer = 0x6237;
```
### 10.3 Palettes
```cpp
constexpr int kDungeonsMainBgPalettePointers = 0xDEC4B;
constexpr int kDungeonsPalettes = 0xDD734;
```
### 10.4 Sprites & Items
```cpp
constexpr int kRoomItemsPointers = 0xDB69;
constexpr int kRoomsSpritePointer = 0x4C298;
constexpr int kSpriteBlocksetPointer = 0x5B57;
constexpr int kSpritesData = 0x4D8B0;
constexpr int kDungeonSpritePointers = 0x090000;
```
### 10.5 Blocks & Features
```cpp
constexpr int kBlocksLength = 0x8896;
constexpr int kBlocksPointer1 = 0x15AFA;
constexpr int kBlocksPointer2 = 0x15B01;
constexpr int kBlocksPointer3 = 0x15B08;
constexpr int kBlocksPointer4 = 0x15B0F;
```
### 10.6 Chests & Torches
```cpp
constexpr int kChestsLengthPointer = 0xEBF6;
constexpr int kChestsDataPointer1 = 0xEBFB;
constexpr int kTorchData = 0x2736A;
constexpr int kTorchesLengthPointer = 0x88C1;
```
### 10.7 Pits & Doors
```cpp
constexpr int kPitPointer = 0x394AB;
constexpr int kPitCount = 0x394A6;
constexpr int kDoorPointers = 0xF83C0;
constexpr int kDoorGfxUp = 0x4D9E;
constexpr int kDoorGfxDown = 0x4E06;
constexpr int kDoorGfxLeft = 0x4E66;
constexpr int kDoorGfxRight = 0x4EC6;
```
---
## Appendix A: Object ID Quick Reference
### Subtype 1 (0x00-0xF7) - Scalable
| Range | Category |
|-------|----------|
| 0x00-0x07 | Wall segments |
| 0x08-0x0B | Pit edges |
| 0x0C-0x20 | Diagonal walls (allBgs=true) |
| 0x21-0x30 | Rails and supports |
| 0x31-0x40 | Carpets and trim |
| 0x41-0x50 | Decorations |
| 0xD0-0xD7 | Floor patterns |
| 0xE0-0xE7 | Ceiling patterns |
| 0xF0-0xF3 | Conveyor belts |
### Subtype 2 (0x100-0x13F) - Fixed Size
| Range | Category |
|-------|----------|
| 0x100-0x107 | Corners |
| 0x108-0x10F | Braziers/statues |
| 0x110-0x117 | Star tiles |
| 0x118-0x11F | Torches/furniture |
| 0x120-0x127 | Stairs |
| 0x128-0x12F | Blocks/platforms |
| 0x130-0x13F | Misc decorations |
### Subtype 3 (0x200-0x27E) - Special
| Range | Category |
|-------|----------|
| 0x200-0x207 | Waterfall faces |
| 0x208-0x20F | Somaria paths |
| 0x210-0x217 | Item piles |
| 0x218-0x21F | Chests |
| 0x220-0x227 | Pipes/conveyors |
| 0x228-0x22F | Pegs/switches |
| 0x230-0x23F | Boss objects |
| 0x240-0x27E | Misc special |
---
## Appendix B: Drawing Routine Reference
| ID | Routine Name | Pattern | Objects |
|----|--------------|---------|---------|
| 0 | Rightwards2x2_1to15or32 | 2x2 horizontal | 0x00, walls |
| 1 | Rightwards2x4_1to15or26 | 2x4 horizontal | 0x01-0x02 |
| 2 | Downwards2x2_1to15or32 | 2x2 vertical | vertical walls |
| 3 | Rightwards2x2_BothBG | 2x2 both layers | 0x03-0x04 |
| 4 | Rightwards2x4spaced4_1to16 | 2x4 spaced | 0x05-0x06 |
| 5 | DiagonalAcute_1to16 | Diagonal / | stairs |
| 6 | DiagonalGrave_1to16 | Diagonal \ | stairs |
| 7 | Downwards4x2_1to15or26 | 4x2 vertical | wide columns |
| 8 | 4x4 | Fixed 4x4 | Type 2 objects |
| 9 | Downwards4x2_BothBG | 4x2 both layers | special walls |
| 17 | DiagonalAcute_BothBG | Diagonal both | diagonal walls |
| 18 | DiagonalGrave_BothBG | Diagonal both | diagonal walls |
---
*Document generated from analysis of yaze, ZScream, and usdasm codebases.*
*Last updated: 2025-12-01*