# Rear Gunner XL – Part 2 – Setting up

I think the best way to do this conversion is type in the BASIC listing as comments, and then add our Z80 conversion of each line as we go.  This will all be stored in our main.z80 file.  That way it will be obvious what code each line translates to, and hopefully be easier to follow.

Note that this isn’t going to be the most optimal or efficient solution to converting the game, as optimising everything often leaves the code being somewhat unreadable.  I’ll offer some thoughts on how it can be improved, but I’ll leave that up to the reader 🙂

So to start:

```; 5 PAUSE 50
; 10 LET A=5
; 20 LET B=7
; 30 LET C=INT (RND*26)
; 40 LET D=INT (RND*17)
; 50 PRINT AT D,C;”(graphic G)”
; 60 PRINT AT A,B;” + “
; 70 PRINT AT A-1,B;”   “
; 80 PRINT AT A+1,B;”   “
; 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```

The first line is simply a pause:

`5 PAUSE 50`

Which the BASIC manual tells us will wait for 50 frames – so a second (if a PAL machine). Luckily for us the ZX81 has a system variable called FRAMES which you can find in template_main, and this decreases as each frame elapses.  You’ll find details of this in the ZX81 manual, which is actually very detailed and tells you just about everything you need to know about writing in both BASIC and machine code, and is very helpful in finding the values of those special ZX81 graphics.  Keep it with you at all times!

Anyway, as the manual says, we can set it to the number of frames we wish to wait for, and loop until it reaches zero.  And, although this game only uses it once, we can put it in a function so we can reuse it another time if we want to.  There’s one gotcha with this method though – you need to keep bit 15 – the highest bit – of the FRAMES value set, otherwise things go wrong.  This equates to bit 7 of H, and so we set this when we start the wait, and ignore it when we test.

``` ld hl, 50
call FUNC_WAITFORFRAMES

; 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
; Read the current value
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```

The next two lines setup variables A & B:

```10 LET A=5
20 LET B=7```

So here we are setting up the starting position of the player’s sights.  This is simple enough – we need to set aside a byte for each in memory, and set them to the required values.  The variables will need to be at the end of the program, as since as they are not code we can’t ‘run’ them:

``` ld a, 5
ld (VARIABLE_A), a
ld a, 7
ld (VARIABLE_B), a
...
...
...
VARIABLE_A
defb 0
VARIABLE_B
defb 0```

This is then followed by another two lines to setup variable C & D:

```30 LET C=INT (RND*26)
40 LET D=INT (RND*17)```

Now we setup the position of the enemy.  Again, we’ll need two bytes for storage:

```VARIABLE_C
defb 0
VARIABLE_D
defb 0```

Now comes the tricky bit – the position is random – between 0 and 25 for C, and 0 and 16 for D.  For this we’ll need our own random number generator function, and here’s such a routine:

```; 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```

It starts with a set number – 91 – and then every time it is called changes that number.  It’s not completely random, but neither is the version in BASIC.  The r register is set by the machine itself in order to keep the contents of the RAM intact, and will be different depending on when we call the function.

So we can use this function to produce a random number from 0 to 255, but we need much smaller numbers than that, so if the number isn’t within the range we need to begin with, we can keep subtracting from it until it is.

```; 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```

So we can now put this all together to get our random numbers:

``` ld b, 26
call FUNC_GETRANDOM_RANGE
ld (VARIABLE_C), a
ld b, 17
call FUNC_GETRANDOM_RANGE
ld (VARIABLE_D), a```

So putting all this in our program gives us:

```; 5 PAUSE 50
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)”
; 60 PRINT AT A,B;” + “
; 70 PRINT AT A-1,B;”   “
; 80 PRINT AT A+1,B;”   “
; 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
push hl
ld (FRAMES), hl
FUNC_WAITFORFRAMES_LOOP
ld hl, (FRAMES)
ld a, h
or l
jp nz, FUNC_WAITFORFRAMES_LOOP
pop hl
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```

That’s the setup done, but we can’t run it yet, as all it does is wait for a second and setup the variables. We need to code the next two sections – displaying the enemy and sights, and movement – before it’ll do anything useful…

## 2 thoughts on “Rear Gunner XL – Part 2 – Setting up”

1. bruno says:

Bob, I was thinking of using ld a,(FRAMES) to get a random number between 0 and 255. Wouldn’t that be random enough?

Like

1. You could, but it would always give the same result if you used it multiple times in the same frame – so you’d need to add some extra value to avoid possibly having the enemy always appear on a diagonal: 1,1 2,2 3,3 etc

Like