473 lines
14 KiB
Markdown
473 lines
14 KiB
Markdown
# Oracle of Secrets: System Architecture
|
|
|
|
**Purpose**: Document how major systems interact to help AI agents understand the codebase structure.
|
|
|
|
---
|
|
|
|
## 1. High-Level Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Oracle_main.asm │
|
|
│ (Master include file - controls ROM layout and build order) │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
│
|
|
┌─────────────────────────┼─────────────────────────┐
|
|
▼ ▼ ▼
|
|
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
|
│ Core/ │ │ Sprites/ │ │ Overworld/ │
|
|
│ - link.asm │ │ - all_sprites│ │ - ZSCustomOW │
|
|
│ - sram.asm │ │ - Bosses/ │ │ - time_system│
|
|
│ - symbols.asm│ │ - NPCs/ │ │ - overlays │
|
|
│ - patches.asm│ │ - Enemies/ │ │ - lost_woods │
|
|
│ - message.asm│ │ - Objects/ │ └───────────────┘
|
|
└───────────────┘ └───────────────┘
|
|
│ │
|
|
▼ ▼
|
|
┌───────────────┐ ┌───────────────┐
|
|
│ Items/ │ │ Menu/ │
|
|
│ - all_items │ │ - menu.asm │
|
|
│ - ocarina │ │ - menu_select│
|
|
│ - magic_bag │ │ - menu_journal│
|
|
└───────────────┘ └───────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Namespace Organization
|
|
|
|
### 2.1 Oracle Namespace
|
|
|
|
All custom Oracle of Secrets code lives inside the `Oracle` namespace:
|
|
|
|
```asm
|
|
namespace Oracle
|
|
{
|
|
; Core systems
|
|
incsrc "Core/link.asm"
|
|
incsrc "Core/sram.asm"
|
|
incsrc "Core/symbols.asm"
|
|
|
|
; Content
|
|
incsrc "Music/all_music.asm"
|
|
incsrc "Sprites/all_sprites.asm"
|
|
incsrc "Items/all_items.asm"
|
|
|
|
; Patches go last
|
|
incsrc "Core/patches.asm"
|
|
}
|
|
namespace off
|
|
|
|
; ZScream code is OUTSIDE the namespace
|
|
incsrc "Overworld/ZSCustomOverworld.asm"
|
|
```
|
|
|
|
### 2.2 Why This Matters
|
|
|
|
- Labels inside `namespace Oracle` become `Oracle.LabelName`
|
|
- ZScream uses its own conventions and must be outside
|
|
- Patches at end to ensure all labels are defined
|
|
|
|
---
|
|
|
|
## 3. Memory Map Overview
|
|
|
|
### 3.1 Bank Organization
|
|
|
|
| Bank Range | Purpose | Notes |
|
|
|------------|---------|-------|
|
|
| $00-$1F | Vanilla ALTTP + small patches | Limited free space |
|
|
| $20-$29 | ZScream Overworld Data | ~1.5MB reserved |
|
|
| $30 | Sprite prep/initialization | Oracle sprites start here |
|
|
| $31 | Main sprite logic | Enemy/NPC behavior |
|
|
| $32 | Boss logic | Complex sprite code |
|
|
| $33-$3F | Free space | Available for expansion |
|
|
|
|
### 3.2 RAM Regions
|
|
|
|
| Region | Purpose |
|
|
|--------|---------|
|
|
| $7E0000-$7E1FFF | Scratch RAM (volatile) |
|
|
| $7E2000-$7EFFFF | Game state RAM |
|
|
| $7EE000-$7EE0FF | TimeState struct |
|
|
| $7EF000-$7EFFFF | SRAM (saved data) |
|
|
| $7EF3C5-$7EF3D6 | Oracle progression flags |
|
|
| $7EF410 | Dreams bitfield |
|
|
|
|
### 3.3 Key SRAM Variables
|
|
|
|
```asm
|
|
; GameState ($7EF3C5) - Overall progression
|
|
; 0x00 = Very start
|
|
; 0x01 = Uncle reached
|
|
; 0x02 = Zelda rescued / Farore intro
|
|
; 0x03 = Agahnim defeated
|
|
|
|
; OOSPROG ($7EF3D6) - Oracle progression bitfield
|
|
; .fmp h.i.
|
|
; i = Intro complete, Maku Tree met
|
|
; h = Hall of Secrets visited
|
|
; p = Pendant quest progress
|
|
; m = Master Sword acquired
|
|
; f = Fortress of Secrets
|
|
|
|
; OOSPROG2 ($7EF3C6) - Secondary progression
|
|
; .fbh .zsu
|
|
; u = Uncle visited
|
|
; s = Priest visited in sanctuary
|
|
; z = Zelda brought to sanctuary
|
|
; h = Uncle left house
|
|
; b = Book of Mudora obtained
|
|
; f = Fortune teller flag
|
|
|
|
; Dreams ($7EF410) - Dream sequence tracking
|
|
; .dts fwpb
|
|
; (Individual dream completion flags)
|
|
```
|
|
|
|
---
|
|
|
|
## 4. System Interactions
|
|
|
|
### 4.1 ZScream Custom Overworld (ZSOW) Integration
|
|
|
|
ZSOW manages:
|
|
- Overworld map transitions
|
|
- Palette events
|
|
- Overlay data
|
|
- Custom collision
|
|
|
|
**Hook Points**:
|
|
```
|
|
OverworldHandleTransitions ($028000 area)
|
|
└── Oracle_CheckIfNight (time-based sprite loading)
|
|
└── LostWoods_PuzzleHandler (navigation puzzle)
|
|
└── SongOfStorms overlay effects
|
|
```
|
|
|
|
**Known Conflicts**:
|
|
- Lost Woods puzzle directly modifies transition logic
|
|
- Day/Night sprites must check `Oracle_CheckIfNight`
|
|
- Song of Storms overlays need coordination with ZSOW
|
|
|
|
### 4.2 Time System
|
|
|
|
**File**: `Overworld/time_system.asm`
|
|
|
|
**Structure**:
|
|
```asm
|
|
struct TimeState $7EE000
|
|
{
|
|
.Hours, .Minutes, .Speed
|
|
.BlueVal, .GreenVal, .RedVal
|
|
.TempColor, .SubColor
|
|
}
|
|
```
|
|
|
|
**Flow**:
|
|
```
|
|
RunClock (called each frame)
|
|
├── TimeSystem_CheckCanRun
|
|
│ └── Check game mode, indoors status
|
|
├── TimeSystem_IncrementTime
|
|
│ └── Update Hours/Minutes based on Speed
|
|
└── TimeSystem_UpdatePalettes
|
|
└── Apply color tinting based on time
|
|
```
|
|
|
|
**Integration Points**:
|
|
- `Oracle_CheckIfNight` - Called by ZSOW for sprite loading
|
|
- Palette system - Affects overworld colors
|
|
- NPC behavior - Some NPCs react to time
|
|
|
|
### 4.3 Sprite System
|
|
|
|
**Entry Points** (standard pattern):
|
|
|
|
```
|
|
Sprite_*_Long (JSL entry from sprite table)
|
|
├── PHB : PHK : PLB (set data bank)
|
|
├── Sprite_*_Draw (JSR - render)
|
|
├── Sprite_CheckActive (JSL - is active?)
|
|
│ └── Sprite_*_Main (JSR - if active)
|
|
├── PLB
|
|
└── RTL
|
|
```
|
|
|
|
**State Machine**:
|
|
```
|
|
SprAction (per-sprite state variable)
|
|
└── JumpTableLocal dispatches to state handlers
|
|
├── State_Idle
|
|
├── State_Chase
|
|
├── State_Attack
|
|
└── State_Retreat
|
|
```
|
|
|
|
**Key Variables** (indexed by X):
|
|
| Address | Name | Purpose |
|
|
|---------|------|---------|
|
|
| $0D00 | SprY | Y position (low byte) |
|
|
| $0D10 | SprX | X position (low byte) |
|
|
| $0D80 | SprAction | Current state |
|
|
| $0DA0 | SprHealth | Hit points remaining |
|
|
| $0E40 | SprNbrOAM | OAM slot count |
|
|
|
|
### 4.4 Menu System
|
|
|
|
**File**: `Menu/menu.asm`
|
|
|
|
**State Machine**:
|
|
```
|
|
MenuMode ($0200) - Current menu state
|
|
├── $00 = Not in menu
|
|
├── $01 = Opening animation
|
|
├── $02 = Item select
|
|
├── $0C = Magic Bag submenu
|
|
├── $0D = Ring Box submenu
|
|
└── $0E = Song select submenu
|
|
```
|
|
|
|
**Flow**:
|
|
```
|
|
Menu_Entry (from pause input)
|
|
├── Menu_InitGraphics
|
|
├── Menu_Upload* (VRAM transfers)
|
|
└── Menu_MainLoop
|
|
├── Handle input
|
|
├── Update selection
|
|
└── Menu_Draw*
|
|
```
|
|
|
|
### 4.5 Dialogue System
|
|
|
|
**Files**: `Core/message.asm`, `Core/messages.org`
|
|
|
|
**Message Format** (in messages.org):
|
|
```
|
|
** 20 - Maku Tree Part1
|
|
[W:02][S:03]Ah, [L]!
|
|
[2]Thank the Goddesses you are
|
|
[3]alright. I feared the worst.
|
|
[V]A dark shadow has befallen us.[K]
|
|
```
|
|
|
|
**Control Codes**:
|
|
| Code | Meaning |
|
|
|------|---------|
|
|
| `[2]`, `[3]` | Line 2, Line 3 |
|
|
| `[K]` | Wait for button press |
|
|
| `[V]` | Continue on same line |
|
|
| `[W:XX]` | Wait time |
|
|
| `[S:XX]` | Text speed |
|
|
| `[SFX:XX]` | Play sound effect |
|
|
| `[CH2I]` | 2-choice prompt |
|
|
| `[CH3]` | 3-choice prompt |
|
|
| `[L]` | Player name |
|
|
|
|
**Display Macros**:
|
|
```asm
|
|
%ShowUnconditionalMessage($20) ; Force display
|
|
%ShowSolicitedMessage($20) ; On interaction only
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Hook Architecture
|
|
|
|
### 5.1 Hook Types
|
|
|
|
**Type 1: Inline Patch** (replace vanilla code)
|
|
```asm
|
|
pushpc
|
|
org $02XXXX ; Vanilla address
|
|
JSL MyHook ; Replace original instruction
|
|
NOP : NOP ; Pad to match original size
|
|
pullpc
|
|
```
|
|
|
|
**Type 2: Table Override** (jump table entry)
|
|
```asm
|
|
pushpc
|
|
org $07F000+($ID*2) ; Jump table for sprite $ID
|
|
dw Sprite_Custom_Prep
|
|
pullpc
|
|
```
|
|
|
|
**Type 3: Extended Logic** (call original + extend)
|
|
```asm
|
|
MyHook:
|
|
{
|
|
JSL OriginalRoutine ; Preserve original behavior
|
|
; Add custom logic
|
|
LDA.w CustomFlag
|
|
BEQ .skip
|
|
JSL CustomHandler
|
|
.skip
|
|
RTL
|
|
}
|
|
```
|
|
|
|
### 5.2 Hook Documentation Pattern
|
|
|
|
Every hook should document:
|
|
|
|
```asm
|
|
; =========================================================
|
|
; Hook: $XXBANK:ADDR
|
|
; Purpose: [What this hook adds/changes]
|
|
; Vanilla Code: [What original code did]
|
|
; Clobbered: [Registers modified]
|
|
; Dependencies: [Other systems affected]
|
|
; =========================================================
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Build System
|
|
|
|
### 6.1 Build Order (Critical)
|
|
|
|
```
|
|
1. Core/symbols.asm - Memory declarations
|
|
2. Core/sram.asm - SRAM layout
|
|
3. Core/link.asm - Player modifications
|
|
4. Music/all_music.asm - SPC700 data
|
|
5. Sprites/all_sprites.asm - All sprite code
|
|
6. Items/all_items.asm - Item handlers
|
|
7. Menu/menu.asm - Menu system
|
|
8. Dungeons/ - Dungeon-specific code
|
|
9. Core/patches.asm - Vanilla patches (LAST)
|
|
10. Overworld/ZSCustomOverworld.asm - ZSOW (OUTSIDE namespace)
|
|
```
|
|
|
|
### 6.2 Build Commands
|
|
|
|
```bash
|
|
# Fast build
|
|
./run.sh
|
|
|
|
# MCP tools
|
|
mcp__book-of-mudora__run_build() # Build ROM
|
|
mcp__book-of-mudora__lint_asm() # Check style
|
|
mcp__book-of-mudora__analyze_patches() # Review patches
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Debugging Workflow
|
|
|
|
### 7.1 Common Debug Points
|
|
|
|
| Symptom | Check First |
|
|
|---------|-------------|
|
|
| Crash on room enter | Sprite prep routine, invalid JSL target |
|
|
| Wrong graphics | SprGfx assignment, DMA timing |
|
|
| Frozen game | Infinite loop in Main, missing RTS/RTL |
|
|
| Black screen | Palette loading, HDMA setup |
|
|
| Corrupt saves | SRAM address conflict, missing bank setup |
|
|
|
|
### 7.2 Debug Tools
|
|
|
|
**Yaze MCP** (in-development):
|
|
```python
|
|
mcp__yaze_mcp__read_memory("7E0010", 2) # Read RAM
|
|
mcp__yaze_mcp__add_breakpoint("02XXXX") # Set breakpoint
|
|
mcp__yaze_mcp__get_game_state() # Dump current state
|
|
```
|
|
|
|
**Hyrule Historian**:
|
|
```python
|
|
mcp__hyrule-historian__lookup_address("02XXXX")
|
|
mcp__hyrule-historian__search_oracle_code("Sprite_Booki")
|
|
mcp__hyrule-historian__get_ram_info("SprAction")
|
|
```
|
|
|
|
### 7.3 Logging
|
|
|
|
```asm
|
|
; Build-time logging
|
|
%log_section("Sprites", !LOG_SPRITES)
|
|
|
|
; Enable in build:
|
|
!LOG_SPRITES = 1 ; Set in config
|
|
|
|
; Output appears in build log
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Common Integration Patterns
|
|
|
|
### 8.1 Adding a New Sprite
|
|
|
|
1. Create file: `Sprites/Enemies/my_sprite.asm`
|
|
2. Define properties using standard order
|
|
3. Implement `_Long`, `_Prep`, `_Main`, `_Draw`
|
|
4. Add include to `Sprites/all_sprites.asm`
|
|
5. Add to sprite table with `org` directive
|
|
6. Build and test
|
|
|
|
### 8.2 Adding a Quest Flag
|
|
|
|
1. Find free bit in OOSPROG/OOSPROG2
|
|
2. Document in `Core/sram.asm`
|
|
3. Update this file's SRAM section
|
|
4. Use in code:
|
|
```asm
|
|
LDA.l OOSPROG : ORA.b #$XX : STA.l OOSPROG
|
|
```
|
|
|
|
### 8.3 Adding a New Hook
|
|
|
|
1. Find vanilla address with Hyrule Historian
|
|
2. Document what original code does
|
|
3. Create hook with `pushpc`/`pullpc`
|
|
4. Add `assert` to verify space
|
|
5. Test vanilla behavior still works
|
|
|
|
---
|
|
|
|
## 9. System Dependency Graph
|
|
|
|
```
|
|
┌─────────────┐
|
|
│ TimeSystem │
|
|
└──────┬──────┘
|
|
│ Oracle_CheckIfNight
|
|
▼
|
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
│ Lost Woods │────▶│ ZSOW │◀────│ Overlays │
|
|
│ Puzzle │ │ Transitions │ │ System │
|
|
└─────────────┘ └──────┬──────┘ └─────────────┘
|
|
│
|
|
┌────────────┴────────────┐
|
|
▼ ▼
|
|
┌─────────────┐ ┌─────────────┐
|
|
│ Sprites │ │ Events │
|
|
│ (Loading) │ │ (Triggers) │
|
|
└──────┬──────┘ └──────┬──────┘
|
|
│ │
|
|
└───────────┬─────────────┘
|
|
▼
|
|
┌─────────────┐
|
|
│ Player │
|
|
│ (Link) │
|
|
└─────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 10. AI Agent Checklist
|
|
|
|
When working on Oracle of Secrets:
|
|
|
|
1. [ ] Check `oracle.org` for related tasks
|
|
2. [ ] Read existing code in affected files
|
|
3. [ ] Verify memory map for conflicts
|
|
4. [ ] Use Hyrule Historian for vanilla lookups
|
|
5. [ ] Follow StyleGuide.md conventions
|
|
6. [ ] Run build after changes
|
|
7. [ ] Document any new hooks
|
|
8. [ ] Update this file if adding new systems
|