Jump to content

  • Log In with Google      Sign In   
  • Create Account

New Old Things



A C64 Game - Step 92

Posted by Endurion, in C64 23 March 2013 - - - - - - · 1,020 views

Poor Sam was left out again. Now he can kill the boss too.

Attached Image

Since the boss is a special beast you wouldn't want Sam just to stand there and kill him without any reaction.

We add a new variable BOSS_HELD, similar to the SPRITE_HELD value.
So if SAM hurts the enemy, and it's the boss, the boss is released from Sam's grip:
		  dec SPRITE_HP,x
		  beq .EnemyKilled

		 

		  ;enemy was hurt

		  lda BOSS_HELD

		  beq .EnemyWasHurt

		 

		  ;release if end boss

		  jmp .SamNotFirePushed

BOSS_HELD is set to 1 if Sam has the boss in his force grip. We check if the sprite caught is the last boss or one of his parts:
.EnemyHit		 

		  ;enemy hit!

		  stx SPRITE_HELD

		  ldy SPRITE_HELD

		  inc SPRITE_HELD

		 

		  lda SPRITE_ACTIVE,y

		  cmp #TYPE_BOSS7

		  beq .HoldingBoss

		  cmp #TYPE_BOSS_PART

		  beq .HoldingBoss

		  jmp .NotHoldingBoss

		 

.HoldingBoss		 

		  sty BOSS_HELD

		  inc BOSS_HELD

.NotHoldingBoss


Therefore we also need to clear the bit in case the enemy or Sam is killed:
!zone KillEnemy

KillEnemy

		  ;is the enemy currently held?

		  ldy SPRITE_HELD

		  dey

		  sty PARAM4

		  cpx PARAM4

		  bne .WasNotHeld

		 

		  lda #0

		  sta SPRITE_HELD

		  sta BOSS_HELD

Obviously the boss should not move when being caught, so in BehaviourBoss7 we add an early bail out:
.NoHitBack

		  lda BOSS_HELD

		  beq +

		 

		  rts


+


The step also adds a few bug fixes, as in the boss not auto-moving the bats he spawned (as if they were body parts).

Have fun!


Previous Step Next Step

Attached Files




A C64 Game - Step 91

Posted by Endurion, in C64 16 March 2013 - - - - - - · 1,173 views

Aaaand the torso gets to fight back too, not only sit put.


Attached Image


Time to reuse existing code again. The torso will spit out bats just like the last two bossed did. SPRITE_MODE_POS is used to stop the attacking mode and revert back to movement.

A contains the number of boss parts killed (so 4 = 2 legs plus 2 arms):
		  cmp #4

		  bne +
		  ;attack with bats

		  lda SPRITE_CHAR_POS_X,x

		  sta PARAM1

		  lda SPRITE_CHAR_POS_Y,x

		  clc

		  adc #4

		  sta PARAM2

		  inc PARAM2

		  stx PARAM10

		 

		  jsr GenerateRandomNumber

		  and #$01

		  beq .NoBatLeft
		  jsr FindEmptySpriteSlot

		  beq ++

		 

		  lda #TYPE_BAT_ATTACKING

		  sta PARAM3

		  jsr SpawnObject

		  lda #0

		  sta SPRITE_DIRECTION,x

.NoBatLeft

		  jsr GenerateRandomNumber

		  and #$01

		  beq .NoBatRight
		  jsr FindEmptySpriteSlot

		  beq ++
		  jsr SpawnObject

		  lda #1

		  sta SPRITE_DIRECTION,x

++		 

.NoBatRight

		  ldx CURRENT_INDEX

		 

		  lda SPRITE_MODE_POS,x

		  cmp #20

		  bne +++

				   

		  dec SPRITE_STATE,x

		  lda #0

		  sta SPRITE_MODE_POS,x

+++

		  rts


+

That's all there is for this step Posted Image


Previous Step Next Step

Attached Files




A C64 Game - Step 90

Posted by Endurion, in C64 09 March 2013 - - - - - - · 938 views

And the boss got a bit more lively (visually), it was quite stiff previously. Moving body parts and the head screams (also visually) when getting hurt.

Attached Image


The boss helper code is enhanced by a routine doing circling movements:


jsr GenerateRandomNumber
and #$03
bne .DoY

inc SPRITE_MOVE_POS,x
lda SPRITE_MOVE_POS,x
and #$0f
sta SPRITE_MOVE_POS,x
ldy SPRITE_MOVE_POS,x
lda BOSS_DELTA_TABLE_X,y
beq .DoY
sta PARAM1

bmi .Left

.Right
jsr MoveSpriteRight
dec PARAM1
bne .Right
jmp .DoY

.Left
jsr MoveSpriteLeft
inc PARAM1
bne .Left

.DoY
jsr GenerateRandomNumber
and #$03
bne .Done
inc SPRITE_MOVE_POS_Y,x
lda SPRITE_MOVE_POS_Y,x
and #$0f
sta SPRITE_MOVE_POS_Y,x
ldy SPRITE_MOVE_POS_Y,x
lda BOSS_DELTA_TABLE_Y,y
beq .Done
sta PARAM1

bmi .Up

.Down
jsr MoveSpriteDown
dec PARAM1
bne .Down
jmp .Done

.Up
jsr MoveSpriteUp
inc PARAM1
bne .Up

.Done
rts


Plus a rather simple swinging table:
BOSS_DELTA_TABLE_X
!byte 0, 1, 0, 1, 1, 0, 1, 0
BOSS_DELTA_TABLE_Y
!byte 0, $ff, 0, $ff, $ff, 0, $ff, 0
!byte 0, 1, 0, 1, 1, 0, 1, 0


To make the boss' head scream we adjust its hurt routine:

;------------------------------------------------------------
;hit behaviour getting hurt
;------------------------------------------------------------
!zone HitBehaviourBoss7
HitBehaviourBoss7
lda #SPRITE_BOSS_HEAD_HURT
sta SPRITE_POINTER_BASE,x
jmp HitBehaviourHurt



Previous Step Next Step

Attached Files




A C64 Game - Step 89

Posted by Endurion, in C64 02 March 2013 - - - - - - · 927 views

Now you can kill the last part. Beware, it will fight back though!


Attached Image


All kind of changes are added to the boss 7 behaviour routine, as it now gets a new state. First of all, handle getting hit
;------------------------------------------------------------
;boss #7
;state = 0, 128 -> random movements
;state = 129 -> attack with beams
;------------------------------------------------------------
!zone BehaviourBoss7
BehaviourBoss7
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 #0
          sta SPRITE_STATE,x
          lda #2
          sta VIC_SPRITE_COLOR,x
        
.NoHitBack        

          lda SPRITE_STATE,x
          beq .RandomMovements
          cmp #1
          beq +
          cmp #129
          beq +
          jmp .RandomMovements
          
+          
In AttackWithBeams we add a special case when all body parts have been destroyed:
          lda BOSS_PARTS_KILLED
          cmp #5
          bne +
          jmp FinalAttack
          
+          

FinalAttack is the meat of the new part. Shooting a beam and rotating it over the screen! (Subtly reusing existing beam helper routines)
!zone FinalAttack
.BeamStep1
          ;left arm
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM3
          lda #0
          sta PARAM1
          lda SPRITE_CHAR_POS_X,x
          sta PARAM2
          ldy #0
          jsr CheckIsPlayerCollidingWithYPosH
          ldy #1
          jsr CheckIsPlayerCollidingWithYPosH
          

          ldy #BEAM_TYPE_DARK
          lda BEAM_CHAR_H,y
          sta PARAM1
          lda #1
          sta PARAM2
          lda #0
          sta PARAM3
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM4
          lda SPRITE_CHAR_POS_X,x
          sec
          sbc #2
          sta PARAM5
          jsr DrawBeamHSegment
          rts
          
.BeamStep1End
          ;remove beam
          lda #0
          sta PARAM3
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM4
          lda #39
          sta PARAM5
          jsr RestoreBeamHSegment
          jsr RedrawItems
          rts


.BeamStep2

          lda SPRITE_CHAR_POS_Y,x
          sta PARAM2
          lda SPRITE_CHAR_POS_X,x
          sta PARAM1
          ldy #0
          jsr CheckIsPlayerCollidingWithDiagonalLLUR
          ldy #1
          jsr CheckIsPlayerCollidingWithDiagonalLLUR

          ldy #3
          lda BEAM_CHAR_NESW,y
          sta PARAM1
          lda #1
          sta PARAM2
          lda SPRITE_CHAR_POS_X,x
          sta PARAM3
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM4
          jsr DrawBeamDiagonalLLUR
          rts
          
.BeamStep2End
          lda SPRITE_CHAR_POS_X,x
          sta PARAM3
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM4
          jsr RestoreBeamDiagonalLLUR
          jsr RedrawItems
          rts

FinalAttack
          ;mode 5, 6 = left
          ;     7, 8 = diagonal left down
          ;     9, 10 = down
          ;     11, 12 = diagonal right down
          ;     13, 14 = right
          
          lda SPRITE_MODE_POS,x
          cmp #5
          bne +
          jmp .BeamStep1
+          
          cmp #6
          beq .BeamStep1End
          cmp #7
          beq .BeamStep2
          cmp #8
          beq .BeamStep2End
          cmp #9
          beq .BeamStep3
          cmp #10
          beq .BeamStep3End
          cmp #11
          beq .BeamStep4
          cmp #12
          bne +
          jmp .BeamStep4End
+          
          cmp #13
          bne +
          jmp .BeamStep5
+          
          cmp #14
          bne +
          ; .BeamStep5End
          jmp .BeamStep1End
+
          cmp #15
          bne +

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

.BeamStep3

          ;does player hit beam?
          ldy #0
          jsr CheckIsPlayerCollidingWithBeamV
          ldy #1
          jsr CheckIsPlayerCollidingWithBeamV

          ldy #BEAM_TYPE_DARK
          lda BEAM_CHAR_H,y
          sta PARAM1
          lda BEAM_CHAR_V,y
          sta PARAM2
          lda #1
          sta PARAM3

          lda SPRITE_CHAR_POS_X,x
          sta PARAM4
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM5
          stx PARAM6
          jsr DrawBeamV
          rts
          
.BeamStep3End
          lda SPRITE_CHAR_POS_X,x
          sta PARAM4
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM5

          jsr RestoreBeamHV
          jsr RedrawItems
          rts
          


.BeamStep4
          lda SPRITE_CHAR_POS_X,x
          sta PARAM1
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM2
          ldy #0
          jsr CheckIsPlayerCollidingWithDiagonalULLR
          ldy #1
          jsr CheckIsPlayerCollidingWithDiagonalULLR

          ldy #3
          lda BEAM_CHAR_NWSE,y
          sta PARAM1
          lda #1
          sta PARAM2
          lda SPRITE_CHAR_POS_X,x
          sta PARAM3
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM4
          jsr DrawBeamDiagonalULLR

          rts
          
.BeamStep4End
          lda SPRITE_CHAR_POS_X,x
          sta PARAM3
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM4
          jsr RestoreBeamDiagonalULLR
          jsr RedrawItems
          rts


.BeamStep5

          ;right arm
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM3
          lda SPRITE_CHAR_POS_X,x
          sta PARAM1
          lda #39
          sta PARAM2
          
          ldy #0
          jsr CheckIsPlayerCollidingWithYPosH
          ldy #1
          jsr CheckIsPlayerCollidingWithYPosH

          ldy #BEAM_TYPE_DARK
          lda BEAM_CHAR_H,y
          sta PARAM1
          lda #1
          sta PARAM2
          lda SPRITE_CHAR_POS_X,x
          sta PARAM3
          lda SPRITE_CHAR_POS_Y,x
          sta PARAM4
          lda #39
          sta PARAM5
          jsr DrawBeamHSegment
          rts
Have fun and look out!


Previous Step Next Step

Attached Files




A C64 Game - Step 88

Posted by Endurion, in C64 23 February 2013 - - - - - - · 1,026 views

And finally, here's the big boss. Expect him to put up quite a fight once he is completed. Note that currently you cannot kill the last part.

Attached Image

First of all, the boss is not just simply there, it is entering with a few flashes. We reuse Dean's shot flash code for this. To mark the final boss entry we use a new bit in the level config byte:
		  ;final boss intro
		  lda LEVEL_CONFIG
		  and #$08
		  beq ++
		
		  jsr HandleFinalBossIntro
		  jmp .NotDoneYet
++

The boss is compiled of several sprites which we create once the flashes are done. Also, the boss bit is removed to avoid restarting the boss intro.
!zone HandleFinalBossIntro
HandleFinalBossIntro
		  inc FINAL_INTRO_TIMER_DELAY
		  lda FINAL_INTRO_TIMER_DELAY
		  and #$03
		  beq ++
		  rts
++		
		  inc FINAL_INTRO_TIMER
		  lda FINAL_INTRO_TIMER
		
		  cmp #5
		  beq .Flash
		  cmp #8
		  beq .Flash
		  cmp #10
		  beq .Flash
		  cmp #11
		  beq .SpawnBoss
		  rts
		
.Flash		
		  ;use dean's shot flash
		  lda #5
		  sta PLAYER_RELOAD_FLASH_POS
		  lda #1
		  sta VIC_BACKGROUND_COLOR
		  rts
		
.SpawnBoss
		  ;disable intro flag
		  lda LEVEL_CONFIG
		  and #$f7
		  sta LEVEL_CONFIG
		
		  ;spawn boss
		  lda #0
		  sta BOSS_PARTS_KILLED
		
		  lda #19
		  sta PARAM1
		  lda #6
		  sta PARAM2
		  lda #TYPE_BOSS7
		  sta PARAM3
		  jsr FindEmptySpriteSlot
		  jsr SpawnObject
		  stx PARAM10
		  ;torso
		  lda #19
		  sta PARAM1
		  lda #10
		  sta PARAM2
		  lda #TYPE_BOSS5
		  sta PARAM3
		  jsr FindEmptySpriteSlot
		  jsr SpawnObject
		  lda #TYPE_BOSS_PART
		  sta SPRITE_ACTIVE,x
		  lda #128
		  sta SPRITE_STATE,x
		  jsr MoveSpriteUp
		  jsr MoveSpriteUp
		  lda PARAM10
		  sta SPRITE_VALUE,x
		  lda #2
		  sta VIC_SPRITE_COLOR,x
		  ;left arm
		  lda #17
		  sta PARAM1
		  lda #9
		  sta PARAM2
		  lda #TYPE_BOSS3
		  sta PARAM3
		  jsr FindEmptySpriteSlot
		  jsr SpawnObject
		  lda #TYPE_BOSS_PART
		  sta SPRITE_ACTIVE,x
		  lda #0
		  sta SPRITE_STATE,x
		  lda PARAM10
		  sta SPRITE_VALUE,x
		  lda #2
		  sta VIC_SPRITE_COLOR,x
		  ;right arm
		  lda #21
		  sta PARAM1
		  lda #9
		  sta PARAM2
		  lda #TYPE_BOSS4
		  sta PARAM3
		  jsr FindEmptySpriteSlot
		  jsr SpawnObject
		  lda #TYPE_BOSS_PART
		  sta SPRITE_ACTIVE,x
		  lda #0
		  sta SPRITE_STATE,x
		  lda PARAM10
		  sta SPRITE_VALUE,x
		  lda #2
		  sta VIC_SPRITE_COLOR,x
		  ;left foot
		  lda #18
		  sta PARAM1
		  lda #13
		  sta PARAM2
		  lda #TYPE_BOSS2
		  sta PARAM3
		  jsr FindEmptySpriteSlot
		  jsr SpawnObject
		  lda #TYPE_BOSS_PART
		  sta SPRITE_ACTIVE,x
		  lda #0
		  sta SPRITE_STATE,x
		  lda PARAM10
		  sta SPRITE_VALUE,x
		  lda #2
		  sta VIC_SPRITE_COLOR,x
		  ;right foot
		  lda #20
		  sta PARAM1
		  lda #13
		  sta PARAM2
		  lda #TYPE_BOSS
		  sta PARAM3
		  jsr FindEmptySpriteSlot
		  jsr SpawnObject
		  lda #TYPE_BOSS_PART
		  sta SPRITE_ACTIVE,x
		  lda #0
		  sta SPRITE_STATE,x
		  lda PARAM10
		  sta SPRITE_VALUE,x
		  lda #2
		  sta VIC_SPRITE_COLOR,x
		
		  jmp .Flash

Also, the boss is required to be killed in several steps. First the limbs, followed by torso and finally the head. This is done by setting states accordingly (remember, states >= 128 mark invincibility) increasing the killed body part count and making other parts vulnerable:
		  cpy #TYPE_BOSS_PART
		  bne ++
		
		  inc BOSS_PARTS_KILLED
		  lda BOSS_PARTS_KILLED
		  cmp #5
		  beq .MakeBossHeadVulnerable
		  cmp #4
		  bne ++
		
		  ;make boss torso vulnerable
		  ldy #1
		
-		
		  lda SPRITE_ACTIVE,y
		  cmp #TYPE_BOSS_PART
		  beq +
		
		  iny
		  bne -
		
+		
		  lda #0
		  sta SPRITE_STATE,y
		  jmp ++
		
.MakeBossHeadVulnerable		
		  ldy #1
		
-		
		  lda SPRITE_ACTIVE,y
		  cmp #TYPE_BOSS7
		  beq +
		  iny
		  bne -
		
+		
		  lda #0
		  sta SPRITE_STATE,y
++

Since the boss object is controlled by the head but bigger with all parts attached the possible movement area needs to be limited (the boss body should not move outside the screen). Therefore a little check is added to all movement routines:
		  lda SPRITE_CHAR_POS_X,x
		  cmp MOVE_BORDER_LEFT
		  beq .BlockedLeft

..and similar to the other three directions.

The bosses limbs are shooting beams horizontally and diagonally. These require a few changes to the existing collision check routines to allow for partial beams:
;------------------------------------------------------------
;check player vs. beam H
; YPos in PARAM3
; player index in y
;------------------------------------------------------------
!zone CheckIsPlayerCollidingWithYPosH
CheckIsPlayerCollidingWithYPosH
		  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
		
		  lda SPRITE_CHAR_POS_X,y
		  cmp PARAM1
		  bcc .PlayerNotActive
		  cmp PARAM2
		  bcs .PlayerNotActive
		
		  ;compare char positions in y
		  lda PARAM3
		  cmp SPRITE_CHAR_POS_Y,y
		  beq .PlayerHit
		
		  clc
		  adc #1
		  cmp SPRITE_CHAR_POS_Y,y
		  beq .PlayerHit
		
		  sec
		  sbc #2
		  cmp SPRITE_CHAR_POS_Y,y
		  beq .PlayerHit
		
		  ;not hit
		  rts
		
.PlayerHit		
		  ;player killed
		  jmp KillPlayer

;------------------------------------------------------------
;check player vs. diagonal beam
; X start in PARAM1
; Y start in PARAM2
; player index in y
;------------------------------------------------------------
!zone CheckIsPlayerCollidingWithDiagonalLLUR
CheckIsPlayerCollidingWithDiagonalLLUR
		  lda SPRITE_ACTIVE,y
		  bne .PlayerIsActive
.PlayerNotActive		
		  rts
		
.PlayerIsActive		
		  lda SPRITE_STATE,y
		  cmp #128
		  bcs .PlayerNotActive
		
		  ;compare char positions in x
		  lda PARAM1
		  sec
		  sbc SPRITE_CHAR_POS_X,y
		  bpl .PositiveX
		
		  ;player is to the right
		  rts
.PositiveX
		  sta PARAM3
		
		  lda PARAM2
		  sec
		  sbc SPRITE_CHAR_POS_Y,y
		  bpl .PositiveY
		
		  lda SPRITE_CHAR_POS_Y,y
		  sec
		  sbc PARAM2
.PositiveY
		  sta PARAM4
		
		  lda PARAM3
		  cmp PARAM4
		  beq .PlayerHit
		
		  lda PARAM3
		  sec
		  sbc PARAM4
		  bpl .PositiveDelta
		  lda PARAM4
		  sec
		  sbc PARAM3
.PositiveDelta		
		  cmp #1
		  beq .PlayerHit
		
		
		  ;not hit
		  rts
		
.PlayerHit		
		  ;player killed
		  jmp KillPlayer

;------------------------------------------------------------
;check player vs. diagonal beam
; X start in PARAM1
; Y start in PARAM2
; player index in y
;------------------------------------------------------------
!zone CheckIsPlayerCollidingWithDiagonalULLR
CheckIsPlayerCollidingWithDiagonalULLR
		  lda SPRITE_ACTIVE,y
		  bne .PlayerIsActive
.PlayerNotActive		
		  rts
		
.PlayerIsActive		
		  lda SPRITE_STATE,y
		  cmp #128
		  bcs .PlayerNotActive
		
		  ;compare char positions in x
		  lda PARAM1
		  sec
		  sbc SPRITE_CHAR_POS_X,y
		  bpl .PlayerNotActive
		
		  ;player is to the right
		  lda SPRITE_CHAR_POS_X,y
		  sec
		  sbc PARAM1
		  sta PARAM3
		
		  lda PARAM2
		  sec
		  sbc SPRITE_CHAR_POS_Y,y
		  bpl .PositiveY
		
		  lda SPRITE_CHAR_POS_Y,y
		  sec
		  sbc PARAM2
.PositiveY
		  sta PARAM4
		
		  lda PARAM3
		  cmp PARAM4
		  beq .PlayerHit
		
		  lda PARAM3
		  sec
		  sbc PARAM4
		  bpl .PositiveDelta
		  lda PARAM4
		  sec
		  sbc PARAM3
.PositiveDelta		
		  cmp #1
		  beq .PlayerHit
		
		
		  ;not hit
		  rts
		
.PlayerHit		
		  ;player killed
		  jmp KillPlayer

All the beams are controlled by the boss head. Attack states, firing and collision checks:
;------------------------------------------------------------
;boss #7
;state = 128 -> random movements
;state = 129 -> attack with beams
;------------------------------------------------------------
!zone BehaviourBoss7
BehaviourBoss7
BOSS_MOVE_SPEED = 1
		  lda SPRITE_STATE,x
		  beq .RandomMovements
		  cmp #129
		  bne +
		  jmp .AttackWithBeams
+
.RandomMovements
		  inc SPRITE_MODE_POS,x
		  bne +
		  ;attack mode
		  lda #129
		  sta SPRITE_STATE,x
		  rts
+
		  lda SPRITE_MOVE_POS,x
		  bne .DoMove
		
		  ;find new random dir
		
		  lda #25
		  sta SPRITE_MOVE_POS,x
		
		  jsr GenerateRandomNumber
		  and #$01
		  sta SPRITE_DIRECTION,x
		  jsr GenerateRandomNumber
		  and #$01
		  sta SPRITE_DIRECTION_Y,x
.DoMove
		  dec SPRITE_MOVE_POS,x
		
		  lda #12
		  sta MOVE_BORDER_LEFT
		  lda #39 - 12
		  sta MOVE_BORDER_RIGHT
		  lda #4
		  sta MOVE_BORDER_TOP
		  lda #12
		  sta MOVE_BORDER_BOTTOM
		
		  lda SPRITE_DIRECTION,x
		  beq ++
		  jsr ObjectMoveLeftBlocking
		  beq .DoMoveY
		
		  ;move other parts
		  lda #5
		  sta PARAM10
-		
		  inx
		  jsr ObjectMoveLeft
		  dec PARAM10
		  bne -
		
		  jmp .DoMoveY
++		
		  jsr ObjectMoveRightBlocking	  
		  beq .DoMoveY
		
		  ;move other parts
		  lda #5
		  sta PARAM10
-		
		  inx
		  jsr ObjectMoveRight
		  dec PARAM10
		  bne -
		
.DoMoveY
		  ldx CURRENT_INDEX
		  lda SPRITE_DIRECTION_Y,x
		  beq ++
		  jsr ObjectMoveUpBlocking	  
		  beq .DoMoveDone
		
		  ;move other parts
		  lda #5
		  sta PARAM10
-		
		  inx
		  jsr ObjectMoveUp
		  dec PARAM10
		  bne -
		  jmp .DoMoveDone
++		
		  jsr ObjectMoveDownBlocking
		  beq .DoMoveDone
		
		  ;move other parts
		  lda #5
		  sta PARAM10
-		
		  inx
		  jsr ObjectMoveDown
		  dec PARAM10
		  bne -
.DoMoveDone		
		  lda #0
		  sta MOVE_BORDER_LEFT
		  sta MOVE_BORDER_TOP
		  lda #39
		  sta MOVE_BORDER_RIGHT
		  lda #23
		  sta MOVE_BORDER_BOTTOM
		  rts

.AttackWithBeams
		  inc SPRITE_MOVE_POS,x
		  lda SPRITE_MOVE_POS,x
		  and #$03
		  beq +
		  rts
+

		  inc SPRITE_MODE_POS,x
		
		  lda SPRITE_MODE_POS,x
		  cmp #5
		  bcs +
		  jmp .BeamNotDangerous
+		
		  cmp #12
		  bcc +
		  jmp .BeamNotDangerous
+		
		
		  ;does player hit beam?
		  ;modify x to point to arm object
		
		  ;TODO - only check left/right segment!
		
		  lda SPRITE_ACTIVE + 2,x
		  beq ++
		  ;left arm
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #3
		  sta PARAM3
		  lda #0
		  sta PARAM1
		  lda SPRITE_CHAR_POS_X,x
		  sec
		  sbc #2
		  sta PARAM2
		  ldy #0
		  jsr CheckIsPlayerCollidingWithYPosH
		  ldy #1
		  jsr CheckIsPlayerCollidingWithYPosH
++
		  lda SPRITE_ACTIVE + 3,x
		  beq ++
		  ;right arm
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #3
		  sta PARAM3
		  lda SPRITE_CHAR_POS_X,x
		  clc
		  adc #2
		  sta PARAM1
		  lda #39
		  sta PARAM2
		
		  ldy #0
		  jsr CheckIsPlayerCollidingWithYPosH
		  ldy #1
		  jsr CheckIsPlayerCollidingWithYPosH
++
		  lda SPRITE_ACTIVE + 4,x
		  beq ++
		
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #8
		  sta PARAM2
		  lda SPRITE_CHAR_POS_X,x
		  sec
		  sbc #1
		  sta PARAM1
		  ldy #0
		  jsr CheckIsPlayerCollidingWithDiagonalLLUR
		  ldy #1
		  jsr CheckIsPlayerCollidingWithDiagonalLLUR

++
		  lda SPRITE_ACTIVE + 5,x
		  beq ++
		
		  lda SPRITE_CHAR_POS_X,x
		  clc
		  adc #2
		  sta PARAM1
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #8
		  sta PARAM2
		  ldy #0
		  jsr CheckIsPlayerCollidingWithDiagonalULLR
		  ldy #1
		  jsr CheckIsPlayerCollidingWithDiagonalULLR
++		
		
		
.BeamNotDangerous		
		  lda SPRITE_MODE_POS,x
		  cmp #5
		  beq .BeamStep1
		  cmp #6
		  beq .BeamStep2
		  cmp #7
		  beq .BeamStep3
		  cmp #8
		  beq .BeamStep4
		  cmp #9
		  beq .BeamStep3
		  cmp #10
		  beq .BeamStep4
		  cmp #11
		  beq .BeamStep3
		  cmp #12
		  bne +
		  lda #128
		  sta SPRITE_STATE,x
		  lda #0
		  sta SPRITE_MODE_POS,x
		  ;remove beam
		  lda #0
		  sta PARAM3
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #3
		  sta PARAM4
		  lda #39
		  sta PARAM5
		  jsr RestoreBeamHSegment
		
		  lda SPRITE_CHAR_POS_X,x
		  sec
		  sbc #1
		  sta PARAM3
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #8
		  sta PARAM4
		  jsr RestoreBeamDiagonalLLUR
		
		  lda SPRITE_CHAR_POS_X,x
		  clc
		  adc #2
		  sta PARAM3
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #8
		  sta PARAM4
		  jsr RestoreBeamDiagonalULLR
		
+		
		  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
		
.HandleBeam
		  ;PARAM1 = beam h char
		  ;PARAM2 = beam color
		  ;PARAM3 = x char pos
		  ;PARAM4 = y char pos
		  ;PARAM5 = x end pos
		  tya
		  pha
		  lda BEAM_CHAR_H,y
		  sta PARAM1
		  lda BEAM_COLOR,y
		  sta PARAM2
		  ;left arm
		  lda SPRITE_ACTIVE + 2,x
		  beq ++
		  lda #0
		  sta PARAM3
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #3
		  sta PARAM4
		  lda SPRITE_CHAR_POS_X,x
		  sec
		  sbc #2
		  sta PARAM5
		  jsr DrawBeamHSegment
++
		  lda SPRITE_ACTIVE + 3,x
		  beq ++
		  lda SPRITE_CHAR_POS_X,x
		  clc
		  adc #3
		  sta PARAM3
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #3
		  sta PARAM4
		  lda #39
		  sta PARAM5
		  jsr DrawBeamHSegment
		
++
		  ;diagonal left
		  pla
		  pha
		  tay
		
		  lda SPRITE_ACTIVE + 4,x
		  beq ++
		
		  lda BEAM_CHAR_NESW,y
		  sta PARAM1
		  lda SPRITE_CHAR_POS_X,x
		  sec
		  sbc #1
		  sta PARAM3
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #8
		  sta PARAM4
		  jsr DrawBeamDiagonalLLUR
		
++		
		  pla
		  tay
		
		  lda SPRITE_ACTIVE + 5,x
		  beq ++
		
		  lda BEAM_CHAR_NWSE,y
		  sta PARAM1
		  lda SPRITE_CHAR_POS_X,x
		  clc
		  adc #2
		  sta PARAM3
		  lda SPRITE_CHAR_POS_Y,x
		  clc
		  adc #8
		  sta PARAM4
		  jsr DrawBeamDiagonalULLR
		
++		
		  rts

Firing the beams (and restoring background) is handled by new sub routines:
;PARAM1 = beam h char
;PARAM2 = beam color
;PARAM3 = x char pos
;PARAM4 = y char pos
!zone DrawBeamDiagonalLLUR
DrawBeamDiagonalLLUR
.NextLine
		  ldy PARAM4
		  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
		
		  ;left
		  ldy PARAM3
		  lda PARAM1
		  sta (ZEROPAGE_POINTER_1),y
		  lda PARAM2
		  sta (ZEROPAGE_POINTER_2),y
		
		  inc PARAM4
		  lda PARAM4
		  cmp #22
		  beq .LowerPartDone
	   
		  ;left border reached?
		  lda PARAM3
		  beq .LowerPartDone
		  dec PARAM3
		  jmp .NextLine
.LowerPartDone
		  rts
		
;PARAM3 = x char pos
;PARAM4 = y char pos
!zone RestoreBeamDiagonalLLUR
RestoreBeamDiagonalLLUR
.NextLine
		  ldy PARAM4
		  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
		  clc
		  adc #( ( SCREEN_COLOR - SCREEN_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_2 + 1
		  sec
		  sbc #( ( SCREEN_COLOR - SCREEN_BACK_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_3 + 1
		  sec
		  sbc #( ( SCREEN_BACK_CHAR - SCREEN_BACK_COLOR ) >> 8 )
		  sta ZEROPAGE_POINTER_4 + 1
		
		  ;left
		  ldy PARAM3
		  lda (ZEROPAGE_POINTER_3),y
		  sta (ZEROPAGE_POINTER_1),y
		  lda (ZEROPAGE_POINTER_4),y
		  sta (ZEROPAGE_POINTER_2),y
		
		  inc PARAM4
		  lda PARAM4
		  cmp #22
		  beq .LowerPartDone
	   
		  ;left border reached?
		  lda PARAM3
		  beq .LowerPartDone
		  dec PARAM3
		  jmp .NextLine
.LowerPartDone
		  rts

;PARAM1 = beam h char
;PARAM2 = beam color
;PARAM3 = x char pos
;PARAM4 = y char pos
!zone DrawBeamDiagonalULLR
DrawBeamDiagonalULLR
.NextLine
		  ldy PARAM4
		  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
		
		  ldy PARAM3
		  lda PARAM1
		  sta (ZEROPAGE_POINTER_1),y
		  lda PARAM2
		  sta (ZEROPAGE_POINTER_2),y
		
		  inc PARAM4
		  lda PARAM4
		  cmp #22
		  beq .LowerPartDone
	   
		  ;left border reached?
		  lda PARAM3
		  cmp #39
		  beq .LowerPartDone
		  inc PARAM3
		  jmp .NextLine
.LowerPartDone
		  rts
		
;PARAM3 = x char pos
;PARAM4 = y char pos
!zone RestoreBeamDiagonalULLR
RestoreBeamDiagonalULLR
.NextLine
		  ldy PARAM4
		  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
		  clc
		  adc #( ( SCREEN_COLOR - SCREEN_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_2 + 1
		  sec
		  sbc #( ( SCREEN_COLOR - SCREEN_BACK_CHAR ) >> 8 )
		  sta ZEROPAGE_POINTER_3 + 1
		  sec
		  sbc #( ( SCREEN_BACK_CHAR - SCREEN_BACK_COLOR ) >> 8 )
		  sta ZEROPAGE_POINTER_4 + 1
		
		  ldy PARAM3
		  lda (ZEROPAGE_POINTER_3),y
		  sta (ZEROPAGE_POINTER_1),y
		  lda (ZEROPAGE_POINTER_4),y
		  sta (ZEROPAGE_POINTER_2),y
		
		  inc PARAM4
		  lda PARAM4
		  cmp #22
		  beq .LowerPartDone
	   
		  ;left border reached?
		  lda PARAM3
		  cmp #39
		  beq .LowerPartDone
		  inc PARAM3
		  jmp .NextLine
.LowerPartDone
		  rts

The behaviour of the boss parts is surprisingly simple, just react on being hit:
;------------------------------------------------------------
;boss helper
;------------------------------------------------------------
!zone BehaviourBossHelper
BehaviourBossHelper
		  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 #0
		  sta SPRITE_STATE,x
		  lda #2
		  sta VIC_SPRITE_COLOR,x
	  
.NoHitBack	  
		  rts

Have fun!

Previous Step Next Step

Attached Files




A C64 Game - Step 87

Posted by Endurion, in C64 16 February 2013 - - - - - - · 1,119 views

And the last portal stage, I promise Posted Image

Attached Image


Previous Step Next Step

Attached Files




A C64 Game - Step 86

Posted by Endurion, in C64 09 February 2013 - - - - - - · 820 views

And something different for a change: Added road side stones to the story pages to make it look a bit neater.

Looks better in motion Posted Image



Attached Image


It's actually pretty simple: We add a stone in front and one in the back. Store positions and update them every frame with different deltas.

Start with the position value variables:
MOVE_STONES
		  !byte 0
MOVE_STONE_POS_BACK
		  !byte 0
MOVE_STONE_POS_FRONT
		  !byte 0

...and the actual code.
STONE_BACK_DISTANCE = 20
STONE_FRONT_DISTANCE = 24
		  lda MOVE_STONES
		  bne +
		  jmp .NoStones
+		 
		  ;background
		  ldy #19
		  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
		 
		  ldy MOVE_STONE_POS_BACK
-		 
		  lda #32
		  sta (ZEROPAGE_POINTER_1),y
		  tya
		  clc
		  adc #STONE_BACK_DISTANCE
		  tay
		  cpy #39
		  bcc -
		 
		  lda MOVE_STONE_POS_BACK
		  clc
		  adc #1
-		 
		  cmp #STONE_BACK_DISTANCE
		  bcc +
		  sec
		  sbc #STONE_BACK_DISTANCE
		  jmp -
		 
+		 
		  sta MOVE_STONE_POS_BACK
		 
		  ldy MOVE_STONE_POS_BACK
-		 
		  lda #149
		  sta (ZEROPAGE_POINTER_1),y
		  lda #8
		  sta (ZEROPAGE_POINTER_2),y
		  tya
		  clc
		  adc #STONE_BACK_DISTANCE
		  tay
		  cpy #39
		  bcc -
		  ;foreground
		  ldy #22
		  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
		 
		  ldy MOVE_STONE_POS_FRONT
-		 
		  lda #32
		  sta (ZEROPAGE_POINTER_1),y
		  tya
		  clc
		  adc #STONE_FRONT_DISTANCE
		  tay
		  cpy #39
		  bcc -
		 
		  lda MOVE_STONE_POS_FRONT
		  clc
		  adc #2
-		 
		  cmp #STONE_FRONT_DISTANCE
		  bcc +
		  sec
		  sbc #STONE_FRONT_DISTANCE
		  jmp -
+		 
		  sta MOVE_STONE_POS_FRONT
		 
		  ldy MOVE_STONE_POS_FRONT
-		 
		  lda #148
		  sta (ZEROPAGE_POINTER_1),y
		  lda #9
		  sta (ZEROPAGE_POINTER_2),y
		  tya
		  clc
		  adc #STONE_FRONT_DISTANCE
		  tay
		  cpy #39
		  bcc -
		
.NoStones		



Previous Step Next Step

Attached Files




A C64 Game - Step 85

Posted by Endurion, in C64 02 February 2013 - - - - - - · 927 views

And now? You guessed it, another portal stage Posted Image

Attached Image

Have fun!



Previous Step Next Step

Attached Files




A C64 Game - Step 84

Posted by Endurion, in C64 26 January 2013 - - - - - - · 1,019 views

And here's the next portal.

Attached Image

I hope you don't mind the slower pace, I'm working on a bigger step in the background.

Have fun!



Previous Step Next Step

Attached Files




A C64 Game - Step 83

Posted by Endurion, in C64 19 January 2013 - - - - - - · 992 views

And here's a new extra for Sam. It works similar to the super bullet. For every demon blood picked Sam can destroy an enemy with one touch.


Attached Image


The code is quite similar to the super bullet. Add a new counter variable (DEMON_BLOOD), a new item image, make it possible for the item to spawn as well.

At the item pickup we add this. If the player is Sam (means x = 1) increase the counter.
.EffectDemonBlood
		  cpx #1
		  bne .DeanDoesNotUseForce
		  inc DEMON_BLOOD
		  jmp .RemoveItem
		 




At the hurt enemy part we add this little snippet. If we have a DEMON_BLOOD, decrease the count and kill the enemy right away.




lda DEMON_BLOOD
		  beq +
		  dec DEMON_BLOOD
		  jmp .EnemyKilled+
		  dec SPRITE_HP,x
		  bne .EnemyWasHurt
		 
.EnemyKilled


Have fun!


Previous Step Next Step

Attached Files








July 2016 »

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31       
PARTNERS