Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics


A C64 Game - Step 56

Posted by Endurion, in C64 15 June 2012 · 729 views

And here's the next boss. A striking similarity to the first boss, and yet a little bit different.

The main behaviour of this boss is the same as the previous, only the beam is diagonal this time.

Attached Image

Making a diagonal beam is somewhat more difficult, as you need to check for both playfield borders. The beams are started from the boss position and then all 4 directions are tackled after each other.

;------------------------------------------------------------
;boss
;------------------------------------------------------------
!zone BehaviourBoss2
BehaviourBoss2
		
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 #128
		  bne .NoHitBack
		
		  lda #0
		  sta SPRITE_STATE,x
	  
.NoHitBack	  
		  lda DELAYED_GENERIC_COUNTER
		  and #$03
		  bne .NoAnimUpdate
		
		  ;lda SPRITE_POINTER_BASE,x
		  ;eor #$01
		  ;sta SPRITE_POINTER_BASE,x
		
.NoAnimUpdate	
		  lda SPRITE_STATE,x
		  and #$7f
		  bne .NotFollowPlayer
		  jmp BossFollowPlayer
		
.NotFollowPlayer		
		  cmp #1
		  beq .AttackMode
		  rts
		
.AttackMode		
		  ;Attack modes (more modes?)
		  inc SPRITE_MOVE_POS,x
		  lda SPRITE_MOVE_POS,x
		  cmp #4
		  beq .NextAttackStep
		  rts
		
.NextAttackStep
		  lda #0
		  sta SPRITE_MOVE_POS,x
		  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 CheckIsPlayerCollidingWithDiagonalBeam
		  ldy #1
		  jsr CheckIsPlayerCollidingWithDiagonalBeam
		
.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
		
.BeamStep1
		  ;beam
		  lda #BEAM_TYPE_DARK
		  jsr .DrawBeamDiagonal
		  rts
		
.BeamStep2
		  ;beam
		  lda #BEAM_TYPE_MEDIUM
		  jsr .DrawBeamDiagonal
		  rts
		
.BeamStep3
		  ;beam
		  lda #BEAM_TYPE_LIGHT
		  jsr .DrawBeamDiagonal
		  rts
		
.BeamStep4
		  ;beam
		  lda #BEAM_TYPE_LIGHT2
		  jsr .DrawBeamDiagonal
		  rts
		
.BeamEnd
		  jsr RestoreBeamDiagonal
		
		  lda #0
		  sta SPRITE_STATE,x
		  rts
		
.DrawBeamDiagonal
		  tay
		  lda BEAM_CHAR_NWSE,y
		  sta PARAM1
		  lda BEAM_CHAR_NESW,y
		  sta PARAM2
		  lda BEAM_COLOR,y
		  sta PARAM3
		
		  ldy SPRITE_CHAR_POS_Y,x
		  sty PARAM9
		  stx PARAM6
		
		  lda SPRITE_CHAR_POS_X,x
		  sta PARAM7
		  sta PARAM8
		
		
.NextUpperLine		
		  ldy PARAM9		
		  lda SCREEN_LINE_OFFSET_TABLE_LO,y
		  sta ZEROPAGE_POINTER_1
		  sta ZEROPAGE_POINTER_2
		  lda SCREEN_LINE_OFFSET_TABLE_HI,y
		  sta ZEROPAGE_POINTER_1 + 1
		  clc
		  adc #( ( SCREEN_COLOR - SCREEN_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_2 + 1
		
		
		
		  ;upper part
		  ;left
		  ldy PARAM7
		  beq .NoLeftPart
		  lda PARAM1
		  sta (ZEROPAGE_POINTER_1),y
		  lda PARAM3
		  sta (ZEROPAGE_POINTER_2),y
		
.NoLeftPart		
		  ;right
		  ldy PARAM8
		  beq .NoRightPart
		  lda PARAM2
		  sta (ZEROPAGE_POINTER_1),y
		  lda PARAM3
		  sta (ZEROPAGE_POINTER_2),y
		
.NoRightPart
		  dec PARAM9
		  beq .UpperPartDone
		
		  ;left border reached?
		  lda PARAM7
		  beq .LeftDone
		  dec PARAM7
.LeftDone
		  lda PARAM8
		  beq .RightEndReached
		  cmp #38
		  beq .RightEndReached
		  inc PARAM8
		  jmp .NextUpperLine
		
.RightEndReached
		  lda #0
		  sta PARAM8
		
		  jmp .NextUpperLine
.UpperPartDone

		  ;lower part
		  ldy SPRITE_CHAR_POS_Y,x
		  sty PARAM9
		  stx PARAM6
		
		  lda SPRITE_CHAR_POS_X,x
		  sta PARAM7
		  sta PARAM8
		
		
.NextUpperLineBottom
		  ldy PARAM9		
		  lda SCREEN_LINE_OFFSET_TABLE_LO,y
		  sta ZEROPAGE_POINTER_1
		  sta ZEROPAGE_POINTER_2
		  lda SCREEN_LINE_OFFSET_TABLE_HI,y
		  sta ZEROPAGE_POINTER_1 + 1
		  clc
		  adc #( ( SCREEN_COLOR - SCREEN_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_2 + 1
		
		  ;upper part
		  ;left
		  ldy PARAM7
		  beq .NoLeftPartBottom
		  lda PARAM2
		  sta (ZEROPAGE_POINTER_1),y
		  lda PARAM3
		  sta (ZEROPAGE_POINTER_2),y
		
.NoLeftPartBottom
		  ;right
		  ldy PARAM8
		  beq .NoRightPartBottom
		  lda PARAM1
		  sta (ZEROPAGE_POINTER_1),y
		  lda PARAM3
		  sta (ZEROPAGE_POINTER_2),y
		
.NoRightPartBottom
		  inc PARAM9
		  lda PARAM9
		  cmp #22
		  beq .LowerPartDone
		
		  ;left border reached?
		  lda PARAM7
		  beq .LeftDoneBottom
		  dec PARAM7
.LeftDoneBottom
		  lda PARAM8
		  beq .RightEndReachedBottom
		  cmp #38
		  beq .RightEndReachedBottom
		  inc PARAM8
		  jmp .NextUpperLineBottom
		
.RightEndReachedBottom
		  lda #0
		  sta PARAM8
		
		  jmp .NextUpperLineBottom
.LowerPartDone
		  ldx PARAM6
		  rts

Obviously all the same is repeated for the removal of the beam.

!zone RestoreBeamDiagonal
RestoreBeamDiagonal
		  ldy SPRITE_CHAR_POS_Y,x
		
		  stx PARAM6
		
		  ldy SPRITE_CHAR_POS_Y,x
		  sty PARAM9
		  stx PARAM6
		
		  lda SPRITE_CHAR_POS_X,x
		  sta PARAM7
		  sta PARAM8
		
		
.NextUpperLine		
		  ldy PARAM9		
		
		  lda SCREEN_LINE_OFFSET_TABLE_LO,y
		  sta ZEROPAGE_POINTER_1
		  sta ZEROPAGE_POINTER_2
		  sta ZEROPAGE_POINTER_3
		  sta ZEROPAGE_POINTER_4
		  lda SCREEN_LINE_OFFSET_TABLE_HI,y
		  sta ZEROPAGE_POINTER_1 + 1
		  sec
		  sbc #( ( SCREEN_CHAR - SCREEN_BACK_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_2 + 1
		  clc
		  adc #( ( SCREEN_COLOR - SCREEN_BACK_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_3 + 1
		  sec
		  sbc #( ( SCREEN_COLOR - SCREEN_BACK_COLOR ) >> 8 )
		  sta ZEROPAGE_POINTER_4 + 1
		
		  ;upper part
		  ;left
		  ldy PARAM7
		  beq .NoLeftPart
		  lda (ZEROPAGE_POINTER_2),y
		  sta (ZEROPAGE_POINTER_1),y
		  lda (ZEROPAGE_POINTER_4),y
		  sta (ZEROPAGE_POINTER_3),y
		
.NoLeftPart		
		  ;right
		  ldy PARAM8
		  beq .NoRightPart
		
		  lda (ZEROPAGE_POINTER_2),y
		  sta (ZEROPAGE_POINTER_1),y
		  lda (ZEROPAGE_POINTER_4),y
		  sta (ZEROPAGE_POINTER_3),y
		
.NoRightPart
		  dec PARAM9
		  beq .UpperPartDone
		
		  ;left border reached?
		  lda PARAM7
		  beq .LeftDone
		  dec PARAM7
.LeftDone
		  lda PARAM8
		  beq .RightEndReached
		  cmp #38
		  beq .RightEndReached
		  inc PARAM8
		  jmp .NextUpperLine
		
.RightEndReached
		  lda #0
		  sta PARAM8
		
		  jmp .NextUpperLine
.UpperPartDone

		  ;lower part
		  ldy SPRITE_CHAR_POS_Y,x
		  sty PARAM9
		  stx PARAM6
		
		  lda SPRITE_CHAR_POS_X,x
		  sta PARAM7
		  sta PARAM8
		
		
.NextUpperLineBottom
		  ldy PARAM9		
		
		  lda SCREEN_LINE_OFFSET_TABLE_LO,y
		  sta ZEROPAGE_POINTER_1
		  sta ZEROPAGE_POINTER_2
		  sta ZEROPAGE_POINTER_3
		  sta ZEROPAGE_POINTER_4
		  lda SCREEN_LINE_OFFSET_TABLE_HI,y
		  sta ZEROPAGE_POINTER_1 + 1
		  sec
		  sbc #( ( SCREEN_CHAR - SCREEN_BACK_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_2 + 1
		  clc
		  adc #( ( SCREEN_COLOR - SCREEN_BACK_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_3 + 1
		  sec
		  sbc #( ( SCREEN_COLOR - SCREEN_BACK_COLOR ) >> 8 )
		  sta ZEROPAGE_POINTER_4 + 1
		
		  ;upper part
		  ;left
		  ldy PARAM7
		  beq .NoLeftPartBottom
		
		  lda (ZEROPAGE_POINTER_2),y
		  sta (ZEROPAGE_POINTER_1),y
		  lda (ZEROPAGE_POINTER_4),y
		  sta (ZEROPAGE_POINTER_3),y
		
.NoLeftPartBottom
		  ;right
		  ldy PARAM8
		  beq .NoRightPartBottom
		
		  lda (ZEROPAGE_POINTER_2),y
		  sta (ZEROPAGE_POINTER_1),y
		  lda (ZEROPAGE_POINTER_4),y
		  sta (ZEROPAGE_POINTER_3),y
		
.NoRightPartBottom
		  inc PARAM9
		  lda PARAM9
		  cmp #22
		  beq .LowerPartDone
		
		  ;left border reached?
		  lda PARAM7
		  beq .LeftDoneBottom
		  dec PARAM7
.LeftDoneBottom
		  lda PARAM8
		  beq .RightEndReachedBottom
		  cmp #38
		  beq .RightEndReachedBottom
		  inc PARAM8
		  jmp .NextUpperLineBottom
		
.RightEndReachedBottom
		  lda #0
		  sta PARAM8
		
		  jmp .NextUpperLineBottom
.LowerPartDone
		  ldx PARAM6
		  rts

Checking if the player is hit by the beam as a bit different as well. The previous boss beam was checked simply by comparing X and Y pos. Now we take the distances between X and Y pos and compare them. They must be either equal or only differ by one to count as colliding.

;------------------------------------------------------------
;check player vs. diagonal beam
; beam boss index in x
; player index in y
;------------------------------------------------------------
!zone CheckIsPlayerCollidingWithDiagonalBeam
CheckIsPlayerCollidingWithDiagonalBeam
		  lda SPRITE_ACTIVE,y
		  bne .PlayerIsActive
.PlayerNotActive		
		  rts
		
.PlayerIsActive		
		  lda SPRITE_STATE,y
		  cmp #128
		  bcs .PlayerNotActive
		
		  ;compare char positions in x
		  lda SPRITE_CHAR_POS_X,x
		  sec
		  sbc SPRITE_CHAR_POS_X,y
		  bpl .PositiveX
		
		  lda SPRITE_CHAR_POS_X,y
		  sec
		  sbc SPRITE_CHAR_POS_X,x
.PositiveX
		  sta PARAM1
		
		  lda SPRITE_CHAR_POS_Y,x
		  sec
		  sbc SPRITE_CHAR_POS_Y,y
		  bpl .PositiveY
		
		  lda SPRITE_CHAR_POS_Y,y
		  sec
		  sbc SPRITE_CHAR_POS_Y,x
.PositiveY
		  sta PARAM2
		
		  lda PARAM1
		  cmp PARAM2
		  beq .PlayerHit
		
		  lda PARAM1
		  sec
		  sbc PARAM2
		  and #$7f
		  cmp #1
		  beq .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


Play the first boss, then stumble upon this one. It's not really difficult as well, but annoying to get the habit of moving out of the way for the first boss out of your mind ;)

Have fun!


Previous Step   Next Step

Attached Files






PARTNERS