Update documentation: restructure and expand guides for Dungeons, Items, Masks, Menu, and Music systems

This commit is contained in:
scawful
2025-10-01 23:21:57 -04:00
parent eeeb9ffeb4
commit 15784d397e
6 changed files with 544 additions and 1 deletions

View File

@@ -114,7 +114,7 @@ For a more detailed breakdown of the ROM map, refer to the `ZS ROM MAP.txt` file
--- ---
## 7. Completed Documentation ## 7. Documentation
The following documents have been generated by analyzing the codebase and project files. They serve as key references for understanding the project's architecture and gameplay systems. The following documents have been generated by analyzing the codebase and project files. They serve as key references for understanding the project's architecture and gameplay systems.
@@ -124,3 +124,12 @@ The following documents have been generated by analyzing the codebase and projec
* **`Docs/SpriteCreationGuide.md`:** A step-by-step tutorial for creating a new custom sprite using the project's frameworks and conventions. See [SpriteCreationGuide.md](SpriteCreationGuide.md) for details. * **`Docs/SpriteCreationGuide.md`:** A step-by-step tutorial for creating a new custom sprite using the project's frameworks and conventions. See [SpriteCreationGuide.md](SpriteCreationGuide.md) for details.
* **`Docs/Menu.md`:** A detailed analysis of the custom menu and HUD systems. See [Menu.md](Menu.md) for details.
* **`Docs/Items.md`:** A detailed guide to the custom and modified items in the game. See [Items.md](Items.md) for details.
* **`Docs/Music.md`:** A guide to the custom music tracks and sound effects, including how to add new audio. See [Music.md](Music.md) for details.
* **`Docs/Masks.md`:** A comprehensive overview of the Mask System, including each mask's abilities and implementation details. See [Masks.md](Masks.md) for details.
* **`Docs/Dungeons.md`:** A breakdown of all dungeons, including layouts, enemy placements, and puzzle solutions. See [Dungeons.md](Dungeons.md) for details.

91
Docs/Dungeons.md Normal file
View File

@@ -0,0 +1,91 @@
# Dungeons & Indoor Areas
This document details the various systems and enhancements for dungeons and other indoor areas found within the `Dungeons/` directory. These systems provide a framework for creating unique puzzles, mechanics, and environmental behaviors that go far beyond the vanilla game's capabilities.
## 1. Overview
The code in this directory can be broadly categorized into three main areas:
1. **Custom Room Tags:** New, scriptable room behaviors that can be assigned to any room to create special events or puzzles.
2. **Enhanced Mechanics & Objects:** Modifications or additions to existing dungeon elements like spikes, doors, and enemy stats.
3. **Advanced Collision & Object Rendering:** A powerful, layered system for defining tile collision and drawing complex, multi-tile objects.
## 2. Custom Room Tags
Room "tags" are a vanilla mechanic that allows a room to have special properties (e.g., a kill room, a room with shutter doors). This project expands on this by hooking into the tag processing routines to add new, custom behaviors.
### Floor Puzzle (`floor_puzzle.asm`)
- **Hook:** Replaces Tag `0x00` (`holes_0`).
- **Functionality:** Implements a "light all the tiles" puzzle. When Link steps on a special "off" tile (`$0DED`), it transforms into an "on" tile (`$0DEE`) and plays a sound. The system then checks if any "off" tiles remain.
- If all tiles are on, it opens the room's shutter doors (`$0468`) and plays the secret sound.
- If the player steps on a tile that is already "on", it can trigger a kill room effect (`STZ.b $AE`).
### Crumble Floor (`crumblefloor_tag.asm`)
- **Hook:** Replaces Tag `0x03` (`holes_3`).
- **Functionality:** Creates floors that crumble away after being walked on.
- It tracks the tile Link is currently standing on.
- If he steps on a specific "crumble" tile (`$0C62` or `$0C63`), the code replaces it with a cracked tile and then a pit tile, spawning a falling tile visual effect (`Garnish 03`).
- This is designed for creating temporary paths or "don't stop running" challenges.
### Positional Warp (`together_warp_tag.asm`)
- **Hook:** Replaces Tag `0x08` (`Holes8`).
- **Functionality:** Changes the room's warp destination based on the player's position. It divides the room into four quadrants and sets the target room index based on which quadrant the player is in when they trigger a warp (e.g., by falling in a pit). This allows a single room to lead to four different destinations.
### Minish Shutter Door (`custom_tag.asm`)
- **Hook:** Replaces Tag `0x05` (`Holes5`).
- **Functionality:** Creates a shutter door that only opens if the player is in Minish Form (`!CurrentMask == 0x05`). If the condition is met, it opens the door and plays the corresponding sound effect.
### Intro Cutscene (`custom_tag.asm`)
- **Hook:** Replaces Tag `0x39` (`Holes7`).
- **Functionality:** This tag is repurposed to control the game's opening cutscene in Link's house. It's a state machine that handles:
1. Displaying the initial telepathic message from Farore.
2. Gradually lighting up the screen.
3. Waking Link from his bed and giving control to the player.
4. Setting the `GameState` flags to permanently prevent the "Uncle" sprite from appearing in the house again.
## 3. Dungeon Mechanics & Objects
### Key Blocks (`keyblock.asm`)
- **Functionality:** Replaces the vanilla "prison door" object with a lock block that requires a small key.
- **Implementation:** It hooks the object's interaction routine (`$01EB8C`). Before running the vanilla code to open the door, it checks the player's small key count (`$7EF36F`). If the player has one or more keys, it decrements the count and opens the block. If not, the block remains solid.
### Spike Block Subtypes (`spike_subtype.asm`)
- **Functionality:** Expands the vanilla spike block (trap) to allow for different speeds and directions.
- **Implementation:** It hooks the sprite preparation routine for the spike block (`$0691D7`). It reads the sprite's subtype value and uses it as an index into two tables, `speedValuesH` and `speedValuesV`, to set its horizontal and vertical speed. This allows for placing spikes that move vertically or at various speeds, configured directly in the sprite editor.
## 4. Advanced Collision System
The project features a powerful, three-tiered system for handling tile collision, offering immense flexibility.
### Layer 1: Global Collision Patches (`GlobalCollisionTables.asm`)
- **Purpose:** To make baseline changes to the game's default tile behaviors.
- **Implementation:** This file contains a series of `org` patches that directly overwrite data in the vanilla global tile property tables located in ROM bank `$0E`. These tables define the default physical properties of every 16x16 tile in the game (e.g., solid, water, pit, stairs).
### Layer 2: Tileset-Specific Collision (`CollisionTablesExpanded.asm`)
- **Purpose:** To allow the same tile graphic to have different behaviors in different dungeons (e.g., a normal floor tile that becomes slippery in an ice dungeon).
- **Implementation:** It hooks the dungeon tile attribute loading routine (`$0E942A`). The new routine, `Dungeon_LoadCustomTileAttr`, checks the current dungeon's tileset ID (`$0AA2`) and loads an entire set of custom tile properties from a group of tables. This allows, for example, "Glacia Estate" (`group0B`) to have unique ice physics while "Goron Mines" (`group04`) has its own set of properties for minecart tracks.
### Layer 3: Per-Room Custom Collision (`custom_collision.asm`)
- **Purpose:** To provide the highest level of granularity by defining collision on a room-by-room basis, overriding all other rules.
- **Implementation:** The `CustomRoomCollision` routine hooks the room loading process (`$01B95B`). It uses the current room ID (`$A0`) to look up a pointer in a table at `$258090`. If a pointer exists for the current room, it reads a block of custom collision data and writes it directly to the active collision map in WRAM (`$7E2000+`). This is used for creating unique and complex room layouts that would be impossible with the standard grid-based tile system.
## 5. Custom Object Handler (`Dungeons/Objects/object_handler.asm`)
- **Purpose:** To render complex, multi-tile dungeon objects that are not sprites and cannot be created with the vanilla object system.
- **Implementation:** This system hooks the vanilla object drawing routine for several reserved object IDs (e.g., `$31`, `$32`, `$54`). When the game attempts to draw one of these objects, the custom handler (`CustomObjectHandler`) is called instead.
- **Data-Driven:** The handler reads the object's properties and looks up its corresponding graphical data from a series of `.bin` files included from the `Dungeons/Objects/Data/` directory. It then manually draws the object tile by tile. This is used to render things like minecart tracks, custom boss parts (`KydreeokBody`), and detailed scenery like the `IceFurnace`.
## 6. Miscellaneous Patches
- **`enemy_damage.asm`:** Contains `org` patches that directly modify enemy property tables to change their bump damage values.
- **`house_walls.asm`:** Contains `org` patches that modify tilemap data for house walls, likely for cosmetic changes.
- **`attract_scenes.asm`:** Modifies the game's "attract mode" (the gameplay demos on the title screen) to create custom scenes that take place in dungeon environments.

84
Docs/Items.md Normal file
View File

@@ -0,0 +1,84 @@
# Custom Items System
This document details the functionality of new and modified items in Oracle of Secrets, based on analysis of the `Items/` directory.
## 1. Overview
The item roster has been significantly expanded with new mechanics, and many vanilla items have been reworked to provide new functionality. The system is managed through a combination of hooks into the main player state machine and custom routines for each item.
## 2. Vanilla Item Modifications
Several items from the original game have been altered.
### Hookshot / Goldstar
- **Files:** `goldstar.asm`
- **Functionality:** The Hookshot can be upgraded to the **Goldstar**, a powerful morning star weapon. The two items share an inventory slot.
- **Switching:** When the Goldstar is obtained, the player can switch between the Hookshot and Goldstar by pressing the L/R shoulder buttons while it is selected in the menu. The current mode is tracked by the `GoldstarOrHookshot` WRAM variable.
- **Goldstar Mechanics:** When active, the item functions as a short-range, powerful melee weapon with its own collision and damage properties, distinct from the Hookshot's grappling mechanic.
### Ice Rod
- **File:** `ice_rod.asm`
- **Functionality:** The Ice Rod's projectile now freezes water tiles it hits, creating temporary 16x16 ice platforms. This allows the player to cross water gaps.
- **Implementation:** The `LinkItem_IceRod` routine hooks into the ancilla tile collision logic. When the projectile hits a water tile, it dynamically modifies the tilemap properties in RAM and DMAs new ice graphics to VRAM.
### Bug-Catching Net -> Roc's Feather
- **File:** `jump_feather.asm`
- **Functionality:** The vanilla Bug-Catching Net has been completely replaced by **Roc's Feather**. This item allows Link to perform a short hop.
- **Implementation:** `LinkItem_JumpFeather` initiates the jump by setting Link's state to a recoil/ledge hop state and applying a burst of vertical velocity.
### Bottles
- **File:** `bottle_net.asm`
- **Functionality:** The Bug-Catching Net is no longer required to catch bees, fairies, etc. The Bottle item now has a dual function:
1. If the bottle is **empty**, using it initiates the `LinkItem_CatchBottle` routine, which performs a net-catching swing.
2. If the bottle is **full**, using it calls `LinkItem_Bottles`, which consumes the contents (e.g., drinks a potion, releases a fairy).
### Book of Mudora -> Book of Secrets
- **File:** `book_of_secrets.asm`
- **Functionality:** The Book of Mudora is now the **Book of Secrets**. While its vanilla function of translating Hylian text remains, it has a new secret-revealing capability.
- **Implementation:** The `Dungeon_RevealSecrets` routine checks if the L button is held while inside a building. If it is, it disables the `BG2` layer, which can be used to hide secret passages or objects behind walls that are part of that background layer.
## 3. New Active Items
### Ocarina
- **File:** `ocarina.asm`
- **Functionality:** A multi-song instrument. When selected, the player can cycle through learned songs using the L/R shoulder buttons. Pressing 'Y' plays the selected song, triggering its unique effect.
- **Songs & Effects:**
- **Song of Healing:** Heals certain NPCs or triggers quest events.
- **Song of Storms:** Toggles a rain overlay on the overworld, which can affect the environment (e.g., watering the Magic Bean).
- **Song of Soaring:** Warps the player to pre-defined locations (the vanilla flute's bird travel).
- **Song of Time:** Toggles the in-game time between day and night.
### Shared Slot: Portal Rod & Fishing Rod
- **Files:** `portal_rod.asm`, `fishing_rod.asm`
- **Functionality:** These two distinct items share a single inventory slot. If the player has the upgrade (`$7EF351 >= 2`), they can swap between the two by pressing L/R in the menu.
- **Portal Rod:** Fires a projectile that creates a portal sprite (blue or orange). The `Ancilla_HandlePortalCollision` logic detects when another projectile (like an arrow) hits a portal and teleports it to the other portal's location.
- **Fishing Rod:** Initiates a fishing minigame. `LinkItem_FishingRod` spawns a "floater" sprite, and the player can reel it in to catch fish or other items from a prize table.
## 4. New Passive Items
### Magic Rings
- **File:** `magic_rings.asm`
- **Functionality:** Passive items that grant buffs when equipped in one of the three ring slots in the Quest Status menu. The effects are applied by hooking into various game logic routines.
- **Implemented Rings:**
- **Power Ring:** Increases sword damage.
- **Armor Ring:** Reduces damage taken by half.
- **Heart Ring:** Slowly regenerates health over time.
- **Light Ring:** Allows the sword to shoot beams even when Link is not at full health (down to -2 hearts from max).
- **Blast Ring:** Increases the damage of bombs.
- **Steadfast Ring:** Prevents or reduces knockback from enemy hits.
## 5. Consumable Items (Magic Bag)
- **File:** `all_items.asm`
- **Functionality:** The Magic Bag is a sub-menu that holds new consumable items. The `Link_ConsumeMagicBagItem` routine is a jump table that executes the effect for the selected item.
- **Consumables:**
- **Banana:** Implemented. Restores a small amount of health (`#$10`).
- **Pineapple, Rock Meat, Seashells, Honeycombs, Deku Sticks:** Placeholder entries exist in the jump table, but their effects are not yet implemented (the routines just contain `RTS`).

145
Docs/Masks.md Normal file
View File

@@ -0,0 +1,145 @@
# Mask System
This document provides a detailed analysis of the Mask System in Oracle of Secrets, based on the code in the `Masks/` directory. The system allows Link to transform into various forms, each with unique graphics, palettes, and abilities.
## 1. System Architecture
The Mask System is built around a central WRAM variable and a set of core routines that handle transformations, graphics, and palettes.
- **`!CurrentMask` (`$02B2`):** A WRAM variable that stores the ID of the currently active mask. A value of `0x00` represents Link's normal human form.
- **`!LinkGraphics` (`$BC`):** A WRAM variable that holds the bank number for Link's current graphics sheet. The Mask System changes this value to load the appropriate sprite graphics for each form.
### Mask IDs
| ID | Mask / Form |
|------|---------------|
| `00` | Human (Default) |
| `01` | Deku Mask |
| `02` | Zora Mask |
| `03` | Wolf Mask |
| `04` | Bunny Hood |
| `05` | Minish Form |
| `06` | GBC Form |
| `07` | Moosh Form |
## 2. Core Routines & Hooks (`Masks/mask_routines.asm`)
A set of shared routines and hooks form the backbone of the system.
- **`Link_TransformMask`:** This is the primary function for changing forms. It is typically called when the player uses a mask item.
- **Trigger:** It requires a new R-button press (`CheckNewRButtonPress`) to prevent rapid toggling.
- **Logic:** It takes a mask ID in the A register. If the requested mask is already active, it reverts Link to his human form. Otherwise, it sets `!CurrentMask`, updates the graphics bank in `$BC` from a lookup table, and calls `Palette_ArmorAndGloves` to apply the new look.
- **Effect:** It spawns a "poof" of smoke (`AddTransformationCloud`) and plays a sound effect.
- **`Palette_ArmorAndGloves` (Hook):** This routine hooks the vanilla palette loading function (`$1BEDF9`). It checks `!CurrentMask` and jumps to the appropriate `Update...Palette` routine for the active form, ensuring the correct colors are loaded. If no mask is active, it proceeds with the vanilla logic for loading Link's tunic color.
- **`LinkItem_CheckForSwordSwing_Masks` (Hook):** This routine hooks the vanilla sword swing check (`$079CD9`). It prevents certain forms (Deku, Wolf, Minish, Moosh) from using the sword, while allowing others (Zora, GBC Link) to use it freely.
- **Reset Routines:**
- `ResetToLinkGraphics`: Reverts Link to his default graphics and `!CurrentMask = 0`.
- `ForceResetMask_GameOver` / `ForceResetMask_SaveAndQuit`: Hooks into the game over and save/quit routines to ensure Link's form is reset before the game saves or restarts.
## 3. Transformation Masks
These masks grant Link new forms with significant new abilities.
### Deku Mask
- **File:** `Masks/deku_mask.asm`
- **Transformation:** Replaces the Quake Medallion. Pressing 'Y' with the item selected transforms Link.
- **Abilities:**
- **Spin Attack:** Pressing 'Y' performs a spinning attack.
- **Deku Bubble:** If not on a Deku Flower, the spin attack also shoots a bubble projectile (`Ancilla0E_MagicBubble`).
- **Hover:** If standing on a Deku Flower (tile property check sets WRAM `$71`), the spin attack launches Link into the air, allowing him to hover for a short time.
- **Bomb Drop:** While hovering, pressing 'Y' drops a bomb.
- **Cancel Hover:** Pressing 'B' or letting the timer expire cancels the hover.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x01`
- `DekuFloating` (`$70`): Flag set when Link is hovering.
- `DekuHover` (`$71`): Flag set when Link is standing on a Deku Flower, enabling the hover ability.
- **Code Interactions:**
- Hooks `LinkItem_Quake` (`$07A64B`).
- Repurposes Link's "Using Quake Medallion" state (`$5D = 0x0A`) for the hover ability.
- Hooks `LinkOAM_DrawShield` (`$0DA780`) to prevent the shield from being drawn.
### Zora Mask
- **File:** `Masks/zora_mask.asm`
- **Transformation:** Replaces the Bombos Medallion. Pressing 'Y' with the item selected transforms Link.
- **Abilities:**
- **Diving:** Allows Link to dive in deep water by pressing 'Y'. Pressing 'Y' again resurfaces.
- **Overworld Diving:** When diving in the overworld, Link becomes invincible, moves faster, and is hidden beneath a ripple effect.
- **Dungeon Diving:** When diving in a dungeon, Link moves to the lower layer (`$EE=0`), allowing him to swim under floors and obstacles.
- **Sword:** The Zora form can use the sword.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x02`
- `!ZoraDiving` (`$0AAB`): Flag set when Link is currently underwater.
- **Code Interactions:**
- Hooks `LinkItem_Bombos` (`$07A569`).
- Hooks the end of `LinkState_Swimming` (`$079781`) to handle the dive input.
- Hooks the end of `LinkState_Default` (`$0782D2`) to handle resurfacing in dungeons.
- Hooks `Link_HopInOrOutOfWater_Vertical` (`$07C307`) to reset the dive state when using water stairs.
### Wolf Mask
- **File:** `Masks/wolf_mask.asm`
- **Transformation:** Shares an item slot with the Flute. When selected, it replaces the Shovel. Pressing 'Y' transforms Link.
- **Abilities:**
- **Dig:** When transformed, pressing 'Y' executes the vanilla `LinkItem_Shovel` routine, allowing Wolf Link to dig for items without needing the shovel.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x03`
- **Code Interactions:**
- Hooks the `LinkItem_Shovel` vector (`$07A313`) to a new `LinkItem_ShovelAndFlute` routine that dispatches between the Flute and Wolf Mask logic based on the selected item (`$0202`).
### Minish Form
- **File:** `Masks/minish_form.asm`
- **Transformation:** Context-sensitive. When standing on a special portal tile (`ID 64`), pressing 'R' transforms Link into Minish form. Pressing 'R' on the portal again reverts him.
- **Abilities:**
- **Access Minish Areas:** Allows Link to pass through special small openings (`Tile ID 65`).
- **Restricted Actions:** Cannot lift objects.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x05`
- **Code Interactions:**
- Hooks the overworld (`$07DAF2`) and underworld (`$07D8A0`) tile collision tables to add handlers for the portal and passage tiles.
- Hooks the lift check (`$079C32`) to disable lifting while in Minish form.
### Moosh Form
- **File:** `Masks/moosh.asm`
- **Transformation:** The trigger for transforming into Moosh is not defined within the mask's own file, but is handled by `Link_TransformMoosh`.
- **Abilities:**
- **Hover Dash:** Attempting to use the Pegasus Boots (dash) while in Moosh form will instead trigger a short hover, similar to the Deku Mask's ability.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x07`
- **Code Interactions:**
- Hooks the dash initiation logic (`$079093`) to intercept the dash and call `PrepareQuakeSpell`, which sets Link's state to `0x0A` (hover).
- Shares the hover/recoil animation logic with the Deku Mask.
## 4. Passive & Cosmetic Forms
### Bunny Hood
- **File:** `Masks/bunny_hood.asm`
- **Transformation:** Replaces the Ether Medallion. Pressing 'Y' activates the Bunny Hood state. This is a state change, not a visual transformation.
- **Abilities:**
- **Increased Speed:** While the Bunny Hood is the active mask (`!CurrentMask = 0x04`), Link's movement speed is increased across various actions (walking, carrying, etc.). The specific speed values are defined in `BunnySpeedTable`.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x04`
- **Code Interactions:**
- Hooks `LinkItem_Ether` (`$07A494`) to trigger the state change.
- Hooks the velocity calculation in the player engine (`$07E330`) to load custom speed values from a table.
### GBC Form
- **File:** `Masks/gbc_form.asm`
- **Transformation:** An automatic, cosmetic transformation that occurs whenever Link is in the Dark World.
- **Abilities:**
- Changes Link's graphics to a Game Boy Color-inspired sprite.
- Applies a unique, limited-color palette. The palette correctly reflects Link's current tunic (Green, Blue, or Red).
- This form can still use the sword.
- **Key Flags & Variables:**
- `!CurrentMask`: `0x06`
- `$0FFF`: The vanilla Dark World flag.
- **Code Interactions:**
- Hooks numerous overworld, underworld, and transition routines to consistently apply the effect when in the Dark World and remove it when in the Light World.

77
Docs/Menu.md Normal file
View File

@@ -0,0 +1,77 @@
# Custom Menu & HUD System
This document provides a detailed analysis of the custom menu and Heads-Up Display (HUD) systems in Oracle of Secrets, based on the code in the `Menu/` directory.
## 1. Overview
The project features a completely custom menu and HUD, replacing the vanilla systems. The menu is a robust, multi-screen system, while the HUD provides a clean, modern interface for in-game stats.
- **Menu System**: A two-page design that separates selectable items from quest status and equipment. It is accessible by pressing the Start button.
- **HUD System**: A persistent on-screen display for health, magic, rupees, and the currently equipped item.
## 2. Menu System Architecture
The entire menu operates as a large state machine, with the main entry point being `Menu_Entry` in `Menu/menu.asm`. The flow is controlled by the value in WRAM `$0200`.
### 2.1. Main State Machine
The `Menu_Entry` routine uses a jump table (`.vectors`) to execute different subroutines based on the state in `$0200`. This modular approach allows for a clean separation of tasks like initialization, drawing, input handling, and screen transitions.
**Key States in `$0200`:**
| State ID | Label | Purpose |
|----------|----------------------------|-------------------------------------------------------------------------|
| `0x00` | `Menu_InitGraphics` | Initializes the menu, clears player state, and prepares for drawing. |
| `0x01` | `Menu_UploadRight` | Draws the entire right-hand screen (Quest Status). |
| `0x02` | `Menu_UploadLeft` | Draws the entire left-hand screen (Item Selection). |
| `0x04` | `Menu_ItemScreen` | The main interactive state for the Item screen. Handles cursor movement. |
| `0x05` | `Menu_ScrollTo` | Handles the smooth scrolling animation when moving from Items to Quest. |
| `0x06` | `Menu_StatsScreen` | The main interactive state for the Quest Status screen. |
| `0x0A` | `Menu_Exit` | Exits the menu, restores the game state, and updates the equipped item. |
| `0x0C` | `Menu_MagicBag` | A sub-menu for viewing collectible items. |
| `0x0D` | `Menu_SongMenu` | A sub-menu for selecting Ocarina songs. |
| `0x0E` | `Menu_Journal` | A sub-menu for reading the player's journal. |
| `0x09` | `Menu_RingBox` | A sub-menu for managing magic rings. |
### 2.2. Item Selection Screen (Left Page)
This is the primary interactive screen where the player selects their Y-button item.
- **Drawing (`DrawYItems`):** This routine is responsible for rendering all 24 item slots. It reads the SRAM address for each slot from `Menu_AddressIndex` (`menu_select_item.asm`), checks if the player owns the item, and then calls `DrawMenuItem`.
- **`DrawMenuItem`:** This generic function is the core of the drawing system. It takes an item's SRAM value (e.g., Sword level 0-4) and uses it to look up the correct 16x16 tile data from a large graphics table in `Menu/menu_gfx_table.asm`. This makes the menu highly data-driven.
- **Selection (`menu_select_item.asm`):** Cursor movement is handled by `Menu_FindNextItem`, `Menu_FindPrevItem`, etc. These routines intelligently skip over empty slots, ensuring the cursor always lands on a valid item. The currently selected slot index is stored in `$0202`.
### 2.3. Quest Status Screen (Right Page)
This screen is a static display of the player's overall progress.
- **Drawing:** It is rendered by a series of functions in `menu_draw.asm`, including:
- `Menu_DrawQuestItems`: Draws equipped sword, shield, tunic, etc.
- `Menu_DrawPendantIcons` & `Menu_DrawTriforceIcons`: Reads SRAM flags to draw collected pendants and crystals.
- `Menu_DrawCharacterName`: Reads the player's name from SRAM and renders it.
- `DrawLocationName`: Reads the current overworld area (`$008A`) or underworld room (`$00A0`) and looks up the corresponding name from the tables in `menu_map_names.asm`.
## 3. HUD System Architecture
The HUD is a separate system that hooks the vanilla game's NMI rendering routines. Its main entry point is `HUD_Update` in `Menu/menu_hud.asm`.
- **Functionality:** The `HUD_Update` routine runs every frame during gameplay. It reads player stats directly from SRAM and WRAM and draws them to the VRAM buffer for the top of the screen.
- **Key Drawing Logic:**
- **Hearts:** `HUD_UpdateHearts` is a loop that draws empty hearts based on `MAXHP` (`$7EF36C`) and then overlays full/partial hearts based on `CURHP` (`$7EF36D`).
- **Magic Meter:** It reads `MagicPower` (`$7EF36E`) and uses the `MagicTilemap` lookup table to find the correct tiles to display the green bar.
- **Counters:** It uses a `HexToDecimal` routine to convert the values for Rupees, Bombs, and Arrows into drawable digits.
- **Equipped Item:** `HUD_UpdateItemBox` reads the currently equipped item index (`$0202`), finds its graphics data in the `HudItems` table, and draws the icon in the top-left box.
## 4. Data-Driven Design & Areas for Improvement
The entire menu and HUD are heavily data-driven, which is a major strength.
- **Graphics:** All item icons for both the menu and HUD are defined in data tables in `menu_gfx_table.asm` and `menu_hud.asm`, not hardcoded.
- **Item Layout:** The position and SRAM address of every item in the menu are defined in the `Menu_ItemCursorPositions` and `Menu_AddressIndex` tables, allowing the layout to be easily changed.
- **Text:** Item names, location names, and other text are all stored in data tables in `menu_text.asm` and `menu_map_names.asm`.
This analysis confirms the suggestions in the placeholder `Menu.md` file:
1. **Refactor Redundant Code:** The input handling logic for the Magic Bag, Song Menu, and Ring Box is nearly identical and is a prime candidate for being refactored into a single, reusable subroutine.
2. **Use `table` for Jump Tables:** The main `Menu_Entry` jump table is created with manual `dw` directives and would be cleaner and safer if generated with asar's `table` directive.
3. **Replace Hardcoded Values:** Hardcoded state values (e.g., `LDA.b #$0C : STA.w $0200`) should be replaced with named constants (`!MENU_STATE_MAGIC_BAG = $0C`) for readability and maintainability.

137
Docs/Music.md Normal file
View File

@@ -0,0 +1,137 @@
# Music Creation Guide
This document details the process for creating and integrating custom music into Oracle of Secrets. The project uses the native Super Nintendo Packet Chip (N-SPC) music format, abstracted through a powerful set of `asar` macros.
## 1. N-SPC Music Format Primer
Music in the N-SPC engine is structured around eight independent channels. Each channel is a stream of bytes that are read sequentially. The stream consists of two types of data:
- **Commands:** Special bytes (from `$E0` to `$FF`) that control aspects of the sound, such as setting the instrument, changing volume, or calling a subroutine.
- **Notes:** A note consists of a duration byte followed by one or more tone bytes. The duration byte (e.g., `$48` for a quarter note) determines how long the following tone(s) will play.
## 2. The Macro System (`Core/music_macros.asm`)
To make composing more intuitive, the project uses a comprehensive library of macros that wrap the raw N-SPC commands into readable names. All music files must include `Core/music_macros.asm`.
### Key Concepts
- **Note Durations:** Constants are defined for standard note lengths (e.g., `!4th`, `!8th`, `!16th`).
- **Note Tones:** Constants are defined for all notes across several octaves (e.g., `C4`, `G4s` for G#4, `A5`).
- **Special Notes:** `Tie` (`$C8`) continues the previous note for the new duration, and `Rest` (`$C9`) signifies silence.
### Core Macros
- **`%SetInstrument(id)`:** Sets the instrument for the current channel (e.g., `%SetInstrument($09)` for Strings). Helper macros like `%Strings()`, `%Piano()`, etc., exist for common instruments.
- **`%SetTempo(value)`:** Sets the overall playback speed of the song.
- **`%SetMasterVolume(value)` / `%SetChannelVolume(value)`:** Sets the volume for the entire song or just the current channel.
- **`%CallSubroutine(address, repeats)`:** The most important macro for structuring songs. It jumps to a labeled subroutine, plays it `repeats+1` times, and then returns. **This is the primary method for looping musical phrases.**
- **`%VibratoOn(delay, rate, depth)`:** Adds a vibrato effect.
- **`%TremoloOn(delay, rate, depth)`:** Adds a tremolo (volume fluctuation) effect.
- **`%SetPan(value)`:** Sets the stereo position (left/right) of the channel.
- **`%EchoVBits(switch, left, right)`:** Enables and configures echo for the channel.
## 3. Song File Structure
Every song `.asm` file follows a standard structure.
#### 1. Header
The file begins with a header that defines metadata for the song engine.
```asm
MyNewSong:
!ARAMAddr = $D86A ; Base address in ARAM for this song
dw !ARAMAddr+$0A ; Pointer to the Intro section
dw !ARAMAddr+$1A ; Pointer to the Main (looping) section
dw $00FF ; Default fade-in
dw !ARAMAddr+$02 ; Start of the looping section data
dw $0000
```
#### 2. Channel Pointers
Next is a table of pointers to each of the eight channel data blocks. The `!ARAMC` constant is used to make these pointers relative to the song's ARAM address.
```asm
.Channels
!ARAMC = !ARAMAddr-MyNewSong
dw .Channel0+!ARAMC
dw .Channel1+!ARAMC
; ...up to 8 channels, use dw $0000 for unused channels
```
#### 3. Channel Data
Each channel is a block of code containing commands and notes.
```asm
.Channel0
%SetMasterVolume($DA)
%SetTempo(62)
%SetInstrument($02) ; Tympani
%SetDurationN(!4th, $7F)
%CallSubroutine(.sub1+!ARAMC, 23) ; Call subroutine .sub1 24 times
db End ; $00, signifies end of channel data
```
#### 4. Subroutines
The bulk of a song is made of small, labeled subroutines containing musical phrases. These are placed after the channel data.
```asm
.sub1
db !4th, B1, B1, !8th, Tie, C2, !4th, F3s
db End ; Subroutines must also end with $00
```
## 4. How to Add a New Song
1. **Create the File:** Create a new `.asm` file in the `Music/` directory.
2. **Copy Template:** Copy the contents of an existing song (e.g., `stone_tower_temple_v2.asm`) into your new file to use as a template.
3. **Set Header:** Change the main label (e.g., `MyNewSong:`) and set the `!ARAMAddr`. This address must be unique and not conflict with other songs.
4. **Compose:** Write your music in the channel and subroutine blocks using the note constants and macros.
5. **Integrate the Song:**
- Open `Music/all_music.asm` and add an `incsrc` for your new file.
- To replace a vanilla song, find its label in the ROM map and use `org` to place your new song at that address. For example, to replace the Lost Woods theme:
```asm
org $1AADDE ; Original address of Lost Woods theme
incsrc "Music/MyNewSong.asm"
```
- To add a new song to the expanded Dark World bank, open `Music/expanded.asm` and add a new entry to the `SongBank_OverworldExpanded_Main` table.
## 5. Proposals for Improved Organization
The current system is functional but can be made more readable and maintainable.
1. **Standardize Subroutine Naming:** The current convention of `.sub1`, `.sub101`, etc., is ambiguous. A clearer naming scheme would greatly improve readability.
- **Proposal:** Name subroutines based on their musical function, like `.MelodyVerseA`, `.BasslineIntro`, `.PercussionFill1`. This makes the main channel blocks easier to read as a high-level song structure.
2. **Create a Common Patterns Library:** Many songs use similar rhythmic or melodic patterns (e.g., a standard 4/4 drum beat, an arpeggiated chord).
- **Proposal:** Create a `Music/common_patterns.asm` file. This file could contain a library of generic, reusable subroutines for things like drum patterns, basslines, or common arpeggios. Songs could then `incsrc` this library and call these patterns, reducing code duplication and speeding up composition.
3. **Develop Advanced Composition Macros:** The existing helper macros are basic. More advanced macros could abstract away the manual process of defining and calling subroutines.
- **Proposal:**
- `%DefineMeasure(Name, Notes...)`: A macro that takes a name and a list of notes and automatically creates a correctly formatted subroutine block.
- `%PlayMeasure(Name, Repeats)`: A macro that automatically calculates the relative address (`+!ARAMC`) and calls `%CallSubroutine`.
- **Example Workflow with Proposed Macros:**
```asm
; --- Subroutine Definitions ---
%DefineMeasure(VerseMelody, !8th, C4, D4, E4, F4, G4, A4, B4, C5)
%DefineMeasure(VerseBass, !4th, C2, G2, A2, F2)
; --- Channel Data ---
.Channel0
; ... setup ...
%PlayMeasure(VerseMelody, 4) ; Plays the melody 4 times
db End
.Channel1
; ... setup ...
%PlayMeasure(VerseBass, 4) ; Plays the bassline 4 times
db End
```
This approach would make the main channel data blocks read like a high-level song arrangement, significantly improving clarity.
4. **Improve In-File Documentation:**
- **Proposal:** Encourage the use of comments to label major song sections directly within the channel data (e.g., `; --- VERSE 1 ---`, `; --- CHORUS ---`). This provides crucial signposting when navigating complex song files.