# Rear Gunner XL – Part 3 – Drawing

Having converted the first five lines of the game in the last post, which setup the positions of the player and enemy, we can move onto the next four lines, which are concerned with drawing both the player’s sights and enemy:

```; 50 PRINT AT D,C;”(graphic G)”
; 60 PRINT AT A,B;” + “
; 70 PRINT AT A-1,B;”   “
; 80 PRINT AT A+1,B;”   “```

Line 50 is drawing the enemy sights, and 60-80 the player.  It’s interesting to note that the player is drawn in the middle of a 3×3 square, surrounded by spaces, so when the player moves it erases the previous position as it goes.

The ZX81 has a character-mapped display, which means that rather than storing all the pixels required to fill the screen, it stores the actual characters instead.  This makes the drawing of characters on the screen very simple, as we just need to work out where in the display memory to put each one.

The address of the display memory is stored in the system variable named D_FILE, and from there we have to skip the first byte, then 33 bytes for each row (32 characters + newline) then add the column. So…

```; Find the location of a character in the display memory
; Row in D, column in E
; HL returns with character address
; Calculate 33 times the row.
ld h, 0
ld l, d
ld b, 0
ld c, d
ld c, e
; Add to the base of the display memory (+1)
ld de, (D_FILE)
inc de
; Return
ret```

So we now have a function we can pass a row & column position to, and get back the location in the display memory we need to write the characters to.  So for line 50:

`; 50 PRINT AT D,C;”(graphic G)”`

we need to read our C & D variables, get the address, then write a single character to it.  The character – graphic G – you’ll need to look-up in the manual, and is character 137:

```ld a, (VARIABLE_D)
ld d, a
ld a, (VARIABLE_C)
ld e, a
ld (hl), 137```

Lines 60 to 80 are just the same, but we write three characters each time, in successive columns:

```; 60 PRINT AT A,B;” + “
ld a, (VARIABLE_A)
ld d, a
ld a, (VARIABLE_B)
ld e, a
ld (hl), __
inc hl
inc hl
ld (hl), __

; 70 PRINT AT A-1,B;”   “
ld a, (VARIABLE_A)
dec a
ld d, a
ld a, (VARIABLE_B)
ld e, a
ld (hl), __
inc hl
ld (hl), __
inc hl
ld (hl), __

; 80 PRINT AT A+1,B;”   “
ld a, (VARIABLE_A)
inc a
ld d, a
ld a, (VARIABLE_B)
ld e, a
ld (hl), __
inc hl
ld (hl), __
inc hl
ld (hl), __```

We can actually be much more efficient with that section, as we could draw the lines in row order – instead of centre, then above, then below – which would mean we could just add 33 to our display address to get to the next line.  We could also store the nine character in memory somewhere, and copy them from there to the display.  But for the sake of this first-pass, the above will be good enough I think.

This now makes our listing as follows:

```; 5 PAUSE 50
LINE_5:
ld hl, 50
call FUNC_WAITFORFRAMES

; 10 LET A=5
ld a, 5
ld (VARIABLE_A), a

; 20 LET B=7
ld a, 7
ld (VARIABLE_B), a

; 30 LET C=INT (RND*26)
ld b, 26
call FUNC_GETRANDOM_RANGE
ld (VARIABLE_C), a

; 40 LET D=INT (RND*17)
ld b, 17
call FUNC_GETRANDOM_RANGE
ld (VARIABLE_D), a

; 50 PRINT AT D,C;”(graphic G)”
LINE_50:
ld a, (VARIABLE_D)
ld d, a
ld a, (VARIABLE_C)
ld e, a
ld (hl), 137

; 60 PRINT AT A,B;” + “
ld a, (VARIABLE_A)
ld d, a
ld a, (VARIABLE_B)
ld e, a
ld (hl), __
inc hl
inc hl
ld (hl), __

; 70 PRINT AT A-1,B;”   “
ld a, (VARIABLE_A)
dec a
ld d, a
ld a, (VARIABLE_B)
ld e, a
ld (hl), __
inc hl
ld (hl), __
inc hl
ld (hl), __

; 80 PRINT AT A+1,B;”   “
ld a, (VARIABLE_A)
inc a
ld d, a
ld a, (VARIABLE_B)
ld e, a
ld (hl), __
inc hl
ld (hl), __
inc hl
ld (hl), __

; 90 IF INKEY\$=“5” THEN LET B=B-1
; 100 IF INKEY\$=“8” THEN LET B=B+1
; 110 IF INKEY\$=“7” THEN LET A=A-1
; 120 IF INKEY\$=“6” THEN LET A=A+1
; 130 IF INKEY\$=“0” THEN GOTO 150
; 140 GOTO 50
; 150 IF D<>A THEN GOTO 50
; 160 IF C=B THEN GOTO 170
; 170 PRINT AT D-1,C;”(graphic Y;SPACE;graphic T)”
; 180 PRINT AT D,C;”(SPACE;inverse SPACE;SPACE)”
; 190 PRINT AT D+1,C;”(graphic T;SPACE;graphic Y)”
; 200 RUN

; Wait for HL frames
FUNC_WAITFORFRAMES
; Load the system variable FRAMES with the number to wait for
; Remember to keep bit 15 high though
set 7, h
ld (FRAMES), hl
FUNC_WAITFORFRAMES_LOOP
ld hl, (FRAMES)
; Keep looping until it's zero (ignoring bit 15)
ld a, h
and %01111111
or l
jp nz, FUNC_WAITFORFRAMES_LOOP
; Return
ret

; Get a random 8-bit number
FUNC_GETRANDOM
; Calculate a new 'random' number from the last one and r-register
ld a, r
ld hl, LMATH_GR_SEED
rrca
ld (hl), a
ret
LMATH_GR_SEED
defb 91

; Get a random 8-bit number within a range
; Call with B as the maximum value + 1
FUNC_GETRANDOM_RANGE
call FUNC_GETRANDOM
FUNC_GETRANDOM_RANGE_LOOP:
cp b
ret c
sub b
jp FUNC_GETRANDOM_RANGE_LOOP

VARIABLE_A
defb 0
VARIABLE_B
defb 0
VARIABLE_C
defb 0
VARIABLE_D
defb 0```