A C64 Game - Step 74


Another boss!

And one, that works differently than the others before him.



This boss is spawning bats that fly left/right and vanish once hitting the screen border.
Thus we remove the path-8-flying bat and replace it by a simple attacking bat:

!zone BehaviourBatAttacking
BehaviourBatAttacking
lda DELAYED_GENERIC_COUNTER
and #$03
bne .NoAnimUpdate

inc SPRITE_ANIM_POS,x
lda SPRITE_ANIM_POS,x
and #$03
sta SPRITE_ANIM_POS,x

tay
lda BAT_ANIMATION,y
sta SPRITE_POINTER_BASE,x

.NoAnimUpdate
lda #3
sta PARAM1
lda SPRITE_DIRECTION,x
beq .MoveRight

.MoveLeft
jsr ObjectMoveLeft
dec PARAM1
bne .MoveLeft
jmp .XMoveDone

.MoveRight
jsr ObjectMoveRight
dec PARAM1
bne .MoveRight

.XMoveDone
lda SPRITE_CHAR_POS_X,x
cmp #255
beq .RemoveMe
cmp #39
beq .RemoveMe
rts

.RemoveMe
inc SPAWN_NO_ITEM
jsr KillEnemy
dec SPAWN_NO_ITEM
rts



The boss itself is not really clever. It calculates a random y position, moves there, spawns bats and starts all over again. Note that it is only vulnerable while spawning bats though :)
Remember, vulnerability is controlled by having the MSB set in SPRITE_STATE,x.

;------------------------------------------------------------
;boss #5
;state 0 = find target Y
;state 1 = move towards target Y
;state 2 = attack
;state 3 = cool off
;------------------------------------------------------------
!zone BehaviourBoss5
BehaviourBoss5
BOSS_MOVE_SPEED = 1
lda SPRITE_HITBACK,x
beq .NoHitBack
dec SPRITE_HITBACK,x

ldy SPRITE_HITBACK,x
lda BOSS_FLASH_TABLE,y
sta VIC_SPRITE_COLOR,x

cpy #0
bne .NoHitBack
lda #1
sta VIC_SPRITE_COLOR,x
;make vulnerable again
lda SPRITE_STATE,x
cmp #128
bne .NoHitBack

lda #0
sta SPRITE_STATE,x

.NoHitBack
lda DELAYED_GENERIC_COUNTER
and #$03
bne .NoAnimUpdate

.NoAnimUpdate
lda SPRITE_STATE,x
bne +
jmp .FindTargetY

+
cmp #1
beq .MoveTowardsTarget
cmp #2
beq .Attack
cmp #3
beq .CoolOff

lda #0
sta SPRITE_STATE,x
rts

.CoolOff
inc SPRITE_MODE_POS,x
lda SPRITE_MODE_POS,x
cmp #30
bne +

lda #0
sta SPRITE_STATE,x

+
rts

.Attack
inc SPRITE_MOVE_POS,x
lda SPRITE_MOVE_POS,x
and #$1f
cmp #$1f
beq +
rts

+
;free bats
inc SPRITE_MODE_POS,x
lda SPRITE_MODE_POS,x
cmp #5
bne +

inc SPRITE_STATE,x
lda #0
sta SPRITE_MODE_POS,x
rts

+
lda SPRITE_CHAR_POS_X,x
sta PARAM1
lda SPRITE_CHAR_POS_Y,x
sta PARAM2
inc PARAM2
stx PARAM10
jsr FindEmptySpriteSlot
beq ++

lda #TYPE_BAT_ATTACKING
sta PARAM3
jsr SpawnObject
lda #0
sta SPRITE_DIRECTION,x
jsr FindEmptySpriteSlot
beq ++
jsr SpawnObject
lda #1
sta SPRITE_DIRECTION,x

++
ldx PARAM10
rts

.MoveTowardsTarget
;player index in y
lda SPRITE_VALUE,x
cmp SPRITE_CHAR_POS_Y,x
bne +

;arrived at target Y
inc SPRITE_STATE,x
lda #0
sta SPRITE_MODE_POS,x
rts

+
bpl .MoveDown

;move up?
lda SPRITE_DIRECTION_Y,x
bne .AlreadyLookingUp
lda SPRITE_MOVE_POS_Y,x
beq .TurnUNow
dec SPRITE_MOVE_POS_Y,x
bne .DoGhostMove

.TurnUNow
;turning now
lda #1
sta SPRITE_DIRECTION_Y,x
jmp .DoGhostMove

.AlreadyLookingUp
lda SPRITE_MOVE_POS_Y,x
cmp #BOSS_MOVE_SPEED
beq .DoGhostMove
inc SPRITE_MOVE_POS_Y,x
jmp .DoGhostMove

.MoveDown
lda SPRITE_DIRECTION_Y,x
beq .AlreadyLookingDown

lda SPRITE_MOVE_POS_Y,x
beq .TurnDNow
dec SPRITE_MOVE_POS_Y,x
bne .DoGhostMove

;turning now
.TurnDNow
lda #0
sta SPRITE_DIRECTION_Y,x
jmp .DoGhostMove

.AlreadyLookingDown
lda SPRITE_MOVE_POS_Y,x
cmp #BOSS_MOVE_SPEED
beq .DoGhostMove
inc SPRITE_MOVE_POS_Y,x
jmp .DoGhostMove

.DoGhostMove
;move X times
ldy SPRITE_MOVE_POS_Y,x
sty PARAM4
beq .MoveDone

lda SPRITE_DIRECTION_Y,x
beq .DoDown

.MoveLoopU
jsr ObjectMoveUpBlocking
dec PARAM4
bne .MoveLoopU
jmp .MoveDone

.DoDown
.MoveLoopD
jsr ObjectMoveDownBlockingNoPlatform
dec PARAM4
bne .MoveLoopD

.MoveDone
rts

.FindTargetY
lda #4
sta PARAM5
lda #18
sta PARAM6
jsr GenerateRangedRandom
sta SPRITE_VALUE,x
inc SPRITE_STATE,x
rts



For the boss routine we require a little utility function which returns a ranged random number. No division or module means manual work: create random number, subtract range until it's small enough, then add the lower range.

;lower end = PARAM5
;higher end = PARAM6
GenerateRangedRandom
lda PARAM6
sec
sbc PARAM5
clc
adc #1
sta PARAM6
jsr GenerateRandomNumber

.CheckValue
cmp PARAM6
bcc .ValueOk

;too high
sec
sbc PARAM6
jmp .CheckValue

.ValueOk
clc
adc PARAM5
rts



Have fun!


step74.zip