A C64 Game - Step 60
And here's boss #3. Good luck!

A note to the latter code additions: If you wonder about the +(+) and -(-) labels, they are relative labels. They basically work like this: If a jmp or other reference is encountered, the compiler looks forward (+) or backward(-) for the first matching location. The +/- labels can be reused.
This avoids all annoying loop23, otherloop14b, etc. labels.
This boss has a vertical beam again, but this time only downwards. So here's a specialised check routine:
;------------------------------------------------------------
;check player vs. beam
; beam boss index in x
; player index in y
; PARAM5 = beam start Y
;------------------------------------------------------------
!zone CheckIsPlayerCollidingWithBeamV
CheckIsPlayerCollidingWithBeamV
lda SPRITE_ACTIVE,y
bne .PlayerIsActive
.PlayerNotActive
rts
.PlayerIsActive
cmp #TYPE_PLAYER_DEAN
beq +
cmp #TYPE_PLAYER_SAM
beq +
rts
+
lda SPRITE_STATE,y
cmp #128
bcs .PlayerNotActive
;compare char positions in x
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X,y
beq .XMatch
clc
adc #1
cmp SPRITE_CHAR_POS_X,y
beq .XMatch
sec
sbc #2
cmp SPRITE_CHAR_POS_X,y
beq .XMatch
;not hit
rts
.XMatch
;compare char positions in y
lda SPRITE_CHAR_POS_Y,x
cmp SPRITE_CHAR_POS_Y,y
bmi .PlayerHit
;not hit
rts
.PlayerHit
;player killed
lda #129
sta SPRITE_STATE,y
lda #SPRITE_PLAYER_DEAD
sta SPRITE_POINTER_BASE,y
lda #0
sta SPRITE_MOVE_POS,y
lda SPRITE_ACTIVE,y
cmp #TYPE_PLAYER_SAM
bne .PlayerWasDean
;reset Sam specific variables
lda #0
sta SPRITE_HELD
.PlayerWasDean
rts
Code reuse and refactoring from the first boss gives us a routine to draw a vertical beam:
!zone DrawBeamV
DrawBeamV
ldy PARAM4
ldx PARAM5
.NextLine
lda SCREEN_LINE_OFFSET_TABLE_LO,x
sta ZEROPAGE_POINTER_1
sta ZEROPAGE_POINTER_2
lda SCREEN_LINE_OFFSET_TABLE_HI,x
sta ZEROPAGE_POINTER_1 + 1
clc
adc #( ( SCREEN_COLOR - SCREEN_CHAR ) >> 8 )
sta ZEROPAGE_POINTER_2 + 1
lda PARAM2
sta (ZEROPAGE_POINTER_1),y
lda PARAM3
sta (ZEROPAGE_POINTER_2),y
inx
cpx #22
bne .NextLine
ldx PARAM6
rts
And the rather complicated behaviour. The boss has two major states. One, where it flies horizontally and tries to home in on a player, and second, once a player has been seen, shoot downwards.
;------------------------------------------------------------
;boss 3
;state 1 = shoot
;state 128 = follow player
;state 129 = shoot, hitback active
;------------------------------------------------------------
!zone BehaviourBoss3
BehaviourBoss3
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
;make vulnerable again
lda SPRITE_STATE,x
cmp #129
bne .NoHitBack
lda #1
sta SPRITE_STATE,x
.NoHitBack
lda SPRITE_STATE,x
and #$7f
beq .FollowPlayer
;shoot state
jmp .ShootDown
.FollowPlayer
;above player?
txa
and #$01
tay
lda SPRITE_ACTIVE,y
cmp #TYPE_PLAYER_DEAN
beq .FoundPlayer
cmp #TYPE_PLAYER_SAM
beq .FoundPlayer
;check other player
tya
eor #1
tay
lda SPRITE_ACTIVE,y
cmp #TYPE_PLAYER_DEAN
beq .FoundPlayer
cmp #TYPE_PLAYER_SAM
beq .FoundPlayer
;no player to hunt
rts
.FoundPlayer
;player index in y
lda SPRITE_CHAR_POS_X,y
cmp SPRITE_CHAR_POS_X,x
bne +
;enter attack mode
lda #1
sta SPRITE_STATE,x
lda #0
sta SPRITE_MODE_POS,x
rts
+
lda DELAYED_GENERIC_COUNTER
and #$01
beq +
rts
+
;y swing
inc SPRITE_MOVE_POS_Y,x
lda SPRITE_MOVE_POS_Y,x
and #15
sta SPRITE_MOVE_POS_Y,x
ldy SPRITE_MOVE_POS_Y,x
lda PATH_DY,y
beq .NoYMoveNeeded
sta PARAM1
and #$80
beq .MoveDown
;move up
lda PARAM1
and #$7f
sta PARAM1
.MoveUp
jsr ObjectMoveUp
dec PARAM1
bne .MoveUp
jmp BossFollowPlayerX
.MoveDown
jsr ObjectMoveDown
dec PARAM1
bne .MoveDown
.NoYMoveNeeded
jmp BossFollowPlayerX
.ShootDown
;Attack modes (more modes?)
inc SPRITE_ANNOYED,x
lda SPRITE_ANNOYED,x
cmp #4
beq .NextAttackStep
rts
.NextAttackStep
lda #0
sta SPRITE_ANNOYED,x
lda SPRITE_CHAR_POS_X,x
sta PARAM4
lda SPRITE_CHAR_POS_Y,x
sta PARAM5
inc SPRITE_MODE_POS,x
lda SPRITE_MODE_POS,x
cmp #11
bcc .BeamNotDangerous
cmp #29
bcs .BeamNotDangerous
;does player hit beam?
ldy #0
jsr CheckIsPlayerCollidingWithBeamV
ldy #1
jsr CheckIsPlayerCollidingWithBeamV
.BeamNotDangerous
lda SPRITE_MODE_POS,x
cmp #11
beq .BeamStep1
cmp #12
beq .BeamStep2
cmp #13
beq .BeamStep3
cmp #16
beq .BeamStep4
cmp #17
beq .BeamStep3
cmp #18
beq .BeamStep4
cmp #19
beq .BeamStep3
cmp #20
beq .BeamStep4
cmp #21
beq .BeamStep3
cmp #22
beq .BeamStep4
cmp #23
beq .BeamStep3
cmp #24
beq .BeamStep4
cmp #25
beq .BeamStep3
cmp #26
beq .BeamStep4
cmp #27
beq .BeamStep3
cmp #28
beq .BeamStep4
cmp #29
beq .BeamStep3
cmp #30
beq .BeamEnd
rts
.HandleBeam
lda BEAM_CHAR_H,y
sta PARAM1
lda BEAM_CHAR_V,y
sta PARAM2
lda BEAM_COLOR,y
sta PARAM3
txa
pha
jsr DrawBeamV
pla
tax
rts
.BeamStep1
;beam
ldy #BEAM_TYPE_DARK
jmp .HandleBeam
.BeamStep2
;beam
ldy #BEAM_TYPE_MEDIUM
jmp .HandleBeam
.BeamStep3
;beam
ldy #BEAM_TYPE_LIGHT
jmp .HandleBeam
.BeamStep4
;beam
ldy #BEAM_TYPE_LIGHT2
jmp .HandleBeam
.BeamEnd
jsr RestoreBeamHV
lda #128
sta SPRITE_STATE,x
rts
Plus the usual table additions which I don't list here.
Have fun!
step60.zip