Actually a rather simple step, but with a few new changes.
We're adding a new enemy, a bat, that once shot, hides. And randomly reappears to attack you, only to vanish again.
The first problem:
The bat vanishes. However not the object. To tackle that an empty sprite was added to the sheet. This makes the object stay but the image gone. However collision still checks the bat.
Since we have a SPRITE_STATE per object anyway a new design decision get added. Any states >= 128 are treated as non colliding. In other words, bat gets hit, set state to a value >= 128 and set empty sprite. Done. To reappear, repeat reverse.
Let's start with the simpler getting hit part. Set invisible sprite, set sprite state to 128. Voila!
!zone HitBehaviourVanish
HitBehaviourVanish
lda SPRITE_STATE,x
bne .NoHit
lda #SPRITE_BAT_VANISH
sta SPRITE_POINTER_BASE,x
lda #128
sta SPRITE_STATE,x
.NoHit
rts
The behaviour code is at first quite similar to the left/right moving bat. The neat part is the attack flight. The bat appears in any location diagonal from the player. It then swoops toward the player to the opposite side and vanishes again.
A few cautions are taken to avoid trying to appear or move outside the screen. The bat may actually take V shaped route.
!zone BehaviourBatVanishing
BehaviourBatVanishing
lda SPRITE_STATE,x
bne .NotNormal
jmp .NormalUpdate
.NotNormalcmp #128
beq .Vanish1
cmp #129
beq .Hidden
cmp #130
beq .Spawn
cmp #1
bne .NoSpecialBehaviour
jmp .AttackFlight
.NoSpecialBehaviour
rts
.Vanish1
lda DELAYED_GENERIC_COUNTER
and #$7
bne .NoSpecialBehaviour
lda #SPRITE_INVISIBLE
sta SPRITE_POINTER_BASE,x
inc SPRITE_STATE,x
jsr GenerateRandomNumber
adc #24
sta SPRITE_MOVE_POS,x
rts
.Spawn
lda DELAYED_GENERIC_COUNTER
and #$7
bne .NoSpecialBehaviour
lda #1
sta SPRITE_STATE,x
lda #SPRITE_BAT_1
sta SPRITE_POINTER_BASE,x
rts
.Hiddendec SPRITE_MOVE_POS,x
beq .Unhide
rts
.Unhide;position diagonal above/below player
lda SPRITE_CHAR_POS_X
cmp #10
bcc .SpawnOnRight
cmp #30
bcs .SpawnOnLeft
;randomly choose
jsr GenerateRandomNumber
and #$1
beq .SpawnOnRight
.SpawnOnLeft
lda SPRITE_CHAR_POS_X
sec
sbc #5
sta PARAM1
lda #0
sta SPRITE_DIRECTION,x
jmp .FindYSpawnPos
.SpawnOnRight
lda SPRITE_CHAR_POS_X
clcadc #5
sta PARAM1
lda #1
sta SPRITE_DIRECTION,x
.FindYSpawnPos
lda SPRITE_CHAR_POS_Y
cmp #5
bcc .SpawnBelow
cmp #15
bcs .SpawnAbove
;randomly choose
jsr GenerateRandomNumber
and #$1
beq .SpawnAbove
.SpawnBelow
lda SPRITE_CHAR_POS_Y
clcadc #5
sta PARAM2
lda #0
sta SPRITE_FALLING,x
jmp .Reposition
.SpawnAbove
lda SPRITE_CHAR_POS_Y
sec
sbc #5
sta PARAM2
lda #1
sta SPRITE_FALLING,x
.Reposition
jsr CalcSpritePosFromCharPos
inc SPRITE_STATE,x
lda #SPRITE_BAT_VANISH
sta SPRITE_POINTER_BASE,x
rts
.NormalUpdate
lda DELAYED_GENERIC_COUNTER
and #$3
bne .NoAnimUpdate
inc SPRITE_ANIM_POS,x
lda SPRITE_ANIM_POS,x
and #$3
sta SPRITE_ANIM_POS,x
tay
lda BAT_ANIMATION,y
sta SPRITE_POINTER_BASE,x
.NoAnimUpdate
lda SPRITE_STATE,x
bne .NoAction
lda SPRITE_DIRECTION,x
beq .MoveRight
;move left
jsr ObjectMoveLeftBlocking
beq .ToggleDirection
rts
.MoveRight
jsr ObjectMoveRightBlocking
beq .ToggleDirection
rts
.ToggleDirection
lda SPRITE_DIRECTION,x
eor #1
sta SPRITE_DIRECTION,x
.NoAction
rts
.AttackFlightinc SPRITE_MOVE_POS,x
lda SPRITE_MOVE_POS,x
cmp #80
beq .AttackDone
cmp #40
beq .ChangeFlyDirection
;fly towards player
lda SPRITE_DIRECTION,x
beq .FlyRight
stx PARAM5
jsr ObjectMoveLeft
jmp .FlyUpDown
.FlyRight
stx PARAM5
jsr ObjectMoveRight
.FlyUpDown
ldx PARAM5
lda SPRITE_FALLING,x
beq .FlyUp
jsr ObjectMoveDown
rts
.FlyUp
jsr ObjectMoveUp
rts
.ChangeFlyDirection;change direction to avoid flying out of the screen
lda SPRITE_CHAR_POS_Y,x
cmp #5
bcc .ChangeY
cmp #18
bcc .CheckXDir
.ChangeY
lda SPRITE_FALLING,x
eor #$1
sta SPRITE_FALLING,x
.CheckXDir
lda SPRITE_CHAR_POS_X,x
cmp #5
bcc .ChangeX
cmp #32
bcs .ChangeX
rts
.ChangeX
lda SPRITE_DIRECTION,x
eor #$1
sta SPRITE_DIRECTION,x
rts
.AttackDone;auto-vanish
lda #0
sta SPRITE_STATE,x
jmp HitBehaviourVanish