A C64 Game - Step 5
Our next big step:
Obviously we want some play screen, and more obviously, we are not going to store full screens (we've got only 64Kb Ram after all). Therefore there's a level build routine that allows to build a screen with various building elements. For now we'll start out with vertical and horizontal lines. Since we always have a level border at the screen edges we'll have the border as a second screen data block (LEVEL_BORDER_DATA).
To allow faster screen building we also have a table with the precalculated char offsets of a vertical line (SCREEN_LINE_OFFSET_TABLE_LO and SCREEN_LINE_OFFSET_TABLE_HI). Note that with the C64s mnemonics the best way to get stuff done is tables, tables, tables.

The BuildScreen sub routine clears the play screen area, builds the level data and then the border. The level data is a collection of primitives which are then worked through until LD_END is hit.
The first addition is the call to the buildroutine:
;setup level
lda #0
sta LEVEL_NR
jsr BuildScreen
The BuildScreen routine sets up a level completely. It starts out with clearing the current play area (not the full screen). Then LEVEL_NR is used to look up the location of the level data in table SCREEN_DATA_TABLE.
.BuildLevel is jumped to to actually work through the level primitives and put them on screen. Then we use LEVEL_BORDER_DATA as second level to display a border on the screens edges.
.BuildLevel uses Y as index through the data. Depending on the first byte different routines are called (.LineH, .LineV, .LevelComplete). Since I think levels may be complex and use more than 256 bytes we add Y to the level data pointers so we can start out with Y=0 for the next primitive.
;------------------------------------------------------------
;BuildScreen
;creates a screen from level data
;------------------------------------------------------------
!zone BuildScreen
BuildScreen
lda #0
ldy #6
jsr ClearPlayScreen
;get pointer to real level data from table
ldx LEVEL_NR
lda SCREEN_DATA_TABLE,x
sta ZEROPAGE_POINTER_1
lda SCREEN_DATA_TABLE + 1,x
sta ZEROPAGE_POINTER_1 + 1
jsr .BuildLevel
;get pointer to real level data from table
lda #<LEVEL_BORDER_DATA
sta ZEROPAGE_POINTER_1
lda #>LEVEL_BORDER_DATA
sta ZEROPAGE_POINTER_1 + 1
jsr .BuildLevel
rts
.BuildLevel
;work through data
ldy #255
.LevelDataLoop
iny
lda (ZEROPAGE_POINTER_1),y
cmp #LD_END
beq .LevelComplete
cmp #LD_LINE_H
beq .LineH
cmp #LD_LINE_V
beq .LineV
.LevelComplete
rts
.NextLevelData
pla
;adjust pointers so we are able to access more
;than 256 bytes of level data
clc
adc #1
adc ZEROPAGE_POINTER_1
sta ZEROPAGE_POINTER_1
lda ZEROPAGE_POINTER_1 + 1
adc #0
sta ZEROPAGE_POINTER_1 + 1
ldy #255
jmp .LevelDataLoop
The primitive display routines .LineH and .LineV are rather straight forward. Read the parameters, and put the character and color values in place.
.LineH
;X pos
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM1
;Y pos
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM2
;width
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM3
;char
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM4
;color
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM5
;store target pointers to screen and color ram
ldx PARAM2
lda SCREEN_LINE_OFFSET_TABLE_LO,x
sta ZEROPAGE_POINTER_2
sta ZEROPAGE_POINTER_3
lda SCREEN_LINE_OFFSET_TABLE_HI,x
sta ZEROPAGE_POINTER_2 + 1
clc
adc #( ( SCREEN_COLOR - SCREEN_CHAR ) & 0xff00 ) >> 8
sta ZEROPAGE_POINTER_3 + 1
tya
pha
ldy PARAM1
.NextChar
lda PARAM4
sta (ZEROPAGE_POINTER_2),y
lda PARAM5
sta (ZEROPAGE_POINTER_3),y
iny
dec PARAM3
bne .NextChar
jmp .NextLevelData
.LineV
;X pos
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM1
;Y pos
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM2
;height
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM3
;char
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM4
;color
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM5
;store target pointers to screen and color ram
ldx PARAM2
lda SCREEN_LINE_OFFSET_TABLE_LO,x
sta ZEROPAGE_POINTER_2
sta ZEROPAGE_POINTER_3
lda SCREEN_LINE_OFFSET_TABLE_HI,x
sta ZEROPAGE_POINTER_2 + 1
clc
adc #( ( SCREEN_COLOR - SCREEN_CHAR ) & 0xff00 ) >> 8
sta ZEROPAGE_POINTER_3 + 1
tya
pha
ldy PARAM1
.NextCharV
lda PARAM4
sta (ZEROPAGE_POINTER_2),y
lda PARAM5
sta (ZEROPAGE_POINTER_3),y
;adjust pointer
lda ZEROPAGE_POINTER_2
clc
adc #40
sta ZEROPAGE_POINTER_2
sta ZEROPAGE_POINTER_3
lda ZEROPAGE_POINTER_2 + 1
adc #0
sta ZEROPAGE_POINTER_2 + 1
clc
adc #( ( SCREEN_COLOR - SCREEN_CHAR ) & 0xff00 ) >> 8
sta ZEROPAGE_POINTER_3 + 1
dec PARAM3
bne .NextCharV
jmp .NextLevelData
step5.zip