- Created detailed documentation for the Minecart sprite, outlining its properties, constants, collision setup, main logic, and design patterns. - Added documentation for the Pedestal sprite, including its vanilla overrides, custom logic for item interaction, and event triggering based on area context. - Introduced documentation for the Portal sprite, detailing its two-way warping system, initialization, main logic, and helper routines for seamless transitions. - Documented the Switch Track sprite, explaining its interactive behavior, state-based animation, and integration with external switches for dynamic track manipulation.
81 lines
7.2 KiB
Markdown
81 lines
7.2 KiB
Markdown
# Twinrova Boss Sprite Analysis
|
|
|
|
## Overview
|
|
The `twinrova` sprite (ID: `Sprite_Twinrova`, which is `$CE`) is a complex, multi-phase boss designed to override the vanilla Blind and Blind Maiden sprites. It features a dramatic transformation from Blind Maiden into Twinrova, followed by alternating phases where Twinrova switches between Koume (fire) and Kotake (ice) forms, each possessing distinct attacks and environmental interactions.
|
|
|
|
## Key Properties:
|
|
* **Sprite ID:** `Sprite_Twinrova` (`$CE`)
|
|
* **Description:** A multi-phase boss that transforms from Blind Maiden, then alternates between fire (Koume) and ice (Kotake) forms.
|
|
* **Number of Tiles:** 6
|
|
* **Health:** `00` (Health is managed by `Sprite_Twinrova_CheckIfDead` and phase transitions.)
|
|
* **Damage:** `00` (Damage dealt to Link is likely handled by its attacks.)
|
|
* **Special Properties:**
|
|
* `!Boss = 01` (Correctly identified as a boss.)
|
|
* `!Shadow = 01` (Draws a shadow.)
|
|
* `!Hitbox = 03`
|
|
* `!CollisionLayer = 01` (Checks both layers for collision.)
|
|
|
|
## Custom Variables/Macros:
|
|
* `!AnimSpeed = 8`: Defines the animation speed for various states.
|
|
* `Twinrova_Front()`, `Twinrova_Back()`, `Twinrova_Ready()`, `Twinrova_Attack()`, `Show_Koume()`, `Show_Kotake()`, `Twinrova_Hurt()`: Macros for playing specific animations, enhancing code readability.
|
|
* `$AC`: A RAM address used to store the current attack type (Fire or Ice).
|
|
|
|
## Main Logic Flow (`Sprite_Twinrova_Main`):
|
|
The boss's behavior is governed by a detailed state machine:
|
|
* **`Twinrova_Init` (0x00):** Initial state. Displays an introductory message and transitions to `Twinrova_MoveState`.
|
|
* **`Twinrova_MoveState` (0x01):** The core movement and phase management state. It checks `SprHealth, X` to determine if Twinrova is in Phase 1 (single entity) or Phase 2 (alternating forms).
|
|
* **Phase 1:** Twinrova moves around, randomly spawning Fire/Ice Keese, or preparing Fire/Ice attacks.
|
|
* **Phase 2:** Twinrova alternates between `Twinrova_KoumeMode` (fire) and `Twinrova_KotakeMode` (ice) forms.
|
|
* **`Twinrova_MoveForwards` (0x02), `Twinrova_MoveBackwards` (0x03):** Handles movement using `Sprite_FloatTowardPlayer` and `Sprite_CheckTileCollision`.
|
|
* **`Twinrova_PrepareAttack` (0x04):** Prepares either a Fire or Ice attack based on the value in `$AC`.
|
|
* **`Twinrova_FireAttack` (0x05):** Executes a Fire attack. Restores floor tiles, uses `JSL Sprite_Twinrova_FireAttack` (a shared function for the actual attack), and randomly releases fireballs (`ReleaseFireballs`).
|
|
* **`Twinrova_IceAttack` (0x06):** Executes an Ice attack using `JSL Sprite_Twinrova_IceAttack` (a shared function).
|
|
* **`Twinrova_Hurt` (0x07):** Manages Twinrova taking damage. Plays a hurt animation and, after a timer, determines whether to dodge or retaliate with a fire or ice attack.
|
|
* **`Twinrova_KoumeMode` (0x08):** Koume (fire) form. Spawns pit hazards (`AddPitHazard`), falling tiles (`Ganon_SpawnFallingTilesOverlord`), and fireballs (`Sprite_SpawnFireball`). Uses `RageModeMove` for dynamic movement.
|
|
* **`Twinrova_KotakeMode` (0x09):** Kotake (ice) form. Can spawn lightning (`JSL $1DE612`) and uses `RageModeMove` for dynamic movement.
|
|
* **`Twinrova_Dead` (0x0A):** Handles Twinrova's death sequence, killing all spawned friends and playing a hurt animation.
|
|
|
|
## Initialization (`Sprite_Twinrova_Prep`):
|
|
* Checks for the presence of the Blind Maiden (`$7EF3CC = $06`). If the Maiden is present, Twinrova is killed, indicating that Twinrova spawns *from* the Blind Maiden.
|
|
* Sets initial health to `$5A` (90 decimal).
|
|
* Configures deflection (`SprDefl = $80`), bump damage (`SprBump = $04`), and ensures Twinrova is not invincible.
|
|
* Configures Blind Boss startup parameters and initializes various timers and `SprMisc` variables.
|
|
|
|
## Death Check (`Sprite_Twinrova_CheckIfDead`):
|
|
* Monitors `SprHealth, X`. If health is zero or negative, it triggers the boss's death sequence, setting `SprState = $04` (kill sprite boss style) and `SprAction = $0A` (Twinrova_Dead stage).
|
|
|
|
## Movement (`RageModeMove`, `DoRandomStrafe`, `VelocityOffsets`):
|
|
* **`RageModeMove`:** A sophisticated routine for dynamic, floaty movement. It randomly determines a movement mode (predictive movement towards player, random strafe, random dodge, stay in place) based on timers and probabilities. It also handles evasive actions.
|
|
* **`DoRandomStrafe`:** Generates random strafing movement.
|
|
* **`VelocityOffsets`:** A table defining X and Y speed offsets for movement.
|
|
|
|
## Environmental Interactions (`Twinrova_RestoreFloorTile`, `RestoreFloorTile`, `AddPitHazard`, `Ganon_SpawnFallingTilesOverlord`):
|
|
* **`Twinrova_RestoreFloorTile` / `RestoreFloorTile`:** Restores floor tiles, likely after they have been modified by an attack.
|
|
* **`AddPitHazard`:** Adds a pit hazard to the floor.
|
|
* **`Ganon_SpawnFallingTilesOverlord`:** Spawns falling tiles (reused from Ganon's mechanics).
|
|
|
|
## Drawing (`Sprite_Twinrova_Draw`):
|
|
* Uses standard OAM allocation routines.
|
|
* Handles complex animation frames, x/y offsets, character data, properties, and sizes for drawing Twinrova.
|
|
* Utilizes 16-bit operations for precise drawing calculations.
|
|
|
|
## Graphics Transfer (`ApplyTwinrovaGraphics`):
|
|
* Handles DMA transfer of graphics data (`twinrova.bin`) to VRAM.
|
|
|
|
## Attack Spawning (`Fireball_Configure`, `ReleaseFireballs`, `Sprite_SpawnFireKeese`, `Sprite_SpawnIceKeese`, `JSL Sprite_SpawnFireball`, `JSL $1DE612` (Sprite_SpawnLightning)):
|
|
* Twinrova can spawn various projectiles and enemies, including fireballs, Fire Keese, Ice Keese, and lightning.
|
|
|
|
## Blind Maiden Integration:
|
|
Twinrova's fight is deeply integrated with the Blind Maiden mechanics:
|
|
* **`Follower_BasicMover`:** This routine is hooked to check if the follower is the Blind Maiden, triggering the transformation to Twinrova.
|
|
* **`Follower_CheckBlindTrigger`:** Checks if the Blind Maiden follower is within a specific trigger area.
|
|
* **`Blind_SpawnFromMaiden`:** This is the core routine for the transformation. It applies Twinrova graphics, sets Twinrova's initial state and position based on the Maiden's, and sets various timers and properties.
|
|
* **`SpritePrep_Blind_PrepareBattle`:** This routine is overridden to handle Twinrova's prep or to despawn if a room flag is set.
|
|
|
|
## Discrepancies/Notes:
|
|
* **Health Management:** The `!Health` property is `00`. The boss's health is managed by `Sprite_Twinrova_CheckIfDead` and phase transitions.
|
|
* **Code Reuse:** There is extensive code reuse from other sprites/bosses (e.g., `Sprite_Twinrova_FireAttack` is also used by KydreeokHead, `Ganon_SpawnFallingTilesOverlord` in Koume mode, `Sprite_SpawnFireKeese`/`Sprite_SpawnIceKeese` in MoveState). This is an efficient practice but requires careful management to ensure thematic consistency and avoid unintended side effects.
|
|
* **Hardcoded Addresses:** Several `JSL` calls are to hardcoded addresses (e.g., `JSL $1DE612` for lightning). These should ideally be replaced with named labels for better maintainability.
|
|
* **Blind Maiden Overrides:** The boss heavily relies on overriding vanilla Blind Maiden behavior, which is a common ROM hacking technique but requires careful understanding of the original game's code.
|
|
* **`TargetPositions`:** This table is defined but appears unused in the provided code.
|