diff --git a/src/actor.asm b/src/actor.asm index 9ed7d2f..f3a2380 100644 --- a/src/actor.asm +++ b/src/actor.asm @@ -34,6 +34,7 @@ .IMPORT FuncA_Actor_TickBadCrab .IMPORT FuncA_Actor_TickBadFirefly .IMPORT FuncA_Actor_TickBadFish +.IMPORT FuncA_Actor_TickBadFlower .IMPORT FuncA_Actor_TickBadFlydrop .IMPORT FuncA_Actor_TickBadGhostMermaid .IMPORT FuncA_Actor_TickBadGhostOrc @@ -92,6 +93,7 @@ .IMPORT FuncA_Objects_DrawActorBadCrab .IMPORT FuncA_Objects_DrawActorBadFirefly .IMPORT FuncA_Objects_DrawActorBadFish +.IMPORT FuncA_Objects_DrawActorBadFlower .IMPORT FuncA_Objects_DrawActorBadFlydrop .IMPORT FuncA_Objects_DrawActorBadGhostMermaid .IMPORT FuncA_Objects_DrawActorBadGhostOrc @@ -480,6 +482,7 @@ _NoHit: d_byte BadCrab, 6 d_byte BadFirefly, 6 d_byte BadFish, 6 + d_byte BadFlower, 14 d_byte BadFlydrop, 6 d_byte BadGhostMermaid, 13 d_byte BadGhostOrc, kOrcBoundingBoxUp @@ -548,6 +551,7 @@ _NoHit: d_byte BadCrab, 8 d_byte BadFirefly, 8 d_byte BadFish, 4 + d_byte BadFlower, 8 d_byte BadFlydrop, 6 d_byte BadGhostMermaid, 7 d_byte BadGhostOrc, kOrcBoundingBoxDown @@ -616,6 +620,7 @@ _NoHit: d_byte BadCrab, 7 d_byte BadFirefly, 6 d_byte BadFish, 6 + d_byte BadFlower, 12 d_byte BadFlydrop, 6 d_byte BadGhostMermaid, 6 d_byte BadGhostOrc, kOrcBoundingBoxSide @@ -752,6 +757,7 @@ _TypeSpecificTick: d_entry table, BadCrab, FuncA_Actor_TickBadCrab d_entry table, BadFirefly, FuncA_Actor_TickBadFirefly d_entry table, BadFish, FuncA_Actor_TickBadFish + d_entry table, BadFlower, FuncA_Actor_TickBadFlower d_entry table, BadFlydrop, FuncA_Actor_TickBadFlydrop d_entry table, BadGhostMermaid, FuncA_Actor_TickBadGhostMermaid d_entry table, BadGhostOrc, FuncA_Actor_TickBadGhostOrc @@ -925,6 +931,7 @@ _Finish: d_entry table, eActor::BadCrab, Func_InitActorDefault d_entry table, eActor::BadFirefly, FuncA_Room_InitActorBadFirefly d_entry table, eActor::BadFish, Func_InitActorWithFlags + d_entry table, eActor::BadFlower, Func_InitActorDefault d_entry table, eActor::BadFlydrop, FuncA_Room_InitActorBadFlydrop d_entry table, eActor::BadGhostMermaid, Func_InitActorWithState1 d_entry table, eActor::BadGhostOrc, Func_InitActorWithState1 @@ -994,6 +1001,7 @@ _Finish: d_entry table, BadCrab, FuncA_Objects_DrawActorBadCrab d_entry table, BadFirefly, FuncA_Objects_DrawActorBadFirefly d_entry table, BadFish, FuncA_Objects_DrawActorBadFish + d_entry table, BadFlower, FuncA_Objects_DrawActorBadFlower d_entry table, BadFlydrop, FuncA_Objects_DrawActorBadFlydrop d_entry table, BadGhostMermaid, FuncA_Objects_DrawActorBadGhostMermaid d_entry table, BadGhostOrc, FuncA_Objects_DrawActorBadGhostOrc diff --git a/src/actor.inc b/src/actor.inc index 0df5f6f..dd1a439 100644 --- a/src/actor.inc +++ b/src/actor.inc @@ -32,6 +32,7 @@ kMaxActors = 16 BadCrab ; moves left/right randomly on a floor BadFirefly ; flies up and down, and shoots horizontally BadFish ; swims back and forth in water + BadFlower ; grows and shoots fireballs BadFlydrop ; flies left/right randomly, and drops acid BadGhostMermaid ; part of the shadow boss BadGhostOrc ; part of the shadow boss diff --git a/src/actors/explosion.asm b/src/actors/explosion.asm index b1b9475..98abaf3 100644 --- a/src/actors/explosion.asm +++ b/src/actors/explosion.asm @@ -30,7 +30,9 @@ .IMPORT FuncA_Objects_MoveShapeUpByA .IMPORT FuncA_Objects_MoveShapeUpOneTile .IMPORT FuncA_Objects_SetShapePosToActorCenter +.IMPORT Func_FindEmptyActorSlot .IMPORT Func_InitActorDefault +.IMPORT Func_SetActorCenterToPoint .IMPORT Ram_ActorState1_byte_arr .IMPORT Ram_ActorType_eActor_arr @@ -58,6 +60,23 @@ kPaletteObjExplosion = 0 ;;;=========================================================================;;; +.SEGMENT "PRGA_Room" + +;;; Spawns a new smoke explosion actor (if possible), starting it at the +;;; room pixel position stored in Zp_PointX_i16 and Zp_PointY_i16. +;;; @preserve T0+ +.EXPORT FuncA_Room_SpawnExplosionAtPoint +.PROC FuncA_Room_SpawnExplosionAtPoint + jsr Func_FindEmptyActorSlot ; preserves T0+, returns C and X + bcs @done + jsr Func_SetActorCenterToPoint ; preserves X and T0+ + jmp Func_InitActorSmokeExplosion ; preserves T0+ + @done: + rts +.ENDPROC + +;;;=========================================================================;;; + .SEGMENT "PRGA_Actor" ;;; Performs per-frame updates for a smoke explosion actor. diff --git a/src/actors/flower.asm b/src/actors/flower.asm new file mode 100644 index 0000000..fab2834 --- /dev/null +++ b/src/actors/flower.asm @@ -0,0 +1,449 @@ +;;;=========================================================================;;; +;;; Copyright 2022 Matthew D. Steele ;;; +;;; ;;; +;;; This file is part of Annalog. ;;; +;;; ;;; +;;; Annalog is free software: you can redistribute it and/or modify it ;;; +;;; under the terms of the GNU General Public License as published by the ;;; +;;; Free Software Foundation, either version 3 of the License, or (at your ;;; +;;; option) any later version. ;;; +;;; ;;; +;;; Annalog is distributed in the hope that it will be useful, but WITHOUT ;;; +;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ;;; +;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ;;; +;;; for more details. ;;; +;;; ;;; +;;; You should have received a copy of the GNU General Public License along ;;; +;;; with Annalog. If not, see . ;;; +;;;=========================================================================;;; + +.INCLUDE "../devices/flower.inc" +.INCLUDE "../macros.inc" +.INCLUDE "../oam.inc" +.INCLUDE "flower.inc" + +.IMPORT DataA_Objects_FlowerShape_sShapeTile_arr +.IMPORT FuncA_Actor_HarmAvatarIfCollision +.IMPORT FuncA_Actor_IsAvatarWithinHorzDistance +.IMPORT FuncA_Actor_IsAvatarWithinVertDistances +.IMPORT FuncA_Objects_DrawShapeTiles +.IMPORT FuncA_Objects_SetShapePosToActorCenter +.IMPORT Func_FindEmptyActorSlot +.IMPORT Func_GetRandomByte +.IMPORT Func_InitActorProjFireball +.IMPORT Func_MovePointRightByA +.IMPORT Func_MovePointUpByA +.IMPORT Func_PlaySfxShootFire +.IMPORT Func_SetActorCenterToPoint +.IMPORT Func_SetPointToActorCenter +.IMPORT Ram_ActorState1_byte_arr +.IMPORT Ram_ActorState2_byte_arr +.IMPORT Ram_ActorState3_byte_arr + +;;;=========================================================================;;; + +;;; The number of VBlank frames between each animation frame of a flower +;;; baddie's transformation. +.DEFINE kBadFlowerAnimationSlowdown 8 + +;;; The number of VBlank frames it takes for a flower baddie to transform. +kBadFlowerTransformFrames = 4 * kBadFlowerAnimationSlowdown - 1 + +;;; The time between shots when a flower baddie is attacking, in frames. +.DEFINE kBadFlowerShotCooldownFrames 16 + +;;; How many projectiles a flower baddie shoots per attack wave. +kBadFlowerNumShots = 4 + +;;; The time between when a flower baddie decides to attack and when it starts +;;; shooting, in frames. +kBadFlowerWindupFrames = 30 + +;;; The total time for a full attack wave from a flower baddie, in frames. +.LINECONT + +kBadFlowerAttackFrames = \ + kBadFlowerShotCooldownFrames * kBadFlowerNumShots + kBadFlowerWindupFrames +.LINECONT - + +;;;=========================================================================;;; + +.SEGMENT "PRGA_Actor" + +;;; Performs per-frame updates for a flower baddie actor. +;;; @param X The actor index. +;;; @preserve X +.EXPORT FuncA_Actor_TickBadFlower +.PROC FuncA_Actor_TickBadFlower + jsr FuncA_Actor_HarmAvatarIfCollision ; preserves X + ;; Execute mode-specific behavior. + ldy Ram_ActorState1_byte_arr, x ; current eBadFlower mode + lda _JumpTable_ptr_0_arr, y + sta T0 + lda _JumpTable_ptr_1_arr, y + sta T1 + jmp (T1T0) +.REPEAT 2, table + D_TABLE_LO table, _JumpTable_ptr_0_arr + D_TABLE_HI table, _JumpTable_ptr_1_arr + D_TABLE .enum, eBadFlower + d_entry table, Dormant, FuncA_Actor_TickBadFlower_Dormant + d_entry table, Growing, FuncA_Actor_TickBadFlower_Growing + d_entry table, Ready, FuncA_Actor_TickBadFlower_Ready + d_entry table, Attacking, FuncA_Actor_TickBadFlower_Attacking + d_entry table, Shrinking, FuncA_Actor_TickBadFlower_Shrinking + D_END +.ENDREPEAT +.ENDPROC + +;;; Performs per-frame updates for a flower baddie actor that's in Dormant +;;; mode. +;;; @param X The actor index. +;;; @preserve X +.PROC FuncA_Actor_TickBadFlower_Dormant + ;; Check if the player avatar is nearby; if not, stay dormant. + lda #$20 ; param: distance above avatar + tay ; param: distance below avatar + jsr FuncA_Actor_IsAvatarWithinVertDistances ; preserves X, returns C + bcc _Return ; avatar is too far away vertically + lda #$50 ; param: distance + jsr FuncA_Actor_IsAvatarWithinHorzDistance ; preserves X, returns C + bcc _Return ; avatar is too far away horizontally +_StartGrowing: + ;; TODO: play a sound + .assert eBadFlower::Growing = eBadFlower::Dormant + 1, error + inc Ram_ActorState1_byte_arr, x ; current eBadFlower mode +_Return: + rts +.ENDPROC + +;;; Performs per-frame updates for a flower baddie actor that's in Growing +;;; mode. +;;; @param X The actor index. +;;; @preserve X +.PROC FuncA_Actor_TickBadFlower_Growing + lda Ram_ActorState2_byte_arr, x ; mode timer + cmp #kBadFlowerTransformFrames + bge @ready + @grow: + inc Ram_ActorState2_byte_arr, x ; mode timer + lda Ram_ActorState2_byte_arr, x ; mode timer + div #kBadFlowerAnimationSlowdown + sta Ram_ActorState3_byte_arr, x ; animation pose + rts + @ready: + .assert eBadFlower::Ready = eBadFlower::Growing + 1, error + inc Ram_ActorState1_byte_arr, x ; current eBadFlower mode + lda #1 + sta Ram_ActorState2_byte_arr, x ; mode timer + rts +.ENDPROC + +;;; Performs per-frame updates for a flower baddie actor that's in Ready mode. +;;; @param X The actor index. +;;; @preserve X +.PROC FuncA_Actor_TickBadFlower_Ready +_CoolDown: + dec Ram_ActorState2_byte_arr, x ; mode timer + bne _Return +_ChangeModes: + ;; Check if the player avatar is nearby; if so, attack, otherwise shrink. + lda #$3c ; param: distance above avatar + tay ; param: distance below avatar + jsr FuncA_Actor_IsAvatarWithinVertDistances ; preserves X, returns C + bcc _StartShrinking ; avatar is too far away vertically +_StartAttacking: + lda #eBadFlower::Attacking + sta Ram_ActorState1_byte_arr, x ; current eBadFlower mode + lda #kBadFlowerAttackFrames + sta Ram_ActorState2_byte_arr, x ; mode timer + rts +_StartShrinking: + ;; TODO: play a sound + lda #eBadFlower::Shrinking + sta Ram_ActorState1_byte_arr, x ; current eBadFlower mode + lda #kBadFlowerTransformFrames + sta Ram_ActorState2_byte_arr, x ; mode timer +_Return: + rts +.ENDPROC + +;;; Performs per-frame updates for a flower baddie actor that's in Attacking +;;; mode. +;;; @param X The actor index. +;;; @preserve X +.PROC FuncA_Actor_TickBadFlower_Attacking + lda #4 + sta Ram_ActorState3_byte_arr, x ; animation pose + dec Ram_ActorState2_byte_arr, x ; mode timer + bne _ContinueAttacking +_FinishAttacking: + .assert eBadFlower::Ready = eBadFlower::Attacking - 1, error + dec Ram_ActorState1_byte_arr, x ; current eBadFlower mode + lda #60 + sta Ram_ActorState2_byte_arr, x ; mode timer + lda #3 + sta Ram_ActorState3_byte_arr, x ; animation pose + rts +_ContinueAttacking: + lda Ram_ActorState2_byte_arr, x ; mode timer + cmp #kBadFlowerShotCooldownFrames * kBadFlowerNumShots + 1 + bge _Return ; still winding up + mod #kBadFlowerShotCooldownFrames + bne _Return ; still cooling down +_ShootFireball: + jsr Func_SetPointToActorCenter ; preserves X + lda #22 + jsr Func_MovePointRightByA ; preserves X + lda #7 + jsr Func_MovePointUpByA ; preserves X + stx T3 ; flower actor index + jsr Func_FindEmptyActorSlot ; preserves T0+, returns C and X + bcs @done + jsr Func_SetActorCenterToPoint ; preserves X and T0+ + jsr Func_GetRandomByte ; preserves X and T0+, returns A + mod #16 + sub #8 ; param: aim angle + jsr Func_InitActorProjFireball ; preserves X and T3+ + jsr Func_PlaySfxShootFire ; preserves T0+ + @done: + ldx T3 +_Return: + rts +.ENDPROC + +;;; Performs per-frame updates for a flower baddie actor that's in Shrinking +;;; mode. +;;; @param X The actor index. +;;; @preserve X +.PROC FuncA_Actor_TickBadFlower_Shrinking + dec Ram_ActorState2_byte_arr, x ; mode timer + lda Ram_ActorState2_byte_arr, x ; mode timer + beq @becomeDormant + div #kBadFlowerAnimationSlowdown + bpl @setAnimationPose ; unconditional + @becomeDormant: + ;; At this point, A is zero. + .assert eBadFlower::Dormant = 0, error + sta Ram_ActorState1_byte_arr, x ; current eBadFlower mode + @setAnimationPose: + sta Ram_ActorState3_byte_arr, x ; animation pose + rts +.ENDPROC + +;;;=========================================================================;;; + +.SEGMENT "PRGA_Objects" + +.PROC DataA_Objects_BadFlowerShape1_sShapeTile_arr + D_STRUCT sShapeTile + d_byte DeltaX_i8, 0 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 1 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 0 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, <-8 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 2 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 1 + d_byte DeltaY_i8, <-4 + d_byte Flags_bObj, kPaletteObjFlowerTop | bObj::Final + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 19 + D_END +.ENDPROC + +.PROC DataA_Objects_BadFlowerShape2_sShapeTile_arr + D_STRUCT sShapeTile + d_byte DeltaX_i8, 0 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 5 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 4 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 16 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 6 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-8 + d_byte DeltaY_i8, <-8 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 7 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 3 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-8 + d_byte DeltaY_i8, <-8 + d_byte Flags_bObj, kPaletteObjFlowerTop + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 20 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerTop | bObj::Final + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 21 + D_END +.ENDPROC + +.PROC DataA_Objects_BadFlowerShape3_sShapeTile_arr + D_STRUCT sShapeTile + d_byte DeltaX_i8, 0 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 9 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 8 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 16 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 10 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-8 + d_byte DeltaY_i8, <-8 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 12 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 13 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 14 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-16 + d_byte DeltaY_i8, <-8 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 11 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerTop + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 22 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerTop | bObj::Final + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 23 + D_END +.ENDPROC + +.PROC DataA_Objects_BadFlowerShape4_sShapeTile_arr + D_STRUCT sShapeTile + d_byte DeltaX_i8, 0 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 9 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 8 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 16 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 10 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-8 + d_byte DeltaY_i8, <-8 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 16 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 17 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 18 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-16 + d_byte DeltaY_i8, <-8 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 15 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerTop + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 24 + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 8 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerTop | bObj::Final + d_byte Tile_u8, kTileIdObjBadFlowerFirst + 25 + D_END +.ENDPROC + +;;; Draws a flower baddie actor. +;;; @param X The actor index. +;;; @preserve X +.EXPORT FuncA_Objects_DrawActorBadFlower +.PROC FuncA_Objects_DrawActorBadFlower + jsr FuncA_Objects_SetShapePosToActorCenter ; preserves X + ldy Ram_ActorState3_byte_arr, x ; animation pose + lda _Shapes_sShapeTile_arr_ptr_0_arr, y + pha ; sShapeTile arr ptr (lo) + lda _Shapes_sShapeTile_arr_ptr_1_arr, y + tay ; sShapeTile arr ptr (hi) + pla ; sShapeTile arr ptr (lo) + jmp FuncA_Objects_DrawShapeTiles ; preserves X +.REPEAT 2, table + D_TABLE_LO table, _Shapes_sShapeTile_arr_ptr_0_arr + D_TABLE_HI table, _Shapes_sShapeTile_arr_ptr_1_arr + D_TABLE 5 + d_entry table, 0, DataA_Objects_FlowerShape_sShapeTile_arr + d_entry table, 1, DataA_Objects_BadFlowerShape1_sShapeTile_arr + d_entry table, 2, DataA_Objects_BadFlowerShape2_sShapeTile_arr + d_entry table, 3, DataA_Objects_BadFlowerShape3_sShapeTile_arr + d_entry table, 4, DataA_Objects_BadFlowerShape4_sShapeTile_arr + D_END +.ENDREPEAT +.ENDPROC + +;;;=========================================================================;;; diff --git a/src/actors/flower.inc b/src/actors/flower.inc new file mode 100644 index 0000000..cda66a8 --- /dev/null +++ b/src/actors/flower.inc @@ -0,0 +1,44 @@ +;;;=========================================================================;;; +;;; Copyright 2022 Matthew D. Steele ;;; +;;; ;;; +;;; This file is part of Annalog. ;;; +;;; ;;; +;;; Annalog is free software: you can redistribute it and/or modify it ;;; +;;; under the terms of the GNU General Public License as published by the ;;; +;;; Free Software Foundation, either version 3 of the License, or (at your ;;; +;;; option) any later version. ;;; +;;; ;;; +;;; Annalog is distributed in the hope that it will be useful, but WITHOUT ;;; +;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ;;; +;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ;;; +;;; for more details. ;;; +;;; ;;; +;;; You should have received a copy of the GNU General Public License along ;;; +;;; with Annalog. If not, see . ;;; +;;;=========================================================================;;; + +;;; State bytes for flower baddies: +;;; * Param: Unused. +;;; * Flags: Unused. +;;; * State1: The eBadFlower value for the flower's current behavior mode. +;;; * State2: A timer for the current mode that increments or decrements each +;;; frame, depending on the mode. +;;; * State3: The current animation pose (0-4). +;;; * State4: Unused. + +;;; Tile IDs for drawing flower baddie actors. +kTileIdObjBadFlowerFirst = $e0 + +;;;=========================================================================;;; + +;;; Possible values for a flower baddie actor's State1 byte. +.ENUM eBadFlower + Dormant + Growing + Ready + Attacking + Shrinking + NUM_VALUES +.ENDENUM + +;;;=========================================================================;;; diff --git a/src/chr.asm b/src/chr.asm index 2431489..a2deea4 100644 --- a/src/chr.asm +++ b/src/chr.asm @@ -37,6 +37,7 @@ .INCLUDE "actors/firefly.inc" .INCLUDE "actors/fish.inc" .INCLUDE "actors/flamestrike.inc" +.INCLUDE "actors/flower.inc" .INCLUDE "actors/flydrop.inc" .INCLUDE "actors/goo.inc" .INCLUDE "actors/grenade.inc" @@ -1439,10 +1440,10 @@ _chr_begin: ;;;=========================================================================;;; -.SEGMENT "CHR_ObjShadow" +.SEGMENT "CHR_ObjShadow1" -.EXPORT Ppu_ChrObjShadow -.PROC Ppu_ChrObjShadow +.EXPORT Ppu_ChrObjShadow1 +.PROC Ppu_ChrObjShadow1 CHR2_BANK $80 chr_inc "proj_acid", kTileIdObjProjAcid chr_inc "emitter_light", kTileIdObjEmitterLight @@ -1467,6 +1468,24 @@ _chr_begin: ;;;=========================================================================;;; +.SEGMENT "CHR_ObjShadow2" + +.EXPORT Ppu_ChrObjShadow2 +.PROC Ppu_ChrObjShadow2 + CHR2_BANK $80 + chr_res $10 + chr_inc "bad_goo", kTileIdObjBadGooFirst + chr_res $24 + chr_inc "proj_fireball", kTileIdObjProjFireballFirst + chr_res $18 + chr_inc "laser", kTileIdObjLaserFirst + chr_inc "bad_flower", kTileIdObjBadFlowerFirst + chr_res $06 + END_CHR_BANK +.ENDPROC + +;;;=========================================================================;;; + .SEGMENT "CHR_ObjTemple" .EXPORT Ppu_ChrObjTemple diff --git a/src/devices/flower.asm b/src/devices/flower.asm index 717fff9..4cd278c 100644 --- a/src/devices/flower.asm +++ b/src/devices/flower.asm @@ -24,9 +24,8 @@ .INCLUDE "flower.inc" .IMPORT FuncA_Avatar_PlaySfxPickUpFlower -.IMPORT FuncA_Objects_Draw1x1Shape -.IMPORT FuncA_Objects_MoveShapeDownOneTile -.IMPORT FuncA_Objects_MoveShapeRightHalfTile +.IMPORT FuncA_Objects_DrawShapeTiles +.IMPORT FuncA_Objects_MoveShapeDownAndRightOneTile .IMPORT FuncA_Objects_SetShapePosToDeviceTopLeft .IMPORT Func_IsFlagSet .IMPORT Ppu_ChrObjAnnaFlower @@ -130,6 +129,24 @@ _KeepFlower: .SEGMENT "PRGA_Objects" +;;; Shape tile data for drawing flower devices (and the dormant state of flower +;;; baddies). +.EXPORT DataA_Objects_FlowerShape_sShapeTile_arr +.PROC DataA_Objects_FlowerShape_sShapeTile_arr + D_STRUCT sShapeTile + d_byte DeltaX_i8, <-4 + d_byte DeltaY_i8, 0 + d_byte Flags_bObj, kPaletteObjFlowerBottom + d_byte Tile_u8, kTileIdObjFlowerBottom + D_END + D_STRUCT sShapeTile + d_byte DeltaX_i8, 0 + d_byte DeltaY_i8, <-8 + d_byte Flags_bObj, kPaletteObjFlowerTop | bObj::Final + d_byte Tile_u8, kTileIdObjFlowerTop + D_END +.ENDPROC + ;;; Draws a flower device. ;;; @param X The device index. ;;; @preserve X @@ -137,20 +154,13 @@ _KeepFlower: .PROC FuncA_Objects_DrawDeviceFlower lda Ram_DeviceAnim_u8_arr, x and #$02 - bne _Return - jsr FuncA_Objects_SetShapePosToDeviceTopLeft ; preserves X - jsr FuncA_Objects_MoveShapeRightHalfTile ; preserves X -_AllocateUpperObject: - ldy #kPaletteObjFlowerTop ; param: object flags - lda #kTileIdObjFlowerTop ; param: tile ID - jsr FuncA_Objects_Draw1x1Shape ; preserves X -_AllocateLowerObject: - jsr FuncA_Objects_MoveShapeDownOneTile ; preserves X - ldy #kPaletteObjFlowerBottom ; param: object flags - lda #kTileIdObjFlowerBottom ; param: tile ID - jmp FuncA_Objects_Draw1x1Shape ; preserves X -_Return: + beq @draw rts + @draw: + jsr FuncA_Objects_SetShapePosToDeviceTopLeft ; preserves X + jsr FuncA_Objects_MoveShapeDownAndRightOneTile ; preserves X + ldya #DataA_Objects_FlowerShape_sShapeTile_arr + jmp FuncA_Objects_DrawShapeTiles ; preserves X .ENDPROC ;;;=========================================================================;;; diff --git a/src/linker.cfg b/src/linker.cfg index e350e91..0c4f9e9 100644 --- a/src/linker.cfg +++ b/src/linker.cfg @@ -349,8 +349,9 @@ SEGMENTS { CHR_ObjParley: load=CHR2_70, type=ro; CHR_ObjPause: load=CHR2_72, type=ro; CHR_ObjSewer: load=CHR2_74, type=ro; - CHR_ObjShadow: load=CHR2_76, type=ro; - CHR_ObjTemple: load=CHR2_78, type=ro; - CHR_ObjTown: load=CHR2_7A, type=ro; - CHR_ObjVillage: load=CHR2_7C, type=ro; + CHR_ObjShadow1: load=CHR2_76, type=ro; + CHR_ObjShadow2: load=CHR2_78, type=ro; + CHR_ObjTemple: load=CHR2_7A, type=ro; + CHR_ObjTown: load=CHR2_7C, type=ro; + CHR_ObjVillage: load=CHR2_7E, type=ro; } diff --git a/src/machines/laser.asm b/src/machines/laser.asm index 9f7465d..5388746 100644 --- a/src/machines/laser.asm +++ b/src/machines/laser.asm @@ -200,10 +200,10 @@ _Outside: @green: ldy Zp_MachineIndex_u8 eor Ram_MachineState1_byte_arr, y ; laser color (even=red, odd=green) - mod #2 - .assert eActor::BadGooRed .mod 2 = 0, error - .assert eActor::BadGooGreen .mod 2 = 1, error - beq @continue ; goo is same color as laser + mod #2 ; now A is 0 for red laser, or 1 for green laser + .assert eActor::BadGooRed .mod 2 = 1, error + .assert eActor::BadGooGreen .mod 2 = 0, error + bne @continue ; goo is same color as laser ;; If the laser isn't hitting this goo baddie, skip it. jsr Func_SetPointToActorCenter ; preserves X stx T2 ; actor index diff --git a/src/oam.asm b/src/oam.asm index edd8461..29c4ccd 100644 --- a/src/oam.asm +++ b/src/oam.asm @@ -783,4 +783,38 @@ _FinishAllocation: rts .ENDPROC +;;; Draws a list of tiles, starting at the current shape position. +;;; @param YA Pointer to the sShapeTile array. +;;; @preserve X +.EXPORT FuncA_Objects_DrawShapeTiles +.PROC FuncA_Objects_DrawShapeTiles + stya T5T4 ; sShapeTile array pointer + ldy #0 + @loop: + .assert sShapeTile::DeltaX_i8 = 0, error + lda (T5T4), y ; param: signed offset + jsr FuncA_Objects_MoveShapeHorz ; preserves X, Y, and T0+ + iny ; now Y is 1 mod .sizeof(sShapeTile) + .assert sShapeTile::DeltaY_i8 = 1, error + lda (T5T4), y ; param: signed offset + jsr FuncA_Objects_MoveShapeVert ; preserves X, Y, and T0+ + iny ; now Y is 2 mod .sizeof(sShapeTile) + .assert sShapeTile::Flags_bObj = 2, error + lda (T5T4), y + sta T3 ; object flags + iny ; now Y is 3 mod .sizeof(sShapeTile) + .assert sShapeTile::Tile_u8 = 3, error + lda (T5T4), y ; param: tile ID + sty T2 ; sShapeTile array byte offset + ldy T3 ; param: object flags + jsr FuncA_Objects_Draw1x1Shape ; preserves X and T2+ + ldy T2 ; sShapeTile array byte offset + .assert .sizeof(sShapeTile) = 4, error + iny ; now Y is 0 mod .sizeof(sShapeTile) + lda T3 ; object flags + and #bObj::Final + beq @loop + rts +.ENDPROC + ;;;=========================================================================;;; diff --git a/src/oam.inc b/src/oam.inc index 46ccbb0..118abb6 100644 --- a/src/oam.inc +++ b/src/oam.inc @@ -35,6 +35,7 @@ Hw_OamDma_wo = $4014 ;;;=========================================================================;;; +;;; One object slot in OAM. The field order is specified by the hardware. .STRUCT sObj YPos_u8 .byte Tile_u8 .byte @@ -44,11 +45,26 @@ Hw_OamDma_wo = $4014 ;;;=========================================================================;;; +;;; An entry in an array passed to FuncA_Objects_DrawShapeTiles. +.STRUCT sShapeTile + ;; Signed delta to move the shape position by before drawing this object. + DeltaX_i8 .byte + DeltaY_i8 .byte + ;; The flags to use for this object. If bObj::Final is set, then this is + ;; the last tile in the array. + Flags_bObj .byte + ;; The OBJ tile ID to use for this object. + Tile_u8 .byte +.ENDSTRUCT + +;;;=========================================================================;;; + .SCOPE bObj FlipV = %10000000 ; flip object vertically FlipH = %01000000 ; flip object horizontally FlipHV = %11000000 ; flip object both horizontally and vertically Pri = %00100000 ; draw object behind background + Final = %00010000 ; used by FuncA_Objects_DrawShapeTiles PaletteMask = %00000011 ; bits used for the OBJ palette number .ENDSCOPE diff --git a/src/rooms/boss_shadow.asm b/src/rooms/boss_shadow.asm index f51a9b4..1e8608e 100644 --- a/src/rooms/boss_shadow.asm +++ b/src/rooms/boss_shadow.asm @@ -69,7 +69,7 @@ .IMPORT Func_SetPointToPlatformCenter .IMPORT Func_ShakeRoom .IMPORT Func_WriteToLowerAttributeTable -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow1 .IMPORT Ram_ActorState1_byte_arr .IMPORT Ram_ActorState2_byte_arr .IMPORT Ram_MachineGoalHorz_u8_arr @@ -232,7 +232,7 @@ kPaletteObjFinalGhostHurt = 1 d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 2 d_addr Machines_sMachine_arr_ptr, _Machines_sMachine_arr - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow1) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: diff --git a/src/rooms/mermaid_spring.asm b/src/rooms/mermaid_spring.asm index b1e68c7..089c487 100644 --- a/src/rooms/mermaid_spring.asm +++ b/src/rooms/mermaid_spring.asm @@ -58,8 +58,8 @@ .IMPORT FuncA_Objects_MoveShapeRightOneTile .IMPORT FuncA_Objects_SetShapePosToPlatformTopLeft .IMPORT FuncA_Room_InitActorSmokeRaindrop +.IMPORT FuncA_Room_SpawnExplosionAtPoint .IMPORT Func_FindEmptyActorSlot -.IMPORT Func_InitActorSmokeExplosion .IMPORT Func_MovePlatformLeftTowardPointX .IMPORT Func_MovePlatformTopTowardPointY .IMPORT Func_MovePointLeftByA @@ -156,10 +156,10 @@ _Ext_sRoomExt: d_addr Actors_sActor_arr_ptr, _Actors_sActor_arr d_addr Devices_sDevice_arr_ptr, _Devices_sDevice_arr d_addr Passages_sPassage_arr_ptr, _Passages_sPassage_arr - d_addr Enter_func_ptr, DataA_Room_MermaidSpring_EnterRoom + d_addr Enter_func_ptr, FuncA_Room_MermaidSpring_EnterRoom d_addr FadeIn_func_ptr, Func_Noop - d_addr Tick_func_ptr, DataA_Room_MermaidSpring_TickRoom - d_addr Draw_func_ptr, DataC_Mermaid_Spring_DrawRoom + d_addr Tick_func_ptr, FuncA_Room_MermaidSpring_TickRoom + d_addr Draw_func_ptr, FuncC_Mermaid_Spring_DrawRoom D_END _TerrainData: : .incbin "out/rooms/mermaid_spring.room" @@ -288,7 +288,7 @@ _Passages_sPassage_arr: .assert * - :- <= kMaxPassages * .sizeof(sPassage), error .ENDPROC -.PROC DataC_Mermaid_Spring_DrawRoom +.PROC FuncC_Mermaid_Spring_DrawRoom ldx #kRocksPlatformIndex ; param: platform index jsr FuncA_Objects_DrawRocksPlatformHorz ldx #kMonitorPlatformIndex ; param: platform index @@ -370,7 +370,7 @@ _WaterWidth_u8_arr: rts .ENDPROC -.PROC DataA_Room_MermaidSpring_EnterRoom +.PROC FuncA_Room_MermaidSpring_EnterRoom _Alex: ;; If Alex isn't here yet, or the spring is drained, remove him. flag_bit Sram_ProgressFlags_arr, eFlag::CityOutskirtsTalkedToAlex @@ -419,7 +419,7 @@ _DrainSpring: rts .ENDPROC -.PROC DataA_Room_MermaidSpring_TickRoom +.PROC FuncA_Room_MermaidSpring_TickRoom ;; If the lever hasn't been flipped yet, do nothing. lda Zp_RoomState + sState::Lever_u8 beq @return @@ -463,16 +463,10 @@ _AnimateExplodingRocks: jsr Func_SetPointToPlatformCenter lda #kTileWidthPx jsr Func_MovePointLeftByA - jsr _SpawnExplosionAtPoint + jsr FuncA_Room_SpawnExplosionAtPoint lda #kTileWidthPx * 2 jsr Func_MovePointRightByA -_SpawnExplosionAtPoint: - jsr Func_FindEmptyActorSlot ; sets C on failure, returns X - bcs @done - jsr Func_SetActorCenterToPoint ; preserves X - jmp Func_InitActorSmokeExplosion - @done: - rts + jmp FuncA_Room_SpawnExplosionAtPoint _RaindropPosX_u8_arr: .byte $74, $84, $8c, $7c _RaindropVelY_u8_arr: diff --git a/src/rooms/mine_collapse.asm b/src/rooms/mine_collapse.asm index 87dd67d..7dff72b 100644 --- a/src/rooms/mine_collapse.asm +++ b/src/rooms/mine_collapse.asm @@ -116,7 +116,7 @@ _Ext_sRoomExt: d_addr Enter_func_ptr, Func_Noop d_addr FadeIn_func_ptr, Func_Noop d_addr Tick_func_ptr, Func_Noop - d_addr Draw_func_ptr, DataC_Mine_Collapse_DrawRoom + d_addr Draw_func_ptr, FuncC_Mine_Collapse_DrawRoom D_END _TerrainData: : .incbin "out/rooms/mine_collapse.room" @@ -211,7 +211,7 @@ _Passages_sPassage_arr: .assert * - :- <= kMaxPassages * .sizeof(sPassage), error .ENDPROC -.PROC DataC_Mine_Collapse_DrawRoom +.PROC FuncC_Mine_Collapse_DrawRoom ldx #eFlag::BreakerMine ; param: breaker flag jmp FuncA_Objects_AnimateCircuitIfBreakerActive .ENDPROC diff --git a/src/rooms/shadow_depths.asm b/src/rooms/shadow_depths.asm index 0be3ae0..bea73cd 100644 --- a/src/rooms/shadow_depths.asm +++ b/src/rooms/shadow_depths.asm @@ -35,7 +35,7 @@ .IMPORT FuncA_Room_GetDarknessZoneFade .IMPORT FuncA_Terrain_FadeInShortRoomWithLava .IMPORT Func_SetAndTransferBgFade -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow1 .IMPORT Ram_ActorType_eActor_arr .IMPORT Sram_ProgressFlags_arr .IMPORTZP Zp_GoalBg_eFade @@ -68,7 +68,7 @@ kDarknessZonePlatformIndex = 0 d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 0 d_addr Machines_sMachine_arr_ptr, 0 - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow1) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: diff --git a/src/rooms/shadow_descent.asm b/src/rooms/shadow_descent.asm index 374dee2..f272a23 100644 --- a/src/rooms/shadow_descent.asm +++ b/src/rooms/shadow_descent.asm @@ -33,7 +33,7 @@ .IMPORT FuncA_Terrain_FadeInTallRoomWithLava .IMPORT FuncC_Shadow_DrawBarrierPlatform .IMPORT Func_Noop -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow1 .IMPORT Ram_PlatformType_ePlatform_arr .IMPORT Sram_ProgressFlags_arr .IMPORTZP Zp_AvatarFlags_bObj @@ -76,7 +76,7 @@ kBarrierOpenTop = kBarrierShutTop - kBarrierPlatformHeightPx d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 0 d_addr Machines_sMachine_arr_ptr, 0 - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow1) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: diff --git a/src/rooms/shadow_drill.asm b/src/rooms/shadow_drill.asm index e7566d5..fe4c0b9 100644 --- a/src/rooms/shadow_drill.asm +++ b/src/rooms/shadow_drill.asm @@ -50,7 +50,7 @@ .IMPORT Func_SetFlag .IMPORT Func_SetMachineIndex .IMPORT Func_WriteToLowerAttributeTable -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow1 .IMPORT Ram_ActorType_eActor_arr .IMPORT Ram_MachineGoalHorz_u8_arr .IMPORT Ram_PlatformLeft_i16_0_arr @@ -103,7 +103,7 @@ kLaserInitPlatformLeft = \ d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 1 d_addr Machines_sMachine_arr_ptr, _Machines_sMachine_arr - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow1) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: diff --git a/src/rooms/shadow_flower.asm b/src/rooms/shadow_flower.asm index b58abb7..75c5e5e 100644 --- a/src/rooms/shadow_flower.asm +++ b/src/rooms/shadow_flower.asm @@ -18,6 +18,7 @@ ;;;=========================================================================;;; .INCLUDE "../actor.inc" +.INCLUDE "../actors/flower.inc" .INCLUDE "../charmap.inc" .INCLUDE "../device.inc" .INCLUDE "../devices/flower.inc" @@ -39,20 +40,34 @@ .IMPORT FuncA_Machine_ReachedGoal .IMPORT FuncA_Objects_DrawLaserMachine .IMPORT FuncA_Room_HarmAvatarIfWithinLaserBeam +.IMPORT FuncA_Room_IsPointInLaserBeam .IMPORT FuncA_Room_KillGooWithLaserBeam .IMPORT FuncA_Room_MachineLaserReset .IMPORT FuncA_Room_RemoveFlowerDeviceIfCarriedOrDelivered .IMPORT FuncA_Room_RespawnFlowerDeviceIfDropped +.IMPORT FuncA_Room_SpawnExplosionAtPoint +.IMPORT Func_InitActorSmokeExplosion .IMPORT Func_MachineLaserReadRegC .IMPORT Func_Noop .IMPORT Func_SetMachineIndex +.IMPORT Func_SetPointToPlatformCenter .IMPORT Func_WriteToUpperAttributeTable -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow2 +.IMPORT Ram_ActorState1_byte_arr +.IMPORT Ram_ActorType_eActor_arr +.IMPORT Ram_DeviceType_eDevice_arr .IMPORT Ram_MachineGoalHorz_u8_arr .IMPORT Ram_PlatformLeft_i16_0_arr ;;;=========================================================================;;; +;;; The actor index for the flower baddie in this room. +kFlowerActorIndex = 0 + +;;; The platform index for the zone that the flower baddie's head is in when +;;; attacking. +kFlowerHeadPlatformIndex = 1 + ;;; The machine index for the ShadowFlowerLaser machine in this room. kLaserMachineIndex = 0 @@ -85,7 +100,7 @@ kLaserInitPlatformLeft = \ d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 1 d_addr Machines_sMachine_arr_ptr, _Machines_sMachine_arr - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow2) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: @@ -95,7 +110,7 @@ _Ext_sRoomExt: d_addr Actors_sActor_arr_ptr, _Actors_sActor_arr d_addr Devices_sDevice_arr_ptr, _Devices_sDevice_arr d_addr Passages_sPassage_arr_ptr, _Passages_sPassage_arr - d_addr Enter_func_ptr, FuncA_Room_RemoveFlowerDeviceIfCarriedOrDelivered + d_addr Enter_func_ptr, FuncA_Room_ShadowFlower_EnterRoom d_addr FadeIn_func_ptr, FuncA_Terrain_ShadowFlower_FadeInRoom d_addr Tick_func_ptr, FuncA_Room_ShadowFlower_TickRoom d_addr Draw_func_ptr, Func_Noop @@ -134,6 +149,15 @@ _Platforms_sPlatform_arr: d_word Left_i16, kLaserInitPlatformLeft d_word Top_i16, $0020 D_END + ;; Flower baddie head zone: + .assert * - :- = kFlowerHeadPlatformIndex * .sizeof(sPlatform), error + D_STRUCT sPlatform + d_byte Type_ePlatform, ePlatform::Zone + d_word WidthPx_u16, $10 + d_byte HeightPx_u8, $10 + d_word Left_i16, $0030 + d_word Top_i16, $00a8 + D_END ;; Acid: D_STRUCT sPlatform d_byte Type_ePlatform, ePlatform::Kill @@ -145,7 +169,13 @@ _Platforms_sPlatform_arr: .assert * - :- <= kMaxPlatforms * .sizeof(sPlatform), error .byte ePlatform::None _Actors_sActor_arr: -: ;; TODO: fake flower baddie +: .assert * - :- = kFlowerActorIndex * .sizeof(sActor), error + D_STRUCT sActor + d_byte Type_eActor, eActor::BadFlower + d_word PosX_i16, $0028 + d_word PosY_i16, $00b8 + d_byte Param_byte, 0 + D_END D_STRUCT sActor d_byte Type_eActor, eActor::BadGooGreen d_word PosX_i16, $005a @@ -214,12 +244,52 @@ _ReadX: .SEGMENT "PRGA_Room" +.PROC FuncA_Room_ShadowFlower_EnterRoom + ;; Determine if the flower should be present in the room. + jsr FuncA_Room_RemoveFlowerDeviceIfCarriedOrDelivered + ;; IF the flower should be present, then remove the device for now and + ;; leave the baddie in its place. + lda #eDevice::Placeholder + cmp Ram_DeviceType_eDevice_arr + kFlowerDeviceIndex + beq @removeFlowerActor + @removeFlowerDevice: + sta Ram_DeviceType_eDevice_arr + kFlowerDeviceIndex + rts + ;; Otherwise, the flower should be absent, so the device has already been + ;; removed; remove the baddie as well. + @removeFlowerActor: + lda #eActor::None + sta Ram_ActorType_eActor_arr + kFlowerActorIndex + rts +.ENDPROC + .PROC FuncA_Room_ShadowFlower_TickRoom + ;; Apply laser beam damage to the avatar and goo baddies. ldx #kLaserMachineIndex jsr Func_SetMachineIndex jsr FuncA_Room_HarmAvatarIfWithinLaserBeam jsr FuncA_Room_KillGooWithLaserBeam - jmp FuncA_Room_RespawnFlowerDeviceIfDropped +_MaybeRespawnFlower: + ;; If the flower baddie is dead, respawn the flower if/when necessary. + ;; Otherwise, check if the laser beam is hitting the flower baddie. + lda Ram_ActorType_eActor_arr + kFlowerActorIndex + cmp #eActor::BadFlower + jne FuncA_Room_RespawnFlowerDeviceIfDropped +_MaybeKillFlowerBaddie: + ;; Kill the flower baddie if the laser beam hits its head. + lda Ram_ActorState1_byte_arr + kFlowerActorIndex ; current eBadFlower mode + cmp #eBadFlower::Attacking + bne @done ; the flower baddie's head is not in the zone + ldy #kFlowerHeadPlatformIndex ; param: platform index + jsr Func_SetPointToPlatformCenter + jsr FuncA_Room_IsPointInLaserBeam ; returns C + bcc @done ; the laser is not hitting the zone + jsr FuncA_Room_SpawnExplosionAtPoint + ldx #kFlowerActorIndex ; param: actor index + jsr Func_InitActorSmokeExplosion + ;; TODO: play a sound for the flower baddie dying + @done: + rts .ENDPROC .PROC FuncA_Room_ShadowFlowerLaser_InitReset diff --git a/src/rooms/shadow_flower.bg b/src/rooms/shadow_flower.bg index 8d9c50a..d32d168 100644 --- a/src/rooms/shadow_flower.bg +++ b/src/rooms/shadow_flower.bg @@ -14,10 +14,10 @@ EM AB DA EDEEEB CIDBBBCF ENEHBD AK BCEAENENEFEE EFFCCGBABAEAFDEB AK BC AKCKFFEM -EDEC BD AK EAFDEB EMEG +EDEC BD AKEAENFDEB EMEG EEELENFDEBBD BC CMEGEN EDCN BD BC EAEFEE ECBC CGBABABABABMCH FCEMED -EGENENEFECAOAOAOAOAOEOAOAOEAENELEN +EGENENEFECAOEOAOAOAOEOAOAOEAENELEN EEEBECEDEMAPAPAPAPAPAPAPAPEEENEBEE EMECEGENELENEBEAENENFEENENEHEEENEH diff --git a/src/rooms/shadow_gate.asm b/src/rooms/shadow_gate.asm index dd62385..2ddc3aa 100644 --- a/src/rooms/shadow_gate.asm +++ b/src/rooms/shadow_gate.asm @@ -34,7 +34,7 @@ .IMPORT Func_Noop .IMPORT Func_SetAndTransferBgFade .IMPORT Func_WriteToUpperAttributeTable -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow1 .IMPORTZP Zp_GoalBg_eFade .IMPORTZP Zp_RoomState @@ -65,7 +65,7 @@ kDarknessZonePlatformIndex = 0 d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 0 d_addr Machines_sMachine_arr_ptr, 0 - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow1) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: diff --git a/src/rooms/shadow_heart.asm b/src/rooms/shadow_heart.asm index b134f7b..cebbea6 100644 --- a/src/rooms/shadow_heart.asm +++ b/src/rooms/shadow_heart.asm @@ -51,7 +51,7 @@ .IMPORT Func_SetFlag .IMPORT Func_SetPointToAvatarCenter .IMPORT Func_WriteToUpperAttributeTable -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow1 .IMPORT Ram_ActorType_eActor_arr .IMPORT Ram_MachineGoalHorz_u8_arr .IMPORT Sram_ProgressFlags_arr @@ -112,7 +112,7 @@ kForcefieldMinPlatformTop = $0030 d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 2 d_addr Machines_sMachine_arr_ptr, _Machines_sMachine_arr - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow1) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: diff --git a/src/rooms/shadow_office.asm b/src/rooms/shadow_office.asm index bb2ad5f..47f212c 100644 --- a/src/rooms/shadow_office.asm +++ b/src/rooms/shadow_office.asm @@ -53,7 +53,7 @@ .IMPORT Func_SetActorCenterToPoint .IMPORT Func_SetFlag .IMPORT Func_SetPointToAvatarCenter -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow1 .IMPORT Ram_ActorPosY_i16_1_arr .IMPORT Ram_MachineGoalVert_u8_arr .IMPORT Ram_PlatformTop_i16_0_arr @@ -143,7 +143,7 @@ kLiftInitPlatformTop = kLiftMaxPlatformTop - kLiftInitGoalY * kBlockHeightPx d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 1 d_addr Machines_sMachine_arr_ptr, _Machines_sMachine_arr - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow1) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: diff --git a/src/rooms/shadow_trap.asm b/src/rooms/shadow_trap.asm index 3e996b1..10cb953 100644 --- a/src/rooms/shadow_trap.asm +++ b/src/rooms/shadow_trap.asm @@ -59,7 +59,7 @@ .IMPORT Func_SetPointToAvatarCenter .IMPORT Func_SetPointToPlatformCenter .IMPORT Func_WriteToUpperAttributeTable -.IMPORT Ppu_ChrObjShadow +.IMPORT Ppu_ChrObjShadow1 .IMPORT Ram_ActorType_eActor_arr .IMPORT Ram_MachineGoalHorz_u8_arr .IMPORT Ram_PlatformLeft_i16_0_arr @@ -147,7 +147,7 @@ kLaserInitPlatformLeft = \ d_addr TerrainData_ptr, _TerrainData d_byte NumMachines_u8, 1 d_addr Machines_sMachine_arr_ptr, _Machines_sMachine_arr - d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow) + d_byte Chr18Bank_u8, <.bank(Ppu_ChrObjShadow1) d_addr Ext_sRoomExt_ptr, _Ext_sRoomExt D_END _Ext_sRoomExt: diff --git a/src/tiles/bad_flower.ahi b/src/tiles/bad_flower.ahi new file mode 100644 index 0000000..62726bb --- /dev/null +++ b/src/tiles/bad_flower.ahi @@ -0,0 +1,237 @@ +ahi1 f0 p1 i26 w8 h8 + +;0;982220;ECEEEC;FF0;FF0;087C00;FF0;FF0;FF0;FF0;FF0;FF0;FF0;FF0;FF0 + +00000666 +00000006 +00000006 +00006666 +00066606 +00000000 +00000000 +00000000 + +60000660 +60066660 +66666000 +66000660 +06600000 +06600000 +66600000 +66600000 + +00000000 +00000000 +00000000 +06633130 +66633133 +66000030 +60000000 +60000000 + +00000000 +31300000 +31330300 +00333000 +00000000 +00000000 +00000000 +00000000 + +00000666 +00006006 +00000006 +00000666 +00006660 +00066600 +00060000 +00600066 + +60000660 +60066660 +66666000 +66000660 +06600006 +06600006 +66660000 +66666000 + +00000000 +00000000 +00000000 +00000000 +60000000 +66000000 +60600000 +00000000 + +00003330 +66003313 +00666333 +06616630 +66666600 +66006000 +60000000 +60000000 + +00000006 +00006666 +00060006 +00000066 +00006666 +00066600 +00660066 +06600666 + +66000660 +66066660 +66666000 +66000666 +06600006 +06660006 +66066000 +60666660 + +00000000 +00000000 +00000000 +00000000 +66000000 +66600000 +60060000 +06060000 + +00000000 +00000000 +00000003 +00000000 +00000033 +00000031 +00060033 +00006003 + +60666000 +06616663 +06166666 +66666616 +66600666 +66000066 +61600000 +66600000 + +03333000 +31111330 +33333133 +63331333 +00030330 +00000000 +00000000 +00000000 + +00000000 +30000000 +33300000 +30000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00006000 +00000600 +00000600 +00006600 + +60666000 +06616660 +06166666 +66666666 +66600661 +61600006 +66000000 +66000000 + +00333333 +61113333 +61333111 +66133333 +16613333 +66000303 +06000000 +00600000 + +33000000 +30000000 +13000000 +31300000 +13303030 +03333333 +03303000 +00000000 + +00000000 +03313300 +33311300 +33132133 +01323133 +31132110 +33000000 +00000000 + +00000000 +00000000 +00000030 +00000333 +00003313 +00003331 +00000113 +00003311 + +00000000 +00000000 +33300000 +13030000 +11330300 +32133300 +23130330 +32110000 + +03330330 +33313330 +33311133 +13132133 +31323113 +11132113 +33111300 +33333300 + +00000000 +00000000 +00000000 +30000000 +33000000 +03300000 +00000000 +00000000 + +00000000 +00003333 +00031331 +00333331 +00113313 +03333132 +03113113 +03333311 + +03000000 +03300000 +33300000 +11303000 +21333330 +31130333 +20030030 +13000000