diff --git a/Sprites/Bosses/kydreeok.asm b/Sprites/Bosses/kydreeok.asm new file mode 100644 index 0000000..61b9fe2 --- /dev/null +++ b/Sprites/Bosses/kydreeok.asm @@ -0,0 +1,668 @@ +; ========================================================= +; Sprite Properties +; ========================================================= +!SPRID = $7A ; The sprite ID you are overwriting (HEX) +!NbrTiles = 10 ; 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 = 00 ; Number of Health the sprite have +!Damage = 00 ; (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 = $07 ; 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 = 01 ; 00 = normal sprite, 01 = sprite is a boss +%Set_Sprite_Properties(Sprite_Kydreeok_Prep, Sprite_Kydreeok_Long); + +; ========================================================= + +Sprite_Kydreeok_Long: +{ + PHB : PHK : PLB + + JSR Sprite_Kydreeok_Draw ; Call the draw code + JSL Sprite_CheckActive ; Check if game is not paused + BCC .SpriteIsNotActive ; Skip Main code is sprite is innactive + + JSR Sprite_Kydreeok_Main ; Call the main sprite code + + .SpriteIsNotActive + PLB ; Get back the databank we stored previously + RTL ; Go back to original code +} + +; ========================================================= + +Sprite_Kydreeok_Prep: +{ + PHB : PHK : PLB + + LDA #$40 : STA SprTimerA, X + LDA.b #$08 : STA $36 ;stores initial movement speeds + LDA.b #$06 : STA $0428 ;allows BG1 to move + + ; Cache the origin position of the sprite. + LDA SprX, X : STA SprMiscA, X + LDA SprY, X : STA SprMiscB, X + + JSR SpawnLeftHead + JSR SpawnRightHead + + PLB + RTL +} + +; ============================================================================= + + +Sprite_Kydreeok_Main: +{ + LDA.w SprAction, X + JSL UseImplicitRegIndexedLocalJumpTable + + dw Kydreeok_Start ; 00 + dw Kydreeok_StageControl ; 01 + dw Kydreeok_MoveXandY ; 02 + dw Kydreeok_MoveXorY ; 03 + dw Kydreeok_KeepWalking ; 04 + + + Kydreeok_Start: + { + %StartOnFrame(0) + %PlayAnimation(0, 2, 10) + + JSR ApplyPalette + JSL Sprite_PlayerCantPassThrough + + LDA SprTimerA, X : BNE .continue + TXA : STA Kydreeok_Id + LDA #$40 : STA SprTimerA, X + %GotoAction(1) + .continue + + RTS + } + + Kydreeok_StageControl: + { + %StartOnFrame(0) + %PlayAnimation(0, 2, 10) + + PHX + + STZ $0D40 : STZ $0D50 ;set velocitys to 0 + JSR MoveBody + + JSL Sprite_BounceFromTileCollision ; + JSR StopIfOutOfBounds + + LDA SprTimerA, X : BNE .continue + %GotoAction(2) + .continue + + PLX + + RTS + } + + Kydreeok_MoveXandY: + { + %StartOnFrame(0) + %PlayAnimation(0, 2, 10) + + PHX ;saves X so we can use it later + + LDA $36 + JSL Sprite_ApplySpeedTowardsPlayer + JSL Sprite_BounceFromTileCollision ; JSR StopIfOutOfBounds + JSR StopIfOutOfBounds + JSR MoveBody + + JSL Sprite_CheckDamageFromPlayerLong + %DoDamageToPlayerSameLayerOnContact() + + PLX ;restores X + + %GotoAction(4) + + RTS + } + + + Kydreeok_MoveXorY: + { + %StartOnFrame(0) + %PlayAnimation(0, 2, 10) + + PHX ;saves X so we can use it later + + LDA $36 + STA $00 + JSR Sprite_ApplySpeedTowardsPlayerXOrY + JSL Sprite_BounceFromTileCollision ; JSR StopIfOutOfBounds + JSR StopIfOutOfBounds + JSR MoveBody + + JSL Sprite_CheckDamageFromPlayerLong + %DoDamageToPlayerSameLayerOnContact() + + PLX ;restores X + + %GotoAction(4) + + RTS + } + + Kydreeok_KeepWalking: + { + %StartOnFrame(0) + %PlayAnimation(0, 2, 10) + + PHX + REP #$20 + + ; Use a range of + 0x05 because being exact equal didnt trigger consistently + LDA $20 : SBC $0FDA : CMP.w #$FFFB : BCC .notEqualY + + SEP #$20 + %GotoAction(2) ; Kydreeok_MoveXandY + BRA .notEqualX + + .notEqualY + + ; Use a range of + 0x05 because being exact equal didnt trigger consistently + LDA $22 : SBC $0FD8 : CMP.w #$FFFB : BCC .notEqualX + SEP #$20 + %GotoAction(2) ; Kydreeok_MoveXandY + + .notEqualX + SEP #$20 + JSL Sprite_BounceFromTileCollision ; JSR StopIfOutOfBounds + + ;if both velocities are 0 go back to the Stalk_Player_XORY to re-set the course + LDA $0D40 : BNE .notZero + LDA $0D50 : BNE .notZero + %GotoAction(3) ; Kydreeok_MoveXorY + + .notZero + + JSR MoveBody + + JSL Sprite_CheckDamageFromPlayerLong + %DoDamageToPlayerSameLayerOnContact() + + PLX ;restores X + + RTS + } + +} + +SpawnLeftHead: +{ + LDA #$CF + + JSL Sprite_SpawnDynamically : BMI .return + TYA : STA Offspring1_Id + ;store the sub-type + LDA.b #$00 : STA $0E30, Y + + PHX + + ; code that controls where to spawn the offspring. + REP #$20 + LDA $0FD8 : SEC : SBC.w #$000F + SEP #$20 + STA $0D10, Y + XBA : STA $0D30, Y + + REP #$20 + LDA $0FDA : SEC : SBC.w #$000F + SEP #$20 + STA $0D00, Y + XBA : STA $0D20, Y + + LDA.w SprX, Y + STA.w SprMiscA, Y : STA.w $19EA : STA.w $19EC : STA.w $19EE + LDA.w SprY, Y : STA.w $19EB : STA.w $19ED : STA.w $19EF : STA.w SprY, Y + STA.w SprMiscB, Y + + TYX + + STZ $0D60, X + STZ $0D70, X + + PLX + + .return + + RTS +} + +SpawnRightHead: +{ + LDA #$CF + + JSL Sprite_SpawnDynamically : BMI .return + TYA : STA Offspring2_Id + + ;store the sub-type + LDA.b #$01 : STA $0E30, Y + + PHX + + ; code that controls where to spawn the offspring. + REP #$20 + LDA $0FD8 : CLC : ADC.w #$000C + SEP #$20 + STA $0D10, Y + XBA : STA $0D30, Y + + REP #$20 + LDA $0FDA : SEC : SBC.w #$000F + SEP #$20 + STA $0D00, Y + XBA : STA $0D20, Y + + LDA.w SprX, Y : STA.w SprX, Y + STA.w SprMiscA, Y : STA.w $19F0 : STA.w $19F2 : STA.w $19F4 + LDA.w SprY, Y : STA.w $19F1 : STA.w $19F3 : STA.w $19F5 : STA.w SprY, Y + STA.w SprMiscB, Y + + TYX + + STZ $0D60, X + STZ $0D70, X + + PLX + + .return + + RTS +} + + +; ============================================================================== +MoveBody: +{ + ; Handle the shell bg movement + ; Trinexx_MoveBody + #_1DB2E5: LDA.w $0D10, X + #_1DB2E8: PHA + + #_1DB2E9: LDA.w $0D00, X + #_1DB2EC: PHA + + #_1DB2ED: JSL Sprite_Move + + #_1DB2F0: PLA + #_1DB2F1: LDY.b #$00 + + #_1DB2F3: SEC + #_1DB2F4: SBC.w $0D00, X + #_1DB2F7: STA.w $0310 + #_1DB2FA: BPL .pos_y_low + + #_1DB2FC: DEY + + .pos_y_low + #_1DB2FD: STY.w $0311 + + ; ----------------------------------------------------- + + #_1DB300: PLA + #_1DB301: LDY.b #$00 + + #_1DB303: SEC + #_1DB304: SBC.w $0D10, X + #_1DB307: STA.w $0312 + #_1DB30A: BPL .pos_x_low + + #_1DB30C: DEY + + .pos_x_low + #_1DB30D: STY.w $0313 + + ; ----------------------------------------------------- + + #_1DB310: LDA.b #$01 + #_1DB312: STA.w $0428 + + + #_1DB318: LDA.w $0D00, X + #_1DB31B: SEC + #_1DB31C: SBC.b #$0C + #_1DB31E: STA.w $0DB0, X + + #_1DB321: LDA.w $0B08 + #_1DB324: SEC + #_1DB325: SBC.w $0D10, X + #_1DB328: CLC + #_1DB329: ADC.b #$02 + + #_1DB32B: CMP.b #$04 + #_1DB32D: BCS .not_at_target + + #_1DB32F: LDA.w $0B09 + #_1DB332: SEC + #_1DB333: SBC.w $0D00, X + #_1DB336: CLC + #_1DB337: ADC.b #$02 + + #_1DB339: CMP.b #$04 + #_1DB33B: BCS .not_at_target + + .adjust_phase + #_1DB33D: STZ.w $0D80, X + + #_1DB340: LDA.b #$30 + #_1DB342: STA.w $0DF0, X + + .not_at_target + + ; JSR AdjustChildrenPos + + ; LayerEffect_Trinexx $0AFEF0 + REP #$20 + LDA.w $0422 : CLC : ADC.w $0312 : STA.w $0422 + LDA.w $0424 : CLC : ADC.w $0310 : STA.w $0424 + STZ.w $0312 : STZ.w $0310 + SEP #$20 + + + RTS +} + +; ============================================================================== + +StopIfOutOfBounds: +{ + ; Set A to 00 if outside of certain bounds + + REP #$20 + LDA $0FD8 : CMP.w #$0A22 : BCS .notOutOfBoundsLeft + SEP #$20 + LDA $0D50 : CMP.b #$7F : BCC .notOutOfBoundsLeft + LDA.b #-10 : STA $0D50 : STA $0D70 + LDA $19EA : SEC : SBC #$04 : STA $19EA + LDA $19EC : SEC : SBC #$04 : STA $19EC + LDA $19EE : SEC : SBC #$04 : STA $19EE + + LDA $19F0 : SEC : SBC #$04 : STA $19F0 + LDA $19F2 : SEC : SBC #$04 : STA $19F2 + LDA $19F4 : SEC : SBC #$04 : STA $19F4 + + .notOutOfBoundsLeft + SEP #$20 + + REP #$20 + LDA $0FD8 : CMP.w #$1B00 : BCC .notOutOfBoundsRight + SEP #$20 + LDA $0D50 : CMP.b #$80 : BCS .notOutOfBoundsRight + LDA.b #$00 : STA $0D50 : STA $0D70 + LDA $19EA : CLC : ADC #$04 : STA $19EA + LDA $19EC : CLC : ADC #$04 : STA $19EC + LDA $19EE : CLC : ADC #$04 : STA $19EE + + LDA $19F0 : CLC : ADC #$04 : STA $19F0 + LDA $19F2 : CLC : ADC #$04 : STA $19F2 + LDA $19F4 : CLC : ADC #$04 : STA $19F4 + + .notOutOfBoundsRight + SEP #$20 + + ; Upper bound + REP #$20 + LDA $0FDA : CMP.w #$0150 : BCS .notOutOfBoundsUp + SEP #$20 + LDA $0D40 : CMP.b #$7F : BCC .notOutOfBoundsUp + LDA.b #$00 : STA $0D40 : STA $0D60 + LDA $19EA : SEC : SBC #$04 : STA $19EA + LDA $19EC : SEC : SBC #$04 : STA $19EC + LDA $19EE : SEC : SBC #$04 : STA $19EE + + .notOutOfBoundsUp + SEP #$20 + + print "CHECK DOWNS", pc + REP #$20 + LDA $0FDA : CMP.w #$01A0 : BCC .notOutOfBoundsDown + SEP #$20 + LDA $0D40 : CMP.b #$80 : BCS .notOutOfBoundsDown + LDA.b #-10 : STA $0D40 : STA $0D60 ; Reverse the direction + + ; Modify the neck position + ; Makes them move away from each other a bit + LDA $19EA : SEC : SBC #$04 : STA $19EA + LDA $19EC : SEC : SBC #$04 : STA $19EC + LDA $19EE : SEC : SBC #$04 : STA $19EE + + LDA $19F0 : CLC : ADC #$04 : STA $19F0 + LDA $19F2 : CLC : ADC #$04 : STA $19F2 + LDA $19F4 : CLC : ADC #$04 : STA $19F4 + + + .notOutOfBoundsDown + SEP #$20 + + RTS +} + + +Sprite_ApplySpeedTowardsPlayerXOrY: +{ + JSL Sprite_IsBelowPlayer : BEQ .playerBelow + ;playerAbove + + REP #$20 + LDA $0FDA : SEC : SBC $20 : CLC : ADC.w #$0006 : STA $01 ;delta Y + ;added an extra 6 pixels because aparently if link.y is 6 above sprite.y it is concidered below ¯\_(ツ)_/¯ + SEP #$20 + + JSL Sprite_IsToRightOfPlayer : BEQ .playerToTheRight1 + ;playerToTheLeft + + REP #$20 + LDA $0FD8 : SEC : SBC $22 ;delta X + + + CMP $01 : BCS .XGreaterThanY1 + ;YGreaterThanX + SEP #$20 + LDA.b #$00 : SEC : SBC $00 : STA $0D40 + STZ $0D50 + RTS + + .XGreaterThanY1 + SEP #$20 + LDA.b #$00 : SEC : SBC $00 : STA $0D50 + STZ $0D40 + RTS + + + .playerToTheRight1 + REP #$20 + LDA $22 : SEC : SBC $0FD8 ;delta X + + CMP $01 : BCS .XGreaterThanY2 + ;YGreaterThanX + SEP #$20 + LDA.b #$00 : SEC : SBC $00 : STA $0D40 + STZ $0D50 + RTS + + .XGreaterThanY2 + SEP #$20 + LDA.b #$00 : CLC : ADC $00 : STA $0D50 + STZ $0D40 + RTS + + + .playerBelow + REP #$20 + LDA $20 : SEC : SBC $0FDA : CLC : ADC.w #$0006 : STA $01 ;delta Y + ;added an extra 6 pixels because aparently if link.y is 6 above sprite.y it is concidered below ¯\_(ツ)_/¯ + SEP #$20 + + JSL Sprite_IsToRightOfPlayer : BEQ .playerToTheRight2 + ;playerToTheLeft + + REP #$20 + LDA $0FD8 : SEC : SBC $22 ;delta X + + CMP $01 : BCS .XGreaterThanY3 + ;YGreaterThanX + SEP #$20 + LDA.b #$00 : CLC : ADC $00 : STA $0D40 + STZ $0D50 + RTS + + .XGreaterThanY3 + SEP #$20 + LDA.b #$00 : SEC : SBC $00 : STA $0D50 + STZ $0D40 + RTS + + + .playerToTheRight2 + REP #$20 + LDA $22 : SEC : SBC $0FD8 ;delta X + + CMP $01 : BCS .XGreaterThanY4 + ;YGreaterThanX + SEP #$20 + LDA.b #$00 : CLC : ADC $00 : STA $0D40 + STZ $0D50 + RTS + + .XGreaterThanY4 + SEP #$20 + LDA.b #$00 : CLC : ADC $00 : STA $0D50 + STZ $0D40 + RTS +} + +ApplyPalette: +{ + REP #$20 ;Set A in 16bit mode + + ;note, this uses adresses like 7EC300 and not 7EC500 because the game + ;will fade the colors into 7EC500 based on the colors found in 7EC300 + + LDA #$7FFF : STA $7EC5E2 ;BG2 + LDA #$318C : STA $7EC5E4 + LDA #$4E73 : STA $7EC5E6 + LDA #$0C79 : STA $7EC5E8 + LDA #$14A5 : STA $7EC5EA + LDA #$7E56 : STA $7EC5EC + LDA #$65CA : STA $7EC5EE + ; LDA #$14A5 : STA $7EC5F0 + ; LDA #$7E56 : STA $7EC5F2 + ; LDA #$65CA : STA $7EC5F4 + + INC $15 + + SEP #$20 ;Set A in 8bit mode + + RTS +} + +; ============================================================================= + +Sprite_Kydreeok_Draw: + JSL Sprite_PrepOamCoord + JSL Sprite_OAM_AllocateDeferToPlayer + + LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame + LDA .start_index, Y : STA $06 + + + 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 : CLC : ADC .x_offsets, X : 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 : STA ($90), Y + + PHY + + TYA : LSR #2 : TAY + + LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer + + PLY : INY + + PLX : DEX : BPL .nextTile + + PLX + + RTS + + + .start_index + db $00, $0A, $14 + .nbr_of_tiles + db 9, 9, 9 + .x_offsets + dw -8, -16, -16, -16, -32, 8, 16, 16, 16, 32 + dw -8, -16, -16, -16, -32, 8, 16, 16, 16, 32 + dw -8, -16, -16, -16, -32, 8, 16, 16, 16, 32 + .y_offsets + dw 8, -8, 8, -36, -36, 8, -8, 8, -36, -36 + dw 8, -5, 11, -38, -38, 8, -8, 8, -39, -38 + dw 8, -8, 8, -36, -36, 8, -5, 11, -36, -36 + .chr + db $23, $00, $20, $0E, $0C, $23, $00, $20, $0E, $0C + db $23, $00, $20, $0E, $0C, $23, $00, $20, $0E, $0C + db $23, $00, $20, $0E, $0C, $23, $00, $20, $0E, $0C + .properties + db $39, $39, $39, $39, $39, $79, $79, $79, $79, $79 + db $39, $39, $39, $39, $39, $79, $79, $79, $79, $79 + db $39, $39, $39, $39, $39, $79, $79, $79, $79, $79 + .sizes + db $02, $02, $02, $02, $02, $02, $02, $02, $02, $02 + db $02, $02, $02, $02, $02, $02, $02, $02, $02, $02 + db $02, $02, $02, $02, $02, $02, $02, $02, $02, $02 diff --git a/Sprites/Bosses/kydreeok_head.asm b/Sprites/Bosses/kydreeok_head.asm new file mode 100644 index 0000000..435ce3d --- /dev/null +++ b/Sprites/Bosses/kydreeok_head.asm @@ -0,0 +1,677 @@ +; ========================================================= + +!SPRID = $CF ; The sprite ID you are overwriting (HEX) +!NbrTiles = 06 ; 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 = 40 ; Number of Health the sprite have +!Damage = 00 ; (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 +%Set_Sprite_Properties(Sprite_KydreeokHead_Prep, Sprite_KydreeokHead_Long); + +; ========================================================= + +Sprite_KydreeokHead_Long: +{ + PHB : PHK : PLB + + LDA $0D80, X : CMP #$02 : BEQ .no_head + JSR Sprite_KydreeokHead_Draw ; Call the draw code +.no_head + JSL Sprite_CheckActive ; Check if game is not paused + BCC .SpriteIsNotActive + JSR Sprite_KydreeokHead_Main ; Call the main sprite code + + .SpriteIsNotActive + PLB ; Get back the databank we stored previously + RTL ; Go back to original code +} + +; ========================================================= + +Sprite_KydreeokHead_Prep: +{ + PHB : PHK : PLB + + ; Add more code here to initialize data + + + PLB + RTL +} + +; ========================================================= + +Sprite_KydreeokHead_Main: +{ + LDA.w SprAction, X + JSL UseImplicitRegIndexedLocalJumpTable + + dw KydreeokHead_ForwardAnim + dw KydreeokHead_SideAnim + + dw KydreeokHead_SummonFire + + + KydreeokHead_ForwardAnim: + { + %StartOnFrame(0) + %PlayAnimation(0,2,10) + + JSL Sprite_BounceFromTileCollision + + JSL Sprite_CheckDamageFromPlayerLong + %DoDamageToPlayerSameLayerOnContact() + + LDA.w SprTimerA, X : BNE .noSpeedChange + JSL GetRandomInt : AND #$0F : TAY + LDA.w tableSpeed, Y : STA.w SprXSpeed, X + JSL GetRandomInt : AND #$0F : TAY + LDA.w tableSpeed, Y : STA.w SprYSpeed, X + ; LDA #$40 : STA.w SprTimerA, X + .noSpeedChange + + JSL Sprite_Move + JSR AdjustMovementSpeed + JSR KydreeokHead_NeckControl + JSR MoveWithBody + + ; JSL GetRandomInt : AND #$7F : BNE .no_attack + ; LDA #$CF + ; JSL Sprite_SpawnDynamically + ; JSL Sprite_SetSpawnedCoords + ; JSL $09B020 + ; LDA.b #$02 : STA $0D80, Y + ; LDA #$40 : STA.w SprTimerA, Y + ; RTS + ; .no_attack + + JSR RandomlyAttack + + JSL Sprite_IsToRightOfPlayer : TYA : BNE .not_right + %GotoAction(1) + .not_right + + RTS + } + + KydreeokHead_SideAnim: + { + %StartOnFrame(3) + %PlayAnimation(3,5,10) + + JSL Sprite_BounceFromTileCollision + + JSL Sprite_CheckDamageFromPlayerLong + %DoDamageToPlayerSameLayerOnContact() + + LDA.w SprTimerA, X : BNE .noSpeedChange + JSL GetRandomInt : AND #$0F : TAY + LDA.w tableSpeed, Y : STA.w SprXSpeed, X + JSL GetRandomInt : AND #$0F : TAY + LDA.w tableSpeed, Y : STA.w SprYSpeed, X + ; LDA #$40 : STA.w SprTimerA, X + .noSpeedChange + + + JSL Sprite_Move + JSR AdjustMovementSpeed + JSR KydreeokHead_NeckControl + JSR MoveWithBody + + JSR RandomlyAttack + + JSL Sprite_IsToRightOfPlayer : TYA : BNE .not_right + RTS + .not_right + %GotoAction(0) + RTS + } + + KydreeokHead_SummonFire: + { + ; %StartOnFrame(5) + ; %PlayAnimation(5,5,10) + %MoveTowardPlayer(24) + + JSL Sprite_CheckDamageFromPlayerLong + %DoDamageToPlayerSameLayerOnContact() + + JSR Sprite_Twinrova_FireAttack + + JSL Sprite_Move + + LDA SprTimerA, X : BNE .not_done + LDA #$00 : STA $0DD0, X + + .not_done + RTS + } + +} + +RandomlyAttack: +{ + JSL GetRandomInt : AND #$7F : BNE .no_attack + CLC + JSL GetRandomInt : AND #$0F : BNE .no_attack + LDA #$CF + JSL Sprite_SpawnDynamically + JSL Sprite_SetSpawnedCoords + LDA.b #$02 : STA $0D80, Y + LDA #$10 : STA.w SprTimerA, Y +.no_attack + + RTS +} + +Offspring1_Neck1_X = $19EA +Offspring1_Neck2_X = $19EC +Offspring1_Neck3_X = $19EE + +Offspring1_Neck1_Y = $19EB +Offspring1_Neck2_Y = $19ED +Offspring1_Neck3_Y = $19EF + +Offspring2_Neck1_X = $19F0 +Offspring2_Neck2_X = $19F2 +Offspring2_Neck3_X = $19F4 + +Offspring2_Neck1_Y = $19F1 +Offspring2_Neck2_Y = $19F3 +Offspring2_Neck3_Y = $19F5 + +MoveWithBody: +{ + LDA Kydreeok_Id : TAY + + CPX.w Offspring2_Id : BEQ .DoMove + ; The first neck + LDA.w SprX, Y : SEC : SBC #$0F + ; STA.w SprX, X + STA.w SprMiscA, X + STA.w $19EA + ; STA.w $19EC + ; STA.w $19EE + + LDA.w SprY, Y : SEC : SBC #$0F + ; STA.w SprY, X + STA.w SprMiscB, X + STA.w $19EB + ; STA.w $19ED + ; STA.w $19EF + + JMP .return +.DoMove + ; The other neck + LDA.w SprX, Y : CLC : ADC #$0C + ; STA.w SprX, X + STA.w SprMiscA, X + STA.w $19F0 + ; STA.w $19F2 + ; STA.w $19F4 + + LDA.w SprY, Y : SEC : SBC #$0F + ; STA.w SprY, X + STA.w SprMiscB, X + STA.w $19F1 + ; STA.w $19F3 + ; STA.w $19F5 +.return + JSR KydreeokHead_NeckControl + + RTS +} + + +AdjustMovementSpeed: +{ + LDA.w SprX, X : SEC : SBC #$16 ; X-32 + CMP.w SprMiscA, X : BCC .biggerthanorigin + LDA #-8 : STA.w SprXSpeed, X + .biggerthanorigin + + + LDA.w SprX, X : CLC : ADC #$16 ; X+32 + CMP.w SprMiscA, X : BCS .lowerthanorigin + LDA #$08 : STA.w SprXSpeed, X + .lowerthanorigin + + + LDA.w SprY, X : SEC : SBC #$00 ; X-32 + CMP.w SprMiscB, X : BCC .biggerthanorigin2 + LDA #-8 : STA.w SprYSpeed, X + .biggerthanorigin2 + + + LDA.w SprY, X : CLC : ADC #$20 ; X+32 + CMP.w SprMiscB, X : BCS .lowerthanorigin2 + LDA #$08 : STA.w SprYSpeed, X + .lowerthanorigin2 + + RTS +} + +tableSpeed: + db $00, $02, $04, $06, $07, $01, $06, $03 + db 0, -2, -4, -6, -7, -1, -6, -3 + +KydreeokHead_NeckControl: +{ + LDA.w SprSubtype, X : BEQ .DoNeck1 + JMP .DoNeck2 + .DoNeck1 + LDA.w SprX, X : STA.w SprMiscC, X + LDA.w SprY, X : STA.w SprMiscD, X + LDA.w SprXSpeed, X : STA $08 + LDA.w SprYSpeed, X : STA $09 + + LDA.w $19EA : STA $02 ; x + LDA.w $19EB : STA $03 ; y + LDA.w SprX, X : STA $04 + LDA.w SprY, X : STA $05 + JSR GetDistance8bit : CMP #$08 : BCC .TooCloseToHead ; is body1 too close to the head? + + LDA.w SprX, X : STA $04 ; dest X + LDA.w SprXH, X : STA $05 ; dest XH + LDA.w SprY, X : STA $06 ; dest Y + LDA.w SprYH, X : STA $07 ; dest YH + + ;load body position into sprite position + LDA.w $19EA : STA.w SprX, X + LDA.w $19EB : STA.w SprY, X + + LDA #$06 + JSL Sprite_ProjectSpeedTowardsEntityLong + LDA.b $01 : STA.w SprXSpeed, X + LDA.b $00 : STA.w SprYSpeed, X + JSL Sprite_MoveLong + + LDA.w SprX, X : STA.w $19EA + LDA.w SprY, X : STA.w $19EB + + .TooCloseToHead + + ; Do body part 2 + + LDA.w $19EC : STA $02 ; x + LDA.w $19ED : STA $03 ; y + LDA.w $19EA : STA $04 + LDA.w $19EB : STA $05 + JSR GetDistance8bit : CMP #$0D : BCC .TooCloseToBodyPart1 ; is body1 too close to the head? + + LDA.w $19EA : STA $04 ; dest X + LDA.w SprXH, X : STA $05 ; dest XH + LDA.w $19EB : STA $06 ; dest Y + LDA.w SprYH, X : STA $07 ; dest YH + + ;load body position into sprite position + LDA.w $19EC : STA.w SprX, X + LDA.w $19ED : STA.w SprY, X + + LDA #$06 + JSL Sprite_ProjectSpeedTowardsEntityLong + LDA.b $01 : STA.w SprXSpeed, X + LDA.b $00 : STA.w SprYSpeed, X + JSL Sprite_MoveLong + + LDA.w SprX, X : STA.w $19EC + LDA.w SprY, X : STA.w $19ED + + .TooCloseToBodyPart1 + + ; Do body part 2 + + LDA.w $19EE : STA $02 ; x + LDA.w $19EF : STA $03 ; y + LDA.w $19EC : STA $04 + LDA.w $19ED : STA $05 + JSR GetDistance8bit : CMP #$14 : BCC .TooCloseToBodyPart2 ; is body1 too close to the head? + + LDA.w $19EC : STA $04 ; dest X + LDA.w SprXH, X : STA $05 ; dest XH + LDA.w $19ED : STA $06 ; dest Y + LDA.w SprYH, X : STA $07 ; dest YH + ;load body position into sprite position + LDA.w $19EE : STA.w SprX, X + LDA.w $19EF : STA.w SprY, X + + LDA #$06 + JSL Sprite_ProjectSpeedTowardsEntityLong + LDA.b $01 : STA.w SprXSpeed, X + LDA.b $00 : STA.w SprYSpeed, X + JSL Sprite_MoveLong + LDA.w SprX, X : STA.w $19EE + LDA.w SprY, X : STA.w $19EF + + .TooCloseToBodyPart2 + + LDA.w SprMiscC, X : STA.w SprX, X + LDA.w SprMiscD, X : STA.w SprY, X + LDA.b $08 : STA.w SprXSpeed, X + LDA.b $09 : STA.w SprYSpeed, X + + ; Set head pos + LDA $19EE : STA SprX, X + LDA $19EF : CLC : SBC #$10 : STA SprY, X + RTS + + ; ========================================================= + + .DoNeck2 + + LDA.w SprX, X : STA.w SprMiscC, X + LDA.w SprY, X : STA.w SprMiscD, X + LDA.w SprXSpeed, X : STA $08 + LDA.w SprYSpeed, X : STA $09 + + LDA.w $19F0 : STA $02 ; x + LDA.w $19F1 : STA $03 ; y + LDA.w SprX, X : STA $04 + LDA.w SprY, X : STA $05 + JSR GetDistance8bit : CMP #$08 : BCC .TooCloseToHead2 ; is body1 too close to the head? + + LDA.w SprX, X : STA $04 ; dest X + LDA.w SprXH, X : STA $05 ; dest XH + LDA.w SprY, X : STA $06 ; dest Y + LDA.w SprYH, X : STA $07 ; dest YH + ;load body position into sprite position + LDA.w $19F0 : STA.w SprX, X + LDA.w $19F1 : STA.w SprY, X + + LDA #$08 + JSL Sprite_ProjectSpeedTowardsEntityLong + LDA.b $01 : STA.w SprXSpeed, X + LDA.b $00 : STA.w SprYSpeed, X + JSL Sprite_MoveLong + LDA.w SprX, X : STA.w $19F0 + LDA.w SprY, X : STA.w $19F1 + + .TooCloseToHead2 + LDA.w $19F2 : STA $02 ; x + LDA.w $19F3 : STA $03 ; y + LDA.w $19F0 : STA $04 + LDA.w $19F1 : STA $05 + JSR GetDistance8bit : CMP #$0D : BCC .TooCloseToBodyPart12 ; is body1 too close to the head? + + LDA.w $19F0 : STA $04 ; dest X + LDA.w SprXH, X : STA $05 ; dest XH + LDA.w $19F1 : STA $06 ; dest Y + LDA.w SprYH, X : STA $07 ; dest YH + ;load body position into sprite position + LDA.w $19F2 : STA.w SprX, X + LDA.w $19F3 : STA.w SprY, X + + LDA #$04 + JSL Sprite_ProjectSpeedTowardsEntityLong + LDA.b $01 : STA.w SprXSpeed, X + LDA.b $00 : STA.w SprYSpeed, X + JSL Sprite_MoveLong + LDA.w SprX, X : STA.w $19F2 + LDA.w SprY, X : STA.w $19F3 + + .TooCloseToBodyPart12 + + ; Do body part 2 + + LDA.w $19F4 : STA $02 ; x + LDA.w $19F5 : STA $03 ; y + LDA.w $19F2 : STA $04 + LDA.w $19F3 : STA $05 + JSR GetDistance8bit : CMP #$14 : BCC .TooCloseToBodyPart22 ; is body1 too close to the head? + + LDA.w $19F2 : STA $04 ; dest X + LDA.w SprXH, X : STA $05 ; dest XH + LDA.w $19F3 : STA $06 ; dest Y + LDA.w SprYH, X : STA $07 ; dest YH + ;load body position into sprite position + LDA.w $19F4 : STA.w SprX, X + LDA.w $19F5 : STA.w SprY, X + + LDA #$03 + JSL Sprite_ProjectSpeedTowardsEntityLong + LDA.b $01 : STA.w SprXSpeed, X + LDA.b $00 : STA.w SprYSpeed, X + JSL Sprite_MoveLong + LDA.w SprX, X : STA.w $19F4 + LDA.w SprY, X : STA.w $19F5 + + .TooCloseToBodyPart22 + LDA.w SprMiscC, X : STA.w SprX, X + LDA.w SprMiscD, X : STA.w SprY, X + LDA.b $08 : STA.w SprXSpeed, X + LDA.b $09 : STA.w SprYSpeed, X + + ; Set head pos + LDA $19F4 : STA SprX, X + LDA $19F5 : CLC : SBC #$10 : STA SprY, X + + RTS +} + + + +Sprite_KydreeokHead_DrawNeck: +{ + .start_index + db $12 + .nbr_of_tiles + db 0 + .x_offsets + dw 0 + .y_offsets + dw 0 + .chr + db $2E + .properties + db $39 + .sizes + db $02 +} + +; ========================================================= + +Sprite_KydreeokHead_Draw: +{ + JSL Sprite_PrepOamCoord + JSL Sprite_OAM_AllocateDeferToPlayer + + LDA $0DC0, X : CLC : ADC $0D90, X : TAY;Animation Frame + LDA .start_index, Y : STA $06 + + PHX + ; amount of tiles - 1 + LDX .nbr_of_tiles, Y : LDY.b #$00 + .next_tile + + PHX ; Save current Tile Index? + + ; Add Animation Index Offset + TXA : CLC : ADC $06 + + ; Keep the value with animation index offset? + PHA : ASL A : TAX + + REP #$20 + + LDA $00 : CLC : ADC .x_offsets, X : 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 : STA ($90), Y + + PHY + + TYA : LSR #2 : TAY + LDA .sizes, X : ORA $0F : STA ($92), Y ; store size in oam buffer + PLY : INY + PLX : DEX : BPL .next_tile + + PLX + + { + ; Dumb draw neck code + LDA.w SprSubtype, X : BNE .neck2 + + LDA.w $19EA : STA.w $0FD8 + LDA.w $19EB : STA.w $0FDA + JSR .DrawNeckPart + + + LDA.w $19EC : STA.w $0FD8 + LDA.w $19ED : STA.w $0FDA + JSR .DrawNeckPart + + LDA.w $19EE : STA.w $0FD8 + LDA.w $19EF : STA.w $0FDA + JSR .DrawNeckPart + + BRA .skipNeck + .neck2 + ; Dumb draw neck code + LDA.w $19F0 : STA.w $0FD8 + LDA.w $19F1 : STA.w $0FDA + JSR .DrawNeckPart + + LDA.w $19F2 : STA.w $0FD8 + LDA.w $19F3 : STA.w $0FDA + JSR .DrawNeckPart + + LDA.w $19F4 : STA.w $0FD8 + LDA.w $19F5 : STA.w $0FDA + JSR .DrawNeckPart + + .skipNeck + + LDA.b $08 : STA.w $0FD8 + LDA.b $09 : STA.w $0FDA + .skipNeck2 + RTS + + + + .DrawNeckPart + PHY + JSL Sprite_PrepOamCoord + PLY + + REP #$20 + + LDA $00 : STA ($90), Y + AND.w #$0100 : STA $0E + INY + LDA $02 : STA ($90), Y + CLC : ADC #$0010 : CMP.w #$0100 + SEP #$20 + BCC .on_screen_y2 + + LDA.b #$F0 : STA ($90), Y ;Put the sprite out of the way + STA $0E + .on_screen_y2 + + INY + LDA #$2E : STA ($90), Y + INY + LDA #$39 : STA ($90), Y + + PHY + + TYA : LSR #2 : TAY + + LDA #$02 : ORA $0F : STA ($92), Y ; store size in oam buffer + + PLY : INY + + RTS + } + + RTS + + .start_index + db $00, $02, $04, $06, $0A, $0E + .nbr_of_tiles + db 1, 1, 1, 3, 3, 3 + .x_offsets + dw 0, 0 + dw 0, 0 + dw 0, 0 + dw 8, -8, -8, 8 + dw 8, -8, -8, 8 + dw 8, -8, -8, 8 + .y_offsets + dw -8, 8 + dw -8, 8 + dw -8, 8 + dw 4, 4, -12, -12 + dw -8, -8, 8, 8 + dw -8, -8, 8, 8 + .chr + db $40, $60 + db $42, $62 + db $44, $64 + db $68, $66, $46, $48 + db $0A, $08, $28, $2A + db $4C, $4A, $6A, $6C + .properties + db $39, $39 + db $39, $39 + db $39, $39 + db $39, $39, $39, $39 + db $39, $39, $39, $39 + db $39, $39, $39, $39 + .sizes + db $02, $02 + db $02, $02 + db $02, $02 + db $02, $02, $02, $02 + db $02, $02, $02, $02 + db $02, $02, $02, $02 +} + +GetDistance8bit: +{ + LDA $04 ; Sprite X + SEC : SBC $02 ; - Player X + BPL + + EOR.b #$FF : INC + + + STA $00 ; Distance X (ABS) + + LDA $05 ; Sprite Y + SEC : SBC $03 ; - Player Y + BPL + + EOR.b #$FF : INC + + + ; Add it back to X Distance + CLC : ADC $00 : STA $00 ; distance total X, Y (ABS) + RTS +} diff --git a/Sprites/all_sprites.asm b/Sprites/all_sprites.asm index d2ff9fd..9b09558 100644 --- a/Sprites/all_sprites.asm +++ b/Sprites/all_sprites.asm @@ -75,6 +75,9 @@ print "End of minecart.asm ", pc incsrc "Sprites/Bosses/twinrova.asm" print "End of twinrova.asm ", pc +incsrc "Sprites/Bosses/kydreeok.asm" +incsrc "Sprites/Bosses/kydreeok_head.asm" + incsrc "Sprites/deku_leaf.asm" incsrc "Sprites/portal_sprite.asm"