From c8cb6da9cdd017cd4d67f40d5081b4512d9858af Mon Sep 17 00:00:00 2001 From: "Matthew D. Steele" Date: Thu, 1 Aug 2024 17:31:46 -0400 Subject: [PATCH] Refactor boss_garden.asm to make more room in PRGA_Objects --- src/rooms/boss_garden.asm | 470 +++++++++++++++++++------------------- 1 file changed, 234 insertions(+), 236 deletions(-) diff --git a/src/rooms/boss_garden.asm b/src/rooms/boss_garden.asm index efa70dc3..888d9fa0 100644 --- a/src/rooms/boss_garden.asm +++ b/src/rooms/boss_garden.asm @@ -245,7 +245,7 @@ _Ext_sRoomExt: d_addr Actors_sActor_arr_ptr, Data_Empty_sActor_arr d_addr Devices_sDevice_arr_ptr, _Devices_sDevice_arr d_addr Passages_sPassage_arr_ptr, 0 - d_addr Enter_func_ptr, FuncC_Boss_Garden_EnterRoom + d_addr Enter_func_ptr, FuncA_Room_BossGarden_EnterRoom d_addr FadeIn_func_ptr, Func_Noop d_addr Tick_func_ptr, FuncC_Boss_Garden_TickRoom d_addr Draw_func_ptr, FuncA_Objects_DrawBoss @@ -271,7 +271,7 @@ _Machines_sMachine_arr: d_addr TryAct_func_ptr, FuncA_Machine_CannonTryAct d_addr Tick_func_ptr, FuncA_Machine_CannonTick d_addr Draw_func_ptr, FuncA_Objects_DrawCannonMachine - d_addr Reset_func_ptr, FuncC_Boss_GardenCannon_Reset + d_addr Reset_func_ptr, FuncA_Room_BossGardenCannon_Reset D_END .assert * - :- <= kMaxMachines * .sizeof(sMachine), error _Platforms_sPlatform_arr: @@ -368,36 +368,10 @@ _Devices_sDevice_arr: d_byte Boss_eFlag, eFlag::BossGarden d_byte BodyPlatform_u8, kBossBodyPlatformIndex d_addr Tick_func_ptr, FuncC_Boss_Garden_TickBoss - d_addr Draw_func_ptr, FuncA_Objects_BossGarden_DrawBoss + d_addr Draw_func_ptr, FuncC_Boss_Garden_DrawBoss D_END .ENDPROC -.PROC FuncC_Boss_Garden_EnterRoom -_LockScrolling: - lda #0 - sta Zp_RoomScrollY_u8 - lda #bScroll::LockVert - sta Zp_Camera_bScroll -_InitBoss: - ldax #DataC_Boss_Garden_sBoss ; param: sBoss ptr - jsr FuncA_Room_InitBoss ; sets Z if boss is alive - beq _BossIsAlive -_BossIsDead: - ;; Remove the boss's thorns. - lda #ePlatform::Zone - sta Ram_PlatformType_ePlatform_arr + kThornsPlatformIndex - rts -_BossIsAlive: - lda #kBossInitHealthPerEye - sta Zp_RoomState + sState::BossEyeHealth_u8_arr2 + 0 - sta Zp_RoomState + sState::BossEyeHealth_u8_arr2 + 1 - lda #kBossInitCooldown - sta Zp_RoomState + sState::BossCooldown_u8 - lda #eBossMode::Waiting - sta Zp_RoomState + sState::Current_eBossMode - rts -.ENDPROC - ;;; Room tick function for the BossGarden room. ;;; @prereq PRGA_Room is loaded. .PROC FuncC_Boss_Garden_TickRoom @@ -411,13 +385,14 @@ _Boss: .ENDPROC ;;; Performs per-frame upates for the boss (if it's still alive). +;;; @prereq PRGA_Room is loaded. .PROC FuncC_Boss_Garden_TickBoss - jsr FuncC_Boss_Garden_CheckForGrenadeHit + jsr FuncA_Room_BossGarden_CheckForGrenadeHit ;; Tick eyes. ldx #eEye::Left ; param: eye to tick - jsr FuncC_Boss_Garden_TickEye + jsr FuncA_Room_BossGarden_TickEye ldx #eEye::Right ; param: eye to tick - jsr FuncC_Boss_Garden_TickEye + jsr FuncA_Room_BossGarden_TickEye _TickThorns: ;; Move thorns quickly when hurt. lda Zp_RoomState + sState::BossThornHurt_u8 @@ -467,6 +442,7 @@ _CheckMode: ;;; Performs a state transition for the boss when it's in SprayWindup mode and ;;; the cooldown has expired. +;;; @prereq PRGA_Room is loaded. .PROC FuncC_Boss_Garden_TickBossSprayWindup lda #eBossMode::SprayFire sta Zp_RoomState + sState::Current_eBossMode @@ -475,6 +451,7 @@ _CheckMode: ;;; Performs a state transition for the boss when it's in SprayFire mode and ;;; the cooldown has expired. +;;; @prereq PRGA_Room is loaded. .PROC FuncC_Boss_Garden_TickBossSprayFire jsr Func_GetRandomByte ; returns A ldy #11 ; param: divisor @@ -485,7 +462,7 @@ _CheckMode: ;; Decrement the projectile counter; if it reaches zero, return to waiting ;; mode. dec Zp_RoomState + sState::BossProjCount_u8 - jeq FuncC_Boss_Garden_StartWaiting + jeq FuncA_Room_BossGarden_StartWaiting ;; Otherwise, set the cooldown for the next fireball. lda #kBossSprayFireballCooldown sta Zp_RoomState + sState::BossCooldown_u8 @@ -494,13 +471,14 @@ _CheckMode: ;;; Performs a state transition for the boss when it's in Shoot mode and the ;;; cooldown has expired. +;;; @prereq PRGA_Room is loaded. .PROC FuncC_Boss_Garden_TickBossShoot ldy Zp_RoomState + sState::BossActive_eEye ; param: eye to shoot from jsr FuncC_Boss_Garden_ShootFireballAtAvatar ;; Decrement the projectile counter; if it reaches zero, return to waiting ;; mode. dec Zp_RoomState + sState::BossProjCount_u8 - jeq FuncC_Boss_Garden_StartWaiting + jeq FuncA_Room_BossGarden_StartWaiting ;; Otherwise, set the cooldown for the next fireball. lda #kBossShootFireballCooldown sta Zp_RoomState + sState::BossCooldown_u8 @@ -509,20 +487,47 @@ _CheckMode: ;;; Performs a state transition for the boss when it's in Angry mode and the ;;; cooldown has expired. +;;; @prereq PRGA_Room is loaded. .PROC FuncC_Boss_Garden_TickBossAngry - jsr FuncC_Boss_Garden_DropSpike +_DropSpike: + ;; Drop a spike from a random location. + jsr Func_FindEmptyActorSlot ; sets C on failure, returns X + bcs @done + ;; Set random X-position within room: + jsr Func_GetRandomByte ; returns A, preserves X + cmp #$a0 + blt @noWrap + sbc #$80 + @noWrap: + adc #$30 + sta Ram_ActorPosX_i16_0_arr, x + ;; Set Y-position based on the room block column of the X-position: + div #kTileWidthPx * 2 + tay + lda _SpikePosY_u8_arr, y + sta Ram_ActorPosY_i16_0_arr, x + ;; Initialize the spike: + lda #0 + sta Ram_ActorPosX_i16_1_arr, x + sta Ram_ActorPosY_i16_1_arr, x + jsr Func_InitActorProjSpike + @done: +_UpdateMode: ;; Decrement the projectile counter; if it reaches zero, return to waiting ;; mode. dec Zp_RoomState + sState::BossProjCount_u8 - jeq FuncC_Boss_Garden_StartWaiting + jeq FuncA_Room_BossGarden_StartWaiting ;; Otherwise, set the cooldown for the next spike. lda #kBossAngrySpikeCooldown sta Zp_RoomState + sState::BossCooldown_u8 rts +_SpikePosY_u8_arr: + .byte $00, $00, $41, $39, $41, $49, $61, $61, $71, $81, $81, $81, $81, $81 .ENDPROC ;;; Performs a state transition for the boss when it's in Waiting mode and the ;;; cooldown has expired. +;;; @prereq PRGA_Room is loaded. .PROC FuncC_Boss_Garden_TickBossWaiting _SetActiveEye: ;; If one of the eyes is at zero health, pick the other eye. @@ -576,34 +581,6 @@ _StartShootMode: rts .ENDPROC -;;; Opens or closes the specified boss eye, depending on the boss mode. -;;; @param X Which eEye to update. -.PROC FuncC_Boss_Garden_TickEye - lda Zp_RoomState + sState::BossEyeFlash_u8_arr2, x - beq @noFlash - dec Zp_RoomState + sState::BossEyeFlash_u8_arr2, x - @noFlash: -_CheckIfOpenOrClosed: - lda Zp_RoomState + sState::Current_eBossMode - cmp #kFirstOpenEyeMode - blt _Close - cpx Zp_RoomState + sState::BossActive_eEye - bne _Close -_Open: - lda Zp_RoomState + sState::BossEyeOpen_u8_arr2, x - cmp #kBossEyeOpenFrames - bge @done - inc Zp_RoomState + sState::BossEyeOpen_u8_arr2, x - @done: - rts -_Close: - lda Zp_RoomState + sState::BossEyeOpen_u8_arr2, x - beq @done - dec Zp_RoomState + sState::BossEyeOpen_u8_arr2, x - @done: - rts -.ENDPROC - ;;; Shoots a fireball from the specified eye, towards the player avatar. ;;; @param Y Which eEye to shoot from. .PROC FuncC_Boss_Garden_ShootFireballAtAvatar @@ -656,182 +633,22 @@ _FireballAngle_u8_arr2_arr: .byte 16, 12 .ENDPROC -;;; Drops a spike from a random horizontal position. -.PROC FuncC_Boss_Garden_DropSpike - ;; Drop a spike from a random location. - jsr Func_FindEmptyActorSlot ; sets C on failure, returns X - bcs @done - ;; Set random X-position within room: - jsr Func_GetRandomByte ; returns A, preserves X - cmp #$a0 - blt @noWrap - sbc #$80 - @noWrap: - adc #$30 - sta Ram_ActorPosX_i16_0_arr, x - ;; Set Y-position based on the room block column of the X-position: - div #kTileWidthPx * 2 - tay - lda _SpikePosY_u8_arr, y - sta Ram_ActorPosY_i16_0_arr, x - ;; Initialize the spike: - lda #0 - sta Ram_ActorPosX_i16_1_arr, x - sta Ram_ActorPosY_i16_1_arr, x - jsr Func_InitActorProjSpike - @done: - rts -_SpikePosY_u8_arr: - .byte $00, $00, $41, $39, $41, $49, $61, $61, $71, $81, $81, $81, $81, $81 -.ENDPROC - -;;; Makes the boss enter waiting mode for a random amount of time (between -;;; about 1-2 seconds). -;;; @preserve X -.PROC FuncC_Boss_Garden_StartWaiting - lda #eBossMode::Waiting - sta Zp_RoomState + sState::Current_eBossMode - jsr Func_GetRandomByte ; preserves X, returns A - and #$3f - ora #$40 - sta Zp_RoomState + sState::BossCooldown_u8 - rts -.ENDPROC - -;;; Checks if a grenade has hit a boss eye; if so, explodes the grenade and -;;; makes the boss react accordingly. -;;; @prereq PRGA_Room is loaded. -.PROC FuncC_Boss_Garden_CheckForGrenadeHit - ;; Find the actor index for the grenade in flight (if any). If we don't - ;; find one, then we're done. - jsr FuncA_Room_FindGrenadeActor ; returns C and X - bcs _Done -_CheckEyes: - ;; Check if the grenade hit either eye. - jsr Func_SetPointToActorCenter ; preserves X - ldy #kLeftEyePlatformIndex - jsr Func_IsPointInPlatform ; preserves X and Y, returns C - bcs _HitEye - ldy #kRightEyePlatformIndex - jsr Func_IsPointInPlatform ; preserves X and Y, returns C - bcs _HitEye - rts -_HitEye: - ;; At this point, X is the grenade actor index, and Y is the platform index - ;; of the eye that was hit. Assert that we can use that platform index as - ;; an eEye value. - .assert kLeftEyePlatformIndex = eEye::Left, error - .assert kRightEyePlatformIndex = eEye::Right, error - ;; Check if the hit eye is open or closed. - lda Zp_RoomState + sState::BossEyeOpen_u8_arr2, y - cmp #kBossEyeOpenFrames / 2 - bge _HitOpenEye -_HitClosedEye: - ;; If the hit eye is closed, shake the room and switch the boss to Angry - ;; mode. - ;; TODO: Perhaps only if not in spray mode? - lda #kBossAngrySpikeCooldown * kBossAngryNumSpikes ; param: num frames - jsr Func_ShakeRoom ; preserves X - lda #eBossMode::Angry - sta Zp_RoomState + sState::Current_eBossMode - .assert eBossMode::Angry = 2, error - sta Zp_RoomState + sState::BossCooldown_u8 - lda #kBossAngryNumSpikes - sta Zp_RoomState + sState::BossProjCount_u8 - bne _ExplodeGrenade ; unconditional -_HitOpenEye: - ;; If the hit eye is open, deal damage to that eye (assuming that eye's - ;; health isn't somehow already zero). - lda Zp_RoomState + sState::BossEyeHealth_u8_arr2, y - beq @doneDamage - sub #1 - sta Zp_RoomState + sState::BossEyeHealth_u8_arr2, y - lda #eSample::BossHurtF ; param: eSample to play - jsr Func_PlaySfxSample ; preserves X and Y - @doneDamage: - ;; If the boss's total health is now zero, mark the boss as dead. - lda Zp_RoomState + sState::BossEyeHealth_u8_arr2 + 0 - ora Zp_RoomState + sState::BossEyeHealth_u8_arr2 + 1 - bne @bossIsStillAlive - lda #eActor::ProjFireball ; param: projectile type - jsr FuncA_Room_TurnProjectilesToSmoke ; preserves X - lda #eActor::ProjSpike ; param: projectile type - jsr FuncA_Room_TurnProjectilesToSmoke ; preserves X - lda #ePlatform::Zone - sta Ram_PlatformType_ePlatform_arr + kThornsPlatformIndex - lda #eBossMode::Dead - sta Zp_RoomState + sState::Current_eBossMode - .assert eBossMode::Dead = 0, error - beq _ExplodeGrenade ; unconditional - ;; Otherwise, put the boss into waiting mode. - @bossIsStillAlive: - lda #kBossEyeOpenFrames - sta Zp_RoomState + sState::BossEyeFlash_u8_arr2, y - lda #$10 - sta Zp_RoomState + sState::BossThornHurt_u8 - jsr FuncC_Boss_Garden_StartWaiting ; preserves X -_ExplodeGrenade: - ;; At this point, X is still the grenade actor index. - jsr Func_InitActorSmokeExplosion - jsr Func_PlaySfxExplodeSmall -_Done: - rts -.ENDPROC - .PROC FuncC_Boss_GardenCannon_ReadReg - cmp #$c - beq @readL cmp #$d - beq @readR - @readY: + blt _ReadL + beq _ReadR +_ReadY: jmp Func_MachineCannonReadRegY - @readL: +_ReadL: lda Zp_RoomState + sState::LeverLeft_u8 rts - @readR: +_ReadR: lda Zp_RoomState + sState::LeverRight_u8 rts .ENDPROC -;;; @prereq PRGA_Room is loaded. -.PROC FuncC_Boss_GardenCannon_Reset - ldx #kLeverLeftDeviceIndex ; param: device index - jsr FuncA_Room_ResetLever - ldx #kLeverRightDeviceIndex ; param: device index - jsr FuncA_Room_ResetLever - jsr FuncA_Room_MachineCannonReset - ;; If the boss is currently shooting/spraying, switch to waiting mode (to - ;; avoid the player cheesing by reprogramming the machine every time the - ;; boss opens an eye). - lda Zp_RoomState + sState::Current_eBossMode - cmp #kFirstOpenEyeMode - blt @done - jmp FuncC_Boss_Garden_StartWaiting - @done: - rts -.ENDPROC - -;;;=========================================================================;;; - -.SEGMENT "PRGA_Machine" - -.PROC FuncA_Machine_BossGardenCannon_WriteReg - cpx #$d - beq _WriteR -_WriteL: - ldx #kLeverLeftDeviceIndex ; param: device index - jmp FuncA_Machine_WriteToLever -_WriteR: - ldx #kLeverRightDeviceIndex ; param: device index - jmp FuncA_Machine_WriteToLever -.ENDPROC - -;;;=========================================================================;;; - -.SEGMENT "PRGA_Objects" - ;;; Draws the boss. -.PROC FuncA_Objects_BossGarden_DrawBoss +.PROC FuncC_Boss_Garden_DrawBoss _AnimateThorns: lda Zp_RoomState + sState::BossThornCounter_u8 div #4 @@ -861,7 +678,7 @@ _DrawBossLeftMiniEyes: lda _LeftMiniEyeVertShift_i8_arr4, x ; param: signed offset jsr FuncA_Objects_MoveShapeVert ; preserves X cpx Zp_RoomState + sState::BossEyeHealth_u8_arr2 + eEye::Left ; param: C - jsr FuncA_Objects_BossGarden_DrawMiniEyeShape ; preserves X + jsr FuncC_Boss_Garden_DrawMiniEyeShape ; preserves X dex bpl @loop _DrawBossRightMiniEyes: @@ -875,15 +692,15 @@ _DrawBossRightMiniEyes: jsr FuncA_Objects_MoveShapeVert ; preserves X lda #kTileIdObjBossGardenEyeMiniFirst + 0 ; param: tile ID cpx Zp_RoomState + sState::BossEyeHealth_u8_arr2 + eEye::Right ; param: C - jsr FuncA_Objects_BossGarden_DrawMiniEyeShape ; preserves X + jsr FuncC_Boss_Garden_DrawMiniEyeShape ; preserves X dex bpl @loop _DrawBossEyes: ldx #eEye::Left ; param: eye - jsr FuncA_Objects_BossGarden_DrawEye ; preserves X + jsr FuncC_Boss_Garden_DrawEye ; preserves X .assert eEye::Right = 1 + eEye::Left, error inx ; param: eye - jmp FuncA_Objects_BossGarden_DrawEye + jmp FuncC_Boss_Garden_DrawEye _LeftMiniEyeHorzShift_i8_arr4: .byte 16, <-24, 48, <-8 _LeftMiniEyeVertShift_i8_arr4: @@ -899,7 +716,7 @@ _RightMiniEyeVertShift_i8_arr4: ;;; @param C Set if the eye is potentially open. ;;; @param X The index of the mini eye. ;;; @preserve X -.PROC FuncA_Objects_BossGarden_DrawMiniEyeShape +.PROC FuncC_Boss_Garden_DrawMiniEyeShape ;; If the C paramters is cleared, the eye is definitely closed. bcc _EyeIsClosed ;; Otherwise, the eye is still closed if the boss is dropping spikes. @@ -945,7 +762,7 @@ _OpenEyeTileId_u8_arr16: ;;; Allocates and populates OAM slots for one of the boss's eyes. ;;; @param X Which eEye to draw. ;;; @preserve X -.PROC FuncA_Objects_BossGarden_DrawEye +.PROC FuncC_Boss_Garden_DrawEye ;; Assert that we can use the eEye value as a platform index. .assert kLeftEyePlatformIndex = eEye::Left, error .assert kRightEyePlatformIndex = eEye::Right, error @@ -989,6 +806,187 @@ _OpenEyeTileId_u8_arr16: ;;;=========================================================================;;; +.SEGMENT "PRGA_Room" + +.PROC FuncA_Room_BossGarden_EnterRoom +_LockScrolling: + lda #0 + sta Zp_RoomScrollY_u8 + lda #bScroll::LockVert + sta Zp_Camera_bScroll +_InitBoss: + ldax #DataC_Boss_Garden_sBoss ; param: sBoss ptr + jsr FuncA_Room_InitBoss ; sets Z if boss is alive + beq _BossIsAlive +_BossIsDead: + ;; Remove the boss's thorns. + lda #ePlatform::Zone + sta Ram_PlatformType_ePlatform_arr + kThornsPlatformIndex + rts +_BossIsAlive: + lda #kBossInitHealthPerEye + sta Zp_RoomState + sState::BossEyeHealth_u8_arr2 + 0 + sta Zp_RoomState + sState::BossEyeHealth_u8_arr2 + 1 + lda #kBossInitCooldown + sta Zp_RoomState + sState::BossCooldown_u8 + lda #eBossMode::Waiting + sta Zp_RoomState + sState::Current_eBossMode + rts +.ENDPROC + +;;; Checks if a grenade has hit a boss eye; if so, explodes the grenade and +;;; makes the boss react accordingly. +;;; @prereq PRGA_Room is loaded. +.PROC FuncA_Room_BossGarden_CheckForGrenadeHit + ;; Find the actor index for the grenade in flight (if any). If we don't + ;; find one, then we're done. + jsr FuncA_Room_FindGrenadeActor ; returns C and X + bcs _Done +_CheckEyes: + ;; Check if the grenade hit either eye. + jsr Func_SetPointToActorCenter ; preserves X + ldy #kLeftEyePlatformIndex + jsr Func_IsPointInPlatform ; preserves X and Y, returns C + bcs _HitEye + ldy #kRightEyePlatformIndex + jsr Func_IsPointInPlatform ; preserves X and Y, returns C + bcs _HitEye + rts +_HitEye: + ;; At this point, X is the grenade actor index, and Y is the platform index + ;; of the eye that was hit. Assert that we can use that platform index as + ;; an eEye value. + .assert kLeftEyePlatformIndex = eEye::Left, error + .assert kRightEyePlatformIndex = eEye::Right, error + ;; Check if the hit eye is open or closed. + lda Zp_RoomState + sState::BossEyeOpen_u8_arr2, y + cmp #kBossEyeOpenFrames / 2 + bge _HitOpenEye +_HitClosedEye: + ;; If the hit eye is closed, shake the room and switch the boss to Angry + ;; mode. + ;; TODO: Perhaps only if not in spray mode? + lda #kBossAngrySpikeCooldown * kBossAngryNumSpikes ; param: num frames + jsr Func_ShakeRoom ; preserves X + lda #eBossMode::Angry + sta Zp_RoomState + sState::Current_eBossMode + .assert eBossMode::Angry = 2, error + sta Zp_RoomState + sState::BossCooldown_u8 + lda #kBossAngryNumSpikes + sta Zp_RoomState + sState::BossProjCount_u8 + bne _ExplodeGrenade ; unconditional +_HitOpenEye: + ;; If the hit eye is open, deal damage to that eye (assuming that eye's + ;; health isn't somehow already zero). + lda Zp_RoomState + sState::BossEyeHealth_u8_arr2, y + beq @doneDamage + sub #1 + sta Zp_RoomState + sState::BossEyeHealth_u8_arr2, y + lda #eSample::BossHurtF ; param: eSample to play + jsr Func_PlaySfxSample ; preserves X and Y + @doneDamage: + ;; If the boss's total health is now zero, mark the boss as dead. + lda Zp_RoomState + sState::BossEyeHealth_u8_arr2 + 0 + ora Zp_RoomState + sState::BossEyeHealth_u8_arr2 + 1 + bne @bossIsStillAlive + lda #eActor::ProjFireball ; param: projectile type + jsr FuncA_Room_TurnProjectilesToSmoke ; preserves X + lda #eActor::ProjSpike ; param: projectile type + jsr FuncA_Room_TurnProjectilesToSmoke ; preserves X + lda #ePlatform::Zone + sta Ram_PlatformType_ePlatform_arr + kThornsPlatformIndex + lda #eBossMode::Dead + sta Zp_RoomState + sState::Current_eBossMode + .assert eBossMode::Dead = 0, error + beq _ExplodeGrenade ; unconditional + ;; Otherwise, put the boss into waiting mode. + @bossIsStillAlive: + lda #kBossEyeOpenFrames + sta Zp_RoomState + sState::BossEyeFlash_u8_arr2, y + lda #$10 + sta Zp_RoomState + sState::BossThornHurt_u8 + jsr FuncA_Room_BossGarden_StartWaiting ; preserves X +_ExplodeGrenade: + ;; At this point, X is still the grenade actor index. + jsr Func_InitActorSmokeExplosion + jsr Func_PlaySfxExplodeSmall +_Done: + rts +.ENDPROC + +;;; Opens or closes the specified boss eye, depending on the boss mode. +;;; @param X Which eEye to update. +.PROC FuncA_Room_BossGarden_TickEye + lda Zp_RoomState + sState::BossEyeFlash_u8_arr2, x + beq @noFlash + dec Zp_RoomState + sState::BossEyeFlash_u8_arr2, x + @noFlash: +_CheckIfOpenOrClosed: + lda Zp_RoomState + sState::Current_eBossMode + cmp #kFirstOpenEyeMode + blt _Close + cpx Zp_RoomState + sState::BossActive_eEye + bne _Close +_Open: + lda Zp_RoomState + sState::BossEyeOpen_u8_arr2, x + cmp #kBossEyeOpenFrames + bge @done + inc Zp_RoomState + sState::BossEyeOpen_u8_arr2, x + @done: + rts +_Close: + lda Zp_RoomState + sState::BossEyeOpen_u8_arr2, x + beq @done + dec Zp_RoomState + sState::BossEyeOpen_u8_arr2, x + @done: + rts +.ENDPROC + +;;; Makes the garden boss enter waiting mode for a random amount of time +;;; (between about 1-2 seconds). +;;; @preserve X +.PROC FuncA_Room_BossGarden_StartWaiting + lda #eBossMode::Waiting + sta Zp_RoomState + sState::Current_eBossMode + jsr Func_GetRandomByte ; preserves X, returns A + and #$3f + ora #$40 + sta Zp_RoomState + sState::BossCooldown_u8 + rts +.ENDPROC + +.PROC FuncA_Room_BossGardenCannon_Reset + ldx #kLeverLeftDeviceIndex ; param: device index + jsr FuncA_Room_ResetLever + ldx #kLeverRightDeviceIndex ; param: device index + jsr FuncA_Room_ResetLever + jsr FuncA_Room_MachineCannonReset + ;; If the boss is currently shooting/spraying, switch to waiting mode (to + ;; avoid the player cheesing by reprogramming the machine every time the + ;; boss opens an eye). + lda Zp_RoomState + sState::Current_eBossMode + cmp #kFirstOpenEyeMode + bge FuncA_Room_BossGarden_StartWaiting + rts +.ENDPROC + +;;;=========================================================================;;; + +.SEGMENT "PRGA_Machine" + +.PROC FuncA_Machine_BossGardenCannon_WriteReg + cpx #$d + beq _WriteR +_WriteL: + ldx #kLeverLeftDeviceIndex ; param: device index + jmp FuncA_Machine_WriteToLever +_WriteR: + ldx #kLeverRightDeviceIndex ; param: device index + jmp FuncA_Machine_WriteToLever +.ENDPROC + +;;;=========================================================================;;; + .SEGMENT "PRGE_Irq" ;;; HBlank IRQ handler function for the top of the boss's zone in the