backend-infra-engineer: Post v0.3.9-hotfix7 snapshot (build cleanup)
This commit is contained in:
542
docs/internal/zelda3/alttp-object-handlers.md
Normal file
542
docs/internal/zelda3/alttp-object-handlers.md
Normal file
@@ -0,0 +1,542 @@
|
||||
# ALTTP Dungeon Object Handler Tables
|
||||
|
||||
Source: `zelda3.sfc` (usdasm) — generated via `scripts/dump_object_handlers.py`.
|
||||
|
||||
## Table Summary
|
||||
- Type 1 (standard objects) — SNES $01:8200 — 256 entries
|
||||
- Type 2 (extended objects) — SNES $01:8470 — 64 entries
|
||||
- Type 3 (special objects) — SNES $01:85F0 — 128 entries
|
||||
|
||||
## Type 1 (Object 0x000–0x0FF)
|
||||
- Handler table: $01:8200 (PC 0x008200)
|
||||
- Total objects: 256
|
||||
- Unique handlers: 100
|
||||
- Shared handlers: 156
|
||||
- Most common handlers:
|
||||
- $01:8AA3 — used by 32 objects
|
||||
- $01:8F62 — used by 22 objects
|
||||
- $01:8FA5 — used by 19 objects
|
||||
- $01:8C58 — used by 6 objects
|
||||
- $01:8C61 — used by 6 objects
|
||||
|
||||
Example entries:
|
||||
- 0x000 → $01:8B89
|
||||
- 0x001 → $01:8A92
|
||||
- 0x005 → $01:8C37
|
||||
- 0x009 → $01:8C58
|
||||
- 0x00A → $01:8C61
|
||||
|
||||
## Type 2 (Object 0x000–0x03F)
|
||||
- Handler table: $01:8470 (PC 0x008470)
|
||||
- Total objects: 64
|
||||
- Unique handlers: 30
|
||||
- Shared handlers: 34
|
||||
- Most common handlers:
|
||||
- $01:97ED — used by 12 objects
|
||||
- $01:9813 — used by 8 objects
|
||||
- $01:9895 — used by 7 objects
|
||||
- $01:9854 — used by 4 objects
|
||||
- $01:985C — used by 4 objects
|
||||
|
||||
Example entries:
|
||||
- 0x000 → $01:97ED
|
||||
- 0x010 → $01:9854
|
||||
- 0x01D → $01:8F30
|
||||
- 0x02D → $01:A41B
|
||||
- 0x03F → $01:9A0C
|
||||
|
||||
## Type 3 (Object 0x000–0x07F)
|
||||
- Handler table: $01:85F0 (PC 0x0085F0)
|
||||
- Total objects: 128
|
||||
- Unique handlers: 59
|
||||
- Shared handlers: 69
|
||||
- Most common handlers:
|
||||
- $01:9895 — used by 35 objects
|
||||
- $01:9C3E — used by 10 objects
|
||||
- $01:99E6 — used by 7 objects
|
||||
- $01:9BD9 — used by 4 objects
|
||||
- $01:97ED — used by 4 objects
|
||||
|
||||
Example entries:
|
||||
- 0x000 → $01:9D29
|
||||
- 0x00F → $01:9C3E
|
||||
- 0x016 → $01:B493
|
||||
- 0x02A → $01:9DE5
|
||||
- 0x07F → $01:8AA3
|
||||
|
||||
## Handler Bytes (samples)
|
||||
- Handler $01:8B89 (Type1 Obj 0x000): first 64 bytes:
|
||||
`20 CC B0 20 95 98 C6 B2 D0 F9 60 E6 B2 E6 B4 A5 B2 85 0A BD 52 9B 97 BF 97 C2 97 C5 97 C8 97 CB 97 CE 97 D1 97 D4 98 18 69 00 01 A8 BD 52 9B 97 BF 97 C2 97 C5 97 C8 97 CB 97 CE 97 D1 97 D4 98`
|
||||
- Handler $01:8A92 (Type1 shared): first 32 bytes:
|
||||
`20 BE B0 86 0A A9 02 00 20 F0 97 A6 0A C6 B2 D0 F4 60 8A BB A8 20 AC B0 B9 52 9B 9F 00 40 7E 9F`
|
||||
- Handler $01:97ED (Type2 common): first 32 bytes:
|
||||
`A9 04 00 85 0E BD 52 9B 97 BF BD 54 9B 97 CB BD 56 9B 97 D7 BD 58 9B 97 DA 8A 18 69 08 00 AA C8`
|
||||
|
||||
## Notes / Next Steps
|
||||
- Full per-object table (256/64/128 entries) was emitted by the script; consider importing the CSV/TSV variant if we want all rows in-doc.
|
||||
- Phase 1 follow-up: for each handler, map WRAM touches (tilemaps, offsets, flags) and shared subroutines in bank $01 to build `alttp-wram-state.md`.
|
||||
- Handler hotspots to debug (from prior plan): $01:3479 (reported loop); use cycle trace + WRAM init capture when emulating.
|
||||
|
||||
---
|
||||
|
||||
## Full Handler Tables (from zelda3.sfc)
|
||||
|
||||
### Type 1 (0x000-0x0FF)
|
||||
Object | Handler (SNES) | Handler (PC)
|
||||
------ | -------------- | -------------
|
||||
0x000 | $01:8B89 | 0x008B89
|
||||
0x001 | $01:8A92 | 0x008A92
|
||||
0x002 | $01:8A92 | 0x008A92
|
||||
0x003 | $01:8B0D | 0x008B0D
|
||||
0x004 | $01:8B0D | 0x008B0D
|
||||
0x005 | $01:8C37 | 0x008C37
|
||||
0x006 | $01:8C37 | 0x008C37
|
||||
0x007 | $01:8B79 | 0x008B79
|
||||
0x008 | $01:8B79 | 0x008B79
|
||||
0x009 | $01:8C58 | 0x008C58
|
||||
0x00A | $01:8C61 | 0x008C61
|
||||
0x00B | $01:8C61 | 0x008C61
|
||||
0x00C | $01:8C58 | 0x008C58
|
||||
0x00D | $01:8C58 | 0x008C58
|
||||
0x00E | $01:8C61 | 0x008C61
|
||||
0x00F | $01:8C61 | 0x008C61
|
||||
0x010 | $01:8C58 | 0x008C58
|
||||
0x011 | $01:8C58 | 0x008C58
|
||||
0x012 | $01:8C61 | 0x008C61
|
||||
0x013 | $01:8C61 | 0x008C61
|
||||
0x014 | $01:8C58 | 0x008C58
|
||||
0x015 | $01:8C58 | 0x008C58
|
||||
0x016 | $01:8C61 | 0x008C61
|
||||
0x017 | $01:8C61 | 0x008C61
|
||||
0x018 | $01:8C58 | 0x008C58
|
||||
0x019 | $01:8C58 | 0x008C58
|
||||
0x01A | $01:8C61 | 0x008C61
|
||||
0x01B | $01:8C61 | 0x008C61
|
||||
0x01C | $01:8C58 | 0x008C58
|
||||
0x01D | $01:8C58 | 0x008C58
|
||||
0x01E | $01:8C61 | 0x008C61
|
||||
0x01F | $01:8C61 | 0x008C61
|
||||
0x020 | $01:8C58 | 0x008C58
|
||||
0x021 | $01:8C58 | 0x008C58
|
||||
0x022 | $01:8C61 | 0x008C61
|
||||
0x023 | $01:8C61 | 0x008C61
|
||||
0x024 | $01:8C58 | 0x008C58
|
||||
0x025 | $01:8C58 | 0x008C58
|
||||
0x026 | $01:8C61 | 0x008C61
|
||||
0x027 | $01:8C61 | 0x008C61
|
||||
0x028 | $01:8C58 | 0x008C58
|
||||
0x029 | $01:8C58 | 0x008C58
|
||||
0x02A | $01:8C61 | 0x008C61
|
||||
0x02B | $01:8C61 | 0x008C61
|
||||
0x02C | $01:8C58 | 0x008C58
|
||||
0x02D | $01:8C58 | 0x008C58
|
||||
0x02E | $01:8C61 | 0x008C61
|
||||
0x02F | $01:8C61 | 0x008C61
|
||||
0x030 | $01:8C58 | 0x008C58
|
||||
0x031 | $01:8C58 | 0x008C58
|
||||
0x032 | $01:8C61 | 0x008C61
|
||||
0x033 | $01:8C61 | 0x008C61
|
||||
0x034 | $01:8C58 | 0x008C58
|
||||
0x035 | $01:8C58 | 0x008C58
|
||||
0x036 | $01:8C61 | 0x008C61
|
||||
0x037 | $01:8C61 | 0x008C61
|
||||
0x038 | $01:8C58 | 0x008C58
|
||||
0x039 | $01:8C58 | 0x008C58
|
||||
0x03A | $01:8C61 | 0x008C61
|
||||
0x03B | $01:8C61 | 0x008C61
|
||||
0x03C | $01:8C58 | 0x008C58
|
||||
0x03D | $01:8C58 | 0x008C58
|
||||
0x03E | $01:8C61 | 0x008C61
|
||||
0x03F | $01:8C61 | 0x008C61
|
||||
0x040 | $01:8C58 | 0x008C58
|
||||
0x041 | $01:8C58 | 0x008C58
|
||||
0x042 | $01:8C61 | 0x008C61
|
||||
0x043 | $01:8C61 | 0x008C61
|
||||
0x044 | $01:8C58 | 0x008C58
|
||||
0x045 | $01:8C58 | 0x008C58
|
||||
0x046 | $01:8C61 | 0x008C61
|
||||
0x047 | $01:8C61 | 0x008C61
|
||||
0x048 | $01:8C58 | 0x008C58
|
||||
0x049 | $01:8C58 | 0x008C58
|
||||
0x04A | $01:8C61 | 0x008C61
|
||||
0x04B | $01:8C61 | 0x008C61
|
||||
0x04C | $01:8C58 | 0x008C58
|
||||
0x04D | $01:8C58 | 0x008C58
|
||||
0x04E | $01:8C61 | 0x008C61
|
||||
0x04F | $01:8C61 | 0x008C61
|
||||
0x050 | $01:8C58 | 0x008C58
|
||||
0x051 | $01:8C58 | 0x008C58
|
||||
0x052 | $01:8C61 | 0x008C61
|
||||
0x053 | $01:8C61 | 0x008C61
|
||||
0x054 | $01:8C58 | 0x008C58
|
||||
0x055 | $01:8C58 | 0x008C58
|
||||
0x056 | $01:8C61 | 0x008C61
|
||||
0x057 | $01:8C61 | 0x008C61
|
||||
0x058 | $01:8C58 | 0x008C58
|
||||
0x059 | $01:8C58 | 0x008C58
|
||||
0x05A | $01:8C61 | 0x008C61
|
||||
0x05B | $01:8C61 | 0x008C61
|
||||
0x05C | $01:8C58 | 0x008C58
|
||||
0x05D | $01:8C58 | 0x008C58
|
||||
0x05E | $01:8C61 | 0x008C61
|
||||
0x05F | $01:8C61 | 0x008C61
|
||||
0x060 | $01:8C58 | 0x008C58
|
||||
0x061 | $01:8C58 | 0x008C58
|
||||
0x062 | $01:8C61 | 0x008C61
|
||||
0x063 | $01:8C61 | 0x008C61
|
||||
0x064 | $01:8C58 | 0x008C58
|
||||
0x065 | $01:8C58 | 0x008C58
|
||||
0x066 | $01:8C61 | 0x008C61
|
||||
0x067 | $01:8C61 | 0x008C61
|
||||
0x068 | $01:8C58 | 0x008C58
|
||||
0x069 | $01:8C58 | 0x008C58
|
||||
0x06A | $01:8C61 | 0x008C61
|
||||
0x06B | $01:8C61 | 0x008C61
|
||||
0x06C | $01:8C58 | 0x008C58
|
||||
0x06D | $01:8C58 | 0x008C58
|
||||
0x06E | $01:8C61 | 0x008C61
|
||||
0x06F | $01:8C61 | 0x008C61
|
||||
0x070 | $01:8C58 | 0x008C58
|
||||
0x071 | $01:8C58 | 0x008C58
|
||||
0x072 | $01:8C61 | 0x008C61
|
||||
0x073 | $01:8C61 | 0x008C61
|
||||
0x074 | $01:8C58 | 0x008C58
|
||||
0x075 | $01:8C58 | 0x008C58
|
||||
0x076 | $01:8C61 | 0x008C61
|
||||
0x077 | $01:8C61 | 0x008C61
|
||||
0x078 | $01:8C58 | 0x008C58
|
||||
0x079 | $01:8C58 | 0x008C58
|
||||
0x07A | $01:8C61 | 0x008C61
|
||||
0x07B | $01:8C61 | 0x008C61
|
||||
0x07C | $01:8C58 | 0x008C58
|
||||
0x07D | $01:8C58 | 0x008C58
|
||||
0x07E | $01:8C61 | 0x008C61
|
||||
0x07F | $01:8C61 | 0x008C61
|
||||
0x080 | $01:8C58 | 0x008C58
|
||||
0x081 | $01:8C58 | 0x008C58
|
||||
0x082 | $01:8C61 | 0x008C61
|
||||
0x083 | $01:8C61 | 0x008C61
|
||||
0x084 | $01:8C58 | 0x008C58
|
||||
0x085 | $01:8C58 | 0x008C58
|
||||
0x086 | $01:8C61 | 0x008C61
|
||||
0x087 | $01:8C61 | 0x008C61
|
||||
0x088 | $01:8C58 | 0x008C58
|
||||
0x089 | $01:8C58 | 0x008C58
|
||||
0x08A | $01:8C61 | 0x008C61
|
||||
0x08B | $01:8C61 | 0x008C61
|
||||
0x08C | $01:8C58 | 0x008C58
|
||||
0x08D | $01:8C58 | 0x008C58
|
||||
0x08E | $01:8C61 | 0x008C61
|
||||
0x08F | $01:8C61 | 0x008C61
|
||||
0x090 | $01:8C58 | 0x008C58
|
||||
0x091 | $01:8C58 | 0x008C58
|
||||
0x092 | $01:8C61 | 0x008C61
|
||||
0x093 | $01:8C61 | 0x008C61
|
||||
0x094 | $01:8C58 | 0x008C58
|
||||
0x095 | $01:8C58 | 0x008C58
|
||||
0x096 | $01:8C61 | 0x008C61
|
||||
0x097 | $01:8C61 | 0x008C61
|
||||
0x098 | $01:8C58 | 0x008C58
|
||||
0x099 | $01:8C58 | 0x008C58
|
||||
0x09A | $01:8C61 | 0x008C61
|
||||
0x09B | $01:8C61 | 0x008C61
|
||||
0x09C | $01:8C58 | 0x008C58
|
||||
0x09D | $01:8C58 | 0x008C58
|
||||
0x09E | $01:8C61 | 0x008C61
|
||||
0x09F | $01:8C61 | 0x008C61
|
||||
0x0A0 | $01:8C58 | 0x008C58
|
||||
0x0A1 | $01:8C58 | 0x008C58
|
||||
0x0A2 | $01:8C61 | 0x008C61
|
||||
0x0A3 | $01:8C61 | 0x008C61
|
||||
0x0A4 | $01:8C58 | 0x008C58
|
||||
0x0A5 | $01:8C58 | 0x008C58
|
||||
0x0A6 | $01:8C61 | 0x008C61
|
||||
0x0A7 | $01:8C61 | 0x008C61
|
||||
0x0A8 | $01:8C58 | 0x008C58
|
||||
0x0A9 | $01:8C58 | 0x008C58
|
||||
0x0AA | $01:8C61 | 0x008C61
|
||||
0x0AB | $01:8C61 | 0x008C61
|
||||
0x0AC | $01:8C58 | 0x008C58
|
||||
0x0AD | $01:8C58 | 0x008C58
|
||||
0x0AE | $01:8C61 | 0x008C61
|
||||
0x0AF | $01:8C61 | 0x008C61
|
||||
0x0B0 | $01:8C58 | 0x008C58
|
||||
0x0B1 | $01:8C58 | 0x008C58
|
||||
0x0B2 | $01:8C61 | 0x008C61
|
||||
0x0B3 | $01:8C61 | 0x008C61
|
||||
0x0B4 | $01:8C58 | 0x008C58
|
||||
0x0B5 | $01:8C58 | 0x008C58
|
||||
0x0B6 | $01:8C61 | 0x008C61
|
||||
0x0B7 | $01:8C61 | 0x008C61
|
||||
0x0B8 | $01:8C58 | 0x008C58
|
||||
0x0B9 | $01:8C58 | 0x008C58
|
||||
0x0BA | $01:8C61 | 0x008C61
|
||||
0x0BB | $01:8C61 | 0x008C61
|
||||
0x0BC | $01:8C58 | 0x008C58
|
||||
0x0BD | $01:8C58 | 0x008C58
|
||||
0x0BE | $01:8C61 | 0x008C61
|
||||
0x0BF | $01:8C61 | 0x008C61
|
||||
0x0C0 | $01:8C58 | 0x008C58
|
||||
0x0C1 | $01:8C58 | 0x008C58
|
||||
0x0C2 | $01:8C61 | 0x008C61
|
||||
0x0C3 | $01:8C61 | 0x008C61
|
||||
0x0C4 | $01:8C58 | 0x008C58
|
||||
0x0C5 | $01:8C58 | 0x008C58
|
||||
0x0C6 | $01:8C61 | 0x008C61
|
||||
0x0C7 | $01:8C61 | 0x008C61
|
||||
0x0C8 | $01:8C58 | 0x008C58
|
||||
0x0C9 | $01:8C58 | 0x008C58
|
||||
0x0CA | $01:8C61 | 0x008C61
|
||||
0x0CB | $01:8C61 | 0x008C61
|
||||
0x0CC | $01:8C58 | 0x008C58
|
||||
0x0CD | $01:8C58 | 0x008C58
|
||||
0x0CE | $01:8C61 | 0x008C61
|
||||
0x0CF | $01:8C61 | 0x008C61
|
||||
0x0D0 | $01:8C58 | 0x008C58
|
||||
0x0D1 | $01:8C58 | 0x008C58
|
||||
0x0D2 | $01:8C61 | 0x008C61
|
||||
0x0D3 | $01:8C61 | 0x008C61
|
||||
0x0D4 | $01:8C58 | 0x008C58
|
||||
0x0D5 | $01:8C58 | 0x008C58
|
||||
0x0D6 | $01:8C61 | 0x008C61
|
||||
0x0D7 | $01:8C61 | 0x008C61
|
||||
0x0D8 | $01:8C58 | 0x008C58
|
||||
0x0D9 | $01:8C58 | 0x008C58
|
||||
0x0DA | $01:8C61 | 0x008C61
|
||||
0x0DB | $01:8C61 | 0x008C61
|
||||
0x0DC | $01:8C58 | 0x008C58
|
||||
0x0DD | $01:8C58 | 0x008C58
|
||||
0x0DE | $01:8C61 | 0x008C61
|
||||
0x0DF | $01:8C61 | 0x008C61
|
||||
0x0E0 | $01:8C58 | 0x008C58
|
||||
0x0E1 | $01:8C58 | 0x008C58
|
||||
0x0E2 | $01:8C61 | 0x008C61
|
||||
0x0E3 | $01:8C61 | 0x008C61
|
||||
0x0E4 | $01:8C58 | 0x008C58
|
||||
0x0E5 | $01:8C58 | 0x008C58
|
||||
0x0E6 | $01:8C61 | 0x008C61
|
||||
0x0E7 | $01:8C61 | 0x008C61
|
||||
0x0E8 | $01:8C58 | 0x008C58
|
||||
0x0E9 | $01:8C58 | 0x008C58
|
||||
0x0EA | $01:8C61 | 0x008C61
|
||||
0x0EB | $01:8C61 | 0x008C61
|
||||
0x0EC | $01:8C58 | 0x008C58
|
||||
0x0ED | $01:8C58 | 0x008C58
|
||||
0x0EE | $01:8C61 | 0x008C61
|
||||
0x0EF | $01:8C61 | 0x008C61
|
||||
0x0F0 | $01:8C58 | 0x008C58
|
||||
0x0F1 | $01:8C58 | 0x008C58
|
||||
0x0F2 | $01:8C61 | 0x008C61
|
||||
0x0F3 | $01:8C61 | 0x008C61
|
||||
0x0F4 | $01:8C58 | 0x008C58
|
||||
0x0F5 | $01:8C58 | 0x008C58
|
||||
0x0F6 | $01:8C61 | 0x008C61
|
||||
0x0F7 | $01:8C61 | 0x008C61
|
||||
0x0F8 | $01:8C58 | 0x008C58
|
||||
0x0F9 | $01:8C58 | 0x008C58
|
||||
0x0FA | $01:8C61 | 0x008C61
|
||||
0x0FB | $01:8C61 | 0x008C61
|
||||
0x0FC | $01:8C58 | 0x008C58
|
||||
0x0FD | $01:8C58 | 0x008C58
|
||||
0x0FE | $01:8C61 | 0x008C61
|
||||
0x0FF | $01:8C61 | 0x008C61
|
||||
|
||||
### Type 2 (0x000-0x03F)
|
||||
Object | Handler (SNES) | Handler (PC)
|
||||
------ | -------------- | -------------
|
||||
0x000 | $01:97ED | 0x0097ED
|
||||
0x001 | $01:97ED | 0x0097ED
|
||||
0x002 | $01:97ED | 0x0097ED
|
||||
0x003 | $01:97ED | 0x0097ED
|
||||
0x004 | $01:97ED | 0x0097ED
|
||||
0x005 | $01:97ED | 0x0097ED
|
||||
0x006 | $01:97ED | 0x0097ED
|
||||
0x007 | $01:97ED | 0x0097ED
|
||||
0x008 | $01:9813 | 0x009813
|
||||
0x009 | $01:9813 | 0x009813
|
||||
0x00A | $01:9813 | 0x009813
|
||||
0x00B | $01:9813 | 0x009813
|
||||
0x00C | $01:9813 | 0x009813
|
||||
0x00D | $01:9813 | 0x009813
|
||||
0x00E | $01:9813 | 0x009813
|
||||
0x00F | $01:9813 | 0x009813
|
||||
0x010 | $01:9854 | 0x009854
|
||||
0x011 | $01:9854 | 0x009854
|
||||
0x012 | $01:9854 | 0x009854
|
||||
0x013 | $01:9854 | 0x009854
|
||||
0x014 | $01:985C | 0x00985C
|
||||
0x015 | $01:985C | 0x00985C
|
||||
0x016 | $01:985C | 0x00985C
|
||||
0x017 | $01:985C | 0x00985C
|
||||
0x018 | $01:9895 | 0x009895
|
||||
0x019 | $01:9895 | 0x009895
|
||||
0x01A | $01:9895 | 0x009895
|
||||
0x01B | $01:9895 | 0x009895
|
||||
0x01C | $01:97ED | 0x0097ED
|
||||
0x01D | $01:8F30 | 0x008F30
|
||||
0x01E | $01:9A8D | 0x009A8D
|
||||
0x01F | $01:9A6F | 0x009A6F
|
||||
0x020 | $01:9892 | 0x009892
|
||||
0x021 | $01:8F30 | 0x008F30
|
||||
0x022 | $01:9AEE | 0x009AEE
|
||||
0x023 | $01:99E6 | 0x0099E6
|
||||
0x024 | $01:97ED | 0x0097ED
|
||||
0x025 | $01:97ED | 0x0097ED
|
||||
0x026 | $01:8F30 | 0x008F30
|
||||
0x027 | $01:9895 | 0x009895
|
||||
0x028 | $01:9AEE | 0x009AEE
|
||||
0x029 | $01:97ED | 0x0097ED
|
||||
0x02A | $01:9B48 | 0x009B48
|
||||
0x02B | $01:9895 | 0x009895
|
||||
0x02C | $01:9B50 | 0x009B50
|
||||
0x02D | $01:A41B | 0x00A41B
|
||||
0x02E | $01:A458 | 0x00A458
|
||||
0x02F | $01:A486 | 0x00A486
|
||||
0x030 | $01:A25D | 0x00A25D
|
||||
0x031 | $01:A26D | 0x00A26D
|
||||
0x032 | $01:A2C7 | 0x00A2C7
|
||||
0x033 | $01:A2DF | 0x00A2DF
|
||||
0x034 | $01:9895 | 0x009895
|
||||
0x035 | $01:9B1E | 0x009B1E
|
||||
0x036 | $01:A3AE | 0x00A3AE
|
||||
0x037 | $01:9BF8 | 0x009BF8
|
||||
0x038 | $01:A4B4 | 0x00A4B4
|
||||
0x039 | $01:A533 | 0x00A533
|
||||
0x03A | $01:A4F5 | 0x00A4F5
|
||||
0x03B | $01:A584 | 0x00A584
|
||||
0x03C | $01:9B56 | 0x009B56
|
||||
0x03D | $01:99E6 | 0x0099E6
|
||||
0x03E | $01:9A0C | 0x009A0C
|
||||
0x03F | $01:9A12 | 0x009A12
|
||||
|
||||
### Type 3 (0x000-0x07F)
|
||||
Object | Handler (SNES) | Handler (PC)
|
||||
------ | -------------- | -------------
|
||||
0x000 | $01:9D29 | 0x009D29
|
||||
0x001 | $01:9D5D | 0x009D5D
|
||||
0x002 | $01:9D67 | 0x009D67
|
||||
0x003 | $01:9C3B | 0x009C3B
|
||||
0x004 | $01:9C3E | 0x009C3E
|
||||
0x005 | $01:9C3E | 0x009C3E
|
||||
0x006 | $01:9C3E | 0x009C3E
|
||||
0x007 | $01:9C3E | 0x009C3E
|
||||
0x008 | $01:9C3E | 0x009C3E
|
||||
0x009 | $01:9C3E | 0x009C3E
|
||||
0x00A | $01:9C3E | 0x009C3E
|
||||
0x00B | $01:9C3E | 0x009C3E
|
||||
0x00C | $01:9C3E | 0x009C3E
|
||||
0x00D | $01:9C44 | 0x009C44
|
||||
0x00E | $01:9C3B | 0x009C3B
|
||||
0x00F | $01:9C3E | 0x009C3E
|
||||
0x010 | $01:9895 | 0x009895
|
||||
0x011 | $01:9895 | 0x009895
|
||||
0x012 | $01:9AA9 | 0x009AA9
|
||||
0x013 | $01:9895 | 0x009895
|
||||
0x014 | $01:99E6 | 0x0099E6
|
||||
0x015 | $01:9D96 | 0x009D96
|
||||
0x016 | $01:B493 | 0x00B493
|
||||
0x017 | $01:9C44 | 0x009C44
|
||||
0x018 | $01:98AE | 0x0098AE
|
||||
0x019 | $01:98D0 | 0x0098D0
|
||||
0x01A | $01:99B8 | 0x0099B8
|
||||
0x01B | $01:A30C | 0x00A30C
|
||||
0x01C | $01:A31C | 0x00A31C
|
||||
0x01D | $01:A36E | 0x00A36E
|
||||
0x01E | $01:A5D2 | 0x00A5D2
|
||||
0x01F | $01:A5F4 | 0x00A5F4
|
||||
0x020 | $01:A607 | 0x00A607
|
||||
0x021 | $01:A626 | 0x00A626
|
||||
0x022 | $01:9895 | 0x009895
|
||||
0x023 | $01:9895 | 0x009895
|
||||
0x024 | $01:9895 | 0x009895
|
||||
0x025 | $01:9895 | 0x009895
|
||||
0x026 | $01:A664 | 0x00A664
|
||||
0x027 | $01:A695 | 0x00A695
|
||||
0x028 | $01:A71C | 0x00A71C
|
||||
0x029 | $01:A74A | 0x00A74A
|
||||
0x02A | $01:9DE5 | 0x009DE5
|
||||
0x02B | $01:B306 | 0x00B306
|
||||
0x02C | $01:B310 | 0x00B310
|
||||
0x02D | $01:9E30 | 0x009E30
|
||||
0x02E | $01:9EA3 | 0x009EA3
|
||||
0x02F | $01:B395 | 0x00B395
|
||||
0x030 | $01:B30B | 0x00B30B
|
||||
0x031 | $01:99BB | 0x0099BB
|
||||
0x032 | $01:9A00 | 0x009A00
|
||||
0x033 | $01:A380 | 0x00A380
|
||||
0x034 | $01:9BD9 | 0x009BD9
|
||||
0x035 | $01:9BD9 | 0x009BD9
|
||||
0x036 | $01:9B50 | 0x009B50
|
||||
0x037 | $01:9B50 | 0x009B50
|
||||
0x038 | $01:9BD9 | 0x009BD9
|
||||
0x039 | $01:9BD9 | 0x009BD9
|
||||
0x03A | $01:9A90 | 0x009A90
|
||||
0x03B | $01:9A90 | 0x009A90
|
||||
0x03C | $01:9AA3 | 0x009AA3
|
||||
0x03D | $01:9AA3 | 0x009AA3
|
||||
0x03E | $01:9895 | 0x009895
|
||||
0x03F | $01:9895 | 0x009895
|
||||
0x040 | $01:9895 | 0x009895
|
||||
0x041 | $01:9895 | 0x009895
|
||||
0x042 | $01:9895 | 0x009895
|
||||
0x043 | $01:9895 | 0x009895
|
||||
0x044 | $01:9895 | 0x009895
|
||||
0x045 | $01:9895 | 0x009895
|
||||
0x046 | $01:9895 | 0x009895
|
||||
0x047 | $01:B3E1 | 0x00B3E1
|
||||
0x048 | $01:97ED | 0x0097ED
|
||||
0x049 | $01:9895 | 0x009895
|
||||
0x04A | $01:9895 | 0x009895
|
||||
0x04B | $01:9A06 | 0x009A06
|
||||
0x04C | $01:9A66 | 0x009A66
|
||||
0x04D | $01:9A0C | 0x009A0C
|
||||
0x04E | $01:99E6 | 0x0099E6
|
||||
0x04F | $01:9895 | 0x009895
|
||||
0x050 | $01:9A8D | 0x009A8D
|
||||
0x051 | $01:9895 | 0x009895
|
||||
0x052 | $01:9895 | 0x009895
|
||||
0x053 | $01:9895 | 0x009895
|
||||
0x054 | $01:A095 | 0x00A095
|
||||
0x055 | $01:A194 | 0x00A194
|
||||
0x056 | $01:9895 | 0x009895
|
||||
0x057 | $01:9895 | 0x009895
|
||||
0x058 | $01:9895 | 0x009895
|
||||
0x059 | $01:9895 | 0x009895
|
||||
0x05A | $01:9D6C | 0x009D6C
|
||||
0x05B | $01:A194 | 0x00A194
|
||||
0x05C | $01:9AA3 | 0x009AA3
|
||||
0x05D | $01:9A0C | 0x009A0C
|
||||
0x05E | $01:9895 | 0x009895
|
||||
0x05F | $01:9895 | 0x009895
|
||||
0x060 | $01:A7A3 | 0x00A7A3
|
||||
0x061 | $01:A7A3 | 0x00A7A3
|
||||
0x062 | $01:A1D1 | 0x00A1D1
|
||||
0x063 | $01:9895 | 0x009895
|
||||
0x064 | $01:9895 | 0x009895
|
||||
0x065 | $01:9895 | 0x009895
|
||||
0x066 | $01:97ED | 0x0097ED
|
||||
0x067 | $01:99E6 | 0x0099E6
|
||||
0x068 | $01:99E6 | 0x0099E6
|
||||
0x069 | $01:99EC | 0x0099EC
|
||||
0x06A | $01:99EC | 0x0099EC
|
||||
0x06B | $01:97ED | 0x0097ED
|
||||
0x06C | $01:99E6 | 0x0099E6
|
||||
0x06D | $01:99E6 | 0x0099E6
|
||||
0x06E | $01:99EC | 0x0099EC
|
||||
0x06F | $01:99EC | 0x0099EC
|
||||
0x070 | $01:A7B6 | 0x00A7B6
|
||||
0x071 | $01:A7D3 | 0x00A7D3
|
||||
0x072 | $01:9DD9 | 0x009DD9
|
||||
0x073 | $01:A255 | 0x00A255
|
||||
0x074 | $01:A7DC | 0x00A7DC
|
||||
0x075 | $01:9895 | 0x009895
|
||||
0x076 | $01:9A06 | 0x009A06
|
||||
0x077 | $01:9A06 | 0x009A06
|
||||
0x078 | $01:A7F0 | 0x00A7F0
|
||||
0x079 | $01:99E6 | 0x0099E6
|
||||
0x07A | $01:97ED | 0x0097ED
|
||||
0x07B | $01:A809 | 0x00A809
|
||||
0x07C | $01:9895 | 0x009895
|
||||
0x07D | $01:9895 | 0x009895
|
||||
0x07E | $01:9895 | 0x009895
|
||||
0x07F | $01:8AA3 | 0x008AA3
|
||||
103
docs/internal/zelda3/alttp-wram-state.md
Normal file
103
docs/internal/zelda3/alttp-wram-state.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# ALTTP Dungeon Object WRAM Usage (Initial Pass)
|
||||
|
||||
Heuristic scan: first 64 bytes of all dungeon object handlers (Type1/2/3) from `zelda3.sfc`, looking for absolute/long accesses to $7E:*. This is a starting point; many handlers use indirect addressing, so manual tracing is still required.
|
||||
|
||||
## Observed WRAM Touches (by handler)
|
||||
|
||||
### Handler $01:A7A3
|
||||
Offset | Op | WRAM
|
||||
------ | -- | ----
|
||||
0x30 | AF | $7EF0CA
|
||||
|
||||
### Handler $01:A7B6
|
||||
Offset | Op | WRAM
|
||||
------ | -- | ----
|
||||
0x1D | AF | $7EF0CA
|
||||
|
||||
### Handler $01:A7D3
|
||||
Offset | Op | WRAM
|
||||
------ | -- | ----
|
||||
0x00 | AF | $7EF0CA
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
- Manually trace key handlers (e.g., Type1 $01:8B89, $01:8AA3; Type2 $01:97ED; Type3 $01:9C3E, $01:9895) to capture indirect $7E accesses and required initialization (tilemaps, offsets, flags).
|
||||
- Expand scan window beyond 64 bytes and follow subroutine calls to capture deeper WRAM dependencies.
|
||||
- Cross-reference accesses with known tilemap buffers ($7E2000/$7E4000), offsets ($7E049C/$7E049E), drawing flags ($7E0476), object ptrs ($7E00B7-B9), room state ($7E00AF/$7E00A0), and any temp work areas the handlers expect.
|
||||
- For future state-injection (“load me into dungeon X with items Y”): map and annotate inventory/state WRAM (sword/shield/armor bits, small keys, big key, map/compass, heart count, rupees/bombs/arrows, crystal/pendant flags), Link position ($7E22–$7E2A ranges), camera offsets, submodule/state machine bytes. Use emulator save-state comparisons to seed defaults if not present in handlers.
|
||||
|
||||
---
|
||||
|
||||
## Seeded Known Addresses (to verify/expand)
|
||||
- Room/submodule: `$7E00A0` (submodule/floor), `$7E00AF` (room ID)
|
||||
- Object data pointer: `$7E00B7-$7E00B9` (24-bit pointer)
|
||||
- Drawing flags/context: `$7E0476`
|
||||
- Tilemap offsets: `$7E049C` (X), `$7E049E` (Y)
|
||||
- Tilemap buffers: `$7E2000-$7E3FFF` (BG1), `$7E4000-$7E5FFF` (BG2)
|
||||
- Temp/dungeon draw scratch (from handler traces, needs confirmation):
|
||||
- `$7E7E21-$7E7E26` – frequently touched across handlers (likely temp counters/coords)
|
||||
- `$7E7E71`, `$7E7EAA`, `$7E7EAD`, `$7E7ED1` – sparse temps/state flags
|
||||
- `$7E7E22A8`, `$7E7E2BB2`, `$7E7E411E` – long addresses referenced; verify if pointer tables/accumulators
|
||||
- `$7E7EC000-$7E7EC7FF` region – heavily used; appears to be work buffers (coords, queues, staging). Needs field-by-field labeling.
|
||||
- `$7E7EF0CA`, `$7E7EF3CA` – high WRAM touched by A7xx/B3xx handlers; likely state or decompression buffers.
|
||||
|
||||
## Data to Capture (for emulator state injection)
|
||||
- Link position and camera: positions/velocities, camera scroll, room boundaries
|
||||
- Inventory & flags: sword/shield/armor upgrades, small keys, big key, map/compass, rupees/bombs/arrows, bottle contents, pendant/crystal flags, boss defeat flags
|
||||
- UI/graphics state: HUD counters, palette state, tilemap/CHR load state tied to dungeon/overworld room
|
||||
- State machine: submodule/module bytes that gate movement/control and loading paths
|
||||
|
||||
## Suggested Capture Workflow
|
||||
1. Select a target handler (e.g., Type1 $01:8B89) and run a trace for 256–512 bytes including subroutine calls; log all $7E accesses (direct and via indexed/indirect).
|
||||
2. In emulator, save two WRAM snapshots: before/after drawing a known object; diff to identify required fields. Repeat for a few object classes (floors, walls, special objects).
|
||||
3. Populate this doc with verified addresses: name, size, purpose, default/init value, “required for preview?” flag, and “required for state-injection?” flag.
|
||||
4. Once core init set is stable, script a minimal WRAM initializer for the emulator preview and for “load me into dungeon X with items Y” (inventory/state injection).
|
||||
|
||||
---
|
||||
|
||||
## Static Scan (first 256 bytes per handler)
|
||||
Heuristic, direct $7E absolute/long accesses found in the first 256 bytes of each handler:
|
||||
|
||||
- $01:9DD9 → $7E7E22
|
||||
- $01:9DE5 → $7E7E22, $7E7E23
|
||||
- $01:9E30 → $7E7E22, $7E7E23
|
||||
- $01:9EA3 → $7E7E22, $7E7E23
|
||||
- $01:A095 → $7E7E21
|
||||
- $01:A71C → $7EF0CA
|
||||
- $01:A74A → $7EF0CA
|
||||
- $01:A7A3 → $7EF0CA
|
||||
- $01:A7B6 → $7EF0CA
|
||||
- $01:A7D3 → $7EF0CA
|
||||
- $01:B306 → $7EF3CA
|
||||
- $01:B30B → $7EF3CA
|
||||
- $01:B310 → $7EF3CA
|
||||
- $01:B376 → $7EF3CA
|
||||
- $01:B381 → $7EF3CA
|
||||
- $01:B395 → $7EF3CA
|
||||
|
||||
> These are starting points only; many handlers use indexed/indirect addressing and deeper subroutines that won’t show up in this static slice. Follow-up tracing is required to confirm purpose and defaults.
|
||||
|
||||
---
|
||||
|
||||
## Focus Handlers (1KB trace + subcalls, depth 3)
|
||||
Direct $7E touches seen for each representative handler. Next step: label, size, and defaults via save-state diffs.
|
||||
|
||||
### Type1 $01:8B89 (obj 0x000)
|
||||
Touches include:
|
||||
- Low scratch: `$7E7E21-$7E7E26`, `$7E7E71`, `$7E7EAA`, `$7E7EAD`, `$7E7ED1`
|
||||
- Work buffers: `$7E7EC000-$7E7EC7FF` (numerous fields), `$7E7EF051`, `$7E7EF0CA`, `$7E7EF282`, `$7E7EF2BB`, `$7E7EF2C3`, `$7E7EF2F0`, `$7E7EF2FB`, `$7E7EF340-$7E7EF37B`, `$7E7EF3C5-$7E7EF4FE`
|
||||
|
||||
### Type1 $01:8AA3 (common handler)
|
||||
Touches mirror 8B89: `$7E7E21-$7E7E26`, `$7E7E71`, `$7E7EAA`, `$7E7EAD`, `$7E7ED1`, wide `$7E7EC***` work buffers, `$7E7EF0CA`, `$7E7EF34x` block, `$7E7EF3C5+`, `$7E7EF4FE`.
|
||||
|
||||
### Type2 $01:97ED
|
||||
Touches: `$7E7E21-$7E7E26`, `$7E7ED1`, `$7E7E3F1E`, `$7E7E9059`, many `$7E7EC000+` fields, `$7E7EC3DC/DE/F6/F8`, `$7E7EC4FA`, `$7E7EC5DA+`, `$7E7EC7F2/7F4`, `$7E7EC832/834`, `$7E7EF0CA`, `$7E7EF282`, `$7E7EF2BB`, `$7E7EF2C3`, `$7E7EF2F0`, `$7E7EF2FB`, `$7E7EF340-$7E7EF37B`, `$7E7EF3C5-$7E7EF3D3`, `$7E7EF403`, `$7E7EF4FE`.
|
||||
|
||||
### Type3 $01:9C3E
|
||||
Touches: `$7E7E21-$7E7E26`, `$7E7ED1`, `$7E7E0709`, `$7E7E3F1E`, `$7E7EC000+` region, `$7E7EC3DC/DE/F6/F8`, `$7E7EC4FA`, `$7E7EC5DA+`, `$7E7EC7F2/7F4`, `$7E7EC832/834`, `$7E7EF0CA`, `$7E7EF282`, `$7E7EF2BB`, `$7E7EF2C3`, `$7E7EF2F0`, `$7E7EF2FB`, `$7E7EF300`, `$7E7EF340-$7E7EF379`, `$7E7EF3C5-$7E7EF3D3`, `$7E7EF403`, `$7E7EF4FE`.
|
||||
|
||||
### Type3 $01:9895
|
||||
Touches similar to 9C3E/97ED: `$7E7E21-$7E7E26`, `$7E7ED1`, `$7E7E3F1E`, `$7E7E9059`, `$7E7EC000+`, `$7E7EC3DC/DE/F6/F8`, `$7E7EC4FA`, `$7E7EC5DA+`, `$7E7EC7F2/7F4`, `$7E7EC832/834`, `$7E7EF0CA`, `$7E7EF282`, `$7E7EF2BB`, `$7E7EF2C3`, `$7E7EF2F0`, `$7E7EF2FB`, `$7E7EF340-$7E7EF37B`, `$7E7EF3C5-$7E7EF3D3`, `$7E7EF403`, `$7E7EF4FE`.
|
||||
|
||||
> Labeling needed: Map each address to meaning (coord, size, flags, palette, queues, staging buffers). Use emulator WRAM diffs around object draws and known state toggles to confirm.
|
||||
777
docs/internal/zelda3/dungeon-spec.md
Normal file
777
docs/internal/zelda3/dungeon-spec.md
Normal file
@@ -0,0 +1,777 @@
|
||||
# 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*
|
||||
207
docs/internal/zelda3/overworld-tail-expansion.md
Normal file
207
docs/internal/zelda3/overworld-tail-expansion.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Overworld Tail Map Expansion (0xA0-0xBF)
|
||||
|
||||
**Consolidated:** 2025-12-08
|
||||
**Status:** IMPLEMENTED
|
||||
**Owner:** zelda3-hacking-expert / overworld-specialist
|
||||
**Purpose:** Enable editing of special-world tail map slots (0xA0-0xBF) without corrupting existing data
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Apply tail expansion to a ZSCustomOverworld v3 ROM
|
||||
z3ed overworld-doctor --rom=zelda3.sfc --apply-tail-expansion --output=expanded.sfc
|
||||
|
||||
# Or apply manually with Asar (after ZSCustomOverworld v3)
|
||||
asar assets/patches/Overworld/TailMapExpansion.asm zelda3.sfc
|
||||
```
|
||||
|
||||
**Prerequisites:**
|
||||
1. **ZSCustomOverworld v3** must be applied first
|
||||
2. ROM must be 2MB (standard expanded size)
|
||||
|
||||
---
|
||||
|
||||
## Problem Statement
|
||||
|
||||
**The vanilla pointer tables only have 160 entries (maps 0x00-0x9F).**
|
||||
|
||||
```
|
||||
Original High Table: PC 0x1794D (SNES $02:F94D), 160 entries x 3 bytes
|
||||
Original Low Table: PC 0x17B2D (SNES $02:FB2D), 160 entries x 3 bytes
|
||||
```
|
||||
|
||||
Writing to entries for maps 0xA0+ would overwrite existing data, corrupting Light World maps 0x00-0x1F.
|
||||
|
||||
---
|
||||
|
||||
## Solution: TailMapExpansion.asm
|
||||
|
||||
The `TailMapExpansion.asm` patch relocates pointer tables to safe free space with 192 entries:
|
||||
|
||||
| Component | PC Address | SNES Address | Size |
|
||||
|-----------|------------|--------------|------|
|
||||
| Detection Marker | 0x1423FF | $28:A3FF | 1 byte (value: 0xEA) |
|
||||
| New High Table | 0x142400 | $28:A400 | 576 bytes (192 x 3) |
|
||||
| New Low Table | 0x142640 | $28:A640 | 576 bytes (192 x 3) |
|
||||
| Blank Map High | 0x180000 | $30:8000 | 188 bytes |
|
||||
| Blank Map Low | 0x181000 | $30:9000 | 4 bytes |
|
||||
|
||||
### Game Code Patches
|
||||
|
||||
The patch updates 8 LDA instructions in bank $02:
|
||||
|
||||
**Function 1: `Overworld_DecompressAndDrawOneQuadrant`**
|
||||
|
||||
| PC Address | Original | Patched |
|
||||
|------------|----------|---------|
|
||||
| 0x1F59D | `LDA.l $02F94D,X` | `LDA.l $28A400,X` |
|
||||
| 0x1F5A3 | `LDA.l $02F94E,X` | `LDA.l $28A401,X` |
|
||||
| 0x1F5C8 | `LDA.l $02FB2D,X` | `LDA.l $28A640,X` |
|
||||
| 0x1F5CE | `LDA.l $02FB2E,X` | `LDA.l $28A641,X` |
|
||||
|
||||
**Function 2: Secondary quadrant loader**
|
||||
|
||||
| PC Address | Original | Patched |
|
||||
|------------|----------|---------|
|
||||
| 0x1F7E3 | `LDA.l $02F94D,X` | `LDA.l $28A400,X` |
|
||||
| 0x1F7E9 | `LDA.l $02F94E,X` | `LDA.l $28A401,X` |
|
||||
| 0x1F80E | `LDA.l $02FB2D,X` | `LDA.l $28A640,X` |
|
||||
| 0x1F814 | `LDA.l $02FB2E,X` | `LDA.l $28A641,X` |
|
||||
|
||||
---
|
||||
|
||||
## ROM Layout (LoROM, no header)
|
||||
|
||||
### Expanded Data Regions (DO NOT OVERWRITE)
|
||||
|
||||
| Region | PC Start | PC End | SNES | Contents |
|
||||
|--------|----------|--------|------|----------|
|
||||
| Tile16 Expanded | 0x1E8000 | 0x1EFFFF | $3D:0000-$3D:FFFF | 4096 tile16 entries |
|
||||
| Map32 BL Expanded | 0x1F0000 | 0x1F7FFF | $3E:0000-$3E:7FFF | Map32 bottom-left tiles |
|
||||
| Map32 BR Expanded | 0x1F8000 | 0x1FFFFF | $3E:8000-$3F:FFFF | Map32 bottom-right tiles |
|
||||
| ZSCustom Tables | 0x140000 | 0x1421FF | $28:8000+ | Custom overworld arrays |
|
||||
| Overlay Space | 0x120000 | 0x12FFFF | $24:8000+ | Expanded overlay data |
|
||||
|
||||
### Safe Free Space
|
||||
|
||||
| PC Start | PC End | Size | SNES Bank | Notes |
|
||||
|----------|--------|------|-----------|-------|
|
||||
| 0x1422B2 | 0x17FFFF | ~245 KB | $28-$2F | Primary free space |
|
||||
| 0x180000 | 0x1DFFFF | 384 KB | $30-$3B | Additional free space |
|
||||
|
||||
**WARNING**: Do NOT use addresses 0x1E0000+ for new data!
|
||||
|
||||
---
|
||||
|
||||
## CLI Tools
|
||||
|
||||
### overworld-doctor
|
||||
|
||||
Full diagnostic and repair:
|
||||
|
||||
```bash
|
||||
# Diagnose only
|
||||
z3ed overworld-doctor --rom=file.sfc --verbose
|
||||
|
||||
# Compare with baseline
|
||||
z3ed overworld-doctor --rom=file.sfc --baseline=vanilla.sfc
|
||||
|
||||
# Apply tile16 fixes
|
||||
z3ed overworld-doctor --rom=file.sfc --fix --output=fixed.sfc
|
||||
|
||||
# Apply tail map expansion
|
||||
z3ed overworld-doctor --rom=file.sfc --apply-tail-expansion --output=expanded.sfc
|
||||
|
||||
# Preview tail expansion (dry run)
|
||||
z3ed overworld-doctor --rom=file.sfc --apply-tail-expansion --dry-run
|
||||
```
|
||||
|
||||
### overworld-validate
|
||||
|
||||
Validate map pointers and decompression:
|
||||
|
||||
```bash
|
||||
z3ed overworld-validate --rom=file.sfc # Check maps 0x00-0x9F
|
||||
z3ed overworld-validate --rom=file.sfc --include-tail # Include 0xA0-0xBF
|
||||
z3ed overworld-validate --rom=file.sfc --check-tile16 # Check tile16 region
|
||||
```
|
||||
|
||||
### rom-compare
|
||||
|
||||
Compare two ROMs:
|
||||
|
||||
```bash
|
||||
z3ed rom-compare --rom=target.sfc --baseline=vanilla.sfc --verbose --show-diff
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Detection
|
||||
|
||||
yaze detects expanded pointer tables by checking for the marker byte:
|
||||
|
||||
```cpp
|
||||
// In src/zelda3/overworld/overworld.h
|
||||
bool HasExpandedPointerTables() const {
|
||||
return rom_->data()[0x1423FF] == 0xEA;
|
||||
}
|
||||
```
|
||||
|
||||
The loading code checks BOTH conditions before allowing tail map access:
|
||||
|
||||
```cpp
|
||||
const bool allow_special_tail =
|
||||
core::FeatureFlags::get().overworld.kEnableSpecialWorldExpansion &&
|
||||
HasExpandedPointerTables();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Source Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `assets/patches/Overworld/TailMapExpansion.asm` | ASM patch file |
|
||||
| `src/zelda3/overworld/overworld.h` | `HasExpandedPointerTables()` method |
|
||||
| `src/zelda3/overworld/overworld.cc` | Tail map guards |
|
||||
| `src/cli/handlers/tools/overworld_doctor_commands.cc` | CLI apply logic |
|
||||
| `src/cli/handlers/tools/overworld_validate_commands.cc` | Validator command |
|
||||
| `src/cli/handlers/tools/rom_compare_commands.cc` | ROM comparison |
|
||||
| `src/cli/handlers/tools/diagnostic_types.h` | Constants |
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# 1. Check ROM baseline
|
||||
z3ed rom-doctor --rom vanilla.sfc --format json
|
||||
|
||||
# 2. Apply tail expansion patch
|
||||
z3ed overworld-doctor --rom vanilla.sfc --apply-tail-expansion --output expanded.sfc
|
||||
|
||||
# 3. Verify expansion marker
|
||||
z3ed rom-doctor --rom expanded.sfc --format json | jq '.expanded_pointer_tables'
|
||||
|
||||
# 4. Run integration tests
|
||||
z3ed test-run --label rom_dependent --format json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Known Issues / History
|
||||
|
||||
### Previous Errors (FIXED)
|
||||
|
||||
The original padding attempted to use addresses inside the expanded tile16 region:
|
||||
- ~~0x1E878B, 0x1E95A3, 0x1ED6F3, 0x1EF540~~
|
||||
|
||||
These caused tile corruption. The `overworld-doctor` CLI tool can detect and repair this corruption.
|
||||
|
||||
### Remaining Tasks
|
||||
|
||||
1. Integration testing with fully patched ROM
|
||||
2. GUI indicator in Overworld Editor showing tail map availability
|
||||
3. Unit tests for marker detection and guard logic
|
||||
Reference in New Issue
Block a user