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
clcadc SPRITE_DIRECTION,x
sta SPRITE_POINTER_BASE,x
.UpdateJump
jsr UpdateSpriteJump
;still movejmp .WalkWithoutAnimation
.NoUpdate
rts
.Collapsinginc 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 #$31clcadc #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
.Risinginc 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
clcadc 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
.NormalWalkinc 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
clcadc 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
clcadc 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
clcadc 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
.SlimeDuckeddec 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 donejmp .JumpBlocked
.JumpOn
ldy SPRITE_JUMP_POS,x
inc SPRITE_JUMP_POS,x
lda TOAD_JUMP_TABLE,y
bne .KeepJumping
;no jump movement neededjmp .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
.CanJumpinc 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
clcadc #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_DEANbne .NotDean
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X
bpl .LookingAtPlayer
.NotDean
lda SPRITE_ACTIVE + 1cmp #TYPE_PLAYER_SAMbne .NoPlayerInSight
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X + 1bpl .LookingAtPlayer
jmp .NoPlayerInSight
.LookingRight
lda SPRITE_ACTIVE
cmp #TYPE_PLAYER_DEANbne .NotDeanR
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X
bmi .LookingAtPlayer
.NotDeanR
lda SPRITE_ACTIVE + 1cmp #TYPE_PLAYER_SAMbne .NoPlayerInSight
lda SPRITE_CHAR_POS_X,x
cmp SPRITE_CHAR_POS_X + 1bmi .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