Add comprehensive documentation for sprites and systems

- Introduced detailed analysis for the Minecart system, highlighting its state machine, track system, and areas for improvement.
- Created an NPCs analysis document, summarizing various NPC sprites and their functionalities.
- Added an Objects analysis document, covering interactive elements like collectibles, ice blocks, and minecarts.
- Documented the Overlord sprite system, detailing its role in spawning other sprites and managing events.
- Compiled a Dungeons & Indoor Areas document, outlining custom room tags, enhanced mechanics, and advanced collision systems.
- Developed an Overworld Systems Analysis, focusing on the ZSCustomOverworld architecture and its core features.
- Added a Time System document, explaining the in-game clock and day/night cycle management.
- Documented the ZScream Custom Overworld, detailing its data-driven approach and key features.
This commit is contained in:
scawful
2025-10-02 12:44:30 -04:00
parent 27ffaf16d8
commit 6ba634caa4
23 changed files with 500 additions and 0 deletions

131
Docs/Core/Link.md Normal file
View File

@@ -0,0 +1,131 @@
# Bank $07: Core Player (Link) Engine Analysis
**File**: `ALTTP/bank_07.asm`
**Address Range**: `$078000` - `$07FFFF`
This bank is dedicated entirely to the player character, Link. It contains his core state machine, which governs everything from movement and physics to item usage and interaction with the world. It is executed every frame that the player has control and is not in a cutscene.
---
### 1. Main Entry Point: `Link_Main`
* **Routine**: `Link_Main` (`#_078000`)
* **Purpose**: This is the top-level function for all player-related code, called once per frame from the main game loop when the game is in a playable state (e.g., Overworld or Underworld).
* **Functionality**:
1. It first checks if the player is in a state that prevents control (e.g., a cutscene, indicated by `$02E4` being non-zero).
2. If the player has control, it calls `Link_ControlHandler`, which is the heart of the player engine.
3. After the main handler runs, it calls `HandleSomariaAndGraves` to process interactions with those specific objects, which need to be checked every frame.
---
### 2. The Player State Machine: `Link_ControlHandler`
* **Routine**: `Link_ControlHandler` (`#_07807F`)
* **Purpose**: This function acts as a state machine dispatcher. It reads Link's current state from a single, critical WRAM variable and jumps to the appropriate logic handler for that state.
* **Critical WRAM Variable**: `$7E005D` (`LINKDO`) - This byte holds Link's current state ID. Modifying this value directly forces Link into a different state.
* **Execution Flow**:
1. **Damage Check**: Before any other action, the handler checks if Link has taken damage (`$7E0373`, `HURTME`). If so, it processes the damage, checks for the Magic Cape (`$7E0055`), reduces health, and can trigger a state change to `LinkState_Recoil` or the death sequence.
2. **State Dispatch**: It reads the value of `LINKDO`, multiplies it by two (since each entry is a 2-byte address), and uses it as an index into the `.vectors` jump table (`#_078041`). It then performs a `JMP` to the corresponding state handler routine.
---
### 3. Link State Vector Table
This table at `#_078041` defines all 31 possible states for Link. Understanding this is key to modifying player behavior.
| State ID | Label (`#_07....`) | Description |
|:---:|---|---|
| `0x00` | `LinkState_Default` | The normal on-foot state for walking, standing, and most basic interactions. |
| `0x01` | `LinkState_Pits` | Handles the logic for falling into a pit. |
| `0x02` | `LinkState_Recoil` | Handles being knocked back by an enemy or obstacle. |
| `0x03` | `LinkState_SpinAttack` | Manages the spin attack animation and hitbox. |
| `0x04` | `LinkState_Swimming` | The state for swimming in water. |
| `0x05` | `LinkState_OnIce` | Handles movement physics for icy surfaces. |
| `0x06` | `LinkState_Recoil` | A duplicate pointer to the recoil state, likely for a different impact type. |
| `0x07` | `LinkState_Zapped` | A special recoil state for electrical damage. |
| `0x08` | `LinkState_UsingEther` | Handles the animation and logic for using the Ether medallion. |
| `0x09` | `LinkState_UsingBombos` | Handles the animation and logic for using the Bombos medallion. |
| `0x0A` | `LinkState_UsingQuake` | Handles the animation and logic for using the Quake medallion. |
| `0x0B` | `LinkState_HoppingSouthOW` | Manages the multi-frame action of hopping off a ledge to the south. |
| `0x0C` | `LinkState_HoppingHorizontallyOW` | Manages hopping off a ledge to the east or west. |
| `0x0D` | `LinkState_HoppingDiagonallyUpOW` | Manages hopping off a ledge diagonally up-left or up-right. |
| `0x0E` | `LinkState_HoppingDiagonallyDownOW`| Manages hopping off a ledge diagonally down-left or down-right. |
| `0x0F` | `LinkState_0F` | A generic ledge-hopping state. |
| `0x10` | `LinkState_0F` | (Duplicate) A generic ledge-hopping state. |
| `0x11` | `LinkState_Dashing` | The state for running with the Pegasus Boots. |
| `0x12` | `LinkState_ExitingDash` | The brief turn-around animation after a dash collides with a wall. |
| `0x13` | `LinkState_Hookshotting` | Manages Link's state while the hookshot is extended. |
| `0x14`| `LinkState_CrossingWorlds` | Handles the Magic Mirror animation and world transition. |
| `0x15` | `LinkState_ShowingOffItem` | The "item get" pose when Link holds an item above his head. |
| `0x16` | `LinkState_Sleeping` | For the beginning of the game when Link is in bed. |
| `0x17` | `LinkState_Bunny` | The state for when Link is transformed into a bunny in the Dark World. |
| `0x18` | `LinkState_HoldingBigRock` | The state for lifting a heavy, dark-colored rock (requires Titan's Mitt). |
| `0x19` | `LinkState_ReceivingEther` | The cutscene for receiving the Ether medallion from the tablet. |
| `0x1A` | `LinkState_ReceivingBombos` | The cutscene for receiving the Bombos medallion from the tablet. |
| `0x1B` | `LinkState_ReadingDesertTablet` | The cutscene for reading the Desert Palace tablet. |
| `0x1C` | `LinkState_TemporaryBunny` | The brief bunny transformation sequence when entering the Dark World. |
| `0x1D` | `LinkState_TreePull` | The state for pulling on the tree in the haunted grove for the race game. |
| `0x1E` | `LinkState_SpinAttack` | (Duplicate) A second entry for the spin attack state. |
---
### 4. Analysis of Core States
#### `LinkState_Default` (`#_078109`)
This is the most complex state and serves as the foundation for player control. It is a large routine that dispatches to numerous sub-handlers.
* **Initial Checks**:
* `Link_HandleBunnyTransformation`: Checks if Link should transform into a bunny.
* Checks for recoil/damage (`$7E004D`) and branches to a simplified physics handler if necessary.
* **Action Dispatching**: If not recoiling, it checks for player input and calls the appropriate action handler.
* `Link_HandleToss`: Checks if Link is throwing a carried object.
* `Link_HandleAPress`: Handles context-sensitive actions for the A button (talk, read, lift, open, dash).
* `Link_HandleYItem`: Manages using the currently selected item (bow, boomerang, rods, etc.).
* `Link_HandleSwordCooldown`: Manages sword swings and charging a spin attack.
* **Physics and Collision**: If no other action is taken, it processes movement.
* `ResetAllAcceleration`: Clears speed values if Link is standing still.
* `Link_HandleDiagonalCollision` & `Link_HandleCardinalCollision`: Check for collisions with walls and objects.
* `JSL Link_HandleVelocity`: The main physics engine. Applies acceleration, deceleration, and the final movement vector to Link's coordinates.
* **Animation & Camera**:
* `JSL Link_HandleMovingAnimation_FullLongEntry`: Updates Link's sprite graphics based on his direction and action.
* `HandleIndoorCameraAndDoors`: Manages camera scrolling and door transitions indoors.
#### `LinkState_Recoil` (`#_0786B5`)
This state demonstrates how control is temporarily taken from the player.
* **Z-Axis Movement**: It uses `$7E0024` (Link's Z-position) and `$7E0029` (knockback Z-velocity) to handle Link being knocked into the air and falling back down.
* **Timer-Based**: The duration of the recoil is controlled by a countdown timer in `$7E0046` (`INPAIN`). Once the timer reaches zero, Link's state is typically returned to `LinkState_Default`.
* **Collision & Landing**: While in recoil, it still checks for collisions. It also has special checks for landing, such as `Link_SplashUponLanding` if he falls into water, which can change his state to `LinkState_Swimming`.
#### `LinkState_Bunny` (`#_0783A1`)
This state shows a persistent change in abilities.
* **Simplified Controls**: The bunny state has a much simpler control handler. It still allows for movement but disables all item and sword usage.
* **State Check**: It constantly checks for the condition that allows Link to transform back: the presence of the Moon Pearl (`$7EF357`). If the pearl is obtained or Link leaves the Dark World, it triggers the transformation back to the default state.
---
### 5. Key WRAM Variables for Link
This bank relies on a large number of WRAM addresses to function. Understanding these is critical to debugging or modifying player logic.
| Address | Label | Description |
|:---:|---|---|
| `$7E005D` | `LINKDO` | **Link's State**: The primary state ID, used as an index for the state machine. |
| `$7E0020/21`| `POSY` | Link's 16-bit Y-coordinate. |
| `$7E0022/23`| `POSX` | Link's 16-bit X-coordinate. |
| `$7E0024` | `POSZ` | Link's 8-bit Z-coordinate (height). |
| `$7E0026` | - | Link's facing direction. |
| `$7E0027/28`| - | Link's Y/X velocity. |
| `$7E002A/2B`| - | Link's Y/X sub-pixel position. |
| `$7E003A` | - | Action flags (bitfield for sword charging, etc.). |
| `$7E0046` | `INPAIN` | Recoil/invincibility timer after taking damage. |
| `$7E004D` | - | A flag indicating Link is in a recoil state. |
| `$7E0303` | - | The ID of the currently selected Y-button item. |
| `$7E0373` | `HURTME` | Damage value to be applied to Link on the next frame. |
| `$7E037B` | - | A flag that temporarily disables taking damage. |
| `$7E0372` | - | A flag indicating Link is currently dashing. |

92
Docs/Core/MemoryMap.md Normal file
View File

@@ -0,0 +1,92 @@
# Memory Map
This document provides a detailed map of the WRAM and SRAM memory regions, serving as a central reference for understanding the game's state.
## 1. WRAM (Work RAM) - `$7E0000`
This section details the layout of the game's volatile memory.
### Key Vanilla WRAM Variables
*This section contains a table listing critical vanilla WRAM addresses, their labels (from `Core/ram.asm` and `Core/symbols.asm`), and their purpose.*
| Address | Label | Description |
|----------|------------|---------------------------------------------------|
| `$7E0010` | `MODE` | The main game state/module index. |
| `$7E0011` | `SUBMODE` | The sub-state for the current game mode. |
| `$7E001A` | `FRAME` | A counter that increments each non-lagging frame. |
| `$7E001B` | `INDOORS` | A flag indicating if Link is indoors (0x01) or outdoors (0x00). |
| `$7E002F` | `DIR` | The direction Link is facing (0=U, 2=D, 4=L, 6=R). |
| `$7E005D` | `LINKDO` | Link's personal state machine ID (walking, swimming, etc.). |
| `$7E008A` | `OWSCR` | The current Overworld screen ID. |
| `$7E00A0` | `ROOM` | The current Underworld room ID. |
| `$7E02E0` | `BUNNY` | A flag indicating if Link is in his bunny form (0x01). |
| `$7E031F` | `IFRAMES` | Link's invincibility frame timer after taking damage. |
| `$7E0DD0` | `SprState` | An array storing the state for each of the 16 sprites. |
| `$7E0E20` | `SprType` | An array storing the ID for each of the 16 sprites. |
| `$7E0E50` | `SprHealth`| An array storing the health for each of the 16 sprites. |
### Custom WRAM Region - `$7E0730+`
*This section details the custom WRAM area defined in `Core/ram.asm` and `Core/symbols.asm`. It explains the purpose of each custom variable.*
| Address | Label | Description |
|----------|------------------------|--------------------------------------------------------------------------|
| `$7E0730` | `MenuScrollLevelV` | Vertical scroll position for the menu. |
| `$7E0731` | `MenuScrollLevelH` | Horizontal scroll position for the menu. |
| `$7E0732` | `MenuScrollHDirection` | The direction of horizontal scrolling in the menu. |
| `$7E0734` | `MenuItemValueSpoof` | Used to temporarily override the displayed value of a menu item. |
| `$7E0736` | `ShortSpoof` | A shorter version of the spoof value. |
| `$7E0737` | `MusicNoteValue` | The value of the current music note being played. |
| `$7E0739` | `GoldstarOrHookshot` | Differentiates between the vanilla Hookshot and the custom Goldstar item. |
| `$7E073A` | `Neck_Index` | Used for multi-part sprites, like a centipede body. |
| `$7E0745` | `FishingOrPortalRod` | Differentiates between the Fishing Rod and the Portal Rod. |
---
## 2. SRAM (Save RAM) - `$7EF000`
This section details the layout of the save file memory.
### Key Vanilla SRAM Variables
*This section lists key vanilla save data locations, such as inventory, health, and progression flags, as defined in `Core/sram.asm`.*
| Address | Label | Description |
|----------|------------|-------------------------------------------|
| `$7EF340` | `Bow` | The player's current bow type (0x00-0x04). |
| `$7EF343` | `Bombs` | The number of bombs the player has. |
| `$7EF359` | `Sword` | The player's current sword type (0x00-0x04). |
| `$7EF35A` | `Shield` | The player's current shield type (0x00-0x03). |
| `$7EF360` | `Rupees` | The player's current rupee count. |
| `$7EF36C` | `MAXHP` | The player's maximum health (1 heart = 8 HP). |
| `$7EF36D` | `CURHP` | The player's current health. |
| `$7EF374` | `Pendants` | A bitfield for the collected pendants (Courage, Power, Wisdom). |
| `$7EF37A` | `Crystals` | A bitfield for the collected crystals from Dark World dungeons. |
| `$7EF3C5` | `GameState`| The main progression state of the game. |
### Custom SRAM Region
*This is a critical section. It provides a comprehensive breakdown of all custom variables added to the SRAM, explaining what each flag or value represents. This information is primarily found in `Core/sram.asm`.*
| Address | Label | Description |
|----------|-------------------|--------------------------------------------------------------------------|
| `$7EF3D6` | `OOSPROG` | A primary bitfield for major quest milestones unique to Oracle of Secrets. |
| `$7EF3C6` | `OOSPROG2` | A secondary bitfield for less critical progression flags. |
| `$7EF3D4` | `MakuTreeQuest` | A flag indicating if the Maku Tree has met Link. |
| `$7EF3C7` | `MapIcon` | Controls the position of the guiding 'X' on the world map. |
| `$7EF351` | `CustomRods` | A flag to differentiate between the Fishing Rod (1) and Portal Rod (2). |
| `$7EF38A` | `FishingRod` | Flag indicating if the player has the Fishing Rod. |
| `$7EF38B` | `Bananas` | The number of bananas collected for a side-quest. |
| `$7EF391` | `Seashells` | The number of secret seashells collected. |
| `$7EF398` | `Scrolls` | A bitfield tracking which of the lore scrolls have been found. |
| `$7EF39B` | `MagicBeanProg` | Tracks the multi-day growth cycle of the magic bean side-quest. |
| `$7EF39C` | `JournalState` | The current state of the player's journal. |
| `$7EF39D` | `SRAM_StormsActive`| A flag indicating if the Song of Storms effect is active. |
| `$7EF410` | `Dreams` | A bitfield tracking the collection of the three "Dreams" (Courage, Power, Wisdom). |
| `$7EF347` | `ZoraMask` | Flag indicating if the player has obtained the Zora Mask. |
| `$7EF348` | `BunnyHood` | Flag indicating if the player has obtained the Bunny Hood. |
| `$7EF349` | `DekuMask` | Flag indicating if the player has obtained the Deku Mask. |
| `$7EF34D` | `RocsFeather` | Flag indicating if the player has obtained Roc's Feather. |
| `$7EF352` | `StoneMask` | Flag indicating if the player has obtained the Stone Mask. |
| `$7EF358` | `WolfMask` | Flag indicating if the player has obtained the Wolf Mask. |

66
Docs/Core/Ram.md Normal file
View File

@@ -0,0 +1,66 @@
# RAM Analysis: The Engine's State
This document provides a high-level analysis of how Work RAM (WRAM) and Save RAM (SRAM) are used to manage the game's state. For a raw list of addresses, see `Core/ram.asm` and `Core/sram.asm`.
## 1. The Core Game Loop: WRAM in Motion
The entire game is driven by a master state machine whose state is stored in a single WRAM variable:
- **`MODE` (`$7E0010`):** This is the game's primary state index. The main loop in `bank_00.asm` reads this value every frame and jumps to the corresponding module in the `Module_MainRouting` table.
- **`SUBMODE` (`$7E0011`):** Many modules have their own internal state machines. This variable holds the sub-state for the current `MODE`.
This `MODE`/`SUBMODE` pattern is the fundamental driver of the game's flow. For example:
- When Link opens the menu, the game sets `MODE` to `0x0E` (Interface), which gives control to the menu engine.
- When Link talks to a character, `Interface_PrepAndDisplayMessage` is called, which saves the current game state to `MODECACHE` (`$7E010C`) and then sets `MODE` to `0x0E` to display the text box. When the dialogue is finished, the previous state is restored from the cache.
- Transitioning between the overworld and underworld involves setting `MODE` to `0x08` (Overworld Load) or `0x06` (Underworld Load), respectively.
## 2. Defining the World: Location and Environment
The player's location and the properties of their environment are controlled by a handful of key WRAM variables.
- **`INDOORS` (`$7E001B`):** A simple but powerful flag (`0x01` for indoors, `0x00` for outdoors). This variable is checked by numerous systems to alter their behavior. For instance, the `ZSCustomOverworld` system reads this flag to determine whether to apply day/night palettes, and the audio engine uses it to select the appropriate music track.
- **`OWSCR` (`$7E008A`) and `ROOM` (`$7E00A0`):** These variables store the player's current location. `OWSCR` holds the Overworld screen ID, while `ROOM` holds the Underworld room ID.
The interaction between these variables is central to world traversal. When Link enters a cave on `OWSCR` 0x35, the following happens:
1. The game looks up the entrance data for that tile in `Overworld/entrances.asm`.
2. This data specifies the destination `ROOM` ID (e.g., 0x0104).
3. The `INDOORS` flag is set to `0x01`.
4. The main game `MODE` is set to `0x06` (Underworld Load).
5. The dungeon engine in `bank_01.asm` takes over. It reads the `ROOM` ID and uses it to look up the room's header in `ALTTP/rooms.asm`. This header contains pointers to all the data needed to draw the room, including its layout, objects, and sprites.
## 3. Room-Specific Behavior
Once a room is loaded, its specific behavior is governed by tags and flags.
- **`TAG1`/`TAG2` (`$7E00AE`/`$AF`):** These are "Room Effect" tags loaded from the room's header. They trigger special behaviors like kill rooms, shutter doors, or custom events defined in `Dungeons/custom_tag.asm`. For example, a kill room tag will cause the `Underworld_HandleRoomTags` routine to check if all sprites in the room (`$7E0E20+`) have been defeated.
- **`UWDEATH` (`$7FDF80`) and `OWDEATH` (`$7FEF80`):** These are large bitfields in SRAM that track the state of every overworld screen and underworld room. When a kill room is cleared or a key is taken from a chest, a bit is set in this array. This ensures that the state persists permanently in the save file, preventing enemies from respawning or chests from reappearing.
## 4. The Player and Entities
- **Link:** The player's state is managed by its own state machine in `bank_07.asm`, with the current state held in `LINKDO` (`$7E005D`). This is covered in detail in `Docs/Link.md`.
- **Sprites and Ancillae:** The WRAM regions from `$7E0D00` onwards are large arrays that hold the state of all active entities in the game (16 sprites, ~40 ancillae). These are defined as `structs` in `Core/structs.asm`. While there are dozens of variables for each sprite, the most important for general game logic are:
- `SprState` (`$7E0DD0,X`): The sprite's main state (e.g., `0x09` for active, `0x0B` for stunned).
- `SprType` (`$7E0E20,X`): The sprite's ID number.
- `SprX`/`SprY` (`$0D10,X`/`$0D00,X`): The sprite's coordinates.
The sprite engine in `bank_06.asm` iterates through these arrays each frame, executing the logic for each active sprite.
## 5. Long-Term Progression: SRAM and Custom Flags
SRAM (`$7EF000+`) stores the player's save file and is the key to managing long-term quest progression. Oracle of Secrets heavily expands the vanilla save format to support its new data-driven systems.
- **`OOSPROG` (`$7EF3D6`) and `OOSPROG2` (`$7EF3C6`):** These are the primary bitfields for tracking major and minor quest milestones. They are the heart of the game's custom progression.
- **Example Flow:**
1. The player talks to the `village_elder` NPC for the first time.
2. The NPC's code in `Sprites/NPCs/village_elder.asm` sets a specific bit in `OOSPROG` (e.g., `ORA.b #$10 : STA.l OOSPROG`).
3. Later, the world map code in `Overworld/world_map.asm` checks this bit (`LDA.l OOSPROG : AND.b #$10`). If it's set, a new icon is displayed on the map.
- **Other Custom SRAM:** The project adds many other custom variables to SRAM to track new systems, such as:
- **New Inventory:** `ZoraMask` (`$7EF347`), `RocsFeather` (`$7EF34D`), etc.
- **Side-Quests:** `MagicBeanProg` (`$7EF39B`) tracks the growth of a magic bean over time.
- **New Collectibles:** A block starting at `$7EF38B` tracks items like `Bananas` and `Seashells`.
This data-driven approach, centered on modifying and checking flags in SRAM, allows for complex, stateful quest design that persists across play sessions.

View File

@@ -0,0 +1,140 @@
# System Interaction & Compatibility Analysis
References:
- `Docs/ZSCustomOverworld.md`
- `Docs/TimeSystem.md`
## 1. Overview
This document details the analysis of interactions between `ZSCustomOverworld` and other advanced systems in Oracle of Secrets. It outlines potential conflicts and proposes solutions to ensure they work together correctly.
## 2. ZSCustomOverworld vs. Time System
- **System:** `Overworld/time_system.asm`
- **Interaction Point:** Palette Modulation.
### Analysis
Both systems modify overworld palettes. ZSCustomOverworld sets the **base palette** for each area from its tables. The Time System applies a **color transformation** on top of the existing palette to simulate lighting changes.
The conflict arises if the Time System reads the palette *before* ZSCustomOverworld has loaded the area-specific one, or if one system's writes completely overwrite the other's.
The key routine is `LoadDayNightPaletteEffect` in `time_system.asm`, which is hooked into the game's main palette-loading functions. It intercepts every color write to CGRAM, applies its color subtraction logic, and then writes the final value.
### Conclusion & Solution
The current implementation is **mostly compatible by design**. The Time System's `LoadDayNightPaletteEffect` acts as a filter on all palette writes. When ZSCustomOverworld writes a new base palette to CGRAM, the Time System intercepts these writes and applies the day/night effect.
**Recommendations:**
1. **No Code Change Needed for Compatibility (at this time):** The current hook-based approach should work. ZSCustomOverworld loads the base palette, and the Time System modifies it on the fly.
2. **Move Patches:** The `org` patches in `time_system.asm` should be moved to `Core/patches.asm` for consistency. This is a code organization improvement, not a compatibility fix.
## 3. ZSCustomOverworld vs. Lost Woods Puzzle
- **System:** `Overworld/lost_woods.asm`
- **Interaction Point:** Overworld Screen Transitions.
### Analysis
The Lost Woods puzzle works by intercepting the screen transition logic. When the player is in area `$29`, the `LostWoods` routine at `$A0F000` runs. It checks the player's exit direction against a predefined sequence. If the sequence is incorrect, it manually changes the player's and camera's coordinates to loop them back within the same screen, creating the maze effect.
ZSCustomOverworld heavily modifies the screen transition logic via its hook at `OverworldHandleTransitions` (`$02A9C4`). The conflict is that ZSCustomOverworld's new, more complex transition logic does not account for the Lost Woods puzzle's override.
### Conclusion & Solution
This is a **direct conflict** that requires integration. The Lost Woods logic needs to be explicitly called from within ZSCustomOverworld's transition handler.
**Recommendations:**
1. **Modify `OverworldHandleTransitions`:** In `ZSCustomOverworld.asm`, at the point where a transition is confirmed and the new screen ID is determined, add a check:
```asm
; Inside OverworldHandleTransitions, after a valid transition is detected
LDA.b $8A ; Current Area ID
CMP #$29 ; Is it the Lost Woods?
BNE .normal_transition
; If it is, call the Lost Woods logic
JSL LostWoods_PuzzleHandler
; The handler should return with carry set if it handled the transition
BCS .transition_handled
.normal_transition
; ... existing ZS transition logic ...
.transition_handled
; ... code to finalize the transition after the puzzle logic runs ...
```
2. **Refactor `lost_woods.asm`:** The code in `lost_woods.asm` needs to be refactored into a proper subroutine (`LostWoods_PuzzleHandler`) that can be called via `JSL`. It should be modified to return a status (e.g., using the carry flag) to indicate whether it has overridden the transition or if the final, correct exit has been found.
### Conclusion & Solution
This is a **direct conflict** that requires integration. The Lost Woods logic needs to be explicitly called from within ZSCustomOverworld's transition handler.
**Recommendations:**
1. **Modify `OverworldHandleTransitions`:** In `ZSCustomOverworld.asm`, at the point where a transition is confirmed and the new screen ID is determined, add a check:
```asm
; Inside OverworldHandleTransitions, after a valid transition is detected
LDA.b $8A ; Current Area ID
CMP #$29 ; Is it the Lost Woods?
BNE .normal_transition
; If it is, call the Lost Woods logic
JSL LostWoods_PuzzleHandler
; The handler should return with carry set if it handled the transition
BCS .transition_handled
.normal_transition
; ... existing ZS transition logic ...
.transition_handled
; ... code to finalize the transition after the puzzle logic runs ...
```
2. **Refactor `lost_woods.asm`:** The code in `lost_woods.asm` needs to be refactored into a proper subroutine (`LostWoods_PuzzleHandler`) that can be called via `JSL`. It should be modified to return a status (e.g., using the carry flag) to indicate whether it has overridden the transition or if the final, correct exit has been found.
## 4. ZSCustomOverworld vs. Song of Storms
- **System:** `Items/ocarina.asm`
- **Interaction Point:** Overworld Screen Overlays.
### Analysis
The Song of Storms summons rain by directly writing the rain overlay ID (`#$9F`) to the overlay register (`$8C`). ZSCustomOverworld, however, determines the overlay for each screen via its `.OverlayTable`. A conflict occurs when:
1. The player plays the Song of Storms: The rain appears, but upon the next screen transition, ZSCustomOverworld will reload the area's default overlay, making the rain stop.
2. The player dismisses the storm: The code simply clears the overlay register, potentially removing a default overlay (like fog or clouds) that should be present in that area.
### Conclusion & Solution
This is a **direct conflict**. The Song of Storms logic must be made aware of ZSCustomOverworld's overlay system to properly override and restore the correct overlay.
**Implemented Solution:**
1. **New SRAM Variable:** `SRAM_StormsActive` (`$7EF39D`) has been added to `Core/sram.asm` to persistently track whether the Song of Storms is active.
2. **Modified `OcarinaEffect_SummonStorms`:**
- This routine in `Items/ocarina.asm` now checks the current area's default overlay from `Pool_OverlayTable`. If the default is already rain (`#$9F`), it does nothing, preventing accidental cancellation of natural rain.
- Otherwise, it toggles the `SRAM_StormsActive` flag. Direct manipulation of the overlay register (`$8C`) has been removed from this routine.
3. **New `HandleStormsOverlay` Routine:** A new routine `HandleStormsOverlay` has been added to `Overworld/time_system.asm`. This routine is called from `RunClock` every frame the player is in the overworld.
- If `SRAM_StormsActive` is set, it forces the rain overlay (`$8C = #$9F`).
- If `SRAM_StormsActive` is not set, it does nothing, allowing ZSCustomOverworld's normal overlay logic to apply the area's default overlay.
**Impact:** This solution ensures the rain state persists across transitions (dungeons, warps, screen changes) and correctly interacts with ZSCustomOverworld's overlay system without conflicts. It also prevents the Song of Storms from inadvertently canceling natural rain effects.
## 5. ZSCustomOverworld vs. Day/Night Sprites
- **System:** `Overworld/time_system.asm` and `Overworld/ZSCustomOverworld.asm`
- **Interaction Point:** Sprite Loading.
### Analysis
The original day/night sprite system relied on `CheckIfNight` and `CheckIfNight16Bit` routines to modify the game state (`$7EF3C5`) before vanilla sprite loading functions were called. This allowed different sprite sets to be loaded for day and night.
With ZSOW v3, the vanilla sprite loading hook (`Overworld_LoadSprites` at `$09C4E3`) is replaced by ZSOW's `LoadOverworldSprites_Interupt` (`$09C4C7`). The conflict arose because the old day/night logic was no longer being called at the correct point in the execution flow.
### Conclusion & Solution
This conflict is **ongoing**. An attempted solution to integrate the `CheckIfNight` logic directly into ZSOW's sprite loading routine caused a regression, resulting in a `BRK` after returning from `LoadOverworldSprites_Interupt`.
**Attempted Solution (Caused Regression):**
1. **Modified `LoadOverworldSprites_Interupt`:** In `ZSCustomOverworld.asm`, a `JSL CheckIfNight` call was inserted at the beginning of this routine. `CheckIfNight` returns a potentially modified game state (e.g., `GameState + 1` for night) in the accumulator.
2. **Adjusted Game State Usage:** The `LoadOverworldSprites_Interupt` routine then attempted to use this adjusted game state to look up the appropriate sprite set in ZSOW's `.Overworld_SpritePointers_state_..._New` tables.
3. **`CheckIfNight` and `CheckIfNight16Bit`:** These routines in `Overworld/time_system.asm` were uncommented and available. `CheckIfNight16Bit` is already integrated into ZSOW's `Sprite_LoadGfxProperties_Interupt` (`$00FC67`), ensuring sprite graphics properties are also adjusted for day/night.
**Impact of Regression:** The game crashes with a `BRK` after `LoadOverworldSprites_Interupt` returns, indicating an issue with the state or stack after the `CheckIfNight` call. This solution is currently not viable. Further investigation is required to correctly integrate day/night sprite loading with ZSOW v3 without causing crashes.