## How To Write ZX Spectrum Games – Chapter 5

Simple Background Collision Detection

Note: This article was originally written by Jonathan Cauldwell and is reproduced here with permission.

Finding Attributes

Anyone who ever spent time programming in Sinclair BASIC may well remember the ATTR function. This was a way to detect the colour attributes of any particular character cell on the screen, and though tricky for the BASIC programmer to grasp, could be very handy for simple collision detection. The method was so useful in fact that it its machine language equivalent was employed by a number of commercial games, and it is of great use to the novice Spectrum programmer.

There are two ways to find the colour attribute settings for a particular character cell on the Spectrum. A quick look through the Spectrum’s ROM disassembly reveals a routine at address 9603 which will do the job for us, or we can calculate the memory address ourselves.

The simplest way to find an attribute value is to use a couple of ROM routines:

```       ld bc,(ballx)       ; put x and y in bc register pair.
call 9603           ; call ROM to put attribute (c,b) on stack.
call 11733          ; put attributes in accumulator.```

However, it is much faster to do the calculation ourselves. It is also useful to calculate an attribute’s address, and not just its value, in case we want to write to it as well.

Unlike the Spectrum’s awkward pixel layout, colour cells, located at addresses 22528 to 23295 inclusive, are arranged sequentially in RAM as one would expect. In other words, the screen’s top 32 attribute cells are located at addresses 22528 to 22559 going left to right, the second row of colour cells from 22560 to 22591 and so on. To find the address of a colour cell at print position (x,y) we therefore need only to multiply x by 32, add y, then add 22528 to the result. By then examining the contents of this address we can find out the colours displayed at a particular position, and act accordingly. The following example calculates the address of an attribute at character position (b,c) and returns it in the HL register pair.

```; Calculate address of attribute for character at (b, c).

atadd  ld a,b              ; x position.
rrca                ; multiply by 32.
rrca
rrca
ld l,a              ; store away in l.
and 3               ; mask bits for high byte.
add a,88            ; 88*256=22528, start of attributes.
ld h,a              ; high byte done.
ld a,l              ; get x*32 again.
and 224             ; mask low byte.
ld l,a              ; put in l.
ld a,c              ; get y displacement.
add a,l             ; add to low byte.
ld l,a              ; hl=address of attributes.
ld a,(hl)           ; return attribute in a.
ret```

Interrogating the contents of the byte at hl will give the attribute’s value, while writing to the memory location at hl will change the colour of the square.

To make sense of the result we have to know that each attribute is made up of 8 bits which are arranged in this manner:

```d0-d2		ink colour 0-7,			0=black, 1=blue, 2=red, 3=magenta,
4=green, 5=cyan, 6=yellow, 7=white
d3-d5		paper colour 0-7,		0=black, 1=blue, 2=red, 3=magenta,
4=green, 5=cyan, 6=yellow, 7=white
d6		bright,				0=dull, 1=bright
d7		flash,				0=stable, 1=flashing```

The test for green paper for example, might involve:

```       and 56              ; mask away all but paper bits.
cp 32               ; is it green(4) * 8?
jr z,green          ; yes, do green thing.```

while checking for yellow ink could be done like this:

```       and 7               ; only want bits pertaining to ink.
cp 6                ; is it yellow (6)?
jr z,yellow         ; yes, do yellow wotsit.```

Applying what we Have Learned to the Game

We can now add an attribute collision check to our Centipede game. As before, the new sections are underlined.

```; We want a black screen.

ld a,71             ; white ink (7) on black paper (0),
; bright (64).
ld (23693),a        ; set our screen colours.
xor a               ; quick way to load accumulator with zero.
call 8859           ; set permanent border colours.

; Set up the graphics.

ld hl,blocks        ; address of user-defined graphics data.
ld (23675),hl       ; make UDGs point to it.

; Okay, let's start the game.

call 3503           ; ROM routine - clears screen, opens chan 2.

; Initialise coordinates.

ld hl,21+15*256     ; load hl pair with starting coords.
ld (plx),hl         ; set player coords.

call basexy         ; set the x and y positions of the player.
call splayr         ; show player base symbol.

; Now we want to fill the play area with mushrooms.

ld a,68             ; green ink (4) on black paper (0),
; bright (64).
ld (23695),a        ; set our temporary colours.
ld b,50             ; start with a few.
mushlp ld a,22             ; control code for AT character.
rst 16
call random         ; get a 'random' number.
and 15              ; want vertical in range 0 to 15.
rst 16
call random         ; want another pseudo-random number.
and 31              ; want horizontal in range 0 to 31.
rst 16
ld a,145            ; UDG 'B' is the mushroom graphic.
rst 16              ; put mushroom on screen.
djnz mushlp         ; loop back until all mushrooms displayed.

; This is the main loop.

mloop  equ \$

; Delete the player.

call basexy         ; set the x and y positions of the player.
call wspace         ; display space over player.

; Now we've deleted the player we can move him before redisplaying him
; at his new coordinates.

ld bc,63486         ; keyboard row 1-5/joystick port 2.
in a,(c)            ; see what keys are pressed.
rra                 ; outermost bit = key 1.
push af             ; remember the value.
call nc,mpl         ; it's being pressed, move left.
pop af              ; restore accumulator.
rra                 ; next bit along (value 2) = key 2.
push af             ; remember the value.
call nc,mpr         ; being pressed, so move right.
pop af              ; restore accumulator.
rra                 ; next bit (value 4) = key 3.
push af             ; remember the value.
call nc,mpd         ; being pressed, so move down.
pop af              ; restore accumulator.
rra                 ; next bit (value 8) reads key 4.
call nc,mpu         ; it's being pressed, move up.

; Now he's moved we can redisplay the player.

call basexy         ; set the x and y positions of the player.
call splayr         ; show player.

halt                ; delay.

; Jump back to beginning of main loop.

jp mloop

; Move player left.

mpl    ld hl,ply           ; remember, y is the horizontal coord!
ld a,(hl)           ; what's the current value?
and a               ; is it zero?
ret z               ; yes - we can't go any further left.

; now check that there isn't a mushroom in the way.

ld bc,(plx)         ; current coords.
dec b               ; look 1 square to the left.
call atadd          ; get address of attribute at this position.
cp 68               ; mushrooms are bright (64) + green (4).
ret z               ; there's a mushroom - we can't move there.

dec (hl)            ; subtract 1 from y coordinate.
ret

; Move player right.

mpr    ld hl,ply           ; remember, y is the horizontal coord!
ld a,(hl)           ; what's the current value?
cp 31               ; is it at the right edge (31)?
ret z               ; yes - we can't go any further left.

; now check that there isn't a mushroom in the way.

ld bc,(plx)         ; current coords.
inc b               ; look 1 square to the right.
call atadd          ; get address of attribute at this position.
cp 68               ; mushrooms are bright (64) + green (4).
ret z               ; there's a mushroom - we can't move there.

inc (hl)            ; add 1 to y coordinate.
ret

; Move player up.

mpu    ld hl,plx           ; remember, x is the vertical coord!
ld a,(hl)           ; what's the current value?
cp 4                ; is it at upper limit (4)?
ret z               ; yes - we can go no further then.

; now check that there isn't a mushroom in the way.

ld bc,(plx)         ; current coords.
dec c               ; look 1 square up.
call atadd          ; get address of attribute at this position.
cp 68               ; mushrooms are bright (64) + green (4).
ret z               ; there's a mushroom - we can't move there.

dec (hl)            ; subtract 1 from x coordinate.
ret

; Move player down.

mpd    ld hl,plx           ; remember, x is the vertical coord!
ld a,(hl)           ; what's the current value?
cp 21               ; is it already at the bottom (21)?
ret z               ; yes - we can't go down any more.

; now check that there isn't a mushroom in the way.

ld bc,(plx)         ; current coords.
inc c               ; look 1 square down.
call atadd          ; get address of attribute at this position.
cp 68               ; mushrooms are bright (64) + green (4).
ret z               ; there's a mushroom - we can't move there.

inc (hl)            ; add 1 to x coordinate.
ret

; Set up the x and y coordinates for the player's gunbase position,
; this routine is called prior to display and deletion of gunbase.

basexy ld a,22             ; AT code.
rst 16
ld a,(plx)          ; player vertical coord.
rst 16              ; set vertical position of player.
ld a,(ply)          ; player's horizontal position.
rst 16              ; set the horizontal coord.
ret

; Show player at current print position.

splayr ld a,69             ; cyan ink (5) on black paper (0),
; bright (64).
ld (23695),a        ; set our temporary screen colours.
ld a,144            ; ASCII code for User Defined Graphic 'A'.
rst 16              ; draw player.
ret

wspace ld a,71             ; white ink (7) on black paper (0),
; bright (64).
ld (23695),a        ; set our temporary screen colours.
ld a,32             ; SPACE character.
rst 16              ; display space.
ret

; Simple pseudo-random number generator.
; Steps a pointer through the ROM (held in seed), returning
; the contents of the byte at that location.

random ld hl,(seed)        ; Pointer
ld a,h
and 31              ; keep it within first 8k of ROM.
ld h,a
ld a,(hl)           ; Get "random" number from location.
inc hl              ; Increment pointer.
ld (seed),hl
ret
seed   defw 0

; Calculate address of attribute for character at (dispx, dispy).

atadd  ld a,c              ; vertical coordinate.
rrca                ; multiply by 32.
rrca                ; Shifting right with carry 3 times is
rrca                ; quicker than shifting left 5 times.
ld e,a
and 3
ld d,a
ld a,e
and 224
ld e,a
ld a,b              ; horizontal position.
ld e,a              ; de=address of attributes.
ld a,(de)           ; return with attribute in accumulator.
ret

plx    defb 0              ; player's x coordinate.
ply    defb 0              ; player's y coordinate.

; UDG graphics.

blocks defb 16,16,56,56,124,124,254,254    ; player base.
defb 24,126,255,255,60,60,60,60     ; mushroom.```

## How To Write ZX Spectrum Games – Chapter 4

Random Numbers

Note: This article was originally written by Jonathan Cauldwell and is reproduced here with permission.

Generating random numbers in machine code can be a tricky problem for a novice programmer.

First of all, let’s get one thing straight. There is no such thing as a random number generator. The CPU merely follows instructions and has no mind of its own, it cannot simply pluck a number out of thin air based on a whim. Instead, it needs to follow a formula which will produce an unpredictable sequence of numbers which do not appear to follow any sort of pattern, and therefore give the impression of randomness. All we can do is return a false – or pseudo – random number.

One method of obtaining a pseudo-random number would be to use the Fibonacci sequence, however the easiest and quickest method of generating a pseudo-random 8-bit number on the Spectrum is by stepping a pointer through the ROM, and examining the contents of the byte at each location in turn. There is one small drawback to this method – the Sinclair ROM contains a very uniform and non-random area towards the end which is best avoided. By limiting the pointer to, say, the first 8K of ROM we still have a sequence of 8192 “random” numbers, more than enough for most games. In fact, every game I have ever written with a random number generator uses this method, or a very similar one:

```; Simple pseudo-random number generator.
; Steps a pointer through the ROM (held in seed), returning
; the contents of the byte at that location.

random ld hl,(seed)        ; Pointer
ld a,h
and 31              ; keep it within first 8k of ROM.
ld h,a
ld a,(hl)           ; Get "random" number from location.
inc hl              ; Increment pointer.
ld (seed),hl
ret
seed   defw 0```

Let’s put our new random number generator to use in our Centipede game. Every Centipede game needs mushrooms – lots of them – scattered randomly across the play area, and we can now call the random routine to supply coordinates for each mushroom as we display them. The bits underlined are those we need to add.

```; We want a black screen.

ld a,71             ; white ink (7) on black paper (0),
; bright (64).
ld (23693),a        ; set our screen colours.
xor a               ; quick way to load accumulator with zero.
call 8859           ; set permanent border colours.

; Set up the graphics.

ld hl,blocks        ; address of user-defined graphics data.
ld (23675),hl       ; make UDGs point to it.

; Okay, let's start the game.

call 3503           ; ROM routine - clears screen, opens chan 2.

; Initialise coordinates.

ld hl,21+15*256     ; load hl pair with starting coords.
ld (plx),hl         ; set player coords.

call basexy         ; set the x and y positions of the player.
call splayr         ; show player base symbol.

; Now we want to fill the play area with mushrooms.

ld a,68             ; green ink (4) on black paper (0),
; bright (64).
ld (23695),a        ; set our temporary colours.
ld b,50             ; start with a few.
mushlp ld a,22             ; control code for AT character.
rst 16
call random         ; get a 'random' number.
and 15              ; want vertical in range 0 to 15.
rst 16
call random         ; want another pseudo-random number.
and 31              ; want horizontal in range 0 to 31.
rst 16
ld a,145            ; UDG 'B' is the mushroom graphic.
rst 16              ; put mushroom on screen.
djnz mushlp         ; loop back until all mushrooms displayed.

; This is the main loop.

mloop  equ \$

; Delete the player.

call basexy         ; set the x and y positions of the player.
call wspace         ; display space over player.

; Now we've deleted the player we can move him before redisplaying him
; at his new coordinates.

ld bc,63486         ; keyboard row 1-5/joystick port 2.
in a,(c)            ; see what keys are pressed.
rra                 ; outermost bit = key 1.
push af             ; remember the value.
call nc,mpl         ; it's being pressed, move left.
pop af              ; restore accumulator.
rra                 ; next bit along (value 2) = key 2.
push af             ; remember the value.
call nc,mpr         ; being pressed, so move right.
pop af              ; restore accumulator.
rra                 ; next bit (value 4) = key 3.
push af             ; remember the value.
call nc,mpd         ; being pressed, so move down.
pop af              ; restore accumulator.
rra                 ; next bit (value 8) reads key 4.
call nc,mpu         ; it's being pressed, move up.

; Now he's moved we can redisplay the player.

call basexy         ; set the x and y positions of the player.
call splayr         ; show player.

halt                ; delay.

; Jump back to beginning of main loop.

jp mloop

; Move player left.

mpl    ld hl,ply           ; remember, y is the horizontal coord!
ld a,(hl)           ; what's the current value?
and a               ; is it zero?
ret z               ; yes - we can't go any further left.
dec (hl)            ; subtract 1 from y coordinate.
ret

; Move player right.

mpr    ld hl,ply           ; remember, y is the horizontal coord!
ld a,(hl)           ; what's the current value?
cp 31               ; is it at the right edge (31)?
ret z               ; yes - we can't go any further left.
inc (hl)            ; add 1 to y coordinate.
ret

; Move player up.

mpu    ld hl,plx           ; remember, x is the vertical coord!
ld a,(hl)           ; what's the current value?
cp 4                ; is it at upper limit (4)?
ret z               ; yes - we can go no further then.
dec (hl)            ; subtract 1 from x coordinate.
ret

; Move player down.

mpd    ld hl,plx           ; remember, x is the vertical coord!
ld a,(hl)           ; what's the current value?
cp 21               ; is it already at the bottom (21)?
ret z               ; yes - we can't go down any more.
inc (hl)            ; add 1 to x coordinate.
ret

; Set up the x and y coordinates for the player's gunbase position,
; this routine is called prior to display and deletion of gunbase.

basexy ld a,22             ; AT code.
rst 16
ld a,(plx)          ; player vertical coord.
rst 16              ; set vertical position of player.
ld a,(ply)          ; player's horizontal position.
rst 16              ; set the horizontal coord.
ret

; Show player at current print position.

splayr ld a,69             ; cyan ink (5) on black paper (0),
; bright (64).
ld (23695),a        ; set our temporary screen colours.
ld a,144            ; ASCII code for User Defined Graphic 'A'.
rst 16              ; draw player.
ret

wspace ld a,71             ; white ink (7) on black paper (0),
; bright (64).
ld (23695),a        ; set our temporary screen colours.
ld a,32             ; SPACE character.
rst 16              ; display space.
ret

; Simple pseudo-random number generator.
; Steps a pointer through the ROM (held in seed), returning
; the contents of the byte at that location.

random ld hl,(seed)        ; Pointer
ld a,h
and 31              ; keep it within first 8k of ROM.
ld h,a
ld a,(hl)           ; Get "random" number from location.
inc hl              ; Increment pointer.
ld (seed),hl
ret
seed   defw 0

plx    defb 0              ; player's x coordinate.
ply    defb 0              ; player's y coordinate.

; UDG graphics.

blocks defb 16,16,56,56,124,124,254,254    ; player base.
defb 24,126,255,255,60,60,60,60     ; mushroom.```

Once run this listing looks more like a Centipede game than it did before, but there’s a major problem. The mushrooms are distributed in a random fashion around the screen, but the player can move straight through them. Some form of collision detection is required to prevent this happening, and we shall cover this in the next chapter.

# Simple Text and Graphics

Note: This article was originally written by Jonathan Cauldwell and is reproduced here with permission.

## Introduction

So you’ve read the Z80 documentation, you know how the instructions affect the registers and now you want to put this knowledge to use. Judging by the number of emails I have received asking how to read the keyboard, calculate screen addresses or emit white noise from the beeper it has become clear that there really isn’t much in the way of resources for the new Spectrum programmer. This document, I hope, will grow to fill this void in due course. In its present state it is clearly years from completion, but in publishing the few basic chapters that exist to date I hope it will be of help to other programmers.

The ZX Spectrum was launched in April 1982, and by today’s standards is a primitive machine. In the United Kingdom and a few other countries it was the most popular games machine of the 1980s, and through the joys of emulation many people are enjoying a nostalgic trip back in time with the games of their childhoods. Others are only now discovering the machine for the first time, and some are even taking up the challenge of writing games for this simple little computer. After all, if you can write a decent machine code game for a 1980s computer there probably isn’t much you couldn’t write.

Purists will hate this document, but writing a game isn’t about writing “perfect” Z80 code – as if there were such a thing. A Spectrum game is a substantial undertaking, and you won’t get around to finishing it if you are too obsessed with writing the very best scoring or keyboard reading algorithms. Once you’ve written a routine that works and doesn’t cause problems elsewhere, move on to the next routine. It doesn’t matter if it’s a little messy or inefficient, because the important part is to get the gameplay right. Nobody in his right mind is going to disassemble your code and pick faults with it.

The chapters in this document have been ordered in a way designed to enable the reader to start writing a simple game as soon as possible. Nothing beats the thrill of writing your first full machine-code game, and I have set out this manual in such a way as to cover the very basic minimum requirements for this in the first few chapters. From there we move on to cover more advanced methods which should enable the reader to improve the quality of games he is capable of writing.

Throughout this document a number of assumptions have been made. For a start, it is assumed that the reader is familiar with most Z80 opcodes and what they do. If not there are plenty of guides around which will explain these far better than I could ever do. Learning machine code instructions isn’t difficult, but knowing how to put them together in meaningful ways can be. Familiarity with the load (ld), compare (cp), and conditional jump (jp z / jp c / jp nc) instructions is a good place to start. The rest will fall into place once these are learned.

## Tools

These days we have the benefit of more sophisticated hardware, and there is no need to develop software on the machine for which it is intended. There are plenty of adequate cross-assemblers around which will allow Spectrum software to be developed on a PC and the binary file produced can then be imported into an emulator – SPIN is a popular emulator which has support for this feature.

For graphics there’s a tool called SevenUp which I use, and can thoroughly recommend. This can convert bitmaps into Spectrum images, and allows the programmer to specify the order in which sprites or other graphics are sorted. Output can be in the form of a binary image, or source code. Another popular program is TommyGun.

Music wise I’d recommend the SoundTracker utility which can be downloaded from the World of Spectrum archives. There’s a separate compiler program you’ll also need. Bear in mind that these are Spectrum programs, not PC tools and need to be run on an emulator.

As editors and cross-compilers go I am not in a position to recommend the best available, because I use an archaic editor and Z80 Macro cross-assembler written in 1985, running in DOS windows. Neither are tools I would recommend to others. If you require advice on which tools might be suitable for you, I suggest you try the World of Spectrum development forums. This friendly community has a wide range of experience and is always willing to help.

## Personal Quirks

Over the many years that I have been writing Spectrum software a number of habits have formed which may seem odd. The way I order my coordinates, for example, does not follow the conventions of mathematics. My machine code programs follow the Sinclair BASIC convention of PRINT AT x,y; where x refers to the number of character cells or pixels from the top of the screen and y is the number of characters or pixels from the left edge. If this seems confusing at first I apologise, but it always seemed a more logical way of ordering things and it just stuck with me. Some of my methodology may seem unusual in places, so where you can devise a better way of doing something by all means go with that instead.

One other thing: commenting your code as you go along is important, if not essential. It can be hellishly difficult trying to find a bug in an uncommented routine you wrote only a few weeks ago. It may seem tedious to have to document every subroutine you write, but it will save development time in the long run. In addition, should you wish to re-use a routine in another game at some point in the future, it will be very easy to rip out the required section and adapt it for your next project.

Other than that, just have fun. If you have any suggestions to make or errors to report, please get in touch.

Jonathan Cauldwell, January 2007.

# Hello World

The first BASIC program that most novice programmers write is usually along these lines:

```10 PRINT "Hello World"
20 GOTO 10```

Alright, so the text may differ. Your first effort may have said “Dave is ace” or “Rob woz ere”, but let’s face it, displaying text and graphics on screen is probably the most important aspect of writing any computer game and – with the exception of pinball or fruit machines – it is practically impossible to conceive a game without a display. With this in mind let us begin this tutorial with some important display routines in the Spectrum ROM.

So how would we go about converting the above BASIC program to machine code? Well, we can PRINT by using the RST 16 instruction – effectively the same as PRINT CHR\$ a – but that merely prints the character held in the accumulator to the current channel. To print a string on screen, we need to call two routines – one to open the upper screen for printing (channel 2), then the second to print the string. The routine at ROM address 5633 will open the channel number we pass in the accumulator, and 8252 will print a string beginning at de with length bc to this channel. Once channel 2 is opened, all printing is sent to the upper screen until we call 5633 with another value to send output elsewhere. Other interesting channels are 1 for the lower screen (like PRINT #1 in BASIC, and we can use this to display on the bottom two lines) and 3 for the ZX Printer.

```
ld a,2              ; upper screen
call 5633           ; open channel
loop   ld de,string        ; address of string
ld bc,eostr-string  ; length of string to print
call 8252           ; print our string
jp loop             ; repeat until screen is full

string defb '(your name) is cool'
eostr  equ \$```

Running this listing fills the screen with the text until the scroll? prompt is displayed at the bottom. You will note however, that instead of each line of text appearing on a line of its own as in the BASIC listing, the beginning of each string follows directly on from the end of the previous one which is not exactly what we wanted. To achieve this we need to throw a line ourselves using an ASCII control code. One way of doing this would be to load the accumulator with the code for a new line (13), then use RST 16 to print this code. Another more efficient way is to add this ASCII code to the end of our string thus:

```string defb '(your name) is cool'
defb 13
eostr  equ \$```

There are a number of ASCII control codes like this which alter the current printing position, colours etc. and experimentation will help you to decide which ones you yourself will find most useful. Here are the main ones I use:

13 NEWLINE sets print position to the beginning of the next line.

16,c INK Sets ink colour to the value of the following byte.

17,c PAPER Sets ink colour to the value of the following byte.

22,x,y AT Sets print x and y coordinates to the values specified in the following two bytes.

Code 22 is particularly handy for setting the coordinates at which a string or graphic character is to be displayed. This example will display an exclamation mark in the bottom right of the screen:

```       ld a,2              ; upper screen
call 5633           ; open channel
ld de,string        ; address of string
ld bc,eostr-string  ; length of string to print
call 8252           ; print our string
ret
string defb 22,21,31,'!'
eostr  equ \$```

This program goes one step further and animates an asterisk from the bottom to the top of the screen:

```       ld a,2          ; 2 = upper screen.
call 5633       ; open channel.
ld a,21         ; row 21 = bottom of screen.
ld (xcoord),a   ; set initial x coordinate.
loop   call setxy      ; set up our x/y coords.
ld a,'*'        ; want an asterisk here.
rst 16          ; display it.
call delay      ; want a delay.
call setxy      ; set up our x/y coords.
ld a,32         ; ASCII code for space.
rst 16          ; delete old asterisk.
call setxy      ; set up our x/y coords.
ld hl,xcoord    ; vertical position.
dec (hl)        ; move it up one line.
ld a,(xcoord)   ; where is it now?
cp 255          ; past top of screen yet?
jr nz,loop      ; no, carry on.
ret
delay  ld b,10         ; length of delay.
delay0 halt            ; wait for an interrupt.
djnz delay0     ; loop.
ret             ; return.
setxy  ld a,22         ; ASCII control code for AT.
rst 16          ; print it.
ld a,(xcoord)   ; vertical position.
rst 16          ; print it.
ld a,(ycoord)   ; y coordinate.
rst 16          ; print it.
ret

xcoord defb 0
ycoord defb 15```

## Printing Simple Graphics

Moving asterisks around the screen is all very fine but for even the simplest game we really need to display graphics. Advanced graphics are discussed in later chapters, for now we will only be using simple Space Invader type graphics, and as any BASIC programmer will tell you, the Spectrum has a very simple mechanism for this – the User Defined Graphic, usually abbreviated to UDG.

The Spectrum’s ASCII table contains 21 (19 in 128k mode) user-defined graphics characters, beginning at code 144 and going on up to 164 (162 in 128k mode). In BASIC UDGs are defined by poking data into the UDG area at the top of RAM, but in machine code it makes more sense to change the system variable which points to the memory location at which the UDGs are stored, which is done by changing the two-byte value at address 23675.

We can now modify our moving asterisk program to display a graphic instead with a few changes which are underlined.

```       ld hl,udgs      ; UDGs.
ld (23675),hl   ; set up UDG system variable.
ld a,2          ; 2 = upper screen.
call 5633       ; open channel.
ld a,21         ; row 21 = bottom of screen.
ld (xcoord),a   ; set initial x coordinate.
loop   call setxy      ; set up our x/y coords.
ld a,144        ; show UDG instead of asterisk.
rst 16          ; display it.
call delay      ; want a delay.
call setxy      ; set up our x/y coords.
ld a,32         ; ASCII code for space.
rst 16          ; delete old asterisk.
call setxy      ; set up our x/y coords.
ld hl,xcoord    ; vertical position.
dec (hl)        ; move it up one line.
ld a,(xcoord)   ; where is it now?
cp 255          ; past top of screen yet?
jr nz,loop      ; no, carry on.
ret
delay  ld b,10         ; length of delay.
delay0 halt            ; wait for an interrupt.
djnz delay0     ; loop.
ret             ; return.
setxy  ld a,22         ; ASCII control code for AT.
rst 16          ; print it.
ld a,(xcoord)   ; vertical position.
rst 16          ; print it.
ld a,(ycoord)   ; y coordinate.
rst 16          ; print it.
ret
xcoord defb 0
ycoord defb 15
udgs   defb 60,126,219,153
defb 255,255,219,219```

As Rolf Harris used to say: “Can you tell what it is yet?”

Of course, there’s no reason why you couldn’t use more than the 21 UDGs if you wished. Simply set up a number of banks of them in memory and point to each one as you need it.

Alternatively, you could redefine the character set instead. This gives a larger range of ASCII characters from 32 (SPACE) to 127 (the copyright symbol). You could even mix text and graphics, redefining the letters and numbers of your font to the style of your choice, then using up the symbols and lowercase letters for aliens, zombies or whatever your game requires. To point to another set we subtract 256 from the address at which the font is placed and place this in the two byte system variable at address 23606. The default Sinclair font for example is located at ROM address 15616, so the system variable at address 23606 points to 15360 when the Spectrum is first switched on.

This code copies the Sinclair ROM font to RAM making it “bolder” as it goes, then sets the system variable to point to it:

```       ld hl,15616         ; ROM font.
ld de,60000         ; address of our font.
ld bc,768           ; 96 chars * 8 rows to alter.
font1  ld a,(hl)           ; get bitmap.
rlca                ; rotate it left.
or (hl)             ; combine 2 images.
ld (de),a           ; write to new font.
inc hl              ; next byte of old.
inc de              ; next byte of new.
dec bc              ; decrement counter.
ld a,b              ; high byte.
or c                ; combine with low byte.
jr nz,font1         ; repeat until bc=zero.
ld hl,60000-256     ; font minus 32*8.
ld (23606),hl       ; point to new font.
ret```

## Displaying Numbers

For most games it is better to define the player’s score as a string of ASCII digits, although that does mean more work in the scoring routines and makes high score tables a real pain in the backside for an inexperienced assembly language programmer. We will cover this in a later chapter, but for now we’ll use some handy ROM routines to print numbers for us.

There are two ways of printing a number on the screen, the first of which is to make use of the same routine that the ROM uses to print Sinclair BASIC line numbers. For this we simply load the bc register pair with the number we wish to print, then call 6683:

```      ld bc,(score)
call 6683```

However, since BASIC line numbers can go only as high as 9999, this has the disadvantage of only being capable of displaying a four digit number. Once the player’s score reaches 10000 other ASCII characters are displayed in place of numbers. Fortunately, there is another method which goes much higher. Instead of calling the line number display routine we can call the routine to place the contents of the bc registers on the calculator stack, then another routine which displays the number at the top of this stack. Don’t worry about what the calculator stack is and what its function is because it’s of little use to an arcade games programmer, but where we can make use of it we will. Just remember that the following three lines will display a number from 0 to 65535 inclusive:

```       ld bc,(score)
call 11563          ; stack number in bc.
call 11747          ; display top of calc. stack.```

## Changing Colours

To set the permanent ink, paper, brightness and flash levels we can write directly to the system variable at 23693, then clear the screen with a call to the ROM:

```; We want a yellow screen.
ld a,49             ; blue ink (1) on yellow paper (6*8).
ld (23693),a        ; set our screen colours.
call 3503           ; clear the screen.```

The quickest and simplest way to set the border colour is to write to port 254. The 3 least significant bits of the byte we send determine the colour, so to set the border to red:

```       ld a,2              ; 2 is the code for red.
out (254),a         ; write to port 254.```

Port 254 also drives the speaker and Mic socket in bits 3 and 4. However, the border effect will only last until your next call to the beeper sound routine in the ROM (more on that later), so a more permanent solution is required. To do this, we simply need to load the accumulator with the colour required and call the ROM routine at 8859. This will change the colour and set the BORDCR system variable (located at address 23624) accordingly. To set a permanent red border we can do this:

```       ld a,2              ; 2 is the code for red.
call 8859           ; set border colour.```