And another refinement step:
Two new items are added, one for faster reload, another for temporary invincibility. Also, not every kill is getting you an item to collect.
The most interesting new part is the state of a sprite. For now only used for the player, but will be put to good use for enemies as well. The state of an object is used for different behaviour steps, but also to describe, if an object will react to collisions. If the highest bit is set (0x80), an object will not kill the player (or the player cannot be killed).
We'll start by defining the new constants for the items:
;item types
ITEM_FAST_RELOAD = 2
ITEM_INVINCIBLE = 3
;effect counters
PLAYER_FAST_RELOAD
!byte 0
PLAYER_INVINCIBLE
!byte 0
;item images
ITEM_CHAR_UL
!byte 4,8,16,20
ITEM_COLOR_UL
!byte 7,2,1,1
ITEM_CHAR_UR
!byte 5,9,17,21
ITEM_COLOR_UR
!byte 4,2,2,7
ITEM_CHAR_LL
!byte 6,10,18,22
ITEM_COLOR_LL
!byte 7,2,2,7
ITEM_CHAR_LR
!byte 7,11,19,23
ITEM_COLOR_LR
!byte 4,2,2,4
The actual collect item code is simple, we're just setting some new variables. Note the SPRITE_STATE, which is set to 0x80.
.EffectFastReload
lda #200
sta PLAYER_FAST_RELOAD
jmp .RemoveItem
.EffectInvincible
lda #200
sta PLAYER_INVINCIBLE
lda #128
sta SPRITE_STATE
jmp .RemoveItem
Thus the CheckCollision adds a check for the highest bit in SPRITE_STATE, to allow for player invincibility.
CheckCollisions
lda SPRITE_ACTIVE
bne .PlayerIsAlive
rts
.PlayerIsAlive
lda SPRITE_STATE
cmp #128
bmi .IsVulnerable
rts
.IsVulnerable
ldx #1
.CollisionLoop
To visualize the invincibility state we add this code at the start of PlayerControl. If PLAYER_INVINCIBLE is set, the players color is cycled.
lda PLAYER_INVINCIBLE
beq .NotInvincible
;count down invincibility
inc VIC_SPRITE_COLOR
dec PLAYER_INVINCIBLE
bne .NotInvincible
lda #0
sta SPRITE_STATE
lda #10
sta VIC_SPRITE_COLOR
.NotInvincible
... previous code
In the players reload code we add the double speed reload check:
...
lda PLAYER_FAST_RELOAD
beq .NoFastReload
dec PLAYER_FAST_RELOAD
inc PLAYER_STAND_STILL_TIME
.NoFastReload
...
At the location, where we previously always spawned an item we add this:
;only spawn item randomly
lda GenerateRandomNumber
and #02
beq .CreateItem
jmp .ShotDone
...
.CreateItem
jsr SpawnItem
jmp .ShotDone
To get things running clean we change a few spots:
On restarting the temporary states need to be reset.
lda #0
sta PLAYER_FAST_RELOAD
sta PLAYER_INVINCIBLE
sta SPRITE_STATE