A C64 Game - Step 43
And another two new enemies, Frankenstein's monster and a slime.

Frankenstein's monster behaves very much like zombies, but is a bit stronger.
;------------------------------------------------------------
;simply walk left/right, do not fall off
;state 128 = invisible
; 1 = rising
; 0 = moving
; 2 = collapsing
;------------------------------------------------------------
!zone BehaviourFrankenstein
BehaviourFrankenstein
lda SPRITE_HITBACK,x
beq .NoHitBack
dec SPRITE_HITBACK,x
lda SPRITE_HITBACK_DIRECTION,x
beq .HitBackRight
;move left
jsr ObjectMoveLeftBlocking
rts
.HitBackRight
jsr ObjectMoveRightBlocking
rts
.NoHitBack
lda SPRITE_JUMP_POS,x
bne .IsJumping
jsr ObjectMoveDownBlocking
bne .Falling
.IsJumping
lda DELAYED_GENERIC_COUNTER
and #$03
beq .MovementUpdate
.NoMovement
rts
.Falling
lda DELAYED_GENERIC_COUNTER
and #$03
bne .NoMovement
jmp .WalkWithoutAnimation
.MovementUpdate
lda SPRITE_JUMP_POS,x
bne .UpdateJump
lda SPRITE_STATE,x
bne .OtherStates
;moving
jsr GenerateRandomNumber
cmp #17
beq .Jump
jmp .NormalWalk
.OtherStates
;collapsing?
cmp #2
beq .Collapsing
cmp #1
beq .Rising
cmp #128
bne .NotHidden
jmp .Hidden
.NotHidden
rts
.Jump
;start jump
lda #SPRITE_FRANKIE_JUMP_R
clc
adc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
.UpdateJump
jsr UpdateSpriteJump
;still move
jmp .WalkWithoutAnimation
.NoUpdate
rts
.Collapsing
inc SPRITE_ANIM_DELAY,x
lda SPRITE_ANIM_DELAY,x
cmp #3
bne .NoUpdate
lda #0
sta SPRITE_ANIM_DELAY,x
lda SPRITE_ANIM_POS,x
beq .CollapseDone
dec SPRITE_ANIM_POS,x
lda SPRITE_ANIM_POS,x
clc
asl
adc #SPRITE_FRANKIE_RISE_R_1
adc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
rts
.CollapseDone
;on to hidden state
lda #128
sta SPRITE_STATE,x
lda #SPRITE_INVISIBLE
sta SPRITE_POINTER_BASE,x
;generate hidden time
jsr GenerateRandomNumber
and #$31
clc
adc #25
sta SPRITE_MOVE_POS,x
;normalise position on full char
ldy SPRITE_CHAR_POS_X_DELTA,x
sty PARAM5
.CheckXPos
beq .XPosClear
jsr ObjectMoveLeft
dec PARAM5
jmp .CheckXPos
.XPosClear
ldy SPRITE_CHAR_POS_Y_DELTA,x
sty PARAM5
.CheckYPos
beq .YPosClear
jsr ObjectMoveUp
dec PARAM5
jmp .CheckYPos
.YPosClear
rts
.Rising
inc SPRITE_ANIM_DELAY,x
lda SPRITE_ANIM_DELAY,x
cmp #3
bne .NoUpdate
lda #0
sta SPRITE_ANIM_DELAY,x
inc SPRITE_ANIM_POS,x
lda SPRITE_ANIM_POS,x
cmp #3
beq .RiseDone
clc
asl
adc #SPRITE_FRANKIE_RISE_R_1
adc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
rts
.RiseDone
lda #SPRITE_FRANKIE_WALK_R_1
clc
adc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
lda #0
sta SPRITE_MOVE_POS,x
sta SPRITE_ANIM_DELAY,x
sta SPRITE_ANIM_POS,x
sta SPRITE_STATE,x
rts
.NormalWalk
inc SPRITE_ANIM_DELAY,x
lda SPRITE_ANIM_DELAY,x
cmp #3
bne .NoAnimUpdate
lda #0
sta SPRITE_ANIM_DELAY,x
inc SPRITE_MOVE_POS,x
.NoAnimUpdate
lda SPRITE_MOVE_POS,x
and #$03
sta SPRITE_MOVE_POS,x
clc
asl
adc #SPRITE_FRANKIE_WALK_R_1
adc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
.WalkWithoutAnimation
lda SPRITE_DIRECTION,x
beq .MoveRight
;move left
jsr ObjectMoveLeftBlocking
beq .ToggleDirection
lda SPRITE_ANNOYED,x
beq .NotAnnoyed
jsr ObjectMoveLeftBlocking
beq .ToggleDirection
.NotAnnoyed
rts
.MoveRight
jsr ObjectMoveRightBlocking
beq .ToggleDirection
lda SPRITE_ANNOYED,x
beq .NotAnnoyed
jsr ObjectMoveRightBlocking
beq .ToggleDirection
rts
.ToggleDirection
lda SPRITE_DIRECTION,x
eor #1
sta SPRITE_DIRECTION,x
rts
.Hidden
;are we apt to wake up?
dec SPRITE_MOVE_POS,x
bne .RandomMove
;wake up
lda #1
sta SPRITE_STATE,x
lda #SPRITE_FRANKIE_RISE_R_1
clc
adc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
rts
.RandomMove
;move randomly left/right
jsr GenerateRandomNumber
and #$01
beq .MoveLeft
;move right if possible
jsr CanWalkRight
beq .Blocked
inc SPRITE_CHAR_POS_X,x
ldy #8
sty PARAM5
.MoveSpriteRight
jsr MoveSpriteRight
dec PARAM5
bne .MoveSpriteRight
rts
.MoveLeft
jsr CanWalkLeft
beq .Blocked
dec SPRITE_CHAR_POS_X,x
ldy #8
sty PARAM5
.MoveSpriteLeft
jsr MoveSpriteLeft
dec PARAM5
bne .MoveSpriteLeft
rts
.Blocked
rts
The slime sports new behaviour. Ducking and jumping through the stage trying to slime the player.
;------------------------------------------------------------
;slime
;------------------------------------------------------------
!zone BehaviourSlime
BehaviourSlime
lda SPRITE_HITBACK,x
beq .NoHitBack
dec SPRITE_HITBACK,x
lda SPRITE_HITBACK_DIRECTION,x
beq .HitBackRight
;move left
jsr ObjectMoveLeftBlocking
rts
.HitBackRight
jsr ObjectMoveRightBlocking
rts
.NoHitBack
;state 0 = jumping
;state 1 = ducking
;state 2 = ducked
;state 3 = unducking
lda SPRITE_STATE,x
beq .SlimeJumping
cmp #2
beq .SlimeDucked
inc SPRITE_ANIM_DELAY,x
lda SPRITE_ANIM_DELAY,x
cmp #6
bne .AnimPause
lda #0
sta SPRITE_ANIM_DELAY,x
ldy SPRITE_ANIM_POS,x
inc SPRITE_ANIM_POS,x
lda SPRITE_STATE,x
cmp #3
beq .SlimeUnducking
cpy #3
beq .DuckDone
lda SLIME_DUCK_ANIMATION_TABLE,y
clc
adc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
rts
.DuckDone
;start ducked state
lda #0
sta SPRITE_ANIM_POS,x
lda #2
sta SPRITE_STATE,x
jsr GenerateRandomNumber
sta SPRITE_MOVE_POS,x
.AnimPause
rts
.SlimeUnducking
cpy #3
beq .UnduckDone
lda SLIME_UNDUCK_ANIMATION_TABLE,y
clc
adc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
rts
.UnduckDone
;start jump
lda #0
sta SPRITE_ANIM_POS,x
sta SPRITE_STATE,x
inc SPRITE_JUMP_POS,x
rts
.SlimeDucked
dec SPRITE_MOVE_POS,x
bne .StayDucked
inc SPRITE_STATE,x
.StayDucked
rts
.SlimeJumping
lda SPRITE_JUMP_POS,x
beq .FallIfPossible
;toad is jumping
lda SPRITE_JUMP_POS,x
cmp #TOAD_JUMP_TABLE_SIZE
bne .JumpOn
;jump done
jmp .JumpBlocked
.JumpOn
ldy SPRITE_JUMP_POS,x
inc SPRITE_JUMP_POS,x
lda TOAD_JUMP_TABLE,y
bne .KeepJumping
;no jump movement needed
jmp .SlimeMove
.KeepJumping
sta PARAM5
.JumpContinue
jsr ObjectMoveUpBlocking
beq .JumpBlocked
dec PARAM5
bne .JumpContinue
jmp .SlimeMove
.JumpBlocked
lda #0
sta SPRITE_JUMP_POS,x
jmp .SlimeMove
.FallIfPossible
jsr UpdateSpriteFall
beq .CanJump
jmp .SlimeMove
.CanJump
inc SPRITE_STATE,x
lda #0
sta SPRITE_ANIM_DELAY,x
sta SPRITE_ANIM_POS,x
lda SPRITE_DIRECTION,x
beq .LookingRight
lda #SPRITE_SLIME_L_1
sta SPRITE_POINTER_BASE,x
rts
.LookingRight
lda #SPRITE_SLIME_R_1
sta SPRITE_POINTER_BASE,x
rts
;simple move left/right
.SlimeMove
lda SPRITE_DIRECTION,x
beq .MoveRight
jsr ObjectMoveLeftBlocking
beq .ToggleDirection
rts
.MoveRight
jsr ObjectMoveRightBlocking
beq .ToggleDirection
rts
.ToggleDirection
lda SPRITE_DIRECTION,x
eor #1
sta SPRITE_DIRECTION,x
clc
adc #SPRITE_SLIME_R_1
sta SPRITE_POINTER_BASE,x
rts
Beside the new monsters a few fixes and features are added as well. For one the LookingAtPlayer function would only notice player 1. Now it works for both players:
;------------------------------------------------------------
;determins if object is looking at player
;X = sprite index
;returns 1 if looking at player, 0 if not
;------------------------------------------------------------
!zone LookingAtPlayer
LookingAtPlayer
lda SPRITE_DIRECTION,x
beq .LookingRight
lda SPRITE_ACTIVE
cmp #TYPE_PLAYER_DEAN
bne .NotDean
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X
bpl .LookingAtPlayer
.NotDean
lda SPRITE_ACTIVE + 1
cmp #TYPE_PLAYER_SAM
bne .NoPlayerInSight
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X + 1
bpl .LookingAtPlayer
jmp .NoPlayerInSight
.LookingRight
lda SPRITE_ACTIVE
cmp #TYPE_PLAYER_DEAN
bne .NotDeanR
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X
bmi .LookingAtPlayer
.NotDeanR
lda SPRITE_ACTIVE + 1
cmp #TYPE_PLAYER_SAM
bne .NoPlayerInSight
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X + 1
bmi .LookingAtPlayer
jmp .NoPlayerInSight
.LookingAtPlayer
lda #1
rts
.NoPlayerInSight
lda #0
rts
And a little usability thing. Previously you could only change the game mode by pressing up in the title screen. Now it also works when pressing down:
lda #$02
bit JOYSTICK_PORT_II
bne .NotDownPressed
lda DOWN_RELEASED
beq .DownPressed
lda GAME_MODE
bne .NoGameModeWrap2
lda #3
sta GAME_MODE
.NoGameModeWrap2
dec GAME_MODE
;redisplay game mode
ldx GAME_MODE
lda TEXT_GAME_MODE_LO,x
sta ZEROPAGE_POINTER_1
lda TEXT_GAME_MODE_HI,x
sta ZEROPAGE_POINTER_1 + 1
lda #11
sta PARAM1
lda #21
sta PARAM2
jsr DisplayText
lda #0
jmp .DownPressed
.NotDownPressed
lda #1
.DownPressed
sta DOWN_RELEASED
step43.zip