- 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.
13 KiB
Helmet Chuchu Sprite Analysis
This document provides a detailed analysis of the helmet_chuchu.asm sprite, outlining its properties, core routines, and behavioral patterns.
1. Sprite Properties
The following !SPRID constants define Helmet Chuchu's fundamental characteristics:
!SPRID = Sprite_HelmetChuchu
!NbrTiles = 03 ; Number of tiles used in a frame
!Harmless = 00 ; 00 = Sprite is Harmful, 01 = Sprite is Harmless
!HVelocity = 00 ; Is your sprite going super fast? put 01 if it is
!Health = $10 ; Number of Health the sprite have
!Damage = 04 ; (08 is a whole heart), 04 is half heart
!DeathAnimation = 00 ; 00 = normal death, 01 = no death animation
!ImperviousAll = 00 ; 00 = Can be attack, 01 = attack will clink on it
!SmallShadow = 00 ; 01 = small shadow, 00 = no shadow
!Shadow = 00 ; 00 = don't draw shadow, 01 = draw a shadow
!Palette = 00 ; Unused in this template (can be 0 to 7)
!Hitbox = 00 ; 00 to 31, can be viewed in sprite draw tool
!Persist = 00 ; 01 = your sprite continue to live offscreen
!Statis = 00 ; 00 = is sprite is alive?, (kill all enemies room)
!CollisionLayer = 00 ; 01 = will check both layer for collision
!CanFall = 00 ; 01 sprite can fall in hole, 01 = can't fall
!DeflectArrow = 00 ; 01 = deflect arrows
!WaterSprite = 00 ; 01 = can only walk shallow water
!Blockable = 00 ; 01 = can be blocked by link's shield?
!Prize = 00 ; 00-15 = the prize pack the sprite will drop from
!Sound = 00 ; 01 = Play different sound when taking damage
!Interaction = 00 ; ?? No documentation
!Statue = 00 ; 01 = Sprite is statue
!DeflectProjectiles = 00 ; 01 = Sprite will deflect ALL projectiles
!ImperviousArrow = 00 ; 01 = Impervious to arrows
!ImpervSwordHammer = 00 ; 01 = Impervious to sword and hammer attacks
!Boss = 00 ; 00 = normal sprite, 01 = sprite is a boss
Note: !Health is initially set to $10 but is dynamically determined during initialization based on Link's sword level.
2. Core Routines
2.1. Sprite_HelmetChuchu_Long (Main Loop)
This is the primary entry point for Helmet Chuchu's per-frame execution. It handles drawing, shadow rendering, and then dispatches to the main logic routine if the sprite is active.
Sprite_HelmetChuchu_Long:
{
PHB : PHK : PLB
JSR Sprite_HelmetChuchu_Draw
JSL Sprite_DrawShadow
JSL Sprite_CheckActive : BCC .SpriteIsNotActive
JSR Sprite_HelmetChuchu_Main
.SpriteIsNotActive
PLB
RTL
}
2.2. Sprite_HelmetChuchu_Prep (Initialization)
This routine is executed once when Helmet Chuchu is first spawned. It sets its health based on Link's sword level, randomly assigns an initial SprAction (determining its type and initial frame), and initializes SprMiscB and SprMiscD to zero.
Sprite_HelmetChuchu_Prep:
{
PHB : PHK : PLB
LDA.l Sword : DEC A : TAY
LDA.w .health, Y : STA.w SprHealth, X ; Set health based on sword level
JSL GetRandomInt : AND.b #$02 : STA.w SprAction, X ; Randomly set initial action (0, 1, or 2)
STZ.w SprMiscB, X
STZ.w SprMiscD, X
LDA.w SprAction, X : BNE +
LDA.b #$04 : STA.w SprFrame, X ; If action 0, set frame to 4 (Helmet Green)
+
CMP.b #$02 : BNE +
LDA.b #$02 : STA.w SprFrame, X ; If action 2, set frame to 2 (Mask Red)
+
PLB
RTL
.health
db $08, $0C, $0F, $10 ; Health values for each sword level
}
2.3. Sprite_HelmetChuchu_Main (Behavioral State Machine)
This routine manages Helmet Chuchu's AI through a state machine, using SprAction, X to determine its current behavior. It includes states for different Chuchu types (Green/Red, Helmet/No Helmet, Mask/No Mask) and separate states for the detached helmet and mask.
Sprite_HelmetChuchu_Main:
{
JSL Sprite_DamageFlash_Long
%SpriteJumpTable(GreenChuchu_Helmet,
GreenChuchu_NoHelmet,
RedChuchu_Masked,
RedChuchu_NoMask,
HelmetSubtype,
MaskSubtype)
GreenChuchu_Helmet:
{
%StartOnFrame(4)
%PlayAnimation(4, 5, 16)
JSR Sprite_CheckForHookshot : BCC +
LDA.w SprFlash, X : BEQ +
%GotoAction(1) ; Transition to GreenChuchu_NoHelmet if hookshot hit and not flashing
+
JSL Sprite_CheckDamageFromPlayer
JSR Sprite_Chuchu_Move
RTS
}
GreenChuchu_NoHelmet:
{
%StartOnFrame(0)
%PlayAnimation(0, 1, 16)
LDA.w SprMiscD, X : BNE +
JSR HelmetChuchu_SpawnHookshotDrag ; Spawn detached helmet
LDA.b #$01 : STA.w SprMiscD, X ; Set flag to prevent re-spawning
+
JSL Sprite_CheckDamageFromPlayer
JSR Sprite_Chuchu_Move
RTS
}
RedChuchu_Masked:
{
%StartOnFrame(2)
%PlayAnimation(2, 3, 16)
JSR Sprite_CheckForHookshot : BCC +
LDA.w SprFlash, X : BEQ +
%GotoAction(3) ; Transition to RedChuchu_NoMask if hookshot hit and not flashing
+
JSL Sprite_CheckDamageFromPlayer
JSR Sprite_Chuchu_Move
RTS
}
RedChuchu_NoMask:
{
%StartOnFrame(6)
%PlayAnimation(6, 7, 16)
LDA.w SprMiscD, X : BNE +
JSR HelmetChuchu_SpawnHookshotDrag ; Spawn detached mask
LDA.b #$01 : STA.w SprMiscD, X ; Set flag to prevent re-spawning
+
JSL Sprite_CheckDamageFromPlayer
JSR Sprite_Chuchu_Move
RTS
}
HelmetSubtype:
{
%StartOnFrame(8)
%PlayAnimation(8, 8, 16)
JSL Sprite_Move
JSL Sprite_CheckIfLifted
JSL Sprite_CheckIfRecoiling
JSL ThrownSprite_TileAndSpriteInteraction_long
RTS
}
MaskSubtype:
{
%StartOnFrame(8)
%PlayAnimation(9, 9, 16)
JSL Sprite_Move
JSL Sprite_CheckIfLifted
JSL Sprite_CheckIfRecoiling
JSL ThrownSprite_TileAndSpriteInteraction_long
RTS
}
}
2.4. Sprite_Chuchu_Move (Movement and Interaction Logic)
This routine handles Helmet Chuchu's movement, which involves bouncing towards or recoiling from the player. It uses SprMiscB, X to switch between these two behaviors.
Sprite_Chuchu_Move:
{
JSL Sprite_Move
JSL Sprite_BounceFromTileCollision
JSL Sprite_PlayerCantPassThrough
JSL Sprite_CheckIfRecoiling
LDA.w SprMiscB, X
JSL JumpTableLocal
dw BounceTowardPlayer
dw RecoilFromPlayer
BounceTowardPlayer:
{
JSL GetRandomInt : AND.b #$02 : STA $09 ; Speed
JSL GetRandomInt : AND.b #$07 : STA $08 ; Height
JSL Sprite_MoveAltitude
DEC.w $0F80,X : DEC.w $0F80,X
LDA.w SprHeight, X : BPL .aloft
STZ.w SprHeight, X
LDA.b $08 : STA.w $0F80, X ; set height from 08
LDA.b $09
JSL Sprite_ApplySpeedTowardsPlayer
.aloft
LDA.w SprHeight, X : BEQ .dontmove
JSL Sprite_Move
.dontmove
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage
INC.w SprMiscB, X ; Switch to RecoilFromPlayer
LDA.b #$20 : STA.w SprTimerB, X
.no_damage
JSL Sprite_CheckDamageToPlayer : BCC .no_attack
INC.w SprMiscB, X ; Switch to RecoilFromPlayer
LDA.b #$20 : STA.w SprTimerB, X
.no_attack
RTS
}
RecoilFromPlayer:
{
JSL GetRandomInt : AND.b #$02 : STA $09 ; Speed
LDA.w SprX, X : CLC : ADC $09 : STA $04
LDA.w SprY, X : SEC : SBC $09 : STA $06
LDA.w SprXH, X : ADC #$00 : STA $05
LDA.w SprYH, X : ADC #$00 : STA $07
LDA $09 : STA $00 : STA $01
JSL Sprite_ProjectSpeedTowardsEntityLong
LDA.w SprTimerB, X : BNE .not_done
JSR HelmetChuchu_SpawnHookshotDrag ; Spawn detached helmet/mask
STZ.w SprMiscB, X ; Switch back to BounceTowardPlayer
.not_done
RTS
}
}
2.5. HelmetChuchu_SpawnHookshotDrag
This routine is responsible for spawning the detached helmet or mask as a separate sprite when the Chuchu is hit by a hookshot. It determines whether to spawn a helmet or a mask based on the Chuchu's current SprAction.
HelmetChuchu_SpawnHookshotDrag:
{
; Based on the subtype either spawn the helmet or the mask
PHX
LDA.w SprAction, X : CMP.b #$01 : BEQ .spawn_helmet
CMP.b #$03 : BEQ .spawn_mask
.spawn_helmet
LDA.b #$05 ; Sprite ID for helmet/mask (assuming $05 is the ID)
JSL Sprite_SpawnDynamically : BMI .no_space
LDA.b #$05 : STA.w SprAction, Y ; Set action for detached helmet
JMP .prepare_mask
.no_space
JMP .no_space2
.spawn_mask
LDA.b #$05 ; Sprite ID for helmet/mask
JSL Sprite_SpawnDynamically : BMI .no_space2
LDA.b #$04 : STA.w SprAction, Y ; Set action for detached mask
.prepare_mask
JSL Sprite_SetSpawnedCoordinates
LDA.b #$10 : STA.w SprHealth, Y
LDA.b #$00 : STA.w SprMiscB, Y
LDA.b #$80 : STA.w SprTimerA, Y
LDA.b #$01 : STA.w SprNbrOAM, Y
LDA.w .speed_x, X : STA.w SprXSpeed, Y
LDA.w .speed_y, X : STA.w SprYSpeed, Y
.no_space2
PLX
RTS
.speed_x
db 16, -11, -16, 11
.speed_y
db 0, 11, 0, -11
}
2.6. Sprite_CheckForHookshot
This routine checks if a hookshot is currently active and interacting with the Chuchu. It iterates through ancilla slots to find a hookshot ($1F) and returns with the carry flag set if found.
Sprite_CheckForHookshot:
{
PHX
LDX.b #$0A
.next_ancilla
LDA.w $0C4A, X : CMP.b #$1F : BNE .not_hooker ; Check ancilla type (assuming $1F is hookshot)
PLX
SEC ; Carry set if hookshot found
RTS
.not_hooker
DEX
BPL .next_ancilla
PLX
CLC ; Carry clear if no hookshot found
RTS
}
2.7. Sprite_HelmetChuchu_Draw (Drawing Routine)
This routine is responsible for rendering Helmet Chuchu's graphics. It uses a custom OAM allocation and manipulation logic to handle its multi-tile appearance and animation, dynamically adjusting based on its current state (helmet/mask, color, animation frame).
Sprite_HelmetChuchu_Draw:
{
JSL Sprite_PrepOamCoord
JSL Sprite_OAM_AllocateDeferToPlayer
LDA.w SprGfx, X : CLC : ADC.w SprFrame, X : TAY;Animation Frame
LDA .start_index, Y : STA $06
LDA.w SprFlash, X : STA $08
PHX
LDX .nbr_of_tiles, Y ;amount of tiles -1
LDY.b #$00
.nextTile
PHX ; Save current Tile Index?
TXA : CLC : ADC $06 ; Add Animation Index Offset
PHA ; Keep the value with animation index offset?
ASL A : TAX
REP #$20
LDA $00 : STA ($90), Y
AND.w #$0100 : STA $0E
INY
LDA $02 : CLC : ADC .y_offsets, X : STA ($90), Y
CLC : ADC #$0010 : CMP.w #$0100
SEP #$20
BCC .on_screen_y
LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way
STA $0E
.on_screen_y
PLX ; Pullback Animation Index Offset (without the *2 not 16bit anymore)
INY
LDA .chr, X : STA ($90), Y
INY
LDA .properties, X : ORA $08 : STA ($90), Y
PHY
TYA : LSR #2 : TAY
LDA.b #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer
PLY : INY
PLX : DEX : BPL .nextTile
PLX
RTS
; =======================================================
; chr prop
; Mask $04 $37
; Helmet $08 $3B
.start_index
db $00, $02, $03, $06, $08, $0A, $0C, $0E, $0F, $10
.nbr_of_tiles
db 1, 0, 2, 1, 1, 1, 1, 0, 0, 0
.y_offsets
dw 0, -8
dw 0
dw 0, -8, -8
dw 0, -4
dw 0, -8
dw 0, -4
dw 0, -8
dw 0
dw 0
dw 0
.chr
; No Helmet Green
db $26, $16
db $24
; Mask Red
db $26, $16, $04
db $24, $04
; Helmet Green
db $26, $08
db $24, $08
; No Helmet Red
db $26, $16
db $24
; Mask
db $04
; Helmet
db $08
.properties
db $2B, $2B
db $2B
db $25, $25, $27
db $25, $27
db $2B, $29
db $2B, $29
db $25, $25
db $25
; mask
db $27
; helmet
db $29
}
3. Key Behaviors and Implementation Details
- Dynamic Appearance and State: Helmet Chuchu is a highly dynamic sprite that changes its appearance and behavior based on whether it has a helmet/mask and its color (green/red). This is managed through its
SprActionandSprFramevalues. - Conditional Damage Handling: The Chuchu's vulnerability to damage is tied to the presence of its helmet or mask. When hit by a hookshot, the helmet/mask detaches, making the Chuchu vulnerable.
- Hookshot Interaction: Special logic (
Sprite_CheckForHookshot) is implemented to detect interaction with Link's hookshot, which triggers the detachment of the helmet/mask. - Detached Helmet/Mask as Separate Sprites: When the helmet or mask is detached, it is spawned as an independent sprite (
HelmetSubtypeorMaskSubtype) with its own movement (Sprite_Move), collision (ThrownSprite_TileAndSpriteInteraction_long), and interaction logic. This demonstrates a sophisticated use of child sprites. - Movement Patterns: The Chuchu moves by bouncing towards (
BounceTowardPlayer) and recoiling from (RecoilFromPlayer) the player, with randomness introduced in speed and height. This creates a distinct and challenging movement pattern. - Custom OAM Drawing: The
Sprite_HelmetChuchu_Drawroutine is a complex example of custom OAM manipulation. It dynamically selects tiles and properties based on the Chuchu's current state, allowing for seamless transitions between helmeted, masked, and vulnerable forms. SprMiscBUsage: This variable controls the Chuchu's movement sub-states (BounceTowardPlayerandRecoilFromPlayer). It also plays a role in the detached helmet/mask sprites.SprMiscDUsage: This variable acts as a flag to ensure that theHelmetChuchu_SpawnHookshotDragroutine is called only once when the helmet/mask is detached.SprTimerBUsage: Used to control the duration of the recoil state.