🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

A C64 Game - Step 60

posted in New Old Things
Published July 21, 2012
Advertisement

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

.PlayerIsActivecmp #TYPE_PLAYER_DEANbeq +
          cmp #TYPE_PLAYER_SAMbeq +
          rts

+
          lda SPRITE_STATE,y
          cmp #128bcs .PlayerNotActive

          ;compare char positions in x
          lda SPRITE_CHAR_POS_X,x
          cmp SPRITE_CHAR_POS_X,y
          beq .XMatch

          clc
          adc #1cmp SPRITE_CHAR_POS_X,y
          beq .XMatch

          sec
          sbc #2cmp 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_SAMbne .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 + 1clcadc #( ( 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 #0bne .NoHitBack

          ;make vulnerable again
          lda SPRITE_STATE,x
          cmp #129bne .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_DEANbeq .FoundPlayer
          cmp #TYPE_PLAYER_SAMbeq .FoundPlayer

          ;check other player
          tya
          eor #1
          tay
          lda SPRITE_ACTIVE,y
          cmp #TYPE_PLAYER_DEANbeq .FoundPlayer
          cmp #TYPE_PLAYER_SAMbeq .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 #$01beq +

          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 #$80beq .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 #4beq .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 #11bcc .BeamNotDangerous
          cmp #29bcs .BeamNotDangerous
;does player hit beam?
          ldy #0
          jsr CheckIsPlayerCollidingWithBeamV
          ldy #1
          jsr CheckIsPlayerCollidingWithBeamV

.BeamNotDangerous
          lda SPRITE_MODE_POS,x
          cmp #11beq .BeamStep1
          cmp #12beq .BeamStep2
          cmp #13beq .BeamStep3
          cmp #16beq .BeamStep4
          cmp #17beq .BeamStep3
          cmp #18beq .BeamStep4
          cmp #19beq .BeamStep3
          cmp #20beq .BeamStep4
          cmp #21beq .BeamStep3
          cmp #22beq .BeamStep4
          cmp #23beq .BeamStep3
          cmp #24beq .BeamStep4
          cmp #25beq .BeamStep3
          cmp #26beq .BeamStep4
          cmp #27beq .BeamStep3
          cmp #28beq .BeamStep4
          cmp #29beq .BeamStep3
          cmp #30beq .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

Previous Step Next Step

1 likes 1 comments

Comments

Programming020195BRook
So much to catch up on!! Awesome work! :)

Keep up the great work!
July 24, 2012 11:24 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement