And onwards we go. This time we add spawn spots. These are a different kind of object which spawn a number of one specific enemy type. The level is clear once all enemies are killed and any existing spawn spots are empty.
In case you wonder about the .C64 file inside there: It's a project file for C64Studio, an .NET based IDE I've written for development and debugging alongside with mostly WinVICE.
Spawn spots are handled pretty similar to objects, tables with its data with code to iterate and process them.
Note that for the spawn spot tables we use the !fill macro. It fills memory with n bytes of value x.
;number of possible spawn spots
SPAWN_SPOT_COUNT = 8
SPAWN_SPOT_X
!fill SPAWN_SPOT_COUNT,0
SPAWN_SPOT_Y
!fill SPAWN_SPOT_COUNT,0
SPAWN_SPOT_ACTIVE
!fill SPAWN_SPOT_COUNT,0
SPAWN_SPOT_TYPE
!fill SPAWN_SPOT_COUNT,0
SPAWN_SPOT_SPAWN_COUNT
!fill SPAWN_SPOT_COUNT,0
SPAWN_SPOT_DELAY
!fill SPAWN_SPOT_COUNT,0
NUMBER_SPAWN_SPOTS_ALIVE
!byte 0
In GameFlowControl we add the call to handle the spawn spots, and modify the level-done check:
jsr ProcessSpawnSpots
;------------------------;slow events
inc DELAYED_GENERIC_COUNTER
lda DELAYED_GENERIC_COUNTER
cmp #8bne .NoTimedActionYet
lda #0
sta DELAYED_GENERIC_COUNTER
;level done delay
lda NUMBER_ENEMIES_ALIVE
bne .NotDoneYet
lda NUMBER_SPAWN_SPOTS_ALIVE
bne .NotDoneYet
Handling a spawn spot is easy. If a spawn spots delay counter reaches zero we check if the number of alive enemies is below 4. If it is, spawn an enemy, if it isn't reset the delay counter. Once the spawn spot object counter reaches zero the active spawn spot is removed.
;------------------------------------------------------------
;handle spawn spots
;------------------------------------------------------------
!zone ProcessSpawnSpots
ProcessSpawnSpots
ldx #0
.SpawnSpotLoop
lda SPAWN_SPOT_ACTIVE,x
beq .NextSpawnSpot
lda SPAWN_SPOT_DELAY,x
beq .TryToSpawn
dec SPAWN_SPOT_DELAY,x
jmp .NextSpawnSpot
.RemoveSpawnSpot
lda #0
sta SPAWN_SPOT_ACTIVE,x
dec NUMBER_SPAWN_SPOTS_ALIVE
.NextSpawnSpot
inx
cpx #SPAWN_SPOT_COUNT
bne .SpawnSpotLoop
rts
.TryToSpawn
lda #128
sta SPAWN_SPOT_DELAY,x
lda NUMBER_ENEMIES_ALIVE
cmp #3bpl .DoNotSpawn
stx PARAM4
lda SPAWN_SPOT_TYPE,x
sta PARAM3
lda SPAWN_SPOT_X,x
sta PARAM1
lda SPAWN_SPOT_Y,x
sta PARAM2
;spawn object
jsr FindEmptySpriteSlot
beq .DoNotSpawn
;x is sprite slot;PARAM1 is X;PARAM2 is Y;PARAM3 is object type
jsr SpawnObject
;restore x
ldx PARAM4
dec SPAWN_SPOT_SPAWN_COUNT,x
beq .RemoveSpawnSpot
.DoNotSpawnjmp .NextSpawnSpot
A new level element LD_SPAWN_SPOT is added to add spawn spots to the stage table. The code simply stores the data in the next free spawn spot slot.
!zone LevelSpawnSpot
LevelSpawnSpot
;find free spot
ldx #0
.ExamineNextSpot
lda SPAWN_SPOT_ACTIVE,x
beq .EmptySpotFound
inx
cpx SPAWN_SPOT_COUNT
bne .ExamineNextSpot
jmp NextLevelData
.EmptySpotFound
inc NUMBER_SPAWN_SPOTS_ALIVE
lda #1
sta SPAWN_SPOT_ACTIVE,x
;X pos
iny
lda (ZEROPAGE_POINTER_1),y
sta SPAWN_SPOT_X,x
;Y pos
iny
lda (ZEROPAGE_POINTER_1),y
sta SPAWN_SPOT_Y,x
;type
iny
lda (ZEROPAGE_POINTER_1),y
sta SPAWN_SPOT_TYPE,x
;count
iny
lda (ZEROPAGE_POINTER_1),y
sta SPAWN_SPOT_SPAWN_COUNT,x
tya
pha
jmp NextLevelData