Fix: Zora Sanctuary Waterfall trigger and Lost Woods transition logic
This commit is contained in:
45
Docs/Issues/LostWoods_Transition_Desync.md
Normal file
45
Docs/Issues/LostWoods_Transition_Desync.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Issue: Lost Woods Transition Coordinate Desync
|
||||||
|
|
||||||
|
## Status: Active / Low Priority
|
||||||
|
**Created:** March 2026
|
||||||
|
**Impact:** Visual/Gameplay discontinuity when exiting the Lost Woods (Area 0x29) back to the West (0x28).
|
||||||
|
|
||||||
|
## Problem Description
|
||||||
|
The custom Lost Woods puzzle uses a coordinate manipulation trick (`INC/DEC $21`, `INC/DEC $E7`) to simulate an infinite loop.
|
||||||
|
- **Symptoms:**
|
||||||
|
- When completing the puzzle (Exit East -> 0x2A), the fix implemented (`LostWoods_ResetCoordinates`) correctly snaps Link to the left edge of the new screen, preventing him from skipping the map.
|
||||||
|
- **Regression:** When *returning* to the previous map (Exit West -> 0x28), Link may appear at incorrect coordinates or the camera may be misaligned relative to the player.
|
||||||
|
- The "Snapping" logic forces Link's X/Y to the base of Area 0x29 (e.g., X=0x0200). However, the transition logic in `ZSCustomOverworld.asm` uses these coordinates to calculate the *destination* position in the new area. If the snap happens too early or incorrectly, the destination calculation (Start X - Offset) might underflow or misalign.
|
||||||
|
|
||||||
|
## Technical Analysis
|
||||||
|
|
||||||
|
### Custom Logic (`lost_woods.asm`)
|
||||||
|
The puzzle modifies:
|
||||||
|
- `$21` / `$23`: Link's High-Byte Coordinates (World Grid Position).
|
||||||
|
- `$E1` / `$E7` / `$E9`: Overlay and BG Scroll Registers.
|
||||||
|
|
||||||
|
This desynchronizes the "Visible" position from the "Logical" position expected by the standard Overworld engine.
|
||||||
|
|
||||||
|
### ZSOW Transition Logic
|
||||||
|
`OverworldHandleTransitions` in `ZSCustomOverworld.asm` relies on:
|
||||||
|
- `$20` / `$22`: Link's 16-bit absolute coordinates.
|
||||||
|
- `Pool_OverworldTransitionPositionX/Y`: Lookup tables for screen boundaries.
|
||||||
|
|
||||||
|
### Root Cause Hypothesis
|
||||||
|
1. **Coordinate Mismatch:** The `LostWoods_ResetCoordinates` routine snaps Link to `X=0x0200` (Left edge of 0x29).
|
||||||
|
2. **Transition Calc:** When moving West to 0x28, the engine expects Link to be crossing the boundary.
|
||||||
|
3. **Vanilla vs. Custom:** Vanilla ALTTP does not use infinite looping coordinates in the overworld. This mechanic is entirely custom and fights the static grid nature of the engine.
|
||||||
|
|
||||||
|
## Future Investigation Strategy (Reference `usdasm`)
|
||||||
|
1. **Vanilla Transitions:** Study `Bank02.asm` in `usdasm` to see how `Module09_Overworld` handles coordinate handoffs.
|
||||||
|
- Look for `Overworld_ScrollMap` and `Overworld_HandleCardinalCollision`.
|
||||||
|
2. **Camera Re-centering:** Search for routines that "center" the camera on Link after a transition (`Overworld_SetCameraBoundaries`). We may need to manually invoke this *after* the transition logic finishes, rather than snapping coordinates *before*.
|
||||||
|
3. **Scroll Register Reset:** Instead of zeroing `$E1` etc., we might need to recalculate them based on the *new* area's properties immediately upon load.
|
||||||
|
|
||||||
|
## Workaround
|
||||||
|
The bug is non-fatal. Players can navigate out of the area, though the visual transition may be jarring.
|
||||||
|
|
||||||
|
## Related Files
|
||||||
|
- `Overworld/lost_woods.asm`
|
||||||
|
- `Overworld/ZSCustomOverworld.asm`
|
||||||
|
- `usdasm/bank_02.asm` (Reference)
|
||||||
@@ -252,22 +252,50 @@ OcarinaEffect_SummonStorms:
|
|||||||
LDA.l $7EE00E : BNE .dismiss_storms
|
LDA.l $7EE00E : BNE .dismiss_storms
|
||||||
|
|
||||||
; Area checks only apply when trying to SUMMON rain
|
; Area checks only apply when trying to SUMMON rain
|
||||||
LDA.w $8A : CMP.b #$00 : BEQ .check_for_magic_bean
|
LDA.w $8A : CMP.b #$00 : BNE +
|
||||||
CMP.b #$2E : BEQ .error_beep ; Zora areas already have rain
|
JMP .check_for_magic_bean
|
||||||
CMP.b #$2F : BEQ .error_beep
|
+
|
||||||
|
CMP.b #$2E : BEQ .jump_error_beep ; Zora areas already have rain
|
||||||
|
CMP.b #$2F : BEQ .jump_error_beep
|
||||||
; Check for areas which should not be allowed to have rain
|
; Check for areas which should not be allowed to have rain
|
||||||
CMP.b #$05 : BEQ .error_beep
|
CMP.b #$05 : BEQ .jump_error_beep
|
||||||
CMP.b #$06 : BEQ .error_beep
|
CMP.b #$06 : BEQ .jump_error_beep
|
||||||
CMP.b #$07 : BEQ .error_beep
|
CMP.b #$07 : BEQ .jump_error_beep
|
||||||
CMP.b #$10 : BEQ .error_beep
|
CMP.b #$10 : BEQ .jump_error_beep
|
||||||
CMP.b #$18 : BEQ .error_beep
|
CMP.b #$18 : BEQ .jump_error_beep
|
||||||
CMP.b #$28 : BEQ .error_beep
|
CMP.b #$28 : BEQ .jump_error_beep
|
||||||
CMP.b #$29 : BEQ .error_beep
|
CMP.b #$29 : BNE .no_error_beep
|
||||||
|
|
||||||
|
.jump_error_beep
|
||||||
|
JMP .error_beep
|
||||||
|
|
||||||
|
.no_error_beep
|
||||||
|
|
||||||
; Fall through to summon rain
|
; Fall through to summon rain
|
||||||
JMP .summon_storms
|
JMP .summon_storms
|
||||||
|
|
||||||
.dismiss_storms
|
.dismiss_storms
|
||||||
|
; Check for Zora Temple Waterfall Trigger
|
||||||
|
; Map 1E, High Precision Zone (16x16 pixels)
|
||||||
|
; Target: Y=$06A8, X=$0CB7 (At the statue)
|
||||||
|
; Range: Y=$06A0-$06B0, X=$0CB0-$0CC0
|
||||||
|
|
||||||
|
LDA.w $8A : CMP.b #$1E : BNE .normal_dismiss
|
||||||
|
|
||||||
|
; Y Coordinate Check
|
||||||
|
LDA.b $21 : CMP.b #$06 : BNE .normal_dismiss ; High Byte
|
||||||
|
LDA.b $20 : CMP.b #$A0 : BCC .normal_dismiss ; Low Byte < $A0 (Too North/Close)
|
||||||
|
CMP.b #$B0 : BCS .normal_dismiss ; Low Byte >= $B0 (Too South)
|
||||||
|
|
||||||
|
; X Coordinate Check
|
||||||
|
LDA.b $23 : CMP.b #$0C : BNE .normal_dismiss ; High Byte
|
||||||
|
LDA.b $22 : CMP.b #$B0 : BCC .normal_dismiss ; Low Byte < $B0 (Too West)
|
||||||
|
CMP.b #$C0 : BCS .normal_dismiss ; Low Byte >= $C0 (Too East)
|
||||||
|
|
||||||
|
; Trigger Found!
|
||||||
|
JMP .trigger_zora_waterfall
|
||||||
|
|
||||||
|
.normal_dismiss
|
||||||
; Clear the flag first so the reload routine loads default overlay
|
; Clear the flag first so the reload routine loads default overlay
|
||||||
LDA #$00 : STA $7EE00E
|
LDA #$00 : STA $7EE00E
|
||||||
; Trigger overlay reload - will load area default (pyramid or other)
|
; Trigger overlay reload - will load area default (pyramid or other)
|
||||||
@@ -278,6 +306,22 @@ OcarinaEffect_SummonStorms:
|
|||||||
LDA #$FF : STA $8C
|
LDA #$FF : STA $8C
|
||||||
RTL
|
RTL
|
||||||
|
|
||||||
|
.trigger_zora_waterfall
|
||||||
|
; Clear Rain State
|
||||||
|
LDA #$00 : STA $7EE00E
|
||||||
|
STZ $1D ; Hide Rain Overlay
|
||||||
|
STZ $9A ; Clear Color Math
|
||||||
|
LDA #$FF : STA $8C ; Clear Overlay ID
|
||||||
|
|
||||||
|
; Setup Zora Temple Cutscene
|
||||||
|
STZ.b $B0 ; Reset Animation Timer
|
||||||
|
LDA.b #$01 : STA.w $04C6 ; Set Overlay Index (01 = Zora Temple)
|
||||||
|
LDA.b #$16 : STA.b $11 ; Set Submodule to "Open Entrance" ($16)
|
||||||
|
|
||||||
|
INC.b $15 ; Force Palette Refresh
|
||||||
|
|
||||||
|
RTL
|
||||||
|
|
||||||
.summon_storms
|
.summon_storms
|
||||||
; Set the flag first so the reload routine sees it
|
; Set the flag first so the reload routine sees it
|
||||||
LDA #$01 : STA $7EE00E
|
LDA #$01 : STA $7EE00E
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ LostWoods:
|
|||||||
RTL
|
RTL
|
||||||
|
|
||||||
normalfinish:
|
normalfinish:
|
||||||
|
JSL LostWoods_ResetCoordinates
|
||||||
LDA.l Pool_Overworld_ActualScreenID_New, X
|
LDA.l Pool_Overworld_ActualScreenID_New, X
|
||||||
STZ !ComboCounter
|
STZ !ComboCounter
|
||||||
RTL
|
RTL
|
||||||
@@ -143,3 +144,63 @@ LostWoods:
|
|||||||
RTL
|
RTL
|
||||||
}
|
}
|
||||||
} ; label LOST_WOOD_HOOK
|
} ; label LOST_WOOD_HOOK
|
||||||
|
|
||||||
|
LostWoods_ResetCoordinates:
|
||||||
|
{
|
||||||
|
; Only run if we are in area 0x29
|
||||||
|
LDA.b $8A : CMP.b #$29 : BNE .done
|
||||||
|
|
||||||
|
REP #$20
|
||||||
|
|
||||||
|
; Check Target Area (in X register)
|
||||||
|
CPX !EastArea : BEQ .snap_east
|
||||||
|
CPX !WestArea : BEQ .snap_west
|
||||||
|
CPX !NorthArea : BEQ .snap_north
|
||||||
|
CPX !SouthArea : BEQ .snap_south
|
||||||
|
BRA .done_coords ; Fallback if unknown exit
|
||||||
|
|
||||||
|
.snap_east ; Target 0x2A (Right)
|
||||||
|
; Snap X to Right Edge of 0x29 (0x0400)
|
||||||
|
LDA.w #$0400 : STA.b $22
|
||||||
|
; Modulo Y to 0x29 Base (0x0A00)
|
||||||
|
LDA.b $20 : AND.w #$01FF : ORA.w #$0A00 : STA.b $20
|
||||||
|
BRA .reset_scroll
|
||||||
|
|
||||||
|
.snap_west ; Target 0x28 (Left)
|
||||||
|
; Snap X to Left Edge of 0x29 (0x0200)
|
||||||
|
LDA.w #$0200 : STA.b $22
|
||||||
|
; Modulo Y to 0x29 Base (0x0A00)
|
||||||
|
LDA.b $20 : AND.w #$01FF : ORA.w #$0A00 : STA.b $20
|
||||||
|
BRA .reset_scroll
|
||||||
|
|
||||||
|
.snap_north ; Target 0x21 (Up)
|
||||||
|
; Snap Y to Top Edge of 0x29 (0x0A00)
|
||||||
|
LDA.w #$0A00 : STA.b $20
|
||||||
|
; Modulo X to 0x29 Base (0x0200)
|
||||||
|
LDA.b $22 : AND.w #$01FF : ORA.w #$0200 : STA.b $22
|
||||||
|
BRA .reset_scroll
|
||||||
|
|
||||||
|
.snap_south ; Target 0x31 (Down)
|
||||||
|
; Snap Y to Bottom Edge of 0x29 (0x0C00)
|
||||||
|
LDA.w #$0C00 : STA.b $20
|
||||||
|
; Modulo X to 0x29 Base (0x0200)
|
||||||
|
LDA.b $22 : AND.w #$01FF : ORA.w #$0200 : STA.b $22
|
||||||
|
BRA .reset_scroll
|
||||||
|
|
||||||
|
.done_coords
|
||||||
|
; If we didn't match an exit, fallback to just modulo-ing both
|
||||||
|
LDA.b $20 : AND.w #$01FF : ORA.w #$0A00 : STA.b $20
|
||||||
|
LDA.b $22 : AND.w #$01FF : ORA.w #$0200 : STA.b $22
|
||||||
|
|
||||||
|
.reset_scroll
|
||||||
|
SEP #$20
|
||||||
|
|
||||||
|
; Reset Overlay Scroll Drifts introduced by puzzle
|
||||||
|
STZ.b $E1
|
||||||
|
STZ.b $E3
|
||||||
|
STZ.b $E7
|
||||||
|
STZ.b $E9
|
||||||
|
|
||||||
|
.done
|
||||||
|
RTL
|
||||||
|
}
|
||||||
|
|||||||
25
oracle.org
25
oracle.org
@@ -84,21 +84,22 @@ This section tracks tasks focused on improving the existing codebase's structure
|
|||||||
- [X] Convert all logic blocks (`RunClock`, `DrawClockToHud`, `ColorSubEffect`) into proper `subroutine`s.
|
- [X] Convert all logic blocks (`RunClock`, `DrawClockToHud`, `ColorSubEffect`) into proper `subroutine`s.
|
||||||
- [X] Break down the large `RunClock` routine into smaller, single-purpose functions (e.g., `TimeSystem_CheckCanRun`, `TimeSystem_IncrementTime`, `TimeSystem_UpdatePalettes`).
|
- [X] Break down the large `RunClock` routine into smaller, single-purpose functions (e.g., `TimeSystem_CheckCanRun`, `TimeSystem_IncrementTime`, `TimeSystem_UpdatePalettes`).
|
||||||
|
|
||||||
*** TODO [#A] Fix Time System Custom BG Color Regression
|
*** DONE [#A] Fix Time System Custom BG Color Regression
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:ID: bug-time-system-bg-color
|
:ID: bug-time-system-bg-color
|
||||||
:END:
|
:END:
|
||||||
- *Symptom:* Custom background color not working correctly after recent changes.
|
- *Symptom:* Custom background color not working correctly after recent changes.
|
||||||
- *Likely Cause:* Regression introduced during system refactoring or ZSCustomOverworld changes.
|
- *Root Cause:* The Color Math Control Register ($9A) was persisting when transitioning from an overlay area (Rain/Storms) to a normal area, causing additive color math to apply to the background.
|
||||||
- *Files to Investigate:* =Overworld/time_system.asm=, =Overworld/ZSCustomOverworld.asm=
|
- *Solution:* Explicitly cleared $9A in `Overworld_LoadBGColorAndSubscreenOverlay` and `Overworld_ReloadSubscreenOverlay_Interupt` in `ZSCustomOverworld.asm` when the overlay ID is $FF. Also ensured Time System tint persistence via `Oracle_CgramAuxToMain_Impl` in `mask_routines.asm`.
|
||||||
|
|
||||||
** Minecart System (=Sprites/Objects/minecart.asm=)
|
** Minecart System (=Sprites/Objects/minecart.asm=)
|
||||||
*** TODO [#B] Refactor Minecart System [0/4]
|
*** ACTIVE [#B] Refactor Minecart System [1/4]
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:ID: refactor-minecart
|
:ID: refactor-minecart
|
||||||
:END:
|
:END:
|
||||||
- *Analysis:* An impressive but highly complex system that would benefit greatly from better organization and data-driven design.
|
- *Analysis:* An impressive but highly complex system that would benefit greatly from better organization and data-driven design.
|
||||||
- *Tasks:*
|
- *Tasks:*
|
||||||
|
- [X] Externalize track data into `data/minecart_tracks.asm` (Partial step toward struct/table conversion).
|
||||||
- [ ] Define a `MinecartTrack` struct and convert the SRAM tracking arrays into a `table` of these structs.
|
- [ ] Define a `MinecartTrack` struct and convert the SRAM tracking arrays into a `table` of these structs.
|
||||||
- [ ] Refactor the four `Minecart_Move...` routines into a single `Minecart_Move` subroutine that uses a lookup table for speed and axis.
|
- [ ] Refactor the four `Minecart_Move...` routines into a single `Minecart_Move` subroutine that uses a lookup table for speed and axis.
|
||||||
- [ ] Refactor the `Minecart_SetDirection...` routines into a single `Minecart_SetDirection` subroutine that uses lookup tables.
|
- [ ] Refactor the `Minecart_SetDirection...` routines into a single `Minecart_SetDirection` subroutine that uses lookup tables.
|
||||||
@@ -157,13 +158,14 @@ This section tracks known conflicts between systems and outstanding bugs.
|
|||||||
- *Task:* Refactored the `Sprite_ApplyPush` routine to use a lookup table for setting speed based on direction. Converted `IceBlock_CheckForGround` and `Sprite_IceBlock_CheckForSwitch` to subroutines. Replaced magic numbers with constants.
|
- *Task:* Refactored the `Sprite_ApplyPush` routine to use a lookup table for setting speed based on direction. Converted `IceBlock_CheckForGround` and `Sprite_IceBlock_CheckForSwitch` to subroutines. Replaced magic numbers with constants.
|
||||||
- *Status:* Awaiting emulator verification.
|
- *Status:* Awaiting emulator verification.
|
||||||
|
|
||||||
*** TODO [#A] Resolve ZSOW vs. Lost Woods Conflict
|
*** DONE [#A] Resolve ZSOW vs. Lost Woods Conflict
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:ID: bug-zsow-lostwoods
|
:ID: bug-zsow-lostwoods
|
||||||
:END:
|
:END:
|
||||||
- *Analysis:* The `lost_woods.asm` puzzle directly conflicts with `ZSCustomOverworld.asm`'s transition handler.
|
- *Analysis:* The `lost_woods.asm` puzzle logic was executing prematurely on entry, corrupting coordinates.
|
||||||
- *Task:* Refactor `lost_woods.asm` into a proper `JSL`-callable subroutine (`LostWoods_PuzzleHandler`).
|
- *Fix:* Added a check to ensure puzzle logic only runs when *inside* Area 0x29. Added `LostWoods_ResetCoordinates` to snap Link's position and clear scroll drifts on exit.
|
||||||
- *Implementation:* Modify the `OverworldHandleTransitions` routine in `ZSCustomOverworld.asm` to check if the current area is the Lost Woods (`#$29`) and call the new handler. The handler should return a status indicating if it has overridden the transition.
|
- *Status:* Main "skipping" bug resolved.
|
||||||
|
- *Regression:* Minor camera/coordinate desync when returning West (0x28). Documented in [[file:Docs/Issues/LostWoods_Transition_Desync.md][LostWoods_Transition_Desync.md]]. Low priority.
|
||||||
|
|
||||||
*** DONE [#A] ZSOW vs. Day/Night Sprites
|
*** DONE [#A] ZSOW vs. Day/Night Sprites
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
@@ -270,13 +272,16 @@ This section tracks known conflicts between systems and outstanding bugs.
|
|||||||
- [ ] *Controlled Collapse:* A puzzle where you must intentionally make a floor tile crumble to fall down to a specific spot on the floor below.
|
- [ ] *Controlled Collapse:* A puzzle where you must intentionally make a floor tile crumble to fall down to a specific spot on the floor below.
|
||||||
|
|
||||||
** Quests & Narrative Sequences
|
** Quests & Narrative Sequences
|
||||||
*** ACTIVE [#A] Zora Sanctuary Questline [2/3] :quest:
|
*** ACTIVE [#A] Zora Sanctuary Questline [3/3] :quest:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:ID: quest-zora-sanctuary
|
:ID: quest-zora-sanctuary
|
||||||
:END:
|
:END:
|
||||||
- [X] Meet lone Sea Zora left at the Sanctuary, learn of Zora Princess.
|
- [X] Meet lone Sea Zora left at the Sanctuary, learn of Zora Princess.
|
||||||
- [X] Conflict over territory lead to Zora Princesses imprisonment.
|
- [X] Conflict over territory lead to Zora Princesses imprisonment.
|
||||||
- [ ] Implement waterfall opening event using Song of Storms. This will require coordination between =Items/ocarina.asm= and =Overworld/overlays.asm=.
|
- [X] Implement waterfall opening event using Song of Storms.
|
||||||
|
- Trigger: Song of Storms dismissal at the statue (Map 1E, Top-Left).
|
||||||
|
- Logic: Strict 16x16 pixel trigger zone (Y=$06A0-$06B0, X=$0CB0-$0CC0) to prevent camera desync.
|
||||||
|
- Fixes: Restored `overlays.asm` camera logic and added palette refresh (`INC $15`) to `ocarina.asm`.
|
||||||
|
|
||||||
*** TODO [#A] Kalyxo Castle Prison Sequence [0/4] :sequence:code:
|
*** TODO [#A] Kalyxo Castle Prison Sequence [0/4] :sequence:code:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
|||||||
Reference in New Issue
Block a user