

LASER BASIC
by OASIS SOFTWARE


CONTENTS

TAPE MAP						2

INTRODUCTION						3

USING LASER BASIC WITH MICRODRIVES			3

GLOSSARY OF TERMS USED IN THIS MANUAL			4

EDITING AND RUNNING PROGRAMS				7

GETTING STARTED WITH YOUR FIRST LASER BASIC PROGRAM	7
Loading Laser BASIC
Loading OPTION 2 sprites

LASER BASIC						8
	Tool kit facilities				8
	The graphics variables				11
	Assigning variables				12
	Interrogating variables				13
	Sprite utilities				14
	Horizontal screen scrolls			16
	Vertical screen scrolls				17
	Screen attribute scrolls			18
	Horizontal sprite scrolls			19
	Vertical sprite scrolls				20
	Sprite attribute scrolls			21
	Group 1 GETS and PUTS				21
	Group 2 GETS and PUTS				24
	Group 3 GETS and PUTS				25
	MOVE						25
	Transformations					27
	Miscellaneous words				30
	The extended functions in detail		32
	Additional commands				35

PROCEDURES						35
	Local and global variables			35
	Invoking procedures				36
	Nesting procedures				37

PROGRAMMING TECHNIQUES					38
	Moving software sprites				38
	Screen scrolling under keyboard control		38
	Simple putting					38
	Logical operations				40
	MOVE						42
	Hi-resolution putting				42
	Collision detection				43
	Scrolling landscapes				44
	Redefining character sets and UDGs		44
	The variable sets				45
	Loading and saving Laser BASIC programs		45


++				1

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE SPRITE GENERATOR PROGRAM				48
	Introduction					48
	Loading						48
	Getting started					48
	Glossary of terms				48
	Sprite generator key function summary		51
	Laser BASIC sprite generator example session	56
	Creating Sprites in the Sprite Generator	61
	(a summary)

APPENDIX 1 LASER BASIC COMMANDS				62

APPENDIX 2 SPRITE1A AND SPRITE2A SPRITES		67

APPENDIX 3 SPRITE1B AND SPRITE2B SPRITES		68

APPENDIX 4 THE LASER BASIC DEMO EXPLAINED		70









LASER BASIC TAPE MAP

TAPE 1 SIDE 1
i)	"LASER"     LASER BASIC PROGRAM. Load using LOAD "LASER" or LOAD ""
ii)	"SPRITE2A"  A file of OPTION2 saved sprites for use in Laser BASIC
		    (see Appendix 2)
iii)	"SPRITE2B"  A file of OPTION2 saved sprites for use in Laser BASIC
		    (see Appendix 3)

TAPE 1 SIDE 2
i)	"SPTGEN"    The Sprite Generator Program, used to create and edit
		    your sprites for use in Laser BASIC.
		    To load type RANDOMIZE USR 0 : LOAD ""
ii)	"SPRITE1A"  A file of OPTION1 saved sprites for use with the Sprite
		    Generator Program (see Appendix 2)
iii)	"SPRITE1B"  A file of OPTION1 saved sprites for use with the Sprite
		    Generator Program (see Appendix 3)
TAPE 2 SIDE 1
i)	"DEMO"      LASER BASIC DEMO Load using LOAD "DEMO" or LOAD ""

TAPE 2 SIDE 2
i)	"GAME"      LASER BASIC GAME. Load using LOAD "GAME" or LOAD ""


++				2

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


LASER EXTENDED BASIC
by Kevin Hambleton

INTRODUCTION
Laser Extended BASIC is an extension to the existing BASIC interpreter in
the ZX-Spectrum ROM. Although Sinclair BASIC is a powerful and flexible
implementation of the time honoured language, it was necessary at its
inception to make its features as general as possible. BASIC has numerous
applications but the specific area of our interest is graphics and
animation. Laser BASIC was designed to enhance the ease, and particularly
the speed, with which complex animated graphics could be produced and over
100 commands and functions are included to do this. A technique akin to
semi-compilation is used to further increase the execution speeds of the
extra commands.

Those users already familiar with the Lightning series will recognize most
of the command set, although for clarity a number of the command names have
been changed. At this stage, Laser BASIC does not produce stand-alone
programs (you need the extended interpreter to be resident) but a compiler
is also being developed which will make your BASIC programs run faster and
not require the interpreter to be resident. This will mean that you can
market your programs commercially.

Laser BASIC can also be used by the commercial programmer, already familiar
with the Lightning series, as a quick and simple to use development tool.
The command sets are very similar and so Laser BASIC can be used to get a
quick feel for an animated sequence before conversion to White Lightning or
Machine Lightning. The interpreted nature of BASIC makes it absolutely ideal
for this sort of exercise.


USING LASER BASIC WITH MICRODRIVES
Laser BASIC can be automatically saved to a microdrive cartridge using one
of the options in the loader menu. Once Laser BASIC has loaded rewind the
tape and select option 5. The various files that make up Laser BASIC will be
loaded in and then saved to a microdrive cartridge in microdrive 1, one file
at a time. You will need to stop and start the tape recorder as instructed.

Laser BASIC can then be loaded from a microdrive cartridge by typing:

LOAD *"M";1;"LASER"

Once Laser BASIC has been transferred to microdrive it can be loaded and
then RUN in the same way as the tape based program.

There is, however, one unavoidable problem associated with the use of the
microdrives. If a microdrive error occurs, such as "File not found" or any
other error associated with the microdrive, then control will exit the Laser
interpreter and re-enter the Sinclair interpreter. You will know if this has
happened because any attempts to type an extended command will result in the
flashing "?" symptomatic of a syntax error, or, if you try and RUN a program
containing extended commands then "Nonsense in BASIC" will be issued. To
return control to the extended interpreter just type a hash ("#") followed
by ENTER. If the "#" itself generates a syntax error (the "?") then delete
the "#" and type:

RANDOMIZE USR 58830 followed by ENTER.

We apologise for this unavoidable, annoying inconvenience.

In the extremely unlikely event that the tape based interpreter is exited, use:

RANDOMIZE USR 58820.


++				3

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


GLOSSARY OF TERMS USED IN THIS MANUAL

SPRITES
A sprite is a software controllable graphics character. Laser BASIC allows
up to 255 sprites t0 be defined, each with their own user selectable
dimensions. The limit on the size and number of sprites available to the
user is set by the amount of memory available.

Supplied with Laser BASIC is a program known as the Sprite Generator Program
which is used to create software sprites. Once sprites have been created in
this program you can save them to tape or microdrive cartridge using one of
two "OPTIONS".

"OPTION1" sprites are used exclusively with the Sprite Generator Program whilst
"OPTION2" sprites are used exclusively with Laser BASIC.

Two sets of OPTION2 sprites have been provided on tape ready for you to load
into Laser BASIC, these being "SPRITE2A" and "SPRITE2B" (see Appendices 2
and 3).


SCREEN WINDOWS
A screen window is a section of the screen defined by four variables COL,
ROW, HGT and LEN. COL is in the range 0 to 31, ROW is in the range 0 to 23,
HGT is in the range 1 to 24 and LEN is in the range 1 to 32. The unit for
each of the above is the character. COL and ROW specify the column and row
position on the screen of the top left hand corner of the window, with ROW 0
at the top of the screen and COL 0 on the far left hand side. HGT and LEN
define the size of the window.

To see an example of a window on the screen type in the following line and
hit ENTER.

.ROW=5:.COL=6:.HGT=4:.LEN=3:.INVV


SPRITE WINDOWS
A sprite window is a section of a sprite defined by the variables SPN, SCL,
SRW, HGT and LEN. SPN specifies the sprite, SCL and SRW specify the column
and row within the sprite and HGT and LEN define the size of the window. If
the window defined by these variables lies outside the sprite or overlaps
its borders then the command will not execute but no error message will be
issued.


SPRITE SPACE
Sprite space is the area of memory containing all previously defined
sprites. The top of sprite space is 56575 decimal (DCFF HEX) and the lower
end grows downward from this point. Cautious users may wish to find out how
far down their sprites have grown by using one of the following routines:

	PRINT PEEK (62464)+ 256*PEEK (62465)
OR
	LET X=?PEK(62464): PRINT X


++				4

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


RAMTOP
Note that it is very important that your sprites should never grow down over
RAMTOP. To read the value for RAMTOP use:

	PRINT PEEK (23730)+ 256*PEEK (23731)
OR
	LET X=?PEK(23730): PRINT X

Every time a sprite is defined it uses 9 x sprite HGT x sprite LEN + 5 bytes.

In most cases the user will not need to worry about sprites moving down over
RAMTOP unless sprites are created during runtime using .ISPR or .SPRT. It is
possible to check that a sprite created at runtime will fit by performing
the above calculations. It is not recommended that newcomers define sprites
from within Laser BASIC; instead sprites should be defined from within the
sprite generator program and loaded into sprite space using one of the
following procedures.

Method i)	Using one of the three options presented by the Laser BASIC
		loader menu.
Method ii)	Loading the sprites by hand using the following method.
		Once Laser BASIC has been loaded type:
		CLEAR (SPRITE START ADDRESS) - 1
		LOAD "(FILENAME)" CODE (SPRITE START ADDRESS)
		POKE 62464,(SPRITE START ADDRESS)
Note:		The "FILENAME" is the name given to the sprite file when it
		is saved by the sprite generator program. The sprite start
		address is the lowest byte used by the sprite file and is
		also given by the sprite generator program.


PIXEL DATA
For those not acquainted with the workings of the Spectrum screen display,
each character on the screen is produced as follows: each character cell is
an array of 64 (8 by 8) pixels, represented by bits in memory. A pixel is a
'dot' which can be INK colour or PAPER colour. The bits which define a
particular character or block of characters are referred to as pixel data.


ATTRIBUTE DATA
The colour of the INK and PAPER in each particular cell, together with the
brightness and flashing attributes are controlled by a separate byte. The
bytes which define the attributes of the block of characters are referred to
as attribute data. Pixel data and attribute data are frequently treated as
separate entities in Laser BASIC.


SCREEN OPERATIONS
These are operations which are carried out on a particular area of the
screen. The area of the screen to be operated on is called the screen window
and is defined above. The operations themselves include scrolls, inversions,
reflections etc. and all commands in the category are postfixed by a 'V',
e.g. .SR1V, .INVV, .MIRV etc. If the window overlaps the edge of the screen
then the window will be automatically adjusted to lie "on-screen".


++				5

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


SCREEN/SPRITE OPERATIONS
These are operations between the screen and a sprite. The dimensions of the
sprite are used as the dimensions of the screen window and COL and ROW are
used to give the co-ordinates of the top left hand corner of the window,
thus the operations are defined using the variables SPN, COL and ROW. If the
window lies off the screen or the sprite overlaps the border of the screen
then only part of the sprite will be 'PUT' or 'GOT'. Commands in this
category are prefixed with 'PT' or 'GT', e.g. .GTBL, .PTXR, .PTND etc.


SPRITE OPERATIONS
These cover more or less the same operations as the screen window commands
but this time a complete sprite is operated on in memory instead of a
section of the screen. The only variable used is SPN and all commands in
this category are postfixed with an 'M'.


SCREEN/SPRITE WINDOW OPERATIONS
These are operations between a screen window and a sprite window. As before,
ROW, COL, HGT and LEN define the screen window, but this time SCL and SRW
are used to define the position of the window within the sprite. SCL and SRW
are measured in characters, SCL from the left and SRW from the top. If
SRW+HGT is greater than the sprite height, or if SCL+LEN is greater than the
sprite width, or if LEN+COL is greater than 32, or if HGT+ROW is greater
than 24 then the commands will not execute. Commands in this group are
prefixed with 'GW' or 'PW'.


SPRITE/SPRITE WINDOW OPERATIONS
These are operations between a whole sprite and a window within a second
sprite. The two sprite numbers are held in SP1 (the sprite not containing
the window) and SP2 (the sprite containing the window). The dimensions of
the window are the dimensions of the sprite not containing the window and
the position of the window in the sprite whose number is held in SP2 is
specified by SCL and SRW. If the sprite whose number is held in SP1 overlaps
the border of the sprite whose number is held in SP2 then no execution will
take place. Commands in this group are prefixed with 'PM' or 'GM'.


SPRITE/SPRITE OPERATIONS
These are commands where a sprite is transformed and the result is left in a
second sprite; there are only two commands in this group: .SPNM and .DSPM.


DUMMY SPRITE
A dummy sprite is a sprite which does not contain data for display. It may
be used, for instance, to store a machine code subroutine, an array, or
maybe used as part of a collision detection routine.


++				6

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


EDITING AND RUNNING PROGRAMS

The Spectrum editor has been extended so that the extra Laser BASIC commands
will pass the syntax checking stage of program entry. All Laser Basic
commands start with a full stop '.' and this is followed by 4 characters
which must be typed in upper case. All Sinclair BASIC commands are entered
in the normal way. Assignments such as COL or ROW must not contain any
spaces between the variable name and the '=', e.g. COL =4 will give a syntax
error. All Laser BASIC commands will execute in immediate mode.

The extended functions are made up of a question mark '?' followed by 3
characters, e.g. ?COL, ?ROW, etc. These can only be used to return a value
to a variable and cannot be used as part of an expression or PRINT string.

	LET X=?COL: LET Y=?KBF: LET Z=?SET	would be legal
	LET X=?COL*3+Y				would be illegal
	PRINT ?COL				would be illegal

If Laser BASIC is being used with interface 1 connected then microdrive
errors will cause control to exit from the extended interpreter. When this
happens the editor will no longer accept the extended commands and syntax
errors will occur each time an attempt is made to enter one of those
commands. To re-enter the extended interpreter, delete the line you are
trying to enter and simply type a hash '#' followed by ENTER. You should now
be able to continue as before. If not, consult the earlier section - "Using
Laser BASIC with microdrives".

To execute a BASIC program just type the keyword RUN followed by ENTER.
There will be a pause while the additional commands are tokenised and then
execution will begin at the first line of the program. If you wish to
execute from a specific line of the program then you can do so using RUN
followed by the line number; e.g. RUN 1000 will RUN your program from line
1000. There will also be a pause at the end of program execution, or on
pressing BREAK, while the additional commands are de-tokenised. Note that
programs can also be executed using GOTO, GOSUB or CONTINUE.


GETTING STARTED WITH YOUR FIRST LASER BASIC PROGRAM
At this stage it would be a good idea to load in the Laser BASIC Program and
some sprites if you have not already done so. Most of the text covering the
Laser BASIC commands include example listings which we hope, if typed in,
will enlighten the newcomer to their use. Therefore, we strongly recommend
you should slowly work through this manual typing in the examples as you go.


LOADING LASER BASIC
Firstly load in Laser BASIC by typing LOAD "". Stop tape when instructed to.
Laser BASIC will be ready to use once the menu has appeared on the screen.
You should now load in the "SPRITE2A" file.


LOADING OPTION 2 SPRITES
The OPTION 2 sprites - "SPRITE2A" - are loaded by selecting option 3 of the
menu and then pressing PLAY on your tape recorder. Once sprites are loaded
execute Laser BASIC by selecting option 1 of the menu.

Remember, we are only using the example sprites since the example listings
were written to use them. When you are writing your own programs you would
load in your own sprites created in the Sprite Generator program. You are
now ready to use Laser BASIC.


++				7

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


LASER BASIC

As stated earlier, all the standard Sinclair keywords are entered as normal.
eg. type
	10 REM THIS IS YOUR FIRST LASER BASIC PROGRAM.
This is typed in, in exactly the same way as when using the normal Sinclair
BASIC, the key REM being produced by pressing the E key. Now type in the
next line which contains a Laser BASIC command.
	20.COL=1
Of course there is no keyword .COL= so you have to type. (symbol shift M)
COL=1, a character at a time. Remember, there must be no spaces between any
of the characters including the '.' or the "=". Do not type .COL =

The extended Laser BASIC Interpreter will accept this line when you hit
enter. If you have typed in wrongly an error will be displayed as with the
normal Sinclair editor.

Now type the rest of the program.
	30.ROW=1
	40.HGT=20
	50.LEN=30
	60.INVV
You can now type RUN or GOTO 10 to execute the program.

We will now go into detail explaining the Laser BASIC commands. The best way
to understand their operation is to type in the examples and run them.


TOOLKIT FACILITIES
Four new commands have been added to ease program development, these are
.RNUM, .REMK, TRON and TROF.


.RNUM
This is a fairly standard renumbering utility and will renumber the program
text and any line numbers following GOTO, GOSUB or RESTORE. It executes very
slowly when compared to many of its contemporaries, but does not use any
table space whatsoever. It will not, however, renumber computed GOTOs, i.e.
GOTO 10*X or GOTO 100*5, since the value of expression is not computed until
runtime. The syntax is:
	.RNUM FIRST LINE,NEW VALUE FOR FIRST LINE,INCREMENT

So typing .RNUM 102,1000,5 would leave lines with numbers less than 102 (and
references to them) unaffected, change line 102 to have number 1000, and all
subsequent lines to have numbers increasing in increments of 5, e.g.

  10.COL=1:.ROW=1:.HGT=9:.LEN=9
  32 DEF FN A$(Y,X): PRINT AT Y,
X;".INVV":.RETN
 102 GO SUB 50
 118 STOP
7000.INVV
7520.PROCFN A$(11,11)
8000 RETURN

would become


++				8

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =



  10.COL=1:.ROW=1:.HGT=9:.LEN=9
  32 DEF FN A$(Y,X): PRINT AT Y,
X;".INVV":.RETN
1000 GO SUB 50
1005 STOP
1010.INVV
1015.PROCFN A$(11,11)
1020 RETURN

The default line increment is 10, so if you only specify the first line and
the new value for the first line then all subsequent lines, and references
to subsequent lines, will be renumbered in steps of 10.

So typing .RNUM 102,1000 would produce the following:

  10.COL=1:.ROW=1:.HGT=9:.LEN=9
  32 DEF FN A$(Y,X): PRINT AT Y,
X;".INVV":.RETN
1000 GO SUB 50
1010 STOP
1020.INVV
1030.PROCFN A$(11,11)
1040 RETURN

The default "new line number" for the renumbering to begin at is the "old
line number". So typing .RNUM 32 would produce the following:

  10.COL=1:.ROW=1:.HGT=9:.LEN=9
  32 DEF FN A$(Y,X): PRINT AT Y,
X;".INVV":.RETN
  42 GO SUB 42
  52 STOP
  62.INVV
  72.PROCFN A$(11,11)
  82 RETURN


The default "first line number" is the first line of the program (excluding
line 0). So typing .RNUM with no following parameters would produce the
following:

  10.COL=1:.ROW=1:.HGT=9:.LEN=9
  20 DEF FN A$(Y,X): PRINT AT Y,
X;".INVV":.RETN
  30 GO SUB 30
  40 STOP
  50.INVV
  60.PROCFN A$(11,11)
  70 RETURN


Errors will be generated if:
a)	The new value for the start line is lower than the old value
	for the previous line. This prevents lines becoming out
	of sequence.
b)	Renumbering would cause line numbers to exceed 10000.


++				9

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


.REMK
This command is used simply to strip a program of all its REM statements and
thus save memory when the program is getting large. It does not have any
parameters and removes REM statements throughout the whole program.

If you now type the following:
	10 REM THIS IS AN EXAMPLE
	20 PRINT "HELLO": REM THIS LINE PRINTS HELLO
	30 REM THIS LINE DOES NOT PRINT GOODBYE: PRINT "GOODBYE"

Now type .REMK, noting what happens to lines 20 and 30; you are left with
	20 PRINT "HELLO"

.TRON and .TROF
One of the difficulties with debugging BASIC programs is knowing just how
the program actually flows. The program tracing facility (.TRON) allows you
to single step through your BASIC program line by line. Each line is listed
before it executes and the interpreter waits until you press a key to
execute the line, or CAPS SHIFT BREAK to exit with the option to re-execute
using CONTINUE. Executing .TRON will set the trace facility running at the
next BASIC line executed and must be included in the program (it is disabled
by RUN). The trace is automatically switched off when .TROF is executed or
when the program has finished running.


++				10

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE GRAPHICS VARIABLES
The way in which parameters are passed to the graphics routines is slightly
unusual and is aimed at speeding up program execution. Each graphics command
uses a particular subset of the 10 graphics variables. Some commands require
up to 5 parameters and in most cases more time would be spent evaluating the
5 expressions than executing the command itself. More often than not only
one or two parameters are re-evaluated between successive executions of a
command, and so the extended commands require only those parameters which
need to be changed, to actually be changed. The other advantage of using
dedicated variables is that the routines know exactly where to find the
variables and do not need to search the BASIC variables to find the values.

There are actually 16 sets of the 10 variables and these can be individually
selected using SET=<exp> where <exp> is in the range of 0 to 15 and can be
any BASIC expression, e.g.
	.SET=5*X+PEEK (58471)

The 10 variables are:

VARIABLE	GENERAL USE
ROW	Used to hold the row (Y co-ord) in characters, measured from the
	top of the screen (0-23). The top of the screen has ROW 0.
COL	Used to hold the column (X co-ord) in characters, measured from the
	left of the screen (0-31). The top left of the screen has COL 0.
HGT	Used to hold the height in characters of the current screen window
	(1-24).
LEN	Used to hold the length in characters of the current screen window
	(1-32).
SRW	Used to hold the row (Y co-ord) within a sprite measured from the
	top (0 to height-1) and in units of characters.
SCL	Used to hold the column (X co-ord) within a sprite measured from the
	left (0 to length-1) and in units of characters.
NPX	Used to hold the size and direction of vertical scrolls. Positive
	scrolls are upward and negative scrolls are downward. Units are
	pixels, not characters, and should be in the range +127 to -128.
SPN	Used to hold the sprite number for those commands which operate on
	only one sprite. SPN should be in the range 1 to 255.
SP1	Where operations involve a sprite and a sprite window, SP1 contains
	the number of the sprite which does not contain the window (1-255).
SP2	Where operations involve a sprite and a sprite window, SP2 contains
	the number of the sprite which does contain the window (1-255).


++				11

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


ASSIGNING VARIABLES
	.COL=	.ROW=	.LEN=	.HGT=	.SP1=	.SP2=
	.SPN=	.NPX=	.SCL=	.SRW=	.SET=
Using these functions, the graphics variables can be assigned values.
e.g.	.COL=5:.ROW=2:.SPN=2
Now type in the following sample program, which XORs a sprite across the
screen by changing the value in the variable COL by means of a FOR-NEXT loop.

 1 REM EXAMPLE 1
 5 REM USING ONE SET OF GRAPHICS VARIABLES
10.SET=0:.SPN=4:.ROW=0:.COL=-4
20 BORDER 1: BRIGHT 1: INK 6: PAPER 1: CLS:.ATOF
30 FOR I=-4 TO 32
40.PTXR:.COL=I+1:.PTXR
50 PAUSE 4
60 NEXT I
70 STOP

To execute type RUN or GOTO 1 then press ENTER.

Line 10	Graphics variable set 0 is selected, sprite number is set to 4,
	ROW is set to 0 (top row), and COL is set to -4
Line 20	The screen's attributes are set, the screen is cleared and the
	attribute flag set to off.
Line 30	is a simple loop to move sprite 4 (the duck) from column positions
	-4 to 32.
Line 40	XORs out the old sprite, (see .PTXR) increments the COL variable
	and then XORs in the new sprite.
Line 50	pauses while the sprite is on screen.

We can now extend this simple routine, to move two sprites (in fact mirror
images of the same sprite) in opposite directions again by changing the
values in COL, except in this case two variable sets are used. (Note, if you
intend to use only one variable set in a program the word .SET= does not
have to be used).

 1 REM EXAMPLE 2
10 REM USING TWO SETS OF GRAPHICS VARIABLES
20 DEF FN A#(X,Y):.SET=X:.SPN=4:.ROW=Y
30.RETN
35 INK 6: PAPER 0: BORDER 0: BRIGHT 1: CLS:.ATOF
40.PROCFN A#(0,0):.PROCFN A#(1,1)
50.COL=32:.SET=0:.COL=-4
60 FOR I=-4 TO 32
65.SET=0:.PTXR:.COL=I+1:.PTXR
70.SET=1:.MIRM:.PTXR:.COL=28-I:.PTXR:.MIRM
75 PAUSE2
80 NEXT I
90 GO TO 40

Note the FN part of .PROCFN in line 40 is the keyword FN (symbol shift 2).

This program will move two ducks across each other from either side of the
screen. To run this program just type RUN or GOTO 1 and then press ENTER.


++				12

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Lines 20 and 30 define a procedure which initialises the necessary variables
	of the respective sets. The first time it is executed SET is 0 and
	ROW is 0 and the second time SET is 1 and ROW is also 1 .This means
	that the two variable sets are identical except for the value of ROW.
Line 35	sets the attribute values before clearing the screen and switching
	off the attribute flow.
Line 40	executes the procedure A# twice.
Line 50	initialises the columns for sets 1 and 0 respectively.
Line 60	is a simple loop.
Line 65	moves the sprite from left to right using the variables from set 0.
Line 70	reflects the sprite and moves it from right to left using the
	variables from set 1.  The sprite is re-reflected.
Line 75	is a pause while both sprites are on the screen.


INTERROGATING VARIABLES
As well as being able to assign values to the graphics variables, it is also
necessary to be able to interrogate their current values. There are eleven
functions provided for doing this.
	?COL	?ROW	?LEN	?HGT	?SP1	?SP2
	?SPN	?NPX	?SCL	?SRW	?SET

Using these functions, the current values can be assigned to a normal
Sinclair variable, for example:
	LET X=?COL: LET ROW=?ROW: LET ST=?SET
Notice that ROW=?ROW is allowed, but don't get confused between the normal
variable ROW and the graphics variable ROW.

The above eleven functions cannot be used as part of a normal expression, i.e.:
	LET X=?COL*3+?ROW/8	would not be legal
and they cannot be included as PRINT parameters either, i.e.:
	PRINT X,Y,?ROW		would also be illegal.
However, the same results could be achieved by using:
	LET COL=?COL: LET Y=?ROW: LET X=COL*3+Y/8	in the first case and
	LET R=?ROW: PRINT X,Y,R				in the second case

You can insert the following lines into the above EXAMPLE 2 to print out the
two COL values as the sprites are moved.

75.SET=0: LET X0=?COL:.SET=1: LET X1=?COL
76 PRINT AT 10,16;" ";AT 11,16;" "
77 PRINT AT 10,12;"COL=";X0;AT 11,12;"COL=";X1

Line 75	lets the variable X0 equal the COL value of set 0 and X1 equal the
	value of set 1 COL.
Line 76	blanks out the old values on the screen.
Line 77	prints the new values.


++				13

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE EXTENDED GRAPHICS COMMANDS IN DETAIL

SPRITE UTILITIES

All the sprite utilities described in this section are available at run-time
but should be used with caution. We strongly recommend that the unfamiliar
user creates all his sprites in the Sprite Generator package.

.SPRT	Used to set up a new sprite. Sprite space is extended upward so the
	start of sprites remains fixed but the end of sprites is increased
	by 9xHGTxLEN+5 bytes. If the sprite number has been previously
	allocated then the "old sprite" is first deleted (with the bottom of
	sprite space remaining fixed and the top of sprite space being
	reduced) before the new sprite is allocated. When a sprite is first
	set up it will probably contain garbage, and data will have to be
	"GOT" in it using a command such as .GTBL.

	Parameter		Use
	SPN	Number of the sprite to be set up.  (1-255)
	LEN	Length of the sprite in characters. (1-255)
	HGT	Height of the sprite in characters. (1-255)

	Note: Since this command extends sprite space upwards it will very
	seldom be used and is included for advanced applications only. Most
	uses require the next command .ISPR. Careless use of .SPRT may cause
	the system to crash.

.ISPR	Used to set up a new sprite. Sprite space is extended downward so
	the top of sprites remains fixed but the start of sprites moves
	downward by 9xHGTxLEN+5 bytes. If the sprite has been previously
	allocated then an error is generated. If executing .ISPR causes the
	start of sprite space to move below RAMTOP the system will crash.
	Remember, as with .SPRT the sprite may initially contain garbage and
	data will have to be "GOT" into it using a command such as .GTBL.

	Parameter		Use
	SPN	Number of the sprite to be set up.  (1-255)
	LEN	Length of the sprite in characters. (1-255)
	HGT	Height of the sprite in characters. (1-255)

.WSPR	Used to delete a currently existing sprite. Sprite space is contracted
	so that the start of sprites remains unchanged but the end of
	sprites is reduced. Again this command is only used in advanced
	applications and sprites are normally deleted using .DSPR. An error
	Q is generated if an attempt is made to delete a non-existent sprite.

	e.g. to delete sprite 1 you would type
	.SPN=1:.WSPR

	Parameter		Use
	SPN	The number of the sprite to be deleted. (1-255)

.DSPR	Used to delete a currently existing sprite. Sprite space is contracted
	so that the top of sprites remains fixed but the start of sprites is
	moved up in memory. An error Q is generated if an attempt is made to
	delete a non-existent sprite. This command will normally be used to
	delete a sprite, and .WSPR will only be used in advanced
	applications.

	e.g. to delete sprite 2 you would type
	.SPN=2:.DSPR

	Parameter		Use
	SPN	The number of the sprite to be deleted. (1-255)


++				14

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In example 3 below, memory is checked to see if enough memory is available
for .ISPR.

 5 REM EXAMPLE 3
10 REM PROCEDURE TO CHECK IF SUFFICIENT SPACE IS AVAILABLE FOR .ISPR
20 REM X=LENGTH,Y=HEIGHT
30 DEF FN T#(X,Y)
40 LET SIZE=9*X*Y+5
50 LET SPACE=PEEK (62464)-PEEK (23730)+256*(PEEK (23731)-PEEK (62465))
60 IF SIZE>SPACE THEN PRINT "NO ROOM AVAILABLE"
70 IF SIZE<=SPACE THEN PRINT "ROOM AVAILABLE"
80.RETN

The procedure is entered with X and Y holding length and height, e.g. type
.PROCFN T#(5,5) for a 5 by 5 sprite. The size of the sprite is calculated
and compared with the length of free space (SPST-RAMTOP) and an appropriate
message generated.

 5 REM EXAMPLE 4
10 REM PROCEDURE TO CHECK IF SUFFICIENT SPACE IS
20 REM AVAILABLE AND SET UP SPRITE N IF POSSIBLE
30 DEF FN S#(N,X,Y)
40 LET SIZE=9*X*Y+5
50 LET SPACE=PEEK (62464)-PEEK (23730)+256*(PEEK (23731)-PEEK (62465))
60 IF SIZE<=SPACE THEN .SPN=N:.LEN=X:.HGT=Y:.ISPR
70 IF SIZE>SPACE THEN PRINT "NO ROOM"
80.RETN

The above procedure in example 4 will check if sufficient room is available;
if so, execute .ISPR and if not, generate a message, e.g. you could type
.PROCFN S#(1,2,3) to create sprite 1 of 2 by 3 characters.

 5 REM EXAMPLE 5
10 REM PROCEDURE TO DELETE A SPRITE IF IT EXISTS
20 REM AND PRINT THE NUMBER OF BYTES RECLAIMED
30 DEF FN D#(N)
40.SPN=N: LET START=?TST: LET X=?HGT: LET Y=?LEN
50.DSPR: PRINT 9*X*Y+5;" BYTES SAVED"
60.RETN

The procedure in example 5 will TEST sprite N (see ?TST) to find its
dimensions and then delete it if it exists, displaying the number of bytes
saved, e.g. you could delete sprite number 1 by typing .PROCFN D#(1).


++				15

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


HORIZONTAL SCREEN SCROLLS
The horizontal screen scrolls are by 1, 4 or 8 pixels, left or right, with
or without wrap The horizontal scroll commands are listed below.

	Command		Action
	.WL1V	Scroll left 1 pixel with wrap
	.WR1V	Scroll right 1 pixel with wrap
	.SL1V	Scroll loft 1 pixel, no wrap
	.SR1V	Scroll right 1 pixel, no wrap
	.WL4V	Scroll left 4 pixels with wrap
	.WR4V	Scroll right 4 pixels with wrap
	.SL4V	Scroll left 4 pixels, no wrap
	.SR4V	Scroll right 4 pixels, no wrap
	.WL8V	Scroll left 8 pixels with wrap
	.WR8V	Scroll right 8 pixels with wrap
	.SL8V	Scroll left 8 pixels, no wrap
	.SR8V	Scroll right 8 pixels, no wrap

	Parameter	Use
	COL	Column of left hand edge (0-31)
	ROW	Row of the top edge (0-23)
	LEN	Length of the window (1-32)
	HGT	Height of the window (1-24)

The above commands operate on the screen, scrolling a window whose
dimensions are held in the variables LEN and HGT and is positioned at the
co-ordinates held in COL and ROW.

EXAMPLE 6 will demonstrate the 1, 4 and 8 pixel scrolls with wrap around.

Line 10	fills the screen with data.
Line 20	defines a window 20 by 10 at a position column 6 and row 2, by storing
	the values in LEN, HGT, ROW and COL.
Lines 30 to 80 scroll the window (300 times for each example).

5 REM EXAMPLE 6
10 FOR N=1 TO 55: PRINT "LASER BASIC";: NEXT N
20.LEN=20:.HGT=10:.ROW=2:.COL=6
30 REM 1 PIXEL SCROLL
40 FOR N=1 TO 300:.WL1V: NEXT N
50 REM 4 PIXEL SCROLL
60 FOR N=1 TO 300:.WL4V: NEXT N
70 REM 8 PIXEL SCROLL
80 FOR N=1 TO 300:.WL8V: NEXT N

Replace the .WL1V scroll with SL1V (no wrap) and see the result. You must
remember that pixel data and attribute data are different "chunks" of memory
and that the above scrolling commands only scroll the pixel data.

EXAMPLE 7 will show the difference between the pixel and attribute data by
scrolling data over attributes on the screen.

Line 10	makes sure the attribute flow switch is on.
Line 20	puts sprite 34 (a fly) at position 15,2 (see .PTBL).
Line 30	defines a window the length of the screen around the sprite.
Line 50	scrolls the screen pixel data 256 times to the right with wrap,
	leaving the attribute data behind.


++				16

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 5 REM EXAMPLE 7
10.ATON
20.SPN=34:.ROW=2:.COL=15:.PTBL
30.LEN=32:.HGT=2:.COL=0:.ROW=2
40 PAUSE 50
50 FOR N=1 TO 256:.WR1V: NEXT N

You are not, of course, limited to 1, 4 or 8 pixel scrolls; by combining,
say, three 1 pixel scrolls a 3 pixel scroll can be produced, e.g.
.WR1V:.WR1V:.WR1V

EXAMPLE 8 demonstrates this. Remember that a 9 pixel scroll, for instance,
produced by repeating .WR1V 9 times, might be more elegantly achieved by
using .WR8V:.WR1V

Line 10	prints data on the screen.
Line 20	defines the dimensions of the window (length 32 and height 1).
Line 30	is the loop, that once completed, will reassemble the scrolled screen.
Line 40	is the loop that calculates the ROW and number of scrolls on that line.
Line 50	sets the ROW variable for the scroll window.
Line 60	scrolls the window I times.

 5 REM EXAMPLE 8
10 FOR N=1 TO 20: PRINT AT N,0;N;"PIXEL SCROLL": NEXT N
20.LEN=32:.HGT=1:.COL=0
30 FOR N=1 TO 256
40 FOR I=1 TO 20
50.ROW=I
60 FOR M=1 TO I:.WR1V: NEXT M
70 NEXT I
80 NEXT N


VERTICAL SCREEN SCROLLS
These work in a similar way to the horizontal scrolls, but in addition to
setting up the window with the four window parameters COL, ROW, HGT and LEN,
a further variable NPX is used to give the size and direction of the scroll
in pixels. A positive value for NPX causes upward scrolling and a negative
value causes downward scrolling.

e.g.	.NPX=-1 is one pixel down.
	.NPX=1 is one pixel up.

	Command	Action
	.WCRV	Vertical scroll with wrap
	.SCRV	Vertical scroll, no wrap

	Parameter	Use
	COL	Column of left hand edge	(0-31)
	ROW	Row of top edge			(0-23)
	LEN	Length of the window		(1-32)
	HGT	Height of the window		(1-24)
	NPX	Size and direction of scroll	(-128 to +127)

Note: All vertical scrolling of pixel data and/or attributes for screen or
sprites, requires buffer space. The space required is calculated by
multiplying NPX by LEN. This length must not exceed 256 bytes as the printer
buffer (23296 to 23551) is used as a temporary store. A line to check this
might be:
	LET X=?NPX: LET Y=?LEN: IF ABS (X)*Y<256 THEN .WCRV
Vertical scrolls, as with horizontal scrolls. can be with or without wrap
around.

EXAMPLE 9 is similar to EXAMPLE 6 except that this demonstrates a 1 pixel
scroll up and a 1 pixel scroll down.


++				17

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Line 40	produces 300 1 pixel scrolls up.
Line 60	produces 300 1 pixel scrolls down.

 5 REM EXAMPLE 9
10 FOR N=1 TO 55: PRINT "LASER BASIC";: NEXT N
20.LEN=20:.HGT=10:.ROW=2:.COL=6
30 REM 1 PIXEL SCROLL UP
40.NPX=1: FOR N=1 TO 300:.WCRV: NEXT N
50 REM 1 PIXEL SCROLL DOWN
60.NPX=-1: FOR N=1 TO 300:.WCRV: NEXT N

In EXAMPLE 10 we scroll vertical columns 1 character wide by 1 pixel. The
column is picked at random.

Line 10	prints a row of 'A's on the bottom of the screen.
Line 20	sets up the parameters of the screen window.
Line 30	picks a random column and stores it in the variable COL.
Line 40	scrolls the column up by 1 pixel without wrap.
Line 50	loops around.

 5 REM EXAMPLE 10
10 FOR N=0 TO 31: PRINT AT 21,N;"A": NEXT N
20.LEN=1:.HGT=22:.ROW=0:.NPX=1
30 LET X=INT (RND*33)-1:.COL=X
40.WCRV
50 GO TO 20


SCREEN ATTRIBUTE SCROLLS
Attribute scrolls are similar to the pixel scrolls but all attribute scrolls
are by one character, and with wrap. The buffer size used is equal to LEN
and is therefore always less than 33 bytes.

	Command	Action
	.ATLV	Scroll attributes left		1 character with wrap
	.ATRV	Scroll attributes right		1 character with wrap
	.ATUV	Scroll attributes up		1 character with wrap
	.ATDV	Scroll attributes down		1 character with wrap

	Parameter	Use
	COL	Column of the left hand edge	(0-31)
	ROW	Row of the top edge		(0-23)
	HGT	Height of the window		(1-32)
	LEN	Length of the window		(1-24)


++				18

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


EXAMPLE 11 demonstrates the use of one of the attribute scrolls, .ATRV. In
this example, vertical columns of attributes are placed on the screen. Using
a series of nested FOR-NEXT loops the top row of attributes is scrolled by 1
character, the second row is scrolled by 2 characters etc. As this sequence
is repeated patterns are formed.

  5 REM EXAMPLE 11
 10 INK 7: PAPER 0: BRIGHT 1: CLS
 20 FOR N=0 TO 703: PRINT CHR$(129): NEXT N
 30.LEN=1:.HGT=24:.ROW=0: FOR N=0 TO 31:.COL=N: INK INT (RND*7)+1:.SETV: NEXT N
 40.LEN=32:.COL=0:.HGT=1
 50 FOR I=0 TO 31
 60 FOR Y=1 TO 22
 70.ROW=Y-1
 80 FOR X=1 TO Y
 90.ATRV
100 NEXT X
110 NEXT Y
120 NEXT I

Line 10	sets up the attributes.
Line 20	fills the screen with CHR$ 129.
Line 30	fills the screen with random coloured columns (see .SETV).
Line 40	sets the parameters for .ATRV.
Line 50	I is the number of complete scroll operations to reset the columns.
Line 60	Y is the row.
Line 80	is the number of characters scrolled per row.
Line 90	executes the scroll.

The way in which attribute data is scrolled separately from pixel data is
shown in EXAMPLE 12, which is similar to EXAMPLE 7. In this case it is the
pixel data that is left.

 5 REM EXAMPLE 12
10.ATON
20.SPN=34:.ROW=2:.COL=15:.PTBL
30.LEN=32:.HGT=2:.COL=0:.ROW=2
40 PAUSE 50
50 FOR N=1 TO 32:.ATLV: NEXT N

Due to the limitations of the Spectrum, attributes can only be scrolled by 8
pixels or one character at a time. If you change line 50 in EXAMPLE 12 to:
	50 FOR N=1 TO 32:.ATLV:.WL8V: NEXT N
both the pixel and attribute data will be scrolled.


HORIZONTAL SPRITE SCROLLS
The horizontal sprite scrolls are by 1, 4 or 8 pixels, left or right, with
or without wrap. If the sprite does not exist an error is generated. A list
of sprite scrolls are given below.


++				19

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


	Command	Action
	.WL1M	Scroll left 1 pixel with wrap
	.WR1M	Scroll right 1 pixel with wrap
	.SL1M	Scroll left 1 pixel, no wrap
	.SR1M	Scroll right 1 pixel, no wrap
	.WL4M	Scroll left 4 pixels with wrap
	.WR4M	Scroll right 4 pixels with wrap
	.SL4M	Scroll left 4 pixels, no wrap
	.SR4M	Scroll right 4 pixels, no wrap
	.WL8M	Scroll left 8 pixels with wrap
	.WR8M	Scroll right 8 pixels with wrap
	.SL8M	Scroll left 8 pixels, no wrap
	.SR8M	Scroll right 8 pixels, no wrap

	Parameter	Use
	SPN	Number of the sprite to be scrolled (1-255)

In most of the previous examples, Laser BASIC words have ended in the letter
"V". This implies "video". Operations ending in "V" affect only the screen,
leaving all sprites in memory unaffected.

All the above scroll commands end in "M" which implies "memory", that is to
say that if you execute one of these words the sprite in memory is altered.
Remember that you will not see the change in the sprite until you have
placed it back on the screen.

EXAMPLE 13 is similar to EXAMPLE 6, except a sprite is scrolled in memory
and then placed on the screen 300 times. (Note that, as with screen scrolls,
only the pixel data is scrolled). Remember that you will need the "SPRITE2A"
file of sprites loaded.

 5 REM EXAMPLE 13
10.ROW=10:.COL=14:.SPN=49
20 REM SCROLL SPRITE BY 1 PIXEL
30 FOR N=1 TO 300:.WL1M:.PTBL: NEXT N
40 REM SCROLL SPRITE BY 4 PIXEL
50 FOR N=1 TO 300:.WL4M:.PTBL: NEXT N
60 REM SCROLL SPRITE BY 8 PIXEL
70 FOR N=1 TO 300:.WL8M:.PTBL NEXT N

Line 10	sets the ROW and COL positions for the sprite.
Line 30	scrolls the sprite by 1 pixel and then puts it on the screen 300 times.
Line 50	scrolls the sprite by 4 pixels and then puts it on the screen 300 times.
Line 70	scrolls the sprite by 8 pixels and then puts it on the screen 300 times
	(this happens so fast that the sprite becomes a blur).


VERTICAL SPRITE SCROLLS
These work in the same way as the vertical screen scrolls where the signed
variable NPX is used to determine the size and direction of the scroll. If
the sprite does not exist an error is generated.

	Command	Action
	.WCRM	Vertical scroll with wrap
	.SCRM	Vertical scroll, no wrap

	Parameter	Use
	SPN	Number of the sprite to be scrolled	(1-255)
	NPX	Number of pixels to be scrolled		(-128 to +127


++				20

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Note: As with the vertical screen scrolls the amount of buffer space used
must not exceed 256 bytes. The length of the sprite multiplied by NPX gives
the size of buffer required. The length of the sprite can be obtained by
using the ?TST function.

EXAMPLE 14 demonstrates vertical scrolling of sprites, by scrolling and
placing sprite 5 (the dancer) such that it fills the screen with scrolled
sprites.

 5 REM EXAMPLE 14
10 BORDER 0:.SPN=5:.NPX=8
20 FOR Y=0 TO 20 STEP 4
30 FOR X=0 TO 31 STEP 2
40.COL=X:.ROW=Y:.PTBL
50.WCRM
60 NEXT X
70 NEXT Y
80 GO TO 80

Line 10	sets the parameters and the border colour.
Lines 20 and 30 set the X and Y co-ordinates for placing the sprite.
Line 40	puts sprite 5 at the X,Y co-ordinates.
Line 50	scrolls the sprite upwards by 8 pixels.


SPRITE ATTRIBUTE SCROLLS
As with the screen attribute scrolls there are 4 commands to scroll the
attribute data in the 4 directions by 1 character with wrap.

	Command	Action
	.ATLM	Scroll attributes left 1 character with wrap
	.ATRM	Scroll attributes right 1 character with wrap
	.ATUM	Scroll attributes up 1 character with wrap
	.ATDM	Scroll attributes down 1 character with wrap

	Parameter	Use
	SPN	Number of sprite to be scrolled (1-255)


GROUP 1 PUTS AND GETS
PUTs are operations that "put" a sprite to the screen or another sprite,
whilst GETs are the opposite, getting data from the screen or another sprite
into a sprite. There are three groups of GETs and PUTs. The first, and the
fastest, carry out operations between a full sprite and a previously
positioned screen window. All group 1 GETs and PUTs are prefixed with 'GT'
or 'PT'. This first group does not have separate commands to move pixel data
and attributes but instead uses an attribute switch (see .ATON, .ATOF) to
move pixel data with or without attributes. An error message is generated if
the sprite does not exist.

	Command	Action
	.GTBL	Block move screen window into sprite
	.GTOR	OR screen window into sprite
	.GTXR	XOR screen window into sprite
	.GTND	AND screen window into sprite
	.PTBL	Block move sprite into screen window
	.PTOR	OR sprite into screen window
	.PTXR	XOR sprite into screen window
	.PTND	AND sprite into screen window


++				21

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


	Parameter	Use
	COL	Left hand column of target screen position	(0-31)
	ROW	Top row of target screen position		(0-23)
	SPN	Number of sprite to be PUT or GOT		(1-255)

Note: The dimensions of the screen window are the dimensions of the sprite.
If COL+sprite length is greater than 32 or if ROW+sprite height is greater
than 24 then the command will partially PUT the sprite.

If you now type:
	.SPN=39:.ROW=1:.COL=1:.PTBL
you in fact place sprite 39 on the screen at ROW and COL position 1,1. This
is the fastest and simplest way of putting a sprite on the screen.

Now type .ATOF (see .ATOF) and you have stopped the flow of attributes. So
if you typed .ROW=5:.PTBL (remember there is no need to set SPN or COL as
they remain the same), sprite 39 would appear on the screen again, but this
time without its attributes.

Type .ATON:.PTBL and behold, it has re-appeared with its attributes.

.PTBL removes all data on the screen where the sprite appeared. You are
provided with three other operations - .PTOR, .PTXR and .PTND - which
logically OR, XOR and AND the sprite to the screen.

If you were to type:
	.ATOF:.SPN=18:.ROW=10:.COL=10:.PTBL
you would have put sprite 18 (a tank) on the screen. Now if you type
.SPN=39:.PTXR you would XOR sprite 39 over what was on the screen. Now type
.PTXR and hit enter, and the sprite has removed itself, and reset the
original data.

Example 15 XORs sprite 18 (a tank) through a field of mice non-destructively.

 5 REM EXAMPLE 15
10.ATOF:.SPN=6
20 FOR N=1 TO 50
30 LET X=INT (RND*32): LET Y=INT (RND*20):.COL=X:.ROW=Y:.PTBL
40 NEXT N
50.SPN=16:.ROW=10
60 FOR X=-4 TO 32
70.COL=X:.PTXR: PAUSE 4:.PTXR
80 NEXT X
90.ATON

Line 10	switches oft the attribute flow and sets SPN to 6 (the mice).
Lines 20 to 40 fill the screen with 50 mice.
Line 50	sets the parameters for sprite 16.
Line 60	is a simple loop to work out the positions for COL.
Line 70	sprite 16 is XORed to the screen, a pause is executed while it is
	on the screen and then the same sprite is XORed at the same position,
	thus removing itself and resetting any data previously there.

If you type .SPN=18:.ROW=10:.COL=10:.PTBL sprite 18 appears on the screen as
expected. Now see what happens if you type .COL=29:.PTBL (remember the
sprite is 6 characters long). What has happened is that as much of the
sprite as possible has been placed on the screen. Now try .COL=-3:.PTBL

The GETs (words beginning in GT), unlike the PUTs, take data from the screen
at a position stored in ROW and COL from a window whose dimensions are those
of the sprite, storing the data in the sprite.


++				22

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In EXAMPLE 16 a pixel is plotted in the bottom right hand corner of the
screen, the window around this area is GOT into sprite 1 (destroying the
vintage car) and the sprite is then placed on the screen. Another pixel is
placed in the bottom right hand corner of the screen and sprite 1 is re-GOT
and PUT etc.

  5 REM EXAMPLE 16
 10.SET=0:.SPN=1:.ROW=20:.COL=28
 20.SET=1:.SPN=1:.ROW=0:.COL=0
100 DEF FN A#()
110 LET PX=INT (RND*32): LET PY=INT (RND*16)
120 PLOT PX+223,PY
130.RETN
200 FOR Y=0 TO 20 STEP 2
220 FOR X=0 TO 32 STEP 4
240.PROCFN A#()
250.SET=0:.GTBL
260.SET=1:.ROW=Y:.COL=X:.PTBL
270 NEXT X
280 NEXT Y

Line 10 sets up SET 0 (the position of the bottom right hand corner of
	the screen).
Line 20 sets up SET 1 (the sprite).
Line 100 defines a procedure A#.
Lines 110 and 120 plot a pixel at a random position in the bottom left
	of the screen.
Lines 200 and 210 calculate the COL and ROW positions for putting sprite 1.
Line 240 calls the plotting procedure.
Line 250 GETs sprite 1.
Line 260 PUTs sprite 1.


++				23

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


GROUP 2 GETS AND PUTS
These commands allow operations between sprite windows and screen windows.
Unlike the group 1 commands, there are separate commands to move pixel data
and attributes, although the ATON and ATOF commands have the usual effect on
their operation. Four new parameters are introduced to specify the column
and row in the sprite and the height and length of the window within the
sprite. If the window overlaps the boundaries of the sprite or screen the
command will not execute and if the sprite does not exist an error is
generated. All commands in this group are prefixed with 'GW' or 'PW'.

	Command	Action
	.GWBL	Block move screen window into sprite window
	.GWOR	OR screen window into sprite window
	.GWXR	XOR screen window into sprite window
	.GWND	AND screen window into sprite window

	.PWBL	Block move sprite window into screen window
	.PWOR	OR sprite window into screen window
	.PWXR	XOR sprite window into screen window
	.PWND	AND sprite window into screen window

	.GWAT	Block move screen window into sprite window
	.PWAT	Block move sprite window into screen window

	Parameter	Use
	COL	Left hand column of target screen window(0-31)
	ROW	Top row of target screen window		(0-23)
	SCL	Left hand column of sprite window	(0 to sprite length -1)
	SRW	Top row of sprite window		(0 to sprite height -1)
	HGT	Height of window			(1-24)
	LEN	Length of window			(1-32)
	SPN	Sprite number				(1-255)

In EXAMPLE 17, 1 character by 1 character windows are taken at random from
sprite 49 (the teddy bear) and placed on the screen.

  5 REM EXAMPLE 17
 10.SPN=49:.HGT=1:.LEN=1
200 FOR Y=0 TO 20
220 FOR X=0 TO 32
230 LET GX=INT (RND*4)
240 LET GY=INT (RND*5)
250.COL=X:.ROW=Y:.SCL=GX:.SRW=GY
260.PWBL
270.PWAT
280 NEXT X
290 NEXT Y

Line 10 sets up SPN with the number of the sprite and sets HGT and LEN
	with the dimensions of the window.
Lines 200 and 210 calculate the COL and ROW positions for PUTting the
	1 by 1 window.
Lines 230 and 240 calculate the random COL and ROW positions in the sprite
	for GETting the window.
Line 250 sets up these values.
Line 260 GETs the pixel data from the window and PUTs it on the screen.
Line 270 GETs the attribute data.


++				24

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


GROUP 3 GETS AND PUTS
This group, possibly the most useful in the whole set, comprises commands
which support operations between a sprite and a window in a second sprite.
All group 3 commands are prefixed with 'PM' or 'GM'. If the sprite window
overlaps the boundaries of the sprite, the command will not execute, and if
either of the sprites does not exist an error message Q is generated.

	Command	Action
	.GMBL	Block move sprite pixel data into sprite window
	.GMOR	OR sprite pixel data into sprite window
	.GMXR	XOR sprite pixel data into sprite window
	.GMND	AND sprite pixel data into sprite window

	.PMBL	Block move sprite window pixel data into sprite
	.PMOR	OR sprite window pixel data into sprite
	.PMXR	XOR sprite window pixel data into sprite
	.PMND	AND sprite window pixel data into sprite

	.GMAT	Block move sprite attribute data into sprite window
	.PMAT	Block move sprite window attribute data into sprite

	Parameter	Use
	SP1	Number of the first sprite		(1-255)
	SP2	Number of the second sprite (containing the window)	(1-255)
	SCL	Left hand column of sprite window	(1 - SPRITE LENGTH)
	SRW	Top row of sprite window		(1 - SPRITE HEIGHT)


.MOVE
Used to provide simple and effective animated or non-animated sprite
movement. This command uses the exclusive OR (XOR) operation to provide non
destructive sprite movement, so if your sprite starts on screen you will
need to .PTXR the sprite onto the screen before you use MOVE. If your sprite
moves "on screen" from a position "off screen" then this will be catered for
automatically. The exclusive OR (XOR) operation works in the same way as
Sinclair's OVER 1 printing.

	Parameters	Use
	COL	The COL of the sprite to be moved.		(0-31)
	ROW	The ROW of the sprite to be moved.		(0-23)
	HGT	The HGT in characters of the movement		(-24-+24)
	LEN	The LEN in characters of the movement.		(-32-+32)
	SP1	The number of the sprite to be moved.		(1-255)
	SP2	The number of the sprite after movement.	(1-255)

MOVE XORs out the previously PUT sprite SP1 that is on the screen at a
position held in ROW and COL and places sprite SP2 on the screen at a
position COL + LEN, HGT + ROW. ROW and COL are then incremented by the
values of HGT and LEN, and SP1 and sP2 are left exchanged.

EXAMPLE 18 moves a sprite non destructively across data from the top left
towards the bottom right. It stores in SP1 and SP2 the values of the OLD and
NEW sprites (which in this case are both 6 (the mouse).

Since the sprite is at the top left of the screen ROW and COL values are
initially set to 0.

Now since we wish to move the sprite down and to the right by 1 character,
HGT and LEN must be set to 1. MOVE automatically increments ROW and COL by
the values held in HGT and LEN. So in fact all you have to do is type .MOVE
to move the sprite.


++				25

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


  5 REM EXAMPLE 18
 10 FOR N=1 TO 100
 20 LET X=INT (RND*32)
 30 LET Y=INT (RND*21)
 40 PRINT AT Y,X;"A"
 50 NEXT N
 60.ATOF:.COL=0:.ROW=0:.SPN=6:.PTXR
 70.HGT=1:.LEN=1
 80.SP1=6:.SP2=6
 90 FOR N=1 TO 25
100.MOVE
110 PAUSE 3
120 NEXT N

Lines 10 to 50 fill the screen with letter 'A's at random positions.
Line 60	puts sprite 6 (the mouse) in the top left hand corner of the screen.
Line 70	sets the increments in HGT and LEN to both be 1.
Line 80	sets the OLD and NEW sprites to 6.
Line 90	is a simple loop.
Line 100 executes MOVE.

You can, of course, have negative values in HGT and LEN.

Using suitable values for SP1 and SP2, MOVE can be used to animate as well
as move sprites.

In example 19 negative values are placed in HGT and LEN to give movement in
the opposite direction to those of EXAMPLE 18.

  5 REM EXAMPLE 19
 10 FOR N=1 TO 100
 20 LET X=INT (RND*32)
 30 LET Y=INT (RND*21)
 40 PRINT AT Y,X;"A"
 50 NEXT N
 60.ATOF:.COL=0:.ROW=22:.SPN=6:.PTXR
 70.HGT=-1:.LEN=-1
 80.SP1=6:.SP2=6
 90 FOR N=-1 TO 25
100.MOVE
110 PAUSE 3
120 NEXT N

In EXAMPLE 20 sprite 6 is moved around in a circle by constantly changing
the values in the increments HGT and LEN.

   5 REM EXAMPLE 20
 10 FOR N=1 TO 150
 20 LET X=INT (RND*32)
 30 LET Y=INT (RND*22)
 40 PRINT AT Y,X;"A"
 50 NEXT N:.ATOF
 60.ROW=10:.COL=4:.SPN=6:.PTXR
 70.SP1=6:.SP2=6
 80.HGT=0:.LEN=0
 90 LET C=4: LET R=10
100 FOR N=1 TO 30
110.COL=C:.ROW=R
120 LET C=INT (14-10*COS (N/15*PI))
130 LET R=INT (10+10*SIN (N/15*Pl))
140 LET OC=?COL; LET OR=?ROW
150.LEN=(OC-C)*-1:.HGT=(OR-R)*-1
160.MOVE
170 NEXT N
180 GO TO 100


++				26

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Lines 10 to 50 fill the screen with 'A's.
Line 60	puts sprite 6 on the screen.
Lines 70 to 90 set up the parameters.
Lines 100,120 and 130 calculate the COL and ROW position by calculating
	points on the edge of a circle.
Lines 140 and 150 calculate the offset to be stored in HGT and LEN.
Line 160 executes MOVE


.ATON/.ATOF
The flow of attributes is controlled by two commands which determine whether
or not attributes are to be moved with pixel data by the PUTs and GETs.

	Command	Action
	.ATON	Enable the flow of attributes between sprites
		and the screen.
	.ATof	Disable the flow of attributes between sprites
		and the screen.

	Parameter	Use
	None		None


TRANSFORMATIONS
To increase the utility of the package, four words have been included to
invert (1's complement), spin, reflect and enlarge. The inversion and
reflection routines work for screen and sprite data but the rotation and
enlargement commands work only for sprites and a second target sprite is
required to rotate or enlarge into.


Command	Action
.INVV	The screen window defined by COL, ROW, HGT and LEN is inverted (1's
	complemented), in other words all pixels which were set "on" become
	set "off" and the effect is to exchange the INK and PAPER colours.
	If the window overlaps the screen boundaries then it will be
	"clipped" to lie on screen.

	Parameter		Use
	COL	Column of the left hand edge of the window	(0-31)
	ROW	Row of the top edge of the window		(0-23)
	HGT	Height of the screen window			(1-24)
	LEN	Length of the screen window			(1-32)

If you were to type .ROW=1:.COL=1:.HGT=5:.LEN=5:.INVV then the 5 by 5 window
would have all its pixels inverted. Another example of .INVV is demonstrated
in Example 21.

  5 REM EXAMPLE 21
 10 BORDER 0
 20 FOR N=1 TO 58: PRINT "LASER BASIC";: NEXT N
 30 FOR N=1 TO 10
 40.HGT=22-(N*2)
 50.LEN=32-(N*2)
 60.ROW=N
 70.COL=N
 80.INVV
 90 PAUSE 10
100 NEXT N
110 GO TO 30


++				27

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Example 21 produces a tunnel effect by changing the position and dimensions
of the window.

Command	Action
.INVM	The same operation as .INVV but this time it is carried out on the
	whole sprite whose number is held in SPN.

	Parameter	Use
	SPN	Number of the sprite to be inverted	(1-255)

To invert sprite 10 you simply type .SPN=10:.INVM


Command	Action
.MIRV	The pixel data in the screen window defined by the variables COL,
	ROW, HGT and LEN is reflected about a vertical line through its
	centre. If the window overlaps the screen boundaries the window
	will be "clipped".

	Parameter	Use
	COL	Column of the left hand edge of the window	(0-31)
	ROW	Row of the top edge of the window		(0-23)
	HGT	Height of the screen window			(1-24)
	LEN	Length of the screen window			(1-32)

Example 22 demonstrates .MIRV by mirroring the text on one half of the screen.

 5 REM EXAMPLE 22
10 LET A$="THIS IS AN EXAMPLE OF THE USE OF THE COMMAND .MIRV IN
LASER BASIC FOR THE SPECTRUM FROM OASIS SOFTWARE."
20 LET Y=0: LET X=0
30 FOR S=1 TO LEN A$
40 LET C=CODE A$(S TO S)
50 IF C=32 THEN LET Y=Y+1: LET X=0: GO TO 80
60 PRINT AT Y,X;CHR$ (C);AT Y,X+16;CHR$ (C)
70 LET X=X+1
80 NEXT S
90.ROW=0:.COL=0:.LEN=16:.HGT=22:.MIRV

Line 10	sets up the string of text.
Lines 20 to 80 print out the string with one word per line.
Line 90	mirrors one half of the screen.


Command	Action
.MIRM	The pixel data in the sprite whose number is held in SPN is reflected
	about a vertical line through its centre. If the sprite does not exist
	an error message is generated.

	Parameter	Use
	SPN	The number of the sprite whose pixel data is to be
		reflected. (1-255)


Command	Action
.MARV	The attribute data in the screen window defined by the variables COL,
	ROW, HGT and LEN is reflected about a vertical line through its centre.
	If the window overlaps the screen boundaries the window will be
	"clipped".

	Parameter     Use
	COL	Column of the left hand edge of the window	(0-31)
	ROW	Row of the top edge of the window		(0-23)
	HGT	Height of the screen window			(1-24)
	LEN	Length of the screen window			(1-32)


++				28

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Command	Action
.MARM	The attribute data in the sprite whose number is held in SPN is
	reflected about a vertical line through its centre. If the sprite
	does not exist an error message is generated.

	Parameter	Use
	SPN	The number of the sprite whose attribute data is
	to be reflected. (1-255)


Command	Action
.SPNM	Rotate 90 degrees clockwise sprite SP2 into sprite SP1. This command
	involves an operation between two sprites with transposed
	dimensions. If, for example, a sprite with dimensions 8 by 3 is to
	be spun into a second sprite, this second sprite must have
	dimensions 3 by 8. If the second sprite does not have the transposed
	dimensions of the first then the command will simply not execute.
	Pixel and attribute data are both rotated.

	Parameter	Use
	SP1	Number of the sprite to be rotated	(1-255)
	SP2	Number of the sprite to be rotated into	(1-255)

Note:	Sprite SP1 should be cleared using .CLSM before data is rotated into it.

In EXAMPLE 23 sprite 5 (the dancer) is rotated into the cleared sprite 1 and
then placed on the screen. Sprite 1 (which is now a 90 degree rotation of
sprite 5) is now rotated back into the cleared sprite 5, thus producing a
180 degree rotated sprite 5. This process is continued.

 5 REM EXAMPLE 23
10.ATOF:.COL=15:.ROW=10:.SPN=5:.PTBL
20 FOR N=50 TO 1 STEP -1
30.SPN=1:.CLSM:.SP2=1:.SP1=5:.SPNM
40.ROW=10:.COL=15:.HGT=1:.LEN=-1:.SP1=5:.SP2=1
50.MOVE: PAUSE N
60.SPN=5:.CLSM:.SP2=5:.SP1=1:.SPNM
70.ROW=11:.COL=14:.HGT=-1:.LEN=1:.SP1=1:.SP2=5
80.MOVE: PAUSE N
90 NEXT N

Line 10 places sprite 5 on the screen.
Line 20 is a FOR-NEXT loop that controls the delay while the sprite is on
	the screen.
Line 30 clears sprite 1 and rotates sprite 5 into it.
Line 40 sets up parameters for a MOVE operation.
Line 50 executes MOVE with a pause.
Line 60 clears sprite 5 and rotates sprite 1 into sprite 5.
Line 70 sets up the parameters for a MOVE operation.
Line 80 executes the MOVE with a pause.


Command  Action
.DSPM	Enlarge sprite SP2 into sprite SP1. Sprite SP1 must have exactly
	double the dimensions of sprite SP2 or the command will not execute.
	Pixel and attribute data are enlarged together.

	Parameter	Use
	SP1	Number of target sprite		(1-255)
	SP2	Number of sprite to be enlarged	(1-255)

In EXAMPLE 24 sprite 51, which is a one character space invader, is enlarged
into sprite 32, which is two characters high and wide.

 5 REM EXAMPLE 24
10.ROW=0:.COL=0:.SPN=51:.PTBL
20.SP1=32:.SP2=51:.DSPM
30.COL=2:.SPN=32:.PTBL


++				29

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Line 10 puts sprite 51 on the screen.
Line 20 enlarges sprite 51 into sprite 32.
Line 30 puts sprite 32 on the screen.


MISCELLANEOUS WORDS

Command  Action
.SETV	Set the attributes to the permanent INK and PAPER colours in the
	window defined by HGT, LEN, COL and ROW.

	Parameter	Use
	COL	Column of the left hand edge of the window	(0-31)
	ROW	Row of the top edge of the window		(0-23)
	HGT	Height of the screen window			(1-24)
	LEN	Length of the screen window			(1-32)

In EXAMPLE 25 a 5 by 5 square is filled with random attributes at random
screen positions.

 5 REM EXAMPLE 25
10.LEN=5:.HGT=5
20.COL=INT (RND*28)
30.ROW=INT (RND*18)
40 PAPER INT (RND*7)
45 BRIGHT INT (RND*1)
50.SETV
60 GO TO 20

Line 10 sets the LEN and HGT.
Lines 20 and 30 set the ROW and COL positions.
Line 40 sets a random PAPER colour.
Line 50 executes a .SETV
Line 60 loops around.


Command	Action
.SETM	Set the attributes to the permanent INK and PAPER colours in the
	sprite whose number is held in SPN.

	Parameter	Use
	SPN	Number of the sprite whose attributes are to be set.	(1-255)

In EXAMPLE 26 sprite 2 is repeatedly put on the screen, and has its PAPER
colour changed using .SETM

 5 REM EXAMPLE 26
10.SPN=2: INK 0: BRIGHT 1
20 FOR X=0 TO 32 STEP 4
30 FOR Y=0 TO 21 STEP 2
40.COL=X:.ROW=Y
50 PAPER INT (RND*6)+1
50.SETM
70.PTBL
80 NEXT Y
90 NEXT X


++				30

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Line 10 sets the parameters.
Lines 20 and 30 are the loops for putting the sprite on the screen.
Line 50 picks the paper colour.
Line 60 executes .SETM
Line 70 puts the sprite on the screen.


Command	Action
.CLSV	Clear the screen window defined by variables HGT, LEN, COL and ROW
	and set the attributes to the permanent INK and PAPER colours.

	Parameter     Use
	COL	Column of left hand edge of the window	(0-31)
	ROW	Row of the top edge of the window	(0-23)
	HGT	Height of the screen window		(1-24)
	LEN	Length of the screen window		(1-32)


Command	Action
.CLSM	Clear the pixel data of the sprite whose number is held in SPN.
	Attribute data is unaffected.

	Parameter	Use
	SPN	Number of sprite whose pixel data is to be cleared.	(1-255)


Command  Action
.ADJM	This command is used to adjust the values in the variables COL, ROW,
	HGT, LEN, SCL, SRW, SPN so that a particular sprite can be
	"partially PUT or GOT" to or from the screen using the group 2 PUTs
	or GETs. The value in the PUT variables COL, ROW, HGT, LEN, SCL and
	SRW may all be changed by the execution of this command. Before
	execution SCL and SRW must be zero, HGT and LEN are ignored and the
	HGT and LEN of the sprite whose number is held in SPN are used.

	Parameter	Use
	SPN	Sprite to be PUT or GOT	(1-255)
	COL	Target column		(0-31)
	ROW	Target row		(0-23)
	SCL	Set to 0 before execution
	SRW	Set to 0 before execution


Command	Action
.ADJV	Essentially the same idea as .ADJM but this time the screen window
	defined by HGT, LEN, COL and ROW is adjusted to be "on-screen".

	Parameter     Use
	COL	Target column		(0-31)
	ROW	Target row		(0-23)
	HGT	Height of window	(1-24)
	LEN	Length of window	(1-32)


++				31

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


ASSIGNMENTS
There are 12 assignments in all:
	.COL=	.ROW=	.HGT=	.LEN=	.SP1=	.SP2=
	.SPN=	.SRW=	.SCL=	.NPX=	.SET=
The commands assign the expressions (which can be any legal BASIC
expression, but none of the extended functions) to the graphics variable.
See the section on graphics variables.


THE EXTENDED FUNCTIONS IN DETAIL
There are 16 functions in all:
	?COL	?ROW	?HGT	?LEN
	?SPN	?SP1	?SP2	?SET
	?SCL	?SRW	?NPX	?KBF
	?SCV	?SCM	?TST	?PEK

They are all used in the form:
	LET Var = ?FUN
where Var is any normal BASIC variable (including arrays) and ?FUN is any of
the above 16 functions.

Note that these functions cannot be used as part of normal BASIC
expressions, nor on the left of the above 12 graphics variable assignments,
nor as part of a print statement.

e.g.	Function	Description
	?COL	Returns the current value for COL
	?ROW	Returns the current value for ROW
	?HGT	Returns the current value for HGT
	?LEN	Returns the current value for LEN
	?SPN	Returns the current value for SPN
	?SP1	Returns the current value for SP1
	?SP2	Returns the current value for SP2
	?SCL	Returns the current value for SCL
	?SRW	Returns the current value for SRW
	?SET	Returns the current value for SET
	?NPX	Returns the current value for NPX
	?KBF	This function is provided for the quick detection of multiple
		key presses. All it does in fact is test the specified key
		and return a non-zero result if the specified key was
		pressed or a zero if it was not. The variables COL and ROW
		are used to specify the row and half column of the
		particular key. For a full description of the columns and
		rows of the Spectrum keyboard, see page 160 of the Spectrum
		manual. Below is a summary.

(Spectrum+ keyboard users must note that they should not include the various
extra shift keys in the COL and ROW values.)

	Row	Keys
	1	CAPS SHIFT to V
	2	A to G
	3	Q to T
	4	1 to 5
	5	0 to 6
	6	P to Y
	7	ENTER to H
	8	SPACE to B


++				32

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Columns are organised from 1 to 5 and counted from the outside in. This is
the order above.

?KBF will return a true value (non zero) whenever a key whose ROW and COL
values are stored in the said variables is pressed. Hence if we wished to
write a routine to print "Hello" every time the 'A' key was pressed we would
need to first work out its ROW and COL values, these being 2 and 1
respectively, then use a routine such as:

	10.ROW=2:.COL=1: LET K=?KBF: IF K<>0 THEN PRINT "HELLO":
	20 GO TO 10

The ability of ?KBF to see if a key is pressed or not means that you can in
effect scan all the keys on the keyboard to discover which keys are being
pressed at an instance.

EXAMPLE 27, (although rather long-winded), scans all the top row, (keys 1 to
0) and calculates the total value of the keys that are being pressed.

  5 REM EXAMPLE 27
 10 LET T=0
 20.ROW=4
 30.COL=1: LET K=?KBF: IF K<>0 THEN LET T=T+1
 40.COL=2: LET K=?KBF: IF K<>0 THEN LET T=T+2
 50.COL=3: LET K=?KBF: IF K<>0 THEN LET T=T+3
 60.COL=4: LET K=?KBF: IF K<>0 THEN LET T=T+4
 70.COL=5: LET K=?KBF: IF K<>0 THEN LET T=T+5
 80.ROW=5
 90.COL=1: LET K=?KBF: IF K<>0 THEN LET T=T+0
100.COL=2: LET K=?KBF: IF K<>0 THEN LET T=T+9
110.COL=3: LET K=?KBF: IF K<>0 THEN LET T=T+8
120.COL=4: LET K=?KBF: IF K<>0 THEN LET T=T+7
130.COL=5: LET K=?KBF: IF K<>0 THEN LET T=T+6
140 PRINT AT 10,10:" "AT 10,10;T
150 GO TO 10


?SCV	The character cell of the screen position defined by COL and ROW
	is scanned for pixel data. If data is found, a non-zero result is
	returned, otherwise a zero result is returned. If COL or ROW are
	off-screen a random result is returned.

This is probably one of the most useful functions as it can be used for
sprite crash detection. The character square ahead of a moving sprite can be
checked to see if it contains data, and if there is then a crash can be
reported.


++				33

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In EXAMPLE 28 you are asked to input the values for ROW and COL and the
character square at this position is scanned for data.

 5 REM EXAMPLE 28
10 INPUT ;"COL= ";C: IF C<0 OR C>31 THEN GO TO 10
20 INPUT ;"ROW= ";R: IF R<0 OR R>24 THEN GO TO 20
30.ROW=R:.COL=C
40 LET T=?SCV
50 IF T=0 THEN PRINT "NO DATA THERE": GO TO 10
60 PRINT "THERE IS DATA THERE": GO TO 10

Lines 10 and 20 take the values of ROW and COL and check they lie on the screen.
Line 30 sets ROW and COL
Line 40 scans the character square.
Lines 50 and 60 report the result.

Example 29 uses ?SCV to check for objects in the path of a line of sprites;
these objects, the letter 'A', are then avoided by scanning for possible
clear paths.

  5 REM EXAMPLE 29
 10.SPN=51
 20 FOR N=1 TO 100
 30 LET X=INT (RND*32)
 40 LET Y=INT (RND*22)
 50 PRINT AT Y,X;"A"
 60 NEXT N
 70 LET R=10: LET C=0
 80 LET C=C+1: GO SUB 160: IF G=1 THEN GO TO 80
 90 LET C=C-1
100 LET R=R+1: GO SUB 160: IF G=1 THEN GO TO 80
110 LET R=R-1
120 LET R=R-1: GO SUB 160: IF G=1 THEN GO TO 80
130 LET R=R+1
140 LET C=C-1: GO SUB 160: IF G=1 THEN GO TO 80
150 PRINT AT 0,0;"TRAPPED": STOP
160 LET G=0:.ROW=R:.COL=C: LET S=?SCV
170 IF C=32 THEN PRINT AT 0,0;"SUCCESS": STOP
180 IF S=0 THEN LET G=1:.PTBL
190 RETURN

Lines 20 to 60 fill the screen with randomly positioned "A"s.
Lines 80 to 140 calculate the movement of the sprite.
Lines 160 to 190 are the scanning routines that also report if the sprite
	has reached the other side.


?SCM	The sprite whose number is held in SPN is scanned for pixel data.
	If data is found, a non-zero result is returned, otherwise a zero
	result is returned. If SPN does not exist an error is generated.


?TST	The sprite whose number is held in SPN is searched for. If it is not
	found, an error Q is generated, otherwise the address of the sprite
	in memory is returned and HGT and LEN are set to contain the
	dimensions of the sprite.

NOTE:	Sprites are stored in memory in the following format:
	First byte	= sprite number
	Second byte	= least significant byte of the address of next sprite
	Third byte	= most significant byte of the address of next sprite
	Fourth byte	= sprite length
	Fifth byte	= sprite height
	8xHGTxLEN bytes	= pixel data
	HGTxLEN bytes	= attribute data

This means that each sprite actually occupies 9*HGTxLEN+5 bytes.


++				34

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In EXAMPLE 30 sprites 1 to 50 are interrogated using ?TST and their
addresses in memory and dimensions are printed.

 5 REM EXAMPLE 30
10 FOR N=1 TO 50
20.SPN=N
30 LET AD=?TST
40 LET H=?HGT
50 LET L=?LEN
60 PRINT AD;" SPRITE ";N;" ";H;" HGT ";L;" LEN"
70 NEXT N

Line 10 is the loop for the sprites.
Line 30 lets AD = the address in memory.
Lines 40 and 50 read the HGT and LEN values set by ?TST.
Line 60 prints the data on the screen.


?PEK<exp> This is a 16 bit version of PEEK and unlike the other functions
	is followed by an expression which represents the address from
	which the function should read.

LET X=?PEK(62464) is equivalent to LET X=PEEK (62464)+256*PEEK (62465)

LET X=?PEK(X+3*Y) is equivalent to LET X=PEEK (2+3*Y)+256*PEEK (2+3*Y+1)


ADDITIONAL COMMANDS
.POKE X,Y
This is a 16 bit version of the normal BASIC POKE. It places the least
significant byte of Y into X and the most significant byte of Y into X+1. Y
must be in the range 0 to 65535 and X must be in the range 0 to 65534.

.POKE X,Y is equivalent to POKE X,INT (Y/256): POKE X+1,Y-256*(INT (Y/256))


PROCEDURES
One of the most powerful features of structured programming languages such
as PASCAL and some advanced BASICs, e.g. BBC BASIC, is the facility to
utilise procedures. So what is a procedure?

Quite often a particular piece of code or sequence of instructions is
executed at a number of different places within a program. For this reason
most languages have some facility for subroutines. The Z80 has a CALL
instruction, BASIC has GOSUB, and other languages usually have an
equivalent. As often as not the user needs to pass particular values to a
subroutine and he also needs to know that the subroutine will not corrupt
variables used in other parts of the program. This involves local variables
and is a feature not supported by the standard Sinclair BASIC.

Local and Global Variables
When a procedure is defined, the definition contains a list of parameters
which can be string or numeric but not array variables, e.g.
10 DEF FN A#(X,Y,Z,A$,B$)
(Remembering DEF FN is the keyword EXTENDED SYMBOL SHIFT KEY 1).

The variables X, Y, Z, A$ and B$ are now local variables (as far as the
parameter is concerned). This means that values they are assigned within the
procedure will have no effect on any other variables called X, Y, Z, A$ and
B$ that have been used in other parts of the program. This is a very
powerful feature as will be seen.

Any other variables encountered in the procedure, however, will have the
global value. This means that they will have the value that they would have
had anywhere else in the program and if they are assigned values within the
procedure, will return with this new value.


++				35

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Invoking Procedures

To execute the procedure above you could use:
	.PROCFN A#(3,2,K,"HELLO",B$)
where ere FN is the keyword EXTENDED SYMBOL SHIFT 2).

This would make the local variables in the definition take on the values of
the parameters in the above invocation, i.e.
	X=3, Y=2, Z=K, A$="HELLO" and B$=B$

A procedure must always end with the word .RETN which is similar to the
keyword RETURN in subroutines. The procedure will execute up until the first
.RETN and then control returns to the next instruction after the invocation.
It is worth noting that procedure execution, like user defined function
execution, is speeded up if the definition is put closer to the beginning of
the program.

If BASIC comes across a procedure definition it will not execute any of the
definition and control will jump to the next command after the corresponding
.RETN.

Up to 52 procedures (single letter names or single letters followed by $)
can be defined and to distinguish procedures from user defined functions the
letter of the procedure name is followed a #.

	e.g	DEF FN A#()
		DEF FN C$#()
		DEF FN C#()	etc.


++				36

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


NESTING PROCEDURES
A procedure definition can contain a procedure invocation, but it is
important to remember that if this is done then the values for the local
variables in the latest invocation become the values for both invocations.
This section will be new to most users, and probably rather confusing. So
here are a few examples.

If, for example you wished to write a procedure to print "HELLO" on the
screen it would look like EXAMPLE 31. (Note the two empty two brackets, this
is because no parameters are going to be passed to the procedure).

 5 REM EXAMPLE 31
10 DEF FN A$#()
20 PRINT "HELLO"
30.RETN

To call the procedure you would need to execute .PROCFN A$#(). (Remember the
FN part of .PROCFN is the Sinclair keyword FN under the 2 key).

Now if we wished to specify the X and Y position on the screen where the
"HELLO" is printed, you will have to set up these two parameters in the
brackets, see EXAMPLE 32.

 5 REM EXAMPLE 32
10 DEF FN A$#(X,Y)
20 PRINT AT X,Y;"HELLO"
30.RETN

To print "HELLO" at the X position 1 and the Y position 10, you would type:
.PROCFN A$#(1,10).

If instead of printing "HELLO", we wished to write a procedure that prints
any string. The string parameter will have to be included in the brackets,
see EXAMPLE 33.

 5 REM EXAMPLE 33
10 DEF FN A$#(X,Y,A$)
20 PRINT AT X,Y;A$
30.RETN

To print "GOODBYE" at the X position 5 and Y position 8 you would type:
.PROCFN A$#(5,8,"GOODBYE")

Finally run example 34 to see how local variables are independent of
variables with the same name in the main program.

 5 REM EXAMPLE 34
10 DEF FN A$#(X,Y,A$)
20 PRINT AT X,Y;A$
30.RETN
40 LET A$="GOODBYE":  LET X=1: LET Y=2
50 PRINT Y,X,A$
60.PROCFN A$(3,4,"HELLO")
70 PRINT Y,X,A$


WARNING
The inclusion of PROCEDURES in Laser BASIC interferes with the Spectrum's
own stack security and therefore it is important to execute RETURNs from
GOSUBs and .RETNs from PROCEDURES in the correct order. Failure to do so may
cause the system to crash.


++				37

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


PROGRAMMING TECHNIQUES
The following section is designed to give Laser BASIC newcomers a few hints
on programming techniques.


MOVING SOFTWARE SPRITES
The chief problem facing the programmer who wants to move software sprites
around the screen, is choosing from the numerous schemes available. We will
now consider some of these methods, each with its own merits for speed,
simplicity, smoothness and memory. We will begin with the easiest to
implement and then work up to some of the more elaborate techniques.


SCREEN SCROLLING UNDER KEYBOARD CONTROL
This could be used where a sprite on the screen is moved within a window on
the screen, that does not contain any other sprites or data.

Type in the following example, which scrolls a window on the screen by 1
pixel under keyboard control using the ?KBF function.

 5 REM EXAMPLE PT1
10 INK 6: PAPER 0: BRIGHT 1: BORDER 0: CLS
20.COL=14:.ROW=10:.SPN=2:.PTBL
30.SET=5:.COL=5:.ROW=4
40.SET=6:.COL=3:.ROW=5
50.SET=7:.ROW=10:.COL=0:.LEN=32:.HGT=2
60.SET=5: LET KB=?KBF: IF KB<>0 THEN .SET=7:.WL1V
70.SET=6: LET KB=?KBF: IF KB<>0 THEN .SET=7:.WR1V
80 GO TO 60

Line 10 sets the screen attributes.
Line 20 puts the sprite on the screen.
Line 30 SET 5 points to the ROW and COL position of the 5 key to move left.
Line 40 SET 6 points to the ROW and COL position of the 8 key to move right.
Line 50 sets up the parameters of the window around the screen.
Line 60 if the 5 key is pressed then the window is scrolled left.
Line 70 if the 8 key is pressed then the window is scrolled right.
	.SET=5 = the 5 key (move left)
	.SET=6 = the 8 key (move right)


SIMPLE PUTTING
Another fairly simple means of moving sprites around the screen is to simply
PUT sprites with a blank border around them and simply change the ROW and/or
COL values. The sprite required for this type of movement should have a one
character border of space around it. The sprite we will use is sprite 30
which is 3 by 3 characters.

Firstly, clear the pixel data in the sprite by typing:
	.SPN=30:.CLSM


++				38

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Now put sprite 51 into the centre of sprite 30. Since sprite 51 is only 1
character high and wide there will be a one character empty space all around
it to rub itself out as it is moved. So type:
	.SP1=51:.SP2=30:.SCL=1:.SRW=1:.GMBL

We can now write a routine to move the sprite around the screen under
keyboard control using the cursor keys being scanned by ?KBF. The sprite is
simply put at a ROW and COL position, the old data being simply removed by
the blank part of the sprite. Type in the following program:

  5 REM EXAMPLE PT2
 10.ATOF: INK 5: BRIGHT 1: PAPER 0: BORDER 0: CLS
 20.SET=1:.ROW=4:.COL=5
 30.SET=2:.ROW=5:.COL=5
 40.SET=3:.ROW=5:.COL=4
 50.SET=4:.ROW=5:.COL=3
 60.SET=7:.ROW=10:.COL=13:.SPN=30
 70 LET X=13: LET Y=10
 80.SET=1: LET KB=?KBF: IF KB<>0 THEN LET X=X-1
 90.SET=2: LET KB=?KBF: IF KB<>0 THEN LET Y=Y+1
100.SET=3: LET KB=?KBF: IF KB<>0 THEN LET Y=Y-1
110.SET=4: LET KB=?KBF: IF KB<>0 THEN LET X=X+1
120 IF X>30 THEN LET X=30
130 IF X<-1 THEN LET X=-1
140 IF Y>22 THEN LET Y=22
150 IF Y<-1 THEN LET Y=-1
160.SET=7:.COL=X:.ROW=Y:.PTBL
170 GO TO 80

Line 10	sets the attributes of the screen.
Lines 20 to 50 set the ROW and COL values for the keys 5, 6, 7 and 8
	(cursor keys).
Line 60	sets the parameters for sprite 30.
Line 70	sets X and Y to the COL and ROW positions of sprite 30.
Lines 80 to 110 scan the keyboard and adjust the values of X and Y depending
	on which key has been pressed.
Lines 120 to 150 check that X and Y do not put the sprite off the screen.
Line 160 puts sprite 30 on the screen (the empty border around it removes
	any data on the screen).

	.SET=1 = key 5 left
	.SET=2 = key 6 down
	.SET=3 = key 7 up
	.SET=4 = key 8 right
	X=COL position of sprite
	Y=ROW position of sprite

The great limitation of this routine is, however, that data such as other
sprites, already on the screen, will be removed as the sprite is PUT over it.

We will now look at logical operations available to the Laser BASIC user.


++				39

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


LOGICAL OPERATIONS
There are three types of logical operation that are used in Laser BASIC;
these are OR, XOR and AND. To get the best out of this package it is
important to fully understand these operations.

If a GET or PUT postfixed with "BL" is executed, then data is block moved
from the source, which may be part of the screen, a sprite, or a sprite
window, in such a way that whatever was previously held at the destination,
which may also be part of the screen, a sprite, or a sprite window, is
obliterated and replaced by whatever was at the source. This may not always
be the desired effect and quite often the user will want to merge characters
or remove parts of the characters and so on. Hence the need for the 3 logic
functions which are commands postfixed with "OR", "XR" and "ND". Below is a
truth table that explains what the result of these operations are on the
individual pixels.

If two sprites are "OR"ed together, the resulting sprite will have pixels
set where pixels were set in either or both of the sprites being "OR"ed.

If two sprites are "AND"ed together, the resulting sprite will have pixels
set where pixels were set in both of the sprites being "AND"ed.

If two sprites are "XOR"ed together, the resulting sprite will have pixels
set where pixels were set in either, but reset where pixels were set or
reset in both.

These results are summarised as follows and should make things a little
clearer:

SOURCE		DESTINATION	OPERATION	RESULT
PIXEL		PIXEL		OR		PIXEL
PIXEL		NO PIXEL	OR		PIXEL
NO PIXEL	PIXEL		OR		PIXEL
NO PIXEL	NO PIXEL	OR		NO PIXEL
PIXEL		PIXEL		AND		PIXEL
PIXEL		NO PIXEL	AND		NO PIXEL
NO PIXEL	PIXEL		AND		NO PIXEL
NO PIXEL	NO PIXEL	AND		NO PIXEL
PIXEL		PIXEL		XOR		NO PIXEL
PIXEL		NO PIXEL	XOR		PIXEL
NO PIXEL	PIXEL		XOR		PIXEL
NO PIXEL	NO PIXEL	XOR		NO PIXEL


USE OF "OR"
One way of moving a sprite around the screen without destroying any data is
to BLOCK PUT the moving sprite and then "OR" the rest of the screen data
after each move.

Example PT3 operates in exactly the same way as example PT2 except that
every time sprite 30 is placed on the screen the subroutine at line 300 is
called, which "OR"s the data (4 sprites) on ie screen using .PTOR.

  5 REM EXAMPLE PT3
 10.ATOF: INK 4: BRIGHT 1: PAPER 0: BORDER 0: CLS
 20.SET=1:.ROW=4:.COL=5
 30.SET=2:.ROW=5:.COL=5
 40.SET=3:.ROW=5:.COL=4
 50.SET=4:.ROW=5:.COL=3
 60.SET=7:.ROW=10:.COL=13:.SPN=30: GO SUB 300
 70 LET X=13: LET Y=10
 80.SET=1: LET KB=?KBF: IF KB<>0 THEN LET X=X-1
 90.SET=2: LET KB=?KBF: IF KB<>0 THEN LET Y=Y+1
100.SET=3: LET KB=?KBF: IF KB<>0 THEN LET Y=Y-1
110.SET=4: LET KB=?KBF: IF KB<>0 THEN LET X=X+1
120 IF X>30 THEN LET X=30
130 IF X<-1 THEN LET X=-1
140 IF Y>22 THEN LET Y=22
150 IF Y<-1 THEN LET Y=-1


++				40

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


160.SET=7:.COL=X:.ROW=Y:.SPN=30:.PTBL: GO SUB 300
170 GO TO 80
300.COL=5:.ROW=10:.SPN=5:.PTOR
301.COL=15:.ROW=7:.SPN=15:.PTOR
302.COL=24:.ROW=13:.SPN=23:.PTOR
304.COL=17:.ROW=19:.SPN=32:.PTOR
305 RETURN

The above method is quite acceptable when the position and quantity of data
is known. If, however, the data on the screen is variable a different
approach will be required, and XOR should be used.


USE OF "XOR"
In example PT4 the sprite is XORed on the screen; when a key is pressed to
move it, the sprite is XORed out and XORed back to the screen in a new
position. This means that a sprite can move freely around a screen of
variable data without rubbing any of it out.

  5 REM EXAMPLE PT4
 10 INK 0: PAPER 5: BORDER 5: CLS:.ATOF
 20.SET=1:.ROW=4:.COL=5
 30.SET=2:.ROW=5:.COL=5
 40.SET=3:.ROW=5:.COL=4
 50.SET=4:.ROW=5:.COL=3
 60 FOR N=1 TO 100
 70 LET X=INT (RND*32)
 80 LET Y=INT (RND*22)
 90 PRINT AT Y,X;"*"
100 NEXT N
110.SET=7:.COL=13:.ROW=10:.SPN=47:.PTXR
120 LET X=13: LET Y=10
130.SET=1: LET KB=?KBF: IF KB<>0 THEN LET X=X-1
140.SET=2: LET KB=?KBF: IF KB<>0 THEN LET Y=Y+1
150.SET=3: LET KB=?KBF: IF KB<>0 THEN LET Y=Y-1
160.SET=4: LET KB=?KBF: IF KB<>0 THEN LET X=X+1
170.SET=7: LET S=?COL: LET T=?ROW: IF S=X AND T=Y THEN GO TO 130
180 IF X>29 THEN LET X=29
190 IF X<0 THEN LET X=0
200 IF Y>19 THEN LET Y=19
210 IF Y<0 THEN LET Y=0
220.PTXR:.COL=X:.ROW=Y:.PTXR
230 GO TO 130

Line 10	sets up the attributes.
Lines 20 to 50 set the COL and ROW values for the keyboard.
Lines 60 to 100 print *s at random positions on the screen.
Line 110 sets up the parameters for a sprite (the lunar lander) and puts it
	on the screen.
Lines 130 to 160 scan the keyboard for keys to be pressed and change the
	values of X and Y if a key has been pressed.
Line 170 checks to see if the sprite needs to be moved, by comparing its
	present position with X and Y, and it they are the same, goes back
	to scan the keyboard again.
Lines 180 to 210 check that the sprite is always on the screen.
Line 220 XORs out the sprite, adjusts ROW and COL and XORs the sprite back
	on the screen.


++				41

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


.MOVE
.MOVE achieves what line 220 of example PT4 does. Once the values of ROW and
COL have been set up, and the increments set in HGT and LEN, every execution
of MOVE will increment ROW and COL. So to move a sprite in a particular
direction, XORing over data, you would just have to execute a series of MOVE
commands. Example PT5 demonstrates the use of MOVE to bounce a ball around
the screen, over data.

  5 REM EXAMPLE PT5
 10 INK 0: PAPER 6: BRIGHT 1: BORDER 7: CLS :.ATOF
 20 FOR N=1 TO 100
 30 LET X=INT (RND*32): LET Y=INT (RND*22)
 40 PRINT AT Y,X;"*"
 50 NEXT N
 60 LET DR=1:.HGT=DR: LET DC=1:.LEN=DC
 70.SP1=50:.SP2=50: LET R=10:.ROW=R: LET C=13:.COL=C:.SPN=50:.PTXR
 80.MOVE
 90 LET C=?COL: LET R=?ROW
100 IF C=29 OR C=0 THEN LET DC=DC*-1:.LEN=DC: BEEP 0.01,5
110 IF R=19 OR R=0 THEN LET DR=DR*-1:.HGT=DR: BEEP 0.01,5
120 GO TO 80

Line 10 sets the attributes.
Lines 20 to 50 fill the screen with stars.
Line 60 sets up the initial incrementation values.
Line 70 sets up the parameters for MOVE.
Line 80 executes MOVE.
Line 90 reads the new values of ROW and COL.
Lines 100 and 110 check to see if the ball has hit the side and changes
	its direction accordingly.

You may have noticed in other examples that ROW and COL can have values that
lie outside the dimensions of the screen, e.g. values <0 and >31 for COL and
values <0 and >23 for HGT. If .MOVE or group 1 GETs and PUTs are used a
sprite can be placed partially "off screen".

Two sprite numbers (stored in SP1 and SP2) are required for MOVE; if the
values in SP2 and SP2 are different, a two sprite animation sequence can be
achieved.


HI-RESOLUTION PUTTING
Laser BASIC does not include commands to directly PUT a sprite onto the
screen with pixel resolution. For those who wish to move a sprite about the
screen with a finer resolution, the following methods can be used.

If you wished to move a sprite from left to right by 2 pixels without
scrolling the screen, you would first have to use the Sprite Generator
Program to create 4 sprites, each one successively shifted to the right by 2
pixels, such that if the 4 sprites are sequentially placed, the data in the
sprite will have moved 8 pixels with a 2 pixel resolution. If these sprites
were numbered 1 to 4, the routine to move them could be:

10 FOR C=0 TO 31
20.COL=C:.SPN=1:.PTBL:.SPN=2:.PTBL
30.SPN=3:.PTBL.SPN=4:.PTBL
40 NEXT C

Each time all 4 sprites have been placed, COL is incremented and the
sequence repeated. (Remember, in the above example the sprite must have a
trailing blank column to remove the data it goes along.)

In the demo program a yellow bouncing character is shown, hopping across the
screen. The animation is obtained by the above method using 4 sprite 5.


++				42

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


COLLISION DETECTION
Two words are provided to enable collision detection, these are ?SCV and ?SCM

?SCV is used to scan a particular character position of the screen. If any
data is present in the character position specified by COL and ROW, then a
non-zero value will be returned (a 0 value is returned if there is no data
there).

?SCV is demonstrated in example PT6, which places a random number of stars
on the screen, which is then scanned (an X is placed on the screen after the
character has been scanned so that you can keep track) and the total number
calculated.

  5 REM EXAMPLE PT6
 10 LET E=INT (RND*50)
 20 FOR N=0 TO E
 30 LET X=INT (RND*32)
 40 LET Y=INT (RND*22)
 50 PRINT AT Y,X;"*"
 60 NEXT N
 70 LET C=0
 80 FOR Y=0 TO 21
 90.ROW=Y
100 FOR X=0 TO 31
110.COL=X
12O LET S=?SCV
130 IF S<>0 THEN LET C=C+1: PRINT AT Y,X;" ": BEEP 0.01,40: GO TO 160
140 PRINT AT Y,X;"X": BEEP 0.01,10
150 NEXT X
160 NEXT Y
170 PRINT AT 0,0;"THERE WHERE ";C;" STARS."

Lines 10 to 60 put a random number of stars on the screen as data.
Lines 80 to 110 calculate the COL and ROW positions of the characters on
	the screen using FOR-NEXT loops and set COL and ROW.
Line 120 scans the character square pointed to by ROW and COL and sets S
	with the result.
Line 130 if any data is there, (the *), the count (C) is incremented by 1
	and the star rubbed out.
Line 140 now prints an X where the character was scanned.
Line 170 prints the number of squares that contained data.

Often it is insufficient to determine whether a particular character square
contains data or not, and for this reason the slower, but more powerful
command ?SCM, has been included for the advanced user. This will scan the
sprite whose number is held in SPN and return a non-zero result if the
sprite contains pixel data, or a zero result if it does not. ?SCM is
normally used to perform one of three functions:

	1. To see if data will collide.
	2. To detect an exact pattern.
	3. To detect the presence of a pattern.

Collision detection is most commonly used to detect a collision between a
sprite moving across the screen and any data which lies in its path. Often
the sprite can pass through an occupied character position without a
collision occurring, so the ?SCN command is insufficient. The procedure is
basically to load a dummy sprite with the section of screen into which the
sprite is about to be PUT, "AND" it with the sprite about to be PUT and then
use ?SCM. If a non-zero value is given then the dummy sprite contains data
and therefore a collision has occurred. This is all very well, but a problem
occurs if the new sprite position overlaps the old sprite position, because
this means that the old sprite has to be removed from the screen before
beginning the above detection procedure and subsequently PUTting the new
sprite. This delay causes flicker. The easiest solution is to work with
"XOR"s so that the window can be GOT, "XOR"ed with the old sprite in memory
to remove the old sprite data, and then to do the detection followed finally
by the blotting and then immediate PUTting.


++				43

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


Once an impending collision is detected it is frequently useful to determine
what the sprite has collided with. To begin with, let's assume that the
screen window we're examining contains one of a known set of objects and
that no other data is present in the window. The method is to load the dummy
sprite with the object to be tested and then compare it against the set of
sprites with which a match is being sought. To compare the dummy sprite with
a known sprite, all you need to do is XOR the sprite being tested into the
dummy and do a ?SCM. If the result is zero, an exact match was found; if
not, do a second XOR into the dummy to restore it and test the next
candidate.

Finally, consider the case where the object being tested contains extraneous
data in addition to one of the possible sprites. This time, the dummy sprite
is loaded with the contents of the screen window, but the candidates are
first "AND"ed into the dummy to remove extraneous data before the XOR and
?SCM. Finally the dummy needs to be reloaded from the screen before the next
test. This latter test is limited by the fact that its conclusion is only
that the screen contained all the parts of the sprite with which a
comparison was made. In the extreme case of the screen window containing all
pixels set, then an agreement would be found with all the sprites tested.


SCROLLING LANDSCAPES
Scrolling landscapes are an integral part of so many video games that it is
worth a brief description of how they can best be produced using Laser BASIC.

The first and most obvious point is never to scroll more than you have to.
If, for instance, you are scrolling a mountain range where the variation
takes place over the top three characters, then only the top three
characters need to be stored and moved.

The simplest and most effective method of producing smooth scrolls is to
sacrifice a column of the screen for transactions with the sprite being
scrolled. Suppose you are scrolling a sprite of 4 or 5 screens width which
uses rows 8 to 10 (3 rows). Suppose we require pixel scrolling and there is
no horizontal variation in attributes. It doesn't really matter which column
we sacrifice, far right (column 31) or far left (column 0), but let's, for
this example, use column 0. All that we need to do is set up a window 1
character wide and 3 characters high on the far left of the landscape to
have the same INK and PAPER colours. This means that pixel data cannot be
seen in this region. Use the .SETV command to do this. To begin with, 31
columns of the sprite are PUT to the active part of the screen using the
.PWBL command. If scrolling is to the left, then the dummy column should be
loaded with the next column to the right of the sprite now "on screen". If
scrolling is to the right then the column to the left of the sprite window
should be inserted. The full 32 column screen window is now wrapped in the
appropriate direction until a total of + or - 8 pixels has been accrued. The
dummy column is then loaded from the appropriate sprite column and so on.


REDEFINING CHARACTER SETS AND UDGs
The 21 UDGs available on the Spectrum should not be used as they would
corrupt the program. However, as many users know, there is a Sinclair system
variable known as CHARS which points to the address in memory 256 bytes less
than where the data for the character set is in ROM, starting with character
32 up to character 128. Users can poke new values into CHARS and make it
point to new data that will be treated as the character set. The obvious
place for Laser BASIC users to store character sets is in sprites.

In EXAMPLE PT7 the data for a little man is poked into sprite 1 and then the
system variable CHARS is changed to point to that data and so that every
time the space (character 32) is printed, the little man is printed instead.

 5 REM EXAMPLE PT7
10.SPN=1
20 LET A=?TST
30 LET A=A+5
40 FOR N=0 TO 7
50 READ D
60 POKE A+N,D
70 NEXT N


++				44

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 80.P0KE23606,(A-256)
 90 STOP
100 DATA 24,24,0,255,60,60,36,102
110.P0KE23605,15360

Line 10	sets SPN to 1.
Line 20	finds out the address in memory of sprite 1 using ?TST.
Line 30	REMEMBER THE FIRST 5 BYTES OF SPRITE DATA ARE THE SPRITE
	NUMBER AND POINTERS; DATA SHOULD BE LOCATED 5 BYTES PAST
	THE VALUE FOUND BY ?TST. HENCE A=A+5.
Lines 40 to 70 poke the 8 bytes of data from line 100 into the sprite
	starting 5 bytes after the value of ?TST.
Line 80	pokes CHARS (address 23606) with the address of the data minus 256.
Line 100 is the data for the little man.
Line 110 since all the other characters in the character set have not been
	redefined they will appear as rubbish. Use POKE 23606,15360 to
	restore the character set by re-setting the original value of CHARS.
	(Type GOTO 110).

Using data statements is a slow way of creating character sets in sprites.
It is far better to create the character sets in the Sprite Generator
Program. If you create a sprite, you must note that data in sprites is
stored serially such that the first data is the top line of pixels in the
sprite, the next is the second line of pixels etc.

A sprite used for a character set will need to be 1 character wide and the
required number of characters high.


THE VARIABLE SETS
Making full use of the 16 variable sets will considerably speed up program
execution. If, for instance, you wished to scroll 4 windows on the screen,
you could set up the parameters ROW, COL, HGT and LEN of each window in a
different variable set.

e.g.	.SET=1:.HGT=5:.LEN=5:.ROW=0:.COL=0
	.SET=2:.HGT=4:.LEN=6:.ROW=0:.COL=5
	.SET=3:.HGT=6:.LEN=4:.ROW=0:.COL=12
	.SET=4:.HGT=7:.LEN=3:.ROW=0:.COL=18

To execute the scrolls all you would need to type would be:
	.SET=1:.WR1V:.SET=2:.WL2V:.SET=3:.WL8V:.SET=4:.WR1V

Not only is memory saved by not needing to redefine ROW, COL, HGT and LEN
every time you wish to scroll a window, but also, execution time is speeded
up enormously since less evaluation is done.


LOADING AND SAVING LASER BASIC PROGRAMS
When a Laser BASIC program is running, the extended commands are
semi-compiled into what is referred to as a "tokenised" form. This means
that care needs to be exercised when loading and saving from within
tokenised programs, and a few simple rules need to be observed. Programs can
be loaded and saved in command mode (typed in directly) or from within
programs, so let's deal with the former case first.


LOADing and SAVEing In Command Mode
To save a "non-auto-run" Laser BASIC program directly use:
	SAVE "filename"		for tape
	SAVE *"m";N;"filename"	for microdrive

NOTE:	If you wish, you can put a number of saves and loads into one
	direct statement, such as:
	SAVE "filename": LOAD "filename"CODE			for tape
	SAVE *"m";N;"filename" :LOAD *"m";N;"filename"CODE	for microdrive


++				45

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


If you wish to execute further standard BASIC commands in the same direct
statement line, or if you do not have interface 1, then you should proceed
as normal. If, however, you wish to execute further commands in the same
statement, and you are using microdrives as opposed to tape, then you will
need to execute a RANDOMIZE USR 58841 between loads and saves, and the
extended commands, e.g.

	SAVE *"m";N:"filename": LOAD *"m";N;"filename"CODE:
	RANDOMIZE USR 58841:.REMK:.RNUM

In point of fact, most people would simply split the statement line into
statements, in which case there is no need for the USR call, i.e.
	SAVE *"m";N;"filename": LOAD *"m";N;"filename"CODE
followed by
	.REMK:.RNUM
would be perfectly legal.


SAVEing an "Auto-Run" Program In Command Mode
With the above rules in mind, the auto-run facility is used in the normal
way, i.e.
	SAVE "filename" LINE N		for tape
	SAVE *"m";N:"filename" LINE N	for microdrive

The program being saved however, must execute one of the following
statements before encountering any of the extended commands.
	RUN, GOTO or GOSUB		for tape
	RANDOMIZE USR 58841 followed by	for microdrive
	RUN, GOTO or GOSUB

For example, if using tape:
	10 PRINT "LOADED": GO TO 20
	20.COL=4:.ROW=4:.LEN=1:.HGT=5:.INVV
	30 STOP
would be saved using
	SAVE "TEST" LINE 10
and using microdrive:
	10 PRINT "LOADED": RANDOMIZE USR 58841: GO TO 20
	20.COL=4:.ROW=4:.LEN=1:.HGT=5:.INVV
	30 STOP
	SAVE *"M";1;"TEST" LINE 10

NOTE:	Programs saved in direct mode are not tokenised when they are loaded
	back in.  The GOTO, GOSUB and RUN commands check to see if a program
	is tokenised, and if not, will tokenise it. Hence the procedure.
	Programs saved in direct mode using this format can only be loaded
	back, in direct mode.


++				46

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


SAVEing a "Non-Auto-Run" Program from within a Program
The program will be saved in a tokenised form and can therefore only be
loaded back from within a program. The loaded program will be de-tokenised
on return to command mode.


SAVEing an "Auto-Run" Program from within a Program
The program will be saved in a tokenised form and can therefore only be
loaded back from within a program. If the program is loaded from tape, it
will simply execute; if it is loaded from microdrive then the loaded program
will need to execute a RANDOMIZE USR 58841 before continuing with the rest
of the program.

To summarise, then, programs saved in direct mode are loaded back in direct
mode. Programs saved from within a program are re-loaded from within a
program. Before using any of the above schemes, Laser BASIC must be resident
and running.


++				47

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE SPRITE GENERATOR PROGRAM
by Paul Newnham


INTRODUCTION
The Sprite Generator Program is used for the creation and editing of
software sprites that are going to be used in your Laser Extended BASIC
programs. In fact sprites are created on the screen, then GOT into memory
before being saved to tape. The program is supplied in tape format, but it
can be simply modified for use on microdrives.


LOADING
Clear the Spectrum by typing RANDOMIZE USR 0. Insert the tape and type LOAD
"SPTGEN" or LOAD "".

If you wish to save the sprite generator program, break into it using the
break key in the normal fashion then type GOTO 9999 and the two parts of the
program will be saved to tape and then Verified.

You will have to reload the program before you can run it.

To save the sprite generator program to microdrive, first edit line 2:

change	LOAD ""CODE:
to	LOAD *"M";1;"G"CODE:

Using a formatted cartridge in drive 1 type GOTO 9998. This will save and
verify the program to a microdrive cartridge.

You can load in the sprite generator program by typing:
	PRINT USR 0
	LOAD *"M";1;"S"


GETTING STARTED
First load in the Sprite Generator Program. You will be prompted with COLD
or WARM start. This is the first time you are running the program, so type C
for COLD start, and Y for yes. The working screen will now be displayed.


GLOSSARY OF TERMS

COLD START
If you enter the sprite generator program via a COLD start, then all sprites
previously stored will be cleared and all system variables reset. The
program must always be initially entered via a COLD start.


WARM START
If you enter the program via a WARM start then all sprites will be conserved
and all system variables left unchanged. It is provided principally for
re-entering the program after an accidental BREAK or ERROR. If you do
accidentally BREAK; type: GOTO 3 and then enter via the WARM start. You will
lose, however, any data on the screen. You could type GOTO 100 which will
put you back at command level.


++				48

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE CHR$ SQR
CHR$ SQR is the abbreviation used throughout this text for the character
square, and refers to the 8 by 8 grid to the left of the sprite screen. This
is the area used to create and edit sprites one character at a time.


THE SPRITE SCREEN
This is the area of screen 15 characters by 15 characters on which sprites
are created, developed, transformed and generally worked on.


THE CHR$ SQR CURSOR
This is the non-destructive flashing cursor which is used to design and edit
the character currently held in the CHR$ SQR.


THE SPRITE SCREEN CURSORS
These are the two flashing cursors, displayed in the row beneath the sprite
screen and the column to the right of the sprite screen. They are used to
indicate the position of the top left hand corner of the screen window
currently being operated upon. The actual cursor positions are measured from
the top left hand corner of the sprite screen and are displayed in real time
on the screen as X POS (column) and Y POS (row). Top left is X POS 1 Y POS
1. Bottom right is X POS F Y POS F.


SPRITE SCREEN WINDOW
The area of the screen currently being worked on is referred to as the
screen window. Its position is defined by X POS and Y POS, which correspond
to the positions of the sprite screen cursors, and its dimensions are
defined by SPRITE HEIGHT and SPRITE LENGTH. To see the screen window you are
currently working on just press F. The window will flash.


SPRITES
Once you have finished creating your sprites they can be saved off to tape
or microdrive ready to be loaded into Laser Extended BASIC for use in your
programs. When saving your finished sprites you are given two saving
options:

OPTION 1:	This is the editing save, which saves off your sprites in a
		form such that they can be loaded back into the Sprite
		Generator Program for re-editing etc. Sprites saved via
		OPTION 1 cannot be used in Laser BASIC programs.

OPTION 2:	This saves off the sprites ready to use in Laser BASIC. You
		should note down the loading values and SPST and SPND values
		that are presented to you. Sprites saved in this option
		cannot be loaded back into the Sprite Generator Program.

For those who do not possess an artistic ability, two sets of sprites have
been saved on tape for you in OPTION 1 format ready to be loaded into the
Sprite Generator.
SPRITE1A	This is a file of 50 sprites of various arcade characters.
SPRITE2A	This is a file of all the sprites used in the Laser BASIC demo.

The Sprite Development Program allows sprites to be loaded and saved to and
from microdrive cartridge. Before a cartridge can be used to store sprites,
it has to be specially formatted. This is done from the Sprite Generator
Program by hitting Symbol Shift F (TO). This will format the cartridge and
set up five dummy files numbered 1 to 5. From now on whenever you save a
file of sprites, the old file of that number will be erased to conserve
cartridge storage.


++				49

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE INFORMATION RECTANGLE

	MEMORY LEFT 7488          X POS 1 Y POS 1
	SPRITE 60218            SPRITE HEIGHT - 2
	SPST 60218              SPRITE LENGTH - 4
	SPND 65279              SPRITE NUMBER - 1
		The text line

MEMORY LEFT:	This indicates how much memory is available for sprites.

X POS Y POS:	These are the current positions of the SPRITE SCREEN X and Y
		cursors with reference to the figures on top and to the left
		of the SPRITE SCREEN.

SPRITE:		This indicates the position, in memory, where your defined
		sprite is.

SPST:		This indicates the SPrite space STart point, in memory.
		(Before any sprites are defined this has an initial value
		of 65218).

SPND:		This indicates the SPrite space eND point, in memory.

SPRITE HEIGHT:	This indicates the height of your defined sprite, in character
		squares, as indicated by the figures at the top and to the left
		of the SPRITE SCREEN. (This has an initial value of 1).

SPRITE LENGTH:	This indicates the length of your defined sprite, in character
		squares, as indicated by the figures at the top and to the left
		of the SPRITE SCREEN. (This has an initial value of 1).

SPRITE NUMBER:	This indicates the sprite currently defined.
		(This has an initial value of 1).

The Text Line:	To show the current function and the available options.


++				50

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


SPRITE GENERATOR KEY FUNCTION SUMMARY
All the functions of the Sprite Generator are invoked by pressing the
appropriate key (or SYMBOL SHIFT key). A list of the functions is given
below.

KEY

A	Activates the ATTRIBUTE switch.( same as .ATOF,.ATON)
	Press 1 to set switch ON.
	Press 0 to set switch OFF.

B	Activates the BRIGHT variable.(same as Sinclair BRIGHT)
	Press 1 to set BRIGHT to ON.
	Press 0 to set BRIGHT to OFF.

C	Activates the PAPER variable.(same as Sinclair PAPER)
	Press any key between 0 and 7 to activate the colour indicated
	above the key.(paper 8 and 9 not included).

SYMBOL	CREATION OF LARGE SPRITES
SHIFT	Allows the creation of a sprite, whose number is held in the sprite
C	number variable, of user definable dimensions in the range 1-255
(?)	characters. The sprite can be said to be empty as no data will have been
	"GOT" into it.

D	Activates DIRECT DATA INPUT.
	Accepts 8 bytes of data, one byte at a time, followed by ENTER, via the
	keyboard, to the position on the sprite Screen indicated by the cursors.
	Inputted data must be in the range 0 to 255 Decimal or, H00 to HFF HEX
	(the character H must precede Hex entry).

	NOTE: If Attribute switch = 1, then the four current attributes will
	be set at the same position as well.

E	Activates the SCREEN FUNCTIONS.
	You will be given three options: press 1, 2 or 3.

	1  INVERT (same as .INVV)
	Option 1, INVERT, sets all OFF pixels to ON and all ON pixels to OFF
	in a window whose length is held in the "Sprite length" variable and
	whose height is held in the "Sprite height" variable. The inversion
	will take place from the position of the sprite screen cursors, i.e.
	at the intersection of an imaginary line drawn from each cursor.

	2 MIRROR (same as .MIRV)
	Option 2, MIRROR, "Flips" a window whose height is held in the
	"Sprite height" variable and whose length is held in the "Sprite
	length" variable. The Mirroring will take place about the vertical
	centre of the screen window.

	3 MIRROR ATTRIBUTES (same as .MARV)
	Option 3, MIRROR ATTRIBUTES, "Flips" the attributes in a window
	whose height is held in the "Sprite height" variable and whose
	length is held in the "Sprite length" variable. The Mirroring of
	Attributes will take place about the vertical centre of the screen
	window.

F	Activates FLASH WINDOW.
	Flashes the current screen window whose height is held in the SPRITE
	HEIGHT variable and whose length is held in the SPRITE LENGTH
	variable. The Flash will take place at the position of the sprite
	screen cursors. Flash is used to check the position of the sprite
	screen cursors, to check that the height and length parameters are
	as required or to check that the window is correctly positioned.


++				51

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


SYMBOL	Format Sprite Cartridge
SHIFT	This is used to format a microdrive cartridge ready for saving
F	sprites to. It sets up five dummy files numbered 1 to 5.
(TO)
G	Activates GET SPRITE function.
	Gets a sprite of the dimensions held in the "Sprite height" and
	"Sprite length" variables, using the number held in the "Sprite
	Number" variable and at the window indicated by the sprite screen
	cursors - and stores it in memory.

	NOTE: If the Attribute switch = 1, the sprite and attributes are
	stored; if the Attribute switch = 0, then any Attributes will be
	ignored. If a sprite is defined with the Attribute switch = 0, then
	the attribute data will probably be garbage.

H	Activates the SPRITE HEIGHT Variable.(same as .HGT=) Permits the input
	of the height of a sprite window in the range of 1-15 characters.

I	Activates the ATTRIBUTE DUMP function.
	This fills the window of dimensions held in the "sprite height" and
	"sprite length" variables with the current attribute values.

SYMBOL	Activates the SCROLL WINDOW RIGHT BY 1 PIXEL function.
SHIFT	(same as .WR1V)
I	This scrolls the window whose dimensions are held in the SPRITE
(AT)	HEIGHT and SPRITE LENGTH variable by 1 pixel to the right with wrap
	around.

J	Activates the move CHR$ SQR TO SPRITE SCREEN function.
	Dumps the bit pattern set in the CHR$ SQR to a character square in
	the sprite screen, indicated by the sprite screen cursors.

	NOTE: If the Attribute Switch = 0, no Attributes will move with the
	pattern. If the Attribute switch = 1, then the Attributes held in
	the Attribute Variables will move with the pattern.

SYMBOL	Activates the LOAD SPRITES facility.
SHIFT	Sprites can be loaded in from tape or microdrive. Three groups
J	of data will be loaded. Once loaded the text line will clear.
(-)
	NOTE: Any sprites in memory will be destroyed when this command is
	executed.

K	Activates the MOVE SPRITE SCREEN CHARACTER TO CHR$ SQR function.
	Picks up the Character Square indicated by the Sprite Screen
	Cursors, into the CHR$ SQR.

	NOTE: ATTR = 0 ignores Character Attributes. ATTR= 1 takes the
	Attributes of the character and loads them into the Attribute
	Variables.

L	Activates the SPRITE LENGTH variable.(same as .LEN=)
	Permits the input of the length of a Sprite Window in the range of 1-15
	characters.

M	Activates the Sprite Functions.
	You will be given three options which act in the same way as the
	"SCREEN FUNCTIONS E", except that these functions operate on the
	sprite in memory only and have no effect directly on the screen.

N	Activates the No, negative response to (Y/N) questions.

O	Activates the Sprite Logic functions.
	You will be given three options. Each option GETS an area of the
	sprite screen, the dimensions of which are specified as those of the
	defined sprite, having a top left-hand corner at the sprite screen
	cursor positions and logically GETs the data into the defined sprite
	- whose number is in the Sprite Number Variable.


++				52

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


	NOTE: ATTR = 0 leaves the sprite attributes as they are. ATTR = 1
	takes the attributes from the screen and places them into the
	sprite.

	1 GETORS, ORs the screen data with the pre-defined sprite, and
	leaves the result in the sprite (screen display unaffected).

	2 GETXRS, XORs the screen data with the data of a pre-defined
	sprite, and leaves the result in the sprite (screen display
	unaffected).

	3 GETNDS, ANDs the screen data with the data of a pre-defined
	sprite, and leaves the result in the sprite (screen display
	unaffected).

P	Activates the PUT SPRITE function.(same as .PTBL)
	This PUTs the sprite whose number is held in the "SPRITE NUMBER"
	variable onto the sprite screen at the position indicated by the
	sprite screen cursors.

	NOTE: You will get an error message if the sprite does not exist
	or will not fit on the screen.

Q	Activates the CLEAR CHR$ SQR function. Sets all CHR$ SQR bits to OFF.

SYMBOL	Activates the CLEAR SPRITE SCREEN function. Clears the sprite
SHIFT	screen of all data and attributes.
Q
(<=)
R	Activates the ROTATE SPRITE function.(same as .SPNM)
	Rotates a sprite, in memory, by 90 degrees, leaving the original sprite
	unaffected. The new Rotated sprite must be given a new sprite number, as
	asked for. Attributes are automatically Rotated with the pixel data.

S	Activates the SPRITE NUMBER variable.(same as .SPN=) Permits the
	defining of sprites and asks for a sprite number in the range 1 to 255.

	NOTE: If a sprite to be defined is given an existing sprite number,
	a warning is displayed, advising you of this fact. The existing
	sprite, or the new sprite, are in no way corrupted.

SYMBOL	Activates the SAVE SPRITES facility.
SHIFT	All files will be verified. Once the programs have verified,
S	the sprite development program will return to command level with
(NOT)	the text line cleared.

	NOTE: If the program breaks because of failure to verify, 
	type GOTO 100 and your data will not be lost.

T	Activates the TEST SPRITE function.(same as ?TST)
	Performs a test on the sprite whose number is held in the
	"Sprite Number" variable, and does the following:
	1. Places the sprite height into the "Sprite height" variable.
	2. Places the sprite length into the "Sprite length" variable.
	3. Places the address in memory of where the sprite data starts,
	   into the "Sprite" variable.
	4. Places the address of the start of sprite space into the
	   variable "SPST".
	5. Places the address of the end of sprite space into the
	   variable "SPND".
	6. Calculates the remaining memory available for sprite storage
	   and places it into the "Memory Left" variable.

	NOTE:	The screen display of these variables will be updated
	if necessary.

SYMBOL	Activates the SCROLL WINDOW LEFT BY 1 PIXEL function.
SHIFT	(same as .WL1V)
T	This scrolls the window whose dimensions are held in the SPRITE
(>)	HEIGHT and SPRITE LENGTH variables by 1 pixel to the left with wrap
	around.


++				53

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


U	Activates the PICK UP ATTRIBUTES function.
	Picks up the attributes of the character from the sprite screen,
	indicated by the position of the sprite screen cursors and Loads
	them into the four Attribute variables.

SYMBOL	Activate the SCROLL WINDOW UP BY 1 PIXEL function (same as .WCRV).
SHIFT	This scrolls the window whose dimensions are held in the SPRITE
U	HEIGHT and SPRITE LENGTH variables by 1 pixel up with wrap around.
(OR)
V	Activates the FLASH variable. This is one of the four attributes.
	(same as Sinclair FLASH)
	Press 1 to put switch ON.
	Press 0 to put switch OFF.

W	Activates the WIPE SPRITE function.(same as .DSPR)
	Wipes the sprite indicated by the "Sprite number" variable totally
	from memory. All other sprites stored in memory below that sprite
	are moved up to fill the space previously occupied by the Wiped sprite.

X	Activate the INK variable which is one of the four attributes.
	(same as Sinclair INK)
	Press any key between 0 and 7 to set the colour indicated above the key.

Y	Activates the YES, positive response to (Y/N) questions.

SYMBOL	Activates the SCROLL WINDOW DOWN BY 1 PIXEL function.
SHIFT	(same as .WCRV)
Y	This scrolls the window whose dimensions are held in the SPRITE
(AND)	HEIGHT and SPRITE LENGTH variables by 1 pixel down with wrap around.

BREAK	Activates the PLACE SPRITE INTO SPRITE WINDOW facility.
and	This allows you to place a sprite of smaller dimensions into
SPACE	a second sprite of greater dimensions, at a position of ROW, COL in the
	greater sprite in memory - the smaller sprite is left unaltered.

	NOTE: ATTR = 0, Attributes of smaller sprite ignored.
	ATTR = 1, Attributes of smaller sprite taken and placed with sprite.

	Four options are given:
	1 GETBLS:	GETs the smaller sprite directly into the window of
			the larger sprite.
	2 GETORS:	GETs the smaller sprite and ORs it into the window
			of the larger sprite.
	3 GETXRS:	GETs the smaller sprite and XORs it into the window
			of the larger sprite.
	4 GETNDS:	GETs the smaller sprite and ANDs it into the window of
			the larger sprite.

5	Activates the MOVE CHR$ SQR CURSOR 1 place left - non-destructive.

6	Activates the MOVE CHR$ SQR CURSOR 1 place down - non-destructive.

7	Activates the MOVE CHR$ SQR CURSOR 1 place up - non-destructive.

8	Activates the MOVE CHR$ SQR CURSOR 1 place right - non-destructive.


++				54

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


9	Activates the SET CHR$ ON at current position.

0	Activates the SET CHR$ OFF at current position.

(%)	Activates the MOVE SPRITE SCREEN CURSOR 1 place to the left.
SYMBOL SHIFT 5

(&)	Activates the MOVE SPRITE SCREEN CURSOR 1 place down.
SYMBOL SHIFT 6

(')	Activates the MOVE SPRITE SCREEN CURSOR 1 place up.
SYMBOL SHIFT 7

(()	Activates the MOVE SPRITE SCREEN CURSOR 1 place to the right.
SYMBOL SHIFT 8


++				55

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE LASER BASIC SPRITE GENERATOR EXAMPLE SESSION
This chapter is written to enable the user to gain experience and
understanding of the use of the Sprite Generator Program supplied with the
package.

You will first need some sprites to work with. Position the tape so as to be
ready to load the SPRITE1A file. Type SYMBOL SHIFT J (LOAD SPRITES) and type
Y for yes, press PLAY on the tape recorder and the file of OPTION 1 saved
sprites will be loaded into the memory of the Sprite Generator Program.
(Please note that Sprites are loaded and Saved in 3 parts)


SG1. Let's firstly familiarise ourselves with the use of the two screens.


THE CHR$ SQR
This is the grid square on which you create and edit sprites a character at
a time. To move the cursor:

1. Press the 5 key for each movement to the left.
2. Press the 6 key for each movement downward.
3. Press the 7 key for each movement upward.
4. Press the 8 key for each movement to the right.

Now that you know how to move the cursor, let's fill in a few squares:

1. Move the cursor to any square that you like and release the keys.
2. Press the 9 key to set the square.
3. Now move the direction keys and fill in a few more squares.

Now that we have set some squares, what about deleting a few of them?
This is simple:

1. Move the cursor to a square that you have set and release the keys.
2. Press the 0 key to clear the square.

Now have a go at setting and clearing some squares, just to get used to it.


THE SPRITE SCREEN CURSORS
Moving the sprite screen cursors:

1. Move the X cursor by pressing SYMBOL SHIFT and the 5 or 8 key to move
   left or right respectively.
2. Move the Y cursor by pressing SYMBOL SHIFT and the 7 or 6 key to move
   up or down respectively.


++				56

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


CLEARING THE SCREENS

1. Press the Q key and respond to the prompt in the text line by pressing Y
   and the CHR$ SQR will clear.

   Just to get you used to a similar function, let's clear the Sprite Screen
   as well, even though it's clear.

1. As you can see, to clear the CHR$ SQR press Q, to clear the sprite screen
   press SYMBOL SHIFT Q.


SG2. EDITING A SPRITE BY A CHARACTER AT A TIME USING THE CHR$ SQR

1. Move the X and Y cursors to 1 and 1 respectively.
2. Press the S key to select a sprite number.
3. Input the number 51 and hit ENTER.
4. Now type P (PUT sprite) and hit Y for yes.

(You have now PUT sprite 51 on the screen without any attributes.)

5. Press the K key and hit Y for yes to load the CHR$ SQR with the data of
   the character pointed to by the sprite screen cursors.

(You can now edit the character held in the CHR$ SQR using the 5,6,7,8 keys
to move the non-destructive cursor and the 9 or 0 keys to set or unset the
pixels.)

6. Once you have edited the character, hit the F key to flash the cursor
   in the sprite to check that it is in the right position.
7. Press the J key to move the data on the CHR$ SQR to the sprite screen,
   pressing Y for yes.


SG3. INPUTTING DATA VIA THE DIRECT DATA INPUT FUNCTION

1. Press SYMBOL SHIFT Q to clear the sprite screen.
2. Press the D key, answer Y to the question, and enter the following,
   very carefully, pressing ENTER after each entry:
   a) H24 126 HDB 255 HFF 153 129 102
3. You should have a space invader type character.

This is the DIRECT DATA INPUT. Direct Data characters are built up from 8
bytes of data, one byte at a time.

NOTE: Data can only be entered using values in the range 0 to 255 Decimal or
H00 to HFF HEX. The character H must precede a HEX entry.


++				57

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


SG4. SETTING THE ATTRIBUTE VALUES

1. Clear the sprite screen (SYMBOL SHIFT Q)
2. Press X to activate the INK variable and then set it to 2.
3. Press C to activate the PAPER variable and then set it to 7.
4. Press B to activate the BRIGHT switch and then press 1 to switch it ON.
5. Press V to activate the FLASH variable and then press 0 to switch it OFF.
6. Press A to activate the ATTRIBUTE switch and then press 1 to switch it ON.

(You will have noticed, that both PAPER and FLASH were already set to 7 and
0 respectively from the COLD start; we only run through them all for
completeness and to get used to using them.)

7. Now if you repeat example SG3, because the ATTRIBUTE switch is set to 1,
   attributes will be used, hence you have defined a RED invader.


SG5. GETTING A SPRITE INTO MEMORY

1. Let's imagine we have designed a sprite on the screen, so type S for
   input sprite number and input 6.
2. Type P for PUT SPRITE and hit Y for yes.

(You now have a mouse of 2 characters by 2 characters which we can say is
the data we wish to get.)

3. Type W and Y for yes to wipe sprite 6 from memory.
4. The mouse data is 2 characters wide so type L for length and input 2
   for the length of the window.
5. The mouse data is 2 characters high so type H for height and input 2
   for the length of the window.
6. Type F to flash the current window to check that its dimensions and
   position cover the data you want to get as the sprite.
7. Type S and input 6 as the number of the sprite.
8. Now type G and Y to GET the sprite into memory.
9. You can check that the sprite was correctly got into memory by moving the
   sprite screen cursors and putting the new sprite somewhere else on screen.


SG6. SPRITE SCREEN FUNCTIONS

1. Firstly clear the sprite screen using SYMBOL SHIFT Q.
2. Set the sprite number variable to 19 using the S key.
3. PUT the sprite on the screen using the P key.

(You will see a ship of 7 characters long by 2 high.)

4. If you type E and Y for Sprite Screen functions and then type 1 for INVERT,
   all pixels that were ON are now OFF and all the pixels that were OFF are
   now ON.
5. If in this function you type 2 for MIRROR, the data (not the attributes)
   will be mirrored about a central vertical axis, reversing the direction
   of the ship.
6. Function 3 in this mode will do the same as function 2, except that the
   attributes, not the pixel data, will be mirrored.

(All the above three operations are local operations, that is to say sprite
19 has not been affected, only the data on the screen.)


++				58

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


SG7. SPRITE FUNCTIONS
The same operations as SG6 are available using the M key; however these
operations operate in memory, permanently changing the sprite being operated on.


SG8. SPRITE ROTATION
This enables a sprite to be rotated through 90 degrees (clockwise).

1. PUT sprite 9 on the screen using the S and P keys, and you should have
   a bi-plane.
2. To rotate this sprite hit the R key and Y for ROTATE.
3. You will have to input a new number of a sprite that sprite 9 is going
   to be rotated into, so type 100. Sprite 9 is left unaffected but sprite
   100 contains the rotated sprite 9.
4. Use the S and P keys to PUT sprite 100 on the screen.


SG9. SETTING ATTRIBUTES INTO WINDOWS
Now let's look at attribute handling in more detail - position the X and Y
cursors to X POS 1 Y POS 1. The following two examples will show how to
download and pick-up attributes between the attribute variables and the
sprite screen:

1. Press X (INK) and set to 3 (magenta).
2. Press C (PAPER) and set to 2 (red).
3. Press V (FLASH) and set to 1 (ON).
4. Press B (BRIGHT) and set to 0 (OFF).
5. Press A (ATTR) and set to 0.
6. Set the window length to 5 using the L key.
7. Set the window height to 5 using the H key.
8. Press I (ATTRIBUTE DUMP) - the attributes will appear on the sprite screen
   in the 5 by 5 character window. Any data in that window will remain, but
   its attributes will have changed.
9. Now set all the attributes, X, C, V, B, and A to 0.
10.Press U (PICK UP ATTRIBUTES) and the attributes on the screen will be
   loaded into the attribute variables.


SG10. SCROLLING SPRITE WINDOW DATA
1. First put a sprite on the screen, at X POS 1, Y POS 1, using the S key
   for "Input Sprite Number" and inputting the number 10.
2. Type P for PUT sprite, you will see a helicopter appear on the screen.
3. Now set both the window height and length values to 10 using the H and L
   keys.
4. You can now scroll, with wrap, the helicopter within the window by 1 pixel
   using the SYMBOL SHIFT key in conjunction with the T, Y, U or I keys.

One way of achieving fast, smooth, hi-resolution animation of sprites, is to
define a series of sprites in different positions, offset by a few pixels.
Then by sequentially placing these sprites hi-resolution animation can be
obtained.


++				59

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


SG11. SAVING SPRITES
You may now wish to save off all the sprites that you have just created in a
form that they can be loaded back into the Sprite Generator Program at a
future date. You will have to save the sprites in the OPTION1 format.

1. Type SYMBOL SHIFT S for save sprites.
2. Type Y for yes.
3. Type 1 for OPTION1 sprites.
4. Now save sprites to tape or pre-formatted microdrive, inputting the file
   name.
5. Sprites are saved off in 3 parts, which will be verified, this means once
   saved, the tape will have to be rewound.

Once all your sprites are finished you can save them off in OPTION2 format
ready to load into LASER BASIC.

1. Type SYMBOL SHIFT S for save sprites.
2. Type Y for yes.
3. Type 2 for OPTION2.
4. Input the file name.
5. Note down the CODE values that are displayed on the screen.
6. The code will be verified next, so rewind the tape after it has been saved.


++				60

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


CREATING SPRITES IN THE SPRITE GENERATOR PROGRAM

A SUMMARY
Step 1	Load in the Sprite Generator Program and execute a COLD start.
Step 2	Set the Attribute flag to 1 using the A key.
Step 3	Set the INK and PAPER colours.
Step 4	Create your sprite, a character at a time, using either the CHR$ SQR
	or the direct data entry method.
Step 5	Enlarge the flashable window so that it takes up the dimensions of 
	your sprite, using the H key to set the height and the L key to set
	the length.
Step 6	Position the sprite screen cursors to the top left of your sprite.
Step 7	Flash the window using the F key to make sure all the sprite data
	will be "GOT" into memory.
Step 8	GET the sprite into memory, using the G key.
Step 9	Test to see that the sprite is OK by moving the sprite screen cursors
	to a free part of the screen and "PUT" the sprite, using the P key.
Step 10	Carry out any other operations or create more sprites.
Step 11	Save off the sprites in OPTION1 format so that they can be loaded in
	the sprite generator program for editing etc. at a later stage.
Step 12	Save off the sprites in OPTION2 format for use with Laser BASIC,
	noting down the values of the "Sprite start address".
Step 13	Clear the machine by typing RANDOMIZE USR 0.
Step 14	Load in Laser BASIC by typing LOAD ""
Step 15	Load the sprites using option 2 of the loader menu. The loader will
	prompt you for the "Sprite start address" and you should type in the
	value you noted down at step 12.


++				61

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =




APPENDIX 1 LASER BASIC COMMANDS (IN ALPHABETICAL ORDER)

WORD	PARAMETERS	ACTION

.ADJM	SPN, COL, ROW       Adjust COL, ROW, HGT, LEN, SCOL, SROW
                            such that GETS and PUTS lie on the screen.
.ADJV	HGT, LEN, COL,      Adjust the screen window to lie on
	ROW                 the screen.
.ATDV	HGT, LEN, COL,      Scroll the window attributes 1 character
	ROW                 down with wrap.
.ATDM	SPN                 Scroll the sprite attributes 1 character
                            down with wrap.
.ATLM	SPN                 Scroll the sprite attributes 1 character
                            left with wrap.
.ATLV	HGT, LEN, COL,      Scroll the window attributes 1 character
	ROW                 left with wrap.
.ATOF                       Disable attribute switch.
.ATON                       Enable attribute switch.
.ATRM	SPN                 Scroll the sprite attributes 1 character
                            right with wrap.
.ATRV	HGT, LEN, COL,      Scroll the window attributes 1 character
	ROW                 right with wrap.
.ATUM	SPN                 Scroll the sprite attributes 1 character
                            up with wrap.
.ATUV	HGT, LEN, COL,      Scroll the window attributes 1 character
	ROW                 up with wrap.
.CLSM	SPN                 Clear the sprite.
.CLSV	HGT, LEN, COL,      Clear the screen window and fill with
	ROW                 the current attributes.
?COL                        Assign the value in the Graphics
                            variable COL to a BASIC variable.
.COL=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable COL.
DEF FN	N#()                Define a procedure N.
.DSPM	SP1, SP2            Enlarge sprite SP2 into sprite SP1.
.DSPR	SPN                 Delete sprite and recover bytes from
                            below.
.GMAT	SP1, SP2, SCOL,     Block move attributes of sprite SP1
	SROW                into sprite SP2 at SCOL,SROW.
.GMBL	SP1, SP2, SCOL,     Block move sprite SP1 into sprite
	SROW                SP2 at SCOL,SROW.
.GMND	SP1, SP2, SCOL,     Logically AND sprite SP1 into sprite
	SDROW               SP2 at SCOL,SROW.
.GMOR	SP1, SP2, SCOL,     Logically OR sprite SP1 into sprite
	SROW                SP2 at SCOL,S ROW.
.GMXR	SP1, SP2, SCOL,     Logically XOR sprite SP1 into sprite SP2
	SROW                at SCOL,SROW.
.GTBL	SPN, COL, ROW       Block move screen data from screen to
                            sprite.


++				62

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


.GTND	SPN, COL, ROW       Logically AND screen data into sprite data.
.GTOR	SPN, COL, ROW       Logically OR screen data into sprite data.
.GTXR	SPN, COL, ROW       Logically XOR screen data into sprite data.
.GWAT	SPN, COL, ROW,      Block move attributes from screen window
	SCOL, SROW, HGT,    into sprite window.
	LEN
.GWBL	SPN, COL, ROW,      Block move screen data from screen window
	SCOL, SROW, HGT,    into sprite window.
	LEN
.GWND	SPN, COL, ROW,      Logically AND screen data from screen window
	SCOL, SROW, HGT,    into sprite window.
	LEN.
.GWOR	SPN, COL, ROW,      Logically OR screen data from screen window
	SCOL, SROW, HGT,    into sprite window.
	LEN
.GWXR	SPN, COL, ROW,      Logically XOR screen data from screen window
	SCOL, SROW, HGT,    into sprite window.
	LEN
?HGT                        Assign the value in the Graphics variable
                            HGT to a BASIC variable.
.HGT=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable HGT.
.INVM	SPN                 Invert sprite data.
.INVV	HGT, LEN, COL,      Invert screen window.
	ROW
.ISPR	SPN, HGT, LEN       Create sprite and move current sprites
                            down to accommodate.
?KBF	COL, ROW            Detect multi key presses.
?LEN                        Assign the value in the Graphics variable
                            LEN to a BASIC variable.
.LEN=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable LEN.
.MARM	SPN                 Mirror sprite attributes about centre.
.MARV	HGT, LEN, COL,      Mirror screen window attributes about
	ROW                 centre.
.MIRM	SPN                 Mirror sprite about its centre.
.MIRV	HGT, LEN, COL,      Mirror screen window about its centre.
	ROW
.MOVE	SP1, SP2, HGT,      Move and animate.
	LEN, COL, ROW
?NPX                        Assign the value in the Graphics variable
                            NPX to a BASIC variable.
.NPX=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable NPX.
?PEK                        PEEK a 16 bit number.
.PMAT	SP1, SP2, SCOL,     Block move attributes of window at
	SROW                SCOL, SROW of sprite SP2 into sprite SP1.


++				63

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


.PMBL	SP1, SP2, SCOL,     Block move window at SCOL,SROW of sprite
	SROW                SP2 into sprite SP1.
.PMND	SP1, SP2, SCOL      Logically AND window at SCOL,SROW of
	SROW                sprite SP2 into sprite SP1.
.PMOR	SP1, SP2, SCOL,     Logically OR window at SCOL,SROW of
	SROW                sprite SP2 into sprite SP1.
.PMXR	SP1, SP2, SCOL,     Logically XOR window at SCOL,SROW of
	SROW                sprite SP2 into sprite SP1.
.POKE	N,M                 Poke a 16 bit number M at N.
.PROCFN N#()                Call the procedure N.
.PTBL	SPN, COL, ROW       Block move sprite data from sprite to
                            screen.
.PTND	SPN, COL, ROW       Logically AND sprite data into screen data.
.PTOR	SPN, COL, ROW       Logically OR sprite data into screen data.
.PTXR	SPN, COL, ROW       Logically XOR sprite data into screen data.
.PWAT	SPN, COL, ROW,      Block move sprite window attributes
	SCOL, SROW, HGT,    into screen window.
	LEN
.PWBL	SPN, COL, ROW,      Block move sprite data from sprite window
	SCOL, SROW, HGT,    into screen window.
	LEN
.PWND	SPN, COL, ROW,      Logically AND sprite window data into
	SCOL, SROW, HGT,    screen window.
	LEN
.PWOR	SPN, COL, ROW,      Logically OR sprite window data into
	SCOL, SROW, HGT,    screen window.
	LEN
.PWXR	SPN, COL, ROW,      Logically XOR sprite window into screen
	SCOL, SROW, HGT,    window.
	LEN
.REMK                       Remove all REM statements in a program.
.RETN                       Return from procedure.
?ROW                        Assign the value in the Graphics variable
                            ROW to a BASIC variable.
.ROW=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable ROW.
.RNUM                       Renumber lines.
?SCL                        Assigns a Sinclair variable with the
                            current value of SCL.
.SCL=                       Store a value in the variable SCL.
?SCM	SPN                 Scan the sprite for data. 0 = no data, 1 = data.
.SCRM	SPN                 Scroll the sprite vertically without
                            wrap by NPX pixels.
.SCRV	HGT, LEN, COL,      Scroll the window vertically without
	ROW, NPX            wrap by NPX pixels.
?SCV	ROW, COL            Scan a character square at ROW, COL
                            for data. 0 = no data, 1 = data.


++				64

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


?SET                        Assigns the value in the Graphic variable
                            SET to a BASIC variable.
.SET=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable SET.
.SETM	SPN                 Fill the sprite with the current attributes.
.SETV	HGT, LEN, COL,      Fill the screen window with the current
	ROW                 attributes.
.SL1M	SPN                 Scroll the sprite 1 pixel left without
                            wrap.
.SL1V	HGT, LEN, COL,      Scroll the window 1 pixel left without
	ROW                 wrap.
.SL4M	SPN                 Scroll the sprite 4 pixels left without
                            wrap.
.SL4V	HGT, LEN, COL,      Scroll the window 4 pixels left without
	ROW                 wrap.
.SL8M	SPN                 Scroll the sprite 8 pixels left without
                            wrap.
.SL8V	HGT, LEN, COL,      Scroll the window 8 pixels left without
	ROW                 wrap.
?SP1                        Assign the value in the Graphics variable
                            SP1 to a BASIC variable.
.SP1=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable SP1.
?SP2                        Assign the value in the Graphics variable
                            SP2 to a BASIC variable.
.SP2=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable SP2.
?SPN                        Assign the value in the Graphics variable
                            SPN to a BASIC variable.
.SPN=	BASIC EXPRESSION    Assign the value of the BASIC expression
                            to the Graphics variable SPN.
.SPNM	SP1, SP2            Rotate sprite SP2 90 degrees clockwise
                            into sprite SP1.
.SPRT	SPN, HGT, LEN       Create sprite at free space after last
                            sprite.
.SR1M	SPN                 Scroll the sprite 1 pixel right without
                            wrap.
.SR1V	HGT, LEN, COL,      Scroll the window 1 pixel right without
	ROW                 wrap.
.SR4M	SPN                 Scroll the sprite 4 pixels right without
                            wrap.
.SR4V	HGT, LEN, COL,      Scroll the window 4 pixels right without
	ROW                 wrap.
.SR8M	SPN                 Scroll the sprite 8 pixels right without
                            wrap.
.SR8V	HGT, LEN, COL,      Scroll the window 8 pixels right without
	ROW                 wrap.


++				65

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


.TROF                       Switch off trace function.
.TRON                       Switch on trace function.
?TST	SPN                 Test sprite.
.WCRM	SPN                 Scroll the sprite vertically with wrap
                            by NPX pixels.
.WCRV	HGT, LEN, COL,      Scroll the window vertically with wrap
	ROW, NPX            by NPX pixels.
.WL1M	SPN                 Scroll the sprite 1 pixel left with wrap.
.WL1V	HGT, LEN, COL,      Scroll the window 1 pixel left with wrap.
	ROW
.WL4M	SPN                 Scroll the sprite 4 pixels left with wrap.
.WL4V	HGT, LEN, COL,      Scroll the window 4 pixels left with wrap.
	ROW
.WL8M	SPN                 Scroll the sprite 8 pixels left with wrap.
.WL8V	HGT, LEN, COL,      Scroll the window 8 pixels left with wrap.
	ROW
.WR1M	SPN                 Scroll the sprite 1 pixel right with wrap.
.WR1V	HGT, LEN, COL,      Scroll the window 1 pixel right with wrap.
	ROW
.WR4M	SPN                 Scroll the sprite 4 pixels right with wrap.
.WR4V	HGT, LEN, COL,      Scroll the window 4 pixels right with wrap.
		ROW
.WR8M	SPN                 Scroll the sprite 8 pixels right with wrap.
.WR8V	HGT, LEN, COL,      Scroll the window 8 pixels right with wrap.
	ROW
.WSPR	SPN                 Delete sprite and recover bytes from above.


++				66

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


APPENDIX 2 "SPRITE1A" AND "SPRITE2A" SPRITES

Example sprites for use in user's own Laser BASIC games or the Sprite
Generator Program.

SPRITE  DESCRIPTION	LEN	HGT	INK	PAPER  FLASH  BRIGHT
1	Vintage car	4	2	5	0	0	1
2	Van		4	2	6	0	0	1
3	Dragster	4	2	3	0	0	1
4	Duck		3	3	6	0	0	1
5	Dancer		2	4	7	0	0	1
6	Mouse		2	2	7	0	0	1
7	Spaceship #1	4	2	5	0	0	1
8	Tank #1		4	2	0	4	0	1
9	Bi-plane	4	2	1	5	0	0
10	Helicopter #1	4	2	0	5	0	0
11	Spaceship #2	4	2	5	0	0	1
12	Spacetank	4	2	0	6	0	1
13	Rocket		4	2	7	1	0	1
14	Jet fighter #1	5	2	1	5	0	1
15	Spaceship #3	5	2	5	0	0	1
16	Spaceship #4	4	2	6	0	0	1
17	Jet fighter #2	4	2	2	5	0	1
18	Tank #2		6	3	0	4	0	0
19	Liner		7	2	0	5	0	1
20	Jet fighter #2	5	2	3	5	0	1
21	Alien		4	2	7	2	0	1
22	Spaceship #5	4	2	4	0	0	1
23	Spaceship #6	6	2	5	0	0	1
24	Spaceship #7	6	2	7	0	0	1
25	Tank #3		6	3	4	7	0	0
26	Helicopter	7	2	0	5	0	1
27	Tri-plane	4	2	2	5	0	1
28	Bulldozer	5	2	0	3	0	1
29	Spaceship #8	5	2	7	0	0	1
30	Frog		3	3	4	0	0	1
31	Rabbit		2	3	7	3	0	1
32	Ghost		2	2	6	0	0	1
33	Pac-men		2	2	5	0	0	1
34	Fly		3	2	7	0	0	1
35	Jet fighter #3	5	3	0	5	0	1
36	Crocodile	6	3	4	1	0	1
37	Hovercraft	5	3	1	6	0	1
38	Submarine	8	2	5	1	0	1
39	Tank destroyer	6	3	0	4	0	1
40	Jet fighter #4	5	2	1	7	0	1
41	Space buggy	5	3	0	6	0	1
42	Cannon		5	3	4	0	0	1
43	Soldier		3	6	0	4	0	1
44	Diamond		3	3	7	1	0	1
45	Sword		6	2	6	0	0	1
46	Truck		8	2	5	0	0	1
47	Lunar lander	3	3	6	0	0	1
48	Jet fighter #5	5	2	0	4	0	1
49	Teddy		4	5	6	0	0	1
50	Ball		3	3	0	5	0	1

These sprites can be loaded by the loader program or by hand. To load these
sprites in by hand type:
CLEAR 51512: LOAD "SPRITE2A"CODE 51513: POKE 62464,51513


++				67

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


APPENDIX 3 "SPRITE1B" AND "SPRITE2B" SPRITES

The sprites that were used in the Laser BASiC demo, available to be used in
your Laser BASIC Programs or the Sprite Generator Program.

SPRITE  DESCRIPTION	LEN	HGT	INK	PAPER  FLASH  BRIGHT
1	Tortoise	4	2	5	0	0	0
2	Mouse		4	2	7	0	0	1
3	Hare		4	2	6	0	0	1
4	Flower		2	4	4	0	0	1
5	Car		4	2	3	0	0	0
6	Road section	3	2	-	-	-	-
7	Bouncing man #1	5	4	6	0	0	1
8	Bouncing man #2	5	4	6	0	0	1
9	Bouncing man #3	5	4	6	0	0	1
10	Bouncing man #4	5	4	6	0	0	1
11	Bouncing man #5	2	4	6	0	0	1
12	Girder section	2	2	4	0	0	0
13	Ground		15	1	4	0	0	1
14	Invader		3	3	0	6	0	1
15	Landscape #1	15	3	6	0	0	1
16	Landscape #2	15	3	6	0	0	1
17	Landscape #3	2	3	6	0	0	1
18	Spaceship	3	3	7	1	0	1
19	Planet w/ring	3	3	5	0	0	1
20	Quill		3	3	7	0	0	1
21	Top of space	8	4	5	0	0	1
	vehicle
22	Lantern		4	3	-	-	-	-
23	Spider's web	4	3	7	0	0	1
24	Planet w/moon	3	3	4	0	0	1
25	Clock		3	3	6	0	0	1
26	Track of space	8	2	5	0	0	1
	vehicle
27	Turned track of	8	2	5	0	0	1
	space vehicle
28	Spinner cap	3	3	5	0	0	1
29	Bell		3	3	7	0	0	1
30	Screw jack	3	3	4	0	0	1
31	Lever		3	3	4	0	0	1
32	Chess piece	2	4	0	7	0	1
33	Oasis logo	12	4	-	-	-	-
34	Top of train	11	2	5	0	0	1
35	Train wheels #1	11	1	7	0	0	0
36	Train wheels #2	11	1	7	0	0	0
37	Train wheels #3	11	1	7	0	0	0
38	Train wheels #4	11	1	7	0	0	0
39	Dot		1	1	7	0	0	0
40	Radar dish #1	1	2	5	0	0	1
41	Radar dish #2	1	2	5	0	0	1
42	Radar dish #3	1	2	5	0	0	1
43	Radar dish #4	1	2	5	0	0	1
44	Radar dish #5	1	2	5	0	0	1
45	Radar dish #6	1	2	5	0	0	1
46	Radar dish #7	1	2	5	0	0	1
47	Radar dish #8	1	2	5	0	0	1
48	Top of coach	10	2	-	-	-	-
49	Coach wheels #1	10	1	7	0	0	0
50	Coach wheels #2	10	1	7	0	0	0


++				68

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


51	Track		8	1	7	0	0	1
52	Rotating face	2	2	4	0	0	1
	0 degrees
53	Rotating face	2	2	4	0	0	1
	90 degrees
54	Rotating face	2	2	4	0	0	1
	180 degrees
55	Rotating face	2	2	4	0	0	1
	270 degrees
56	Helicopter #1	3	3	5	0	0	1
57	Helicopter #2	3	3	5	0	0	1
58	Key #1		3	3	7	0	0	1
59	Key #2		3	3	7	0	0	1

These sprites can be loaded using the loader program or by hand. To load
these sprites by hand type:
CLEAR 50303: LOAD "SPRITE2B" CODE 50304: POKE 62464,50304


++				69

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


APPENDIX 4 THE LASER BASIC DEMO EXPLAINED

This appendix is a brief outline of the Laser BASIC Demo. Its aim is to help
users to familiarise themselves with the operation of some of the commands.
The Demo was written as a series of subroutines which run independently of
each other, so they can be simply executed by typing GOSUB (line number)
without having to run the whole program.


THE INTERMEDIATE OASIS LOGO SCREEN

	Execution	variables to be set on entry.
	GOSUB 1000	none.

1000 INK 4: PAPER 0: BRIGHT 1: BORDER 0: CLS 
1001.COL=9:.ROW=6:.SPN=60:.ATON:.PTBL:
1002 PRINT AT 13,11; INK 5;"BASIC DEMO";AT 11,10; INK 5;"    LASER   "
1003 PLOT 73,90: DRAW 108,0: DRAW 0,-14: DRAW -108,0: DRAW 0,14
1004 PLOT 73,74: DRAW 108,0: DRAW 0,-14: DRAW -108,0: DRAW 0,14
1005.NPX=1:.COL=10:.HGT=1:.LEN=12
1006 FOR N=0 TO 192:.ROW=11:.WL1V:.ROW=13:.WCRV: NEXT N: PAUSE 50: RETURN 

In this screen the OASIS logo sprite is placed on the screen. Text is placed
under it with boxes drawn around the text using the Sinclair DRAW commands.

Line 1005 defines a window which will fit over the text but inside the boxes.
Line 1006 scrolls the top text horizontally and the bottom text vertically
	246 times by 1 pixel.


THE SPRITES MOVING THROUGH THE PILLARS SCREEN

	Execution	variables to be set on entry.
	GOSUB 770	none.

 770.ATOF: INK 4: PAPER 0: BRIGHT 1: BORDER 0:.HGT=24:.LEN=32:.ROW=0:.COL=0: CLS
 :.SETV
 771 INK 5: PAPER 5:.LEN=3:.HGT=22:.ROW=0: FOR N=8 TO 26 STEP 8:.COL=N:.SETV: NE
XT N
 772 INK 1: PAPER 1:.LEN=2:.HGT=22:.ROW=0: FOR N=10 TO 29 STEP 8:.COL=N:.SETV: N
EXT N
 774 INK 4: PAPER 1:.LEN=1:.HGT=12:.ROW=8: FOR N=6 TO 26 STEP 8:.COL=N:.SETV: NE
XT N
 775 INK 4: PAPER 5:.LEN=1:.HGT=12:.ROW=8: FOR N=5 TO 26 STEP 8:.COL=N:.SETV: NE
XT N
 776.SPN=33:.COL=0:.ROW=15:.PTBL: PAUSE 50:.HGT=6:.LEN=32: FOR N=1 TO 300:.SR1V:
 NEXT N
 780.SP1=14:.SP2=14:.LEN=1:.HGT=0: FOR N=1 TO 20::.ROW=INT (RND*10)+8:.COL=-4: F
OR X=-4 TO 32:.MOVE: NEXT X: NEXT N:.ATON: RETURN 


++				70

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In this screen, the invader sprites and the Oasis logo appear to move in
front of, and behind blue and cyan pillars. The way this is achieved, is in
fact, quite simple. The pillars that the data moves in front of, are in
fact, just columns of attributes with INK set to green. You cannot see the
green INK until some pixel data (the sprites or logo) pass over it. In order
to give the impression of the sprites moving behind the larger pillars, the
INK colours of these pillars are set to the same colour as the PAPER colour.
Data still passes over the attributes as with the small pillars, but you
cannot see it as there is no difference between the INK and PAPER colours.

The attribute flag must be set to off (.ATOF) for the above method to work
(see line 770).

Lines 771 and 772 create the foreground pillars.
Lines 774 and 775 create the background pillars.
Line 776 places sprite 33 (the Oasis logo) on the screen and a window,
	the length of the screen, is defined around it. The data is then
	simply scrolled by 1 pixel 300 times without wrap.
Line 780 moves sprite 14 across the screen from left to right using MOVE.


THE FIRST JUMPING MAN SCREEN

	Execution	variables to be set on entry.
	GOSUB 160	none.

 160.ATON: INK 5: PAPER 0: BORDER 0: CLS :.SET=4:.HGT=3:.LEN=3:.COL=12:.ROW=11:.
SPN=25:.PTBL:.SET=5:.COL=7:.ROW=21:.SPN=30:.PTBL:.COL=4:.PTBL:.COL=1:.PTBL:.HGT=
3:.LEN=9:.SET=6:.ATOF:.SPN=19:.COL=0:.ROW=3:.PTBL:.ATON:.LEN=32:.HGT=3:.SET=1
 161.COL=13:.ROW=20:.SPN=60:.PTBL:.COL=28:.ROW=20:.SPN=23:.PTBL:.ROW=6: FOR N=2 
TO 32 STEP 8:.COL=N:.SPN=22:.PTBL: NEXT N
 162.ROW=18:.SPN=12: FOR N=-30 TO 32 STEP 2:.COL=N:.PTBL: NEXT N
 163.ROW=14: FOR I=-30 TO 40 STEP 2:.COL=I
 164.SPN=7:.PTBL: GO SUB 165:.SPN=8:.PTBL: GO SUB 165:.SPN=9:.PTBL: GO SUB 165:.
SPN=10:.PTBL: GO SUB 165: NEXT I: RETURN 
 165.SET=4:.MIRV:.SET=5:.MIRV:.SET=6:.WL1V::.SET=1: PAUSE 2: RETURN 

In this screen a little man hops across the screen from left to right, while
a planet scrolls above. A clock and some objects that look like fly presses
are also animated.

Lines 160 to 162 place all the scenario data on the screen.
Line 163 is a loop to set the value of COL in the range -30 to 40.
	A sequence of 4 sprites (7,8,9 and 10) are used to animate the
	little man.
Line 165 mirrors the clock and the sprites in the bottom left of the screen,
	as well as scrolling the planet and taking a PAUSE of 2 to slow the
	movement down.

Once the sequence of 4 sprites has been placed the COL value is incremented
by 2. The trailing blank edge of the sprite removes any data left by the old
sprite.


THE ARRAY OF INVADERS ON THE CYAN BACKGROUND

	Execution	variables to be set on entry.
	GOSUB 680	none.


++				71

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 680 BRIGHT 0: INK 0: PAPER 5: BORDER 5:.HGT=24:.LEN=32:.ROW=0:.COL=0: CLS :.SET
V:.ATOF:.COL=8:.ROW=15:.SPN=33:.PTBL
 681.ATOF:.SPN=15:.ROW=21:.COL=0:.PTBL:.COL=15:.SPN=16:.PTBL:.COL=30:.SPN=17:.PT
BL:.SPN=14:.ROW=0: GO SUB 720:.ROW=3: GO SUB 720:.ROW=6: GO SUB 720:.ROW=9: GO S
UB 720
 682.ROW=0:.COL=0:.HGT=12:.LEN=32: FOR N=1 TO 160:.WR1V: NEXT N
 683.ROW=0:.COL=20:.HGT=15:.LEN=12:.NPX=-1: FOR N=1 TO 24:.WCRV: NEXT N
 684.ROW=3:.COL=0:.HGT=12:.LEN=32: FOR N=1 TO 88:.WL1V: NEXT N
 690 .SP1=14:.SP2=14:.HGT=1
 691 FOR M=1 TO 16
 695 LET X=INT (RND*4): LET Y=INT (RND*4):.COL=(X*3)+9:.ROW=(Y*3)+3
 696 LET S=?SCV: IF S=0 THEN GO TO 695
 698.LEN=INT (RND*5)-2: FOR N=1 TO 30:.MOVE: PAUSE 1: NEXT N: NEXT M:.ATON: BRIG
HT 1: RETURN 
 720.COL=0:.PTBL:.COL=3:.PTBL:.COL=6:.PTBL:.COL=9:.PTBL: RETURN 

In this screen an array of 16 invaders scroll across the screen and then
break off one at a time.

Line 681, which uses line 720 as a subroutine, places the 16 invaders
	(sprite 15) on the screen.
Lines 682, 683 and 684 scroll the array of invaders by creating a window
	around them and then scrolling them by 1 pixel horizontally,
	vertically and then horizontally again.
Lines 690 to 698 scan the area of screen now occupied by the invaders for
	data using ?SCV (line 696). If any data (the invader) exists there,
	then the sprite is moved off screen using MOVE. This process is
	repeated until all the sprites have been removed.


THE CIRCLE OF COLOURED SQUARES

	Execution	variables to be set on entry.
	GOSUB 670	none.

 670.HGT=4:.LEN=4: GO SUB 100: FOR M=1 TO 3: FOR N=1 TO 40:.COL=14-10*COS (N/20*
PI):.ROW=10+10*SIN (N/20*PI)
 671 INK 0: PAPER INT (RND*7)+1:.SETV: NEXT N: NEXT M: RETURN 

In this screen a subroutine starting at line 100 is called which puts some
text and the Oasis logo on the screen.


++				72

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 100.ATOF: INK 7: PAPER 0: BORDER 0: BRIGHT 1: CLS 
 101 PRINT AT 4,8;"THE LASER BASIC";AT 6,4;"EXTENDED INTERPRETER FROM"
 102.COL=9:.ROW=11:.SPN=33:.PTBL:.ATON: PAUSE 100: RETURN 

Line 670 is a simple circle calculating routine.
Line 671 sets windows of 3 by 3 characters with a random PAPER colour and a
	constant INK colour using .SETV.


FALLING INVADERS OVER A STAR FILLED BACKDROP

	Execution	variables to be set on entry.
	GOSUB 380	none.

 380.ATOF: INK 7: BORDER 1: PAPER 1: BRIGHT 1: CLS 
 390 FOR N=1 TO 300: PLOT INT (RND*255),INT (RND*175): NEXT N:.COL=0:.ROW=0:.SPN
=33:.PTBL:.COL=20:.ROW=5:.SPN=19:.PTBL:.ROW=20:.COL=0:.SPN=16:.PTBL:.SPN=17:.COL
=15:.PTBL:.SPN=15:.COL=17:.PTBL
 399 FOR V=1 TO 20
 400.SPN=14:.ROW=-3:.COL=INT (RND*5)+13:.HGT=1:.LEN=INT (RND*3)-1:.SP1=14:.SP2=1
4
 410 FOR N=-4 TO 24:.ROW=N:.MOVE: PAUSE 1: NEXT N
 420 NEXT V:.ATON: RETURN 

In this screen MOVE is used to non-destructively move sprite 14 (the
invader) down from a position above the top of the screen over data below.

Line 390 plots 300 pixels on the screen. Places the ringed planet (sprite 19),
	the Oasis logo (sprite 33), and the landscape sprites (sprites 15,16
	and 17) on the screen.
Lines 399, 400,410 and 420 move twenty invaders down the screen from a
	random COL position. A random value is set in LEN (-1 to 1).
	MOVE is used to move the sprites.


THE SECOND JUMPING MAN SCREEN (THE MOVING FLOOR)

	Execution	variables to be set on entry.
	GOSUB 210	none.


++				73

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 210 BORDER 0: INK 4: PAPER 0: BRIGHT 1: CLS :.COL=9:.ROW=0:.SPN=60:.PTBL
 211.ROW=5:.SPN=22: FOR N=2 TO 32 STEP 8:.COL=N:.PTBL: NEXT N
 212.SPN=24:.ROW=8:.COL=3:.PTBL:.COL=23:.PTBL:.ROW=11:.COL=9:.PTBL:.COL=29:.PTBL
:.SET=5:.HGT=3:.LEN=32:.COL=0:.SET=1
 220.ROW=20:.SPN=12: FOR N=0 TO 20 STEP 2:.COL=N:.PTBL: NEXT N:.COL=30:.PTBL:.CO
L=28:.PTBL
 230.SET=1:.COL=-4:.ROW=16
 231.SET=2:.COL=20:.ROW=20:.LEN=8:.HGT=2
 240 FOR I=-28 TO 32 STEP 2:.SET=1:.COL=I:.SPN=7:.PTBL:.SET=2:.WR4V: GO SUB 244
 241.SPN=8:.PTBL:.SET=2:.WR4V: GO SUB 244
 242.SPN=9:.PTBL:.SET=2:.WR4V: GO SUB 244
 243.SPN=10:.PTBL:.SET=2:.WR4V: GO SUB 244: NEXT I: RETURN 
 244.SET=5:.ROW=8:.WL1V:.ROW=11:.WR1V:.SET=1: PAUSE 4: RETURN 

In this screen the jumping man moves on screen and synchronises his jump
with a part of the floor which is moving.

Lines 211, 212 and 220 place all the data on the screen.
Line 230 sets up SET 1 for the man.
Line 231 sets up SET 2 for moving the floor.
Lines 240 to 243 move the man, scrolling the planets and the floor after
	each movement

The little man is animated using four sprites (7,8,9 and 10), which, when
sequentially put, move the data 2 characters to the right, hence the need
for the STEP2 in the controlling FOR-NEXT loop (line 240).


THE RAT RACE SCREEN

	Execution	variables to be set on entry.
	GOSUB 350	none.

 350 INK 7: PAPER 0: BRIGHT 1: BORDER 0: CLS :.ATOF
 360 LET P1=5: LET P2=2: LET L=16: LET H=3: LET C=8: LET R=1: GO SUB 2000: PRINT
 AT 2,10;"THE RAT RACE"
 365.SPN=2:.LEN=32:.COL=0:.HGT=2: INK 0: FOR N=1 TO 7:.ROW=5+(N*2): PAPER N:.SET
V:.PTBL: NEXT N
 370 FOR N=1 TO 1000: LET R=INT (RND*7)+1:.ROW=5+(R*2):.WR1V: NEXT N:.ATON: RETU
RN 


++				74

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In this screen the 7 colours from Blue to White are used to form 7 tracks 32
characters long by 2 high. Seven rats, 1 in each track, are placed on the
screen.

Line 376 picks one of the tracks at random and scrolls it by 1 pixel to the
	right (.WR1V).  This is repeated 1000 times giving a race with a
	random outcome.

The window and shadow that contains the text "THE RAT RACE" is created in a
subroutine at line 2000 (see later).


THE THIRD JUMPING MAN SCREEN (THROUGH THE PILLARS)

	Execution	variables to be set on entry.
	GOSUB 450	none.

 450 PAPER 0: INK 6: BRIGHT 1: BORDER 0: CLS 
 451 INK 6: PAPER 5:.LEN=3:.HGT=24:.ROW=0:.COL=4:.SETV:.COL=14:.SETV:.COL=24:.SE
TV
 453 INK 1: PAPER 1:.LEN=2:.HGT=24:.ROW=0:.COL=8:.SETV:.COL=18:.SETV:.COL=28:.SE
TV
 460.SPN=12:.ROW=20: FOR N=0 TO 6 STEP 2:.COL=N:.PTBL:.COL=N+10:.PTBL:.COL=N+20:
.PTBL:.COL=N+30:.PTBL: NEXT N
 461 INK 5: PAPER 5:.LEN=1:.HGT=24:.ROW=0:.COL=7:.SETV:.COL=17:.SETV:.COL=27:.SE
TV
 462.LEN=2:.HGT=5:.ROW=15: INK 6: PAPER 1:.COL=5:.SETV:.COL=15:.SETV:.COL=25:.SE
TV
 470.ATOF:.ROW=16: FOR I=-4 TO 32 STEP 2:.COL=I
 480 .SPN=7:.PTBL: PAUSE 8:.SPN=8:.PTBL: PAUSE 8:.SPN=9:.PTBL: PAUSE 8:.SPN=10:.
PTBL: PAUSE 8: NEXT I:.ATON: RETURN 

In this screen the same technique as in "The Sprites moving through the
pillars screen" was used to build up purely attribute based pillars. Their
INK and PAPER colours are set such that data would appear to go either
behind or in front of them.

Lines 470 to 480 sets the attribute switch off (.ATOF). The sprites 7,8,9
and 10 are animated in the previously described manner across the screen
from a COL value of -4 to a value of 32 in steps of 2. (Note the PAUSE 8
after each movement in line 480)


THE ANIMATION SCREEN

	Execution	variables to be set on entry
	GOSUB 870	none.


++				75

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 870.ATON: BORDER 0: INK 7: PAPER 0: BRIGHT 1: CLS :.COL=18:.ROW=20:.SPN=60:.PTB
L:.ATOF: LET C=20: LET R=0: LET L=11: LET H=3: LET P1=6: LET P2=4: GO SUB 2000: 
PRINT AT 1,21;"ANIMATION"
 871.LEN=3:.HGT=3:.ROW=5:.COL=12: GO SUB 860:.ROW=8:.COL=8: GO SUB 860:.COL=16: 
GO SUB 860:.ROW=12:.COL=5: GO SUB 860:.COL=19: GO SUB 860:.ROW=16:.COL=8: GO SUB
 860:.COL=16: GO SUB 860:.ROW=19:.COL=12: GO SUB 860
 872 FOR N=1 TO 40:.SPN=58: GO SUB 850: PAUSE 3:.SPN=59: GO SUB 850:.SPN=58: PAU
SE 3: NEXT N:.ATON: RETURN 

The subroutine at line 2000 is used to draw the window and shadow in which
the text "ANIMATION" is printed.

Line 871 fills windows, the size of the sprites (3x3), with random INK, using a
	subroutine at line 860.

 860 PAPER 0: INK INT (RND*6)+2:.SETV: RETURN 

Line 872 places sprite 58 on the screen and then, after a pause, sprite 59
	is placed, (both use the subroutine at line 850). After a second
	pause, line 872 is repeated giving two frame animation.

 850.ROW=5:.COL=12:.PTBL:.ROW=8:.COL=8:.PTBL:.COL=16:.PTBL:.ROW=12:.COL=5:.PTBL:
.COL=19:.PTBL:.ROW=16:.COL=8:.PTBL:.COL=16:.PTBL:.ROW=19:.COL=12:.PTBL: RETURN 


THE TORTOISE AND THE HARE SCREEN

	Execution	variables to be set on entry.
	GOSUB 600	none

 600 INK 6: PAPER 0: BORDER 0: CLS :.SPN=60:.ROW=15:.COL=10:.PTBL
 601 LET C=3: LET R=19: LET H=3: LET L=28: LET P1=7: LET P2=5: GO SUB 2000: PRIN
T AT 20,4;"THE TORTOISE AND THE HARE"
 605.SPN=39: FOR N=0 TO 31:.COL=N:.ROW=1: GO SUB 630:.ROW=6: GO SUB 630:.ROW=7: 
GO SUB 630:.ROW=12: GO SUB 630: NEXT N
 606.LEN=32:.COL=0:.ROW=3:.HGT=2: INK 5:.SETV
 607.SPN=1:.PTBL:.SPN=3:.ROW=9:.PTBL
 610.LEN=32:.HGT=2:.COL=0: FOR M=1 TO 256:.ROW=9:.SR1V: GO SUB 627:.SR8V: NEXT M
 611 RETURN 


++				76

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 627 IF M<180 THEN .ROW=13: RETURN 
 628.ROW=3: RETURN 

 630 INK INT (RND*7)+1: PAPER 0:.SETM:.PTBL: RETURN 

In this screen the two race tracks for the tortoise and the hare are
outlined by sprite 39 which is put on the screen in the Subroutine at line
630. Since the characters are to be scrolled, the attributes in their
respective screen windows need to be set before the scrolling can begin.

The hare is scrolled by 1 pixel (.SR1V) and the tortoise is scrolled by 8
pixels (.SR8V).


THE RANDOM COLOUR FLOWERS SCREEN

	Execution	variables to be set on entry.
	GOSUB 55O	none

 550.ATON:.SPN=4:.HGT=1:.LEN=2: INK 0: PAPER 0: BORDER 0: CLS 
 555 FOR N=0 TO 200:.COL=INT (RND*30):.ROW=INT (RND*22)
 560.PTBL: INK INT (RND*7)+1:.SETV: NEXT N: PAUSE 50: RETURN 

In this screen sprite 4 is "PUT" on the screen at random COL and ROW
positions. A random INK colour is set and the flower's petals coloured using
.SETV.


THE FOURTH JUMPING MAN SCREEN (RIDE ON THE MOVING PLATFORM)

	Execution	variable to be set on entry.
	GOSUB 510	none.


++				77

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 510 INK 6: PAPER 0: BORDER 0: BRIGHT 1: CLS :.SPN=60:.ROW=16:.COL=7:.PTBL
 511.LEN=2:.HGT=24:.ROW=0:.COL=0: INK 1: PAPER 1:.SETV:.COL=30:.SETV
 512.LEN=3:.COL=2: INK 5: PAPER 5:.SETV:.COL=27:.SETV
 513.LEN=1:.COL=5: INK 6:.SETV:.COL=26:.SETV
 514.LEN=2:.HGT=4:.ROW=1:.COL=3: INK 6: PAPER 1:.SETV:.COL=27:.SETV
 515.ROW=9:.COL=3:.SETV:.COL=27:.SETV
 516.ROW=17:.COL=3:.SETV:.COL=27:.SETV
 517.HGT=3:.ROW=5:.COL=3: INK 4:.SETV:.COL=27:.SETV
 518.ROW=13:.COL=3:.SETV:.COL=27:.SETV
 519.ROW=21:.COL=3:.SETV:.COL=27:.SETV
 520.HGT=3:.LEN=1:.ROW=5:.COL=5: INK 4: PAPER 5:.SETV:.COL=26:.SETV
 521.ROW=13:.COL=5:.SETV:.COL=26:.SETV
 522.ROW=21:.COL=5:.SETV:.COL=26:.SETV
 523.LEN=20:.HGT=3:.ROW=5:.COL=6: INK 4: PAPER 0:.SETV:.ROW=13:.SETV:.ROW=21:.SE
TV
 524 .SPN=12:.ATOF:.ROW=5:.COL=3:.PTBL:.COL=16:.PTBL:.ROW=13:.PTBL:.COL=3:.PTBL:
.ROW=21:.PTBL:.COL=16:.PTBL:.SPN=31:.COL=15:.ROW=1:.PTBL:.SPN=25:.COL=21:.ROW=18
:.PTBL
 530.LEN=26:.HGT=3:.ROW=9: FOR I=-36 TO 32 STEP 2:.COL=I
 531.SPN=7:.PTBL: GO SUB 540:.SPN=8:.PTBL: GO SUB 540:.SPN=9:.PTBL: GO SUB 540:.
SPN=10:.PTBL: GO SUB 540: NEXT I
 532.ATON: RETURN 

In this highly animated screen, the little man is seen to hop in time with a
moving platform as it scrolls across the screen.

Lines 511 to 522 create the pillars from which the man and platforms appear
	to emerge.  The pillars are created from attributes with no pixel
	data present. The technique is described in a previous section.
Line 523 sets attributes for the parts of the screen that are going to be
	occupied by the platforms.
Line 524 places the various sprites on the screen. The animation sequence,
	used in previous example, is used to animate the man, calling the
	subroutine at line 540 after each sprite has been placed.


++				78

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 540.COL=15:.ROW=1:.LEN=3:.MIRV:.ROW=18:.COL=21:.MIRV:.LEN=26:.ROW=5:.COL=3:.WR1
V:.ROW=21:.WR8V:.ROW=13:.WR4V:.ROW=9:.COL=I: RETURN 

This subroutine produces all the other animation that is seen on the screen
by mirroring two sprites and scrolling the 3 platforms by 1,4 and 8 pixels
with wrap around.


THE DIFFERENT COLOURED COLUMNS MOVING ACROSS THE SCREEN

	Execution	variables to be set on entry.
	GOSUB 250	none.

 250 GO SUB 100:.ROW=0:.COL=0:.LEN=2:.HGT=8
 260 INK 0: FOR M=1 TO 500:.INVV
 270 PAPER INT (RND*7)+1:.SETV
 280 LET X=?COL: LET Y=?LEN: IF X+Y>=32 THEN LET X=-1:.COL=0
 290.COL=X+1
 300 LET X=?ROW: LET Y=?HGT: IF X+Y>=25 THEN .ROW=1: LET X=-1
 310.ROW=X+1
 320 NEXT M: RETURN 

This screen starts by inverting a window of length 2 and height 8, using the
.INVV command. Its attributes are then set with a random paper colour using
.SETV.

Lines 280 to 320 calculate the ROW and COL position of the window.


THE TRAIN SCREEN

	Execution	variables to be set on entry.
	GOSUB 130	none.

 130 INK 6: PAPER 0: BORDER 0: CLS :.COL=9:.ROW=20:.SPN=60:.PTBL
 131 LET P1=7: LET P2=6: LET R=4: LET C=2: LET H=3: LET L=28: GO SUB 2000: PRINT
 AT 5,3;"UP TO 255 SOFTWARE SPRITES"
 132.COL=0:.ROW=13:.SPN=48:.PTBL:.COL=10:.PTBL:.COL=20:.SPN=34:.PTBL
 133.ROW=15:.SPN=49:.COL=0:.PTBL:.COL=10:.PTBL:.COL=20:.SPN=35:.PTBL
 134.ROW=16:.SPN=51: FOR N=0 TO 32 STEP 8:.COL=N:.PTBL: NEXT N
 135.SET=1:.COL=0:.ROW=16:.HGT=1:.LEN=32
 136.SET=2:.COL=20:.ROW=15
 137.SET=3:.ROW=15:.COL=0
 139 FOR I=1 TO 200
 140.SET=2:.SPN=35:.PTBL:.SET=3:.SPN=49: GO SUB 150
 141.SET=2:.SPN=36:.PTBL:.SET=3:.SPN=50: GO SUB 150
 142.SET=2:.SPN=37:.PTBL:.SET=3:.SPN=49: GO SUB 150
 143.SET=2:.SPN=38:.PTBL:.SET=3:.SPN=50: GO SUB 150
 144 NEXT I: RETURN 


++				79

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In this screen, 4 sprites (35 to 38) are successively placed to animate the
wheels of the locomotive. The coach is animated using 2 sprites that make up
the wheels. These are sprites 49 and 50. The track is scrolled with wrap
around.

Lines 131 to 134 place the sprites on the screen.
Lines 139 to 143 call up a subroutine at line 150 which animates the wheels
	of the coach.

 150.COL=0: .PTBL:.COL=10:.PTBL:.SET=1:.WL1V: RETURN 


THE HORIZONTAL SCROLLING DEMO

	Execution	variables to be set on entry.
	GOSUB 330	None

 330.ATOF: INK 1: PAPER 1: BORDER 1: BRIGHT 0: CLS 
 332.LEN=32:.HGT=16:.COL=0:.ROW=5: INK 0: PAPER 6:.SETV
 333 LET P1=0: LET P2=2: LET L=22: LET R=2: LET H=3: LET C=5: GO SUB 2000: PRINT
 AT 3,6;"HORIZONTAL SCROLLING"
 334.SPN=15:.COL=0:.ROW=7:.PTBL:.SPN=16:.COL=15:.PTBL:.SPN=17:.COL=30:.PTBL
 335 PLOT 0,20: DRAW 255,0:.COL=0:.ROW=16:.SPN=18:.PTBL:.ROW=10:.COL=1:.PTBL:.CO
L=4:.ROW=13:.PTBL
 340.COL=0:.LEN=32
 341 FOR N=1 TO 500:.HGT=3:.ROW=7:.WL1V:.HGT=3:.ROW=10:.WR4V:.ROW=13:.WR1V:.ROW=
16:.WR8V: NEXT N:.ATON: RETURN 

In this screen the landscape is seen to scroll left by 1 pixel with wrap,
while the 3 spaceships are seen to scroll in the opposite direction by 4, 1
and 8 pixels respectively. The subroutine at line 2000 is used to define a
window and its shadow, in which the text, "HORIZONTAL SCROLLING" is printed.

Lines 334 and 335 PUT all the scenario data on the screen. The landscape
	is built up of 3 sprites, numbers 15, 16 and 17, which are 15, 15
	and 2 characters long.
Line 341 scrolls the landscape and the 3 spaceships in the window whose
	length is 32 columns.


THE FIFTH JUMPING MAN SCREEN (THE EIGHT PLANETS)

	Execution	variables to be set on entry.
	GOSUB 640	none.


++				80

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 640 BORDER 0: INK 6: PAPER 0: CLS :.HGT=24:.LEN=32:.ROW=0:.COL=0:.SETV
 641.COL=10:.ROW=15:.SPN=60:.PTBL:.ROW=5:.SPN=12: FOR N=0 TO 30 STEP 2::.COL=N:.
PTBL: NEXT N
 642.ATOF:.SPN=19:.HGT=3:.LEN=3:.ROW=8:.COL=1: INK 7:.SETV:.PTBL:.COL=7:.ROW=14:
 INK 2:.SETV:.PTBL:.COL=11:.ROW=9: INK 3:.SETV:.PTBL
 643.COL=9:.ROW=21: INK 4:.SETV:.PTBL:.COL=18:.ROW=11: INK 5:.SETV:.PTBL:.COL=29
:.ROW=10: INK 6:.SETV:.PTBL:.COL=24:.ROW=14: INK 7:.SETV:.PTBL:.COL=21:.ROW=21:.
SETV:.PTBL
 645.ROW=1: FOR I=-30 TO 36 STEP 2:.COL=I
 646.SPN=7:.PTBL: GO SUB 660:.SPN=8:.PTBL: GO SUB 660:.SPN=9:.PTBL: GO SUB 660:.
SPN=10:.PTBL: GO SUB 660: NEXT I:.ATON: RETURN 

In this screen the now familiar man moves across a platform at the top of
the screen whilst 8 planets of various colours are being animated.

Lines 612 and 613 set attributes in 3 by 3 windows on the screen using
	.SETV. The planet sprite is now placed in these windows with the
	attribute switch set to off (.ATOF).
Line 660 is used as a subroutine which animates the sprites by mirroring
	the planet sprite data in the 3 by 3 windows.

 660.COL=1:.ROW=8:.MIRV:.COL=7:.ROW=14:.MIRV:.COL=24:.MIRV:.COL=11:.ROW=9:.MIRV:
.COL=9:.ROW=21:.MIRV:.COL=18:.ROW=11:.MIRV:.COL=29:.ROW=10:.MIRV:.COL=21:.ROW=21
:.MIRV:.COL=I:.ROW=1: RETURN 


THE BOUNCING PLANET SCREEN

	Execution	variables to be set on entry.
	GOSUB 110	none

 110 GO SUB 100: INK 0: LET DR=1:.HGT=DR: LET DC=1:.LEN=DC:.SP1=19:.SP2=19: LET 
R=0:.ROW=R: LET C=0:.COL=C:.SPN=19:.PTXR
 115 FOR N=1 TO 1000:.MOVE
 116 LET C=?COL: LET R=?ROW
 117 IF C=29 OR C=0 THEN LET DC=DC*-1:.LEN=DC: GO SUB 120
 118 IF R=20 OR R=0 THEN LET DR=DR*-1:.HGT=DR: GO SUB 120
 119 NEXT N: RETURN 


++				81

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


The original data on the screen is set up by a subroutine at line 100.

Lines 115 to 118 move the planet (sprite 19) about the screen using .MOVE.
Every time the edge of the screen is hit its paper colour is changed by the
subroutine at line 120.

 120 PAPER INT (RND*7)+1:.SETM: RETURN 


THE SMOOTH SCROLLING SCREEN

	Execution	variable to be set on entry.
	GOSUB 500	none.

 500 BORDER 7: INK 1: PAPER 7: BRIGHT 0: CLS :.ATOF:.ROW=16:.COL=1:.SPN=33:.PTBL
 501 LET P1=6: LET P2=0: LET L=11: LET H=5: LET R=7: LET C=4: GO SUB 2000: PRINT
 AT 8,5;"SMOOTH";AT 10,5;"SCROLLING"
 502.ATOF:.COL=25:.ROW=19:.SPN=20:.PTBL
 503.COL=25:.ROW=0:.LEN=3:.HGT=22:.NPX=1: FOR N=1 TO 134: PLOT 212,1:.WCRV: NEXT
 N
 504.COL=0:.ROW=2:.LEN=32:.HGT=3: FOR N=1 TO 170: PLOT 212,136:.WL1V: NEXT N:.AT
ON: PAUSE 50: RETURN 

In this screen a quill appears to draw a blue line vertically and then
horizontally.

This effect is achieved very simply. A window is defined around the quill
sprite and that data is scrolled. A pixel is placed right at the edge of the
window. After every scroll is executed, a pixel is plotted, drawing the line.

Line 503 is the vertical scroll (.WCRV).
Line 504 is the horizontal scroll (.WL1V).


THE ATTRIBUTE SCROLLING SCREEN

	Execution	variable to be set on entry.
	GOSUB 760	none.

 760 GO SUB 100: INK 0:.LEN=1:.HGT=13:.ROW=3: FOR N=3 TO 29:.COL=N: PAPER INT (R
ND*6)+2:.SETV: NEXT N
 761 LET L=19: LET H=3: LET R=19: LET C=7: LET P1=7: LET P2=4: GO SUB 2000: PRIN
T AT 20,8;"ATTRIBUTE SCROLLS":.LEN=27:.COL=3:.HGT=1: FOR I=3 TO 29: FOR Y=3 TO 1
6:.ROW=Y-1
 762 FOR X=1 TO Y:.ATRV: NEXT X: NEXT Y: NEXT I: PAUSE 50: RETURN 


++				82

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


The screen is set up using the subroutine at line 100.

Line 760 sets up 26 widows with INK 0 and a random PAPER colour. These windows
	are 1 character wide by 13 high.
Line 761 creates the window that contains the text "ATTRIBUTE SCROLLS", via the
	subroutine at line 2000.

The top line of attributes is now scrolled by 1 character to the right, the
second line is scrolled by 2 characters, the third by 3, etc., until the
bottom is reached. This process is repeated until the attributes have
reformed in their original columns.


THE SPACE TANKS WITH ROTATING RADAR DISHES SCREEN

	Execution	variable to be set on entry.
	GOSUB 800	none.

 800 INK 4: PAPER 0: BORDER 0: CLS 
 801 .SPN=15:.ROW=6:.COL=0:.PTBL:.COL=15:.SPN=16:.PTBL:.COL=30:.SPN=17:.PTBL
 802.SPN=21:.ROW=9:.COL=13:.PTBL:.COL=5:.PTBL:.SPN=27:.ROW=13:.COL=13:.PTBL:.SPN
=26:.COL=5:.PTBL
 803.ATOF:.SPN=13:.COL=0:.ROW=15:.PTBL:.COL=13:.PTBL:.COL=27:.PTBL:.ATON: PAPER 
4:.LEN=32:.HGT=6:.ROW=16:.COL=0:.SETV
 805 PAPER 0:.HGT=3:.LEN=32:.ROW=0:.COL=0: INK 5:.SETV:.ROW=3: INK 7:.SETV:.ATOF
 806.SPN=18:.ROW=0:.COL=6:.PTBL:.COL=23:.PTBL:.ROW=3:.COL=15:.PTBL
 807 LET L=18: LET H=3: LET P1=6: LET P2=1: LET R=17: LET C=12: GO SUB 2000: PRI
NT AT 18,13;"SPRITE ANIMATION"
 810 FOR M=1 TO 50: FOR N=40 TO 47:.SPN=N: GO SUB 820: NEXT N: NEXT M:.ATON: RET
URN 

In this screen space vehicles are displayed with rotating radar dishes. To
obtain the animation the 8 sprites are sequentially PUT, like frames from a
cartoon. Sprites 40 to 47 are used.

Lines 801, 802,803 and 806 build up the screen scenario.
Line 807 uses the subroutine at line 2000 to setup the window and shadow
	that the text is printed in.
Line 810 animates the radar dishes by sequentially putting a sequence
	of 8 sprites.
Line 820 is used as a subroutine to scroll the spaceships overhead.

 820.COL=15:.ROW=9:.PTBL:.COL=7:.PTBL:.HGT=6:.ROW=0:.COL=0:.LEN=32:.WR8V: RETURN


THE ROTATING SCREEN

	Execution	variables to be set on entry.
	GOSUB 830	none.


++				83

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 830 BORDER 0: INK 6: PAPER 0: BRIGHT 1: CLS :.COL=18:.ROW=20:.SPN=60:.PTBL:.ATO
F: LET C=21: LET R=0: LET L=10: LET H=3: LET P1=7: LET P2=4: GO SUB 2000: PRINT 
AT 1,22;"ROTATION"
 840.LEN=2:.HGT=2:.ROW=5:.COL=12: GO SUB 860:.ROW=8:.COL=8: GO SUB 860:.COL=16: 
GO SUB 860:.ROW=12:.COL=5: GO SUB 860:.COL=19: GO SUB 860:.ROW=16:.COL=8: GO SUB
 860:.COL=16: GO SUB 860:.ROW=19:.COL=12: GO SUB 860
 841 FOR N=1 TO 19:.SPN=52: GO SUB 850: PAUSE 20-N:.SPN=53: GO SUB 850: PAUSE 20
-N:.SPN=54: GO SUB 850: PAUSE 20-N:.SPN=55: GO SUB 850: PAUSE 20-N: NEXT N
 842.ATON: RETURN 

In this screen 8 faces are rotated. These sprites are in fact, rotated
copies of sprite 52. Sprites 53, 54 and 55 were created in the sprite
generator program. The 4 sprites are sequentially "PUT" to achieve a
rotation effect on the screen.

Line 840 sets up the attributes of the rotating characters. Using a
	subroutine at line 860.

 860 PAPER 0: INK INT (RND*6)+2:.SETV: RETURN 

Line 841 places the sprites on the screen with a decrementing pause after
	each PUT operation. The sprites are placed by calling a subroutine
	at line 850.

 850.ROW=5:.COL=12:.PTBL:.ROW=8:.COL=8:.PTBL:.COL=16:.PTBL:.ROW=12:.COL=5:.PTBL:
.COL=19:.PTBL:.ROW=16:.COL=8:.PTBL:.COL=16:.PTBL:.ROW=19:.COL=12:.PTBL: RETURN 


THE ATTRIBUTE TUNNEL SCREEN

	Execution	variables to be set on entry.
	GOSUB 570	none.

 570 GO SUB 100: INK 0: FOR M=1 TO 10
 573 BORDER INT (RND*7)+1: FOR N=16 TO 1 STEP -1
 575 .COL=(16-N):.ROW=(16-N):.HGT=N+8:.LEN=(N*2): PAPER INT (RND*7)+1:.SETV: NEX
T N
 580 BORDER INT (RND*7)+1: FOR N=1 TO 16
 585 .COL=(16-N):.ROW=(16-N):.HGT=N+8:.LEN=(N*2): PAPER INT (RND*7)+1:.SETV: NEX
T N
 590 NEXT M: RETURN 


++				84

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In this screen the data is placed on the screen from the subroutine at line
100, then using a simple routine, the dimensions and position of the window
are changed and a random PAPER colour is set in it using .SETV.


THE SIXTH JUMPING MAN SCREEN (THE STAIRCASE)

	Execution	variables to be set on entry.
	GOSUB 730	none.

 730 INK 6: PAPER 0: BORDER 0: BRIGHT 1: CLS :.COL=0:.ROW=16:.SPN=60:.PTBL
 731.ROW=0:.COL=28:.SPN=23:.PTBL:.ROW=4:.COL=20:.SPN=22:.PTBL:.ROW=12:.COL=28:.P
TBL:.SPN=25:.COL=3:.ROW=12:.PTBL
 740.SPN=12:.COL=0:.ROW=4:.PTBL:.COL=2:.PTBL: FOR N=4 TO 24 STEP 2:.ROW=N:.COL=N
:.PTBL:.COL=N+2:.PTBL: NEXT N:.ROW=22: FOR N=0 TO 32 STEP 2:.COL=N:.PTBL: NEXT N
 750.NPX=-1:.HGT=6:.LEN=3:.ROW=0: FOR I=-10 TO 6 STEP 2:.COL=I:
 751.SPN=7:.PTBL: PAUSE 8:.SPN=8:.PTBL: PAUSE 8:.SPN=9:.PTBL: PAUSE 8:.SPN=10:.P
TBL: PAUSE 8: NEXT I
 752 LET R=0: FOR I=8 TO 24 STEP 2:.COL=I: LET R=R+2
 753 FOR Y=1 TO 16:.WCRV: NEXT Y:.ROW=R:.SPN=7:.PTBL: PAUSE 8:.SPN=8:.PTBL: PAUS
E 8:.SPN=9:.PTBL: PAUSE 8:.SPN=10:.PTBL: PAUSE 8: NEXT I
 754.ROW=18: FOR I=26 TO 34 STEP 2:.COL=I:
 755.SPN=7:.PTBL: PAUSE 8:.SPN=8:.PTBL: PAUSE 8:.SPN=9:.PTBL: PAUSE 8:.SPN=10:.P
TBL: PAUSE 8: NEXT I:.ATON: RETURN 

In this screen the now familiar Jumping Man is seen to jump down a staircase.

Lines 730 to 740 place all the scenario data on the screen.
Lines 750 to 751 animate the man until he reaches a COL value of 6.
Lines 752 and 753 sequentially PUT the man to give the impression of leaping.
	He is then scrolled down in a window defined around him onto the step
	below. The ROW and COL values for the new position of the man are set
	and the process repeated.
Lines 754 to 755 animate the man once he has reached the bottom of the
	staircase. He is moved "off screen" from COL position 26.


THE HELICOPTER ANIMATION SCREEN

	Execution	variables to be set on entry.
	GOSUB 880	none.


++				85

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 880.ATOF: INK 5: PAPER 0: BRIGHT 1: BORDER 0: CLS :.HGT=24:.LEN=32:.ROW=0:.COL=
0:.SETV: FOR N=0 TO 300: PLOT INT (RND*256),INT (RND*143): NEXT N:.HGT=3:.LEN=3:
 INK 6:.COL=5:.ROW=10:.SPN=19:.PTBL:.SETV:.COL=28:.ROW=7:.PTBL: INK 4:.SETV
 881 LET L=11: LET R=0: LET H=3: LET C=9: LET P1=7: LET P2=3: GO SUB 2000: PRINT
 AT 1,10;"ANIMATION": .ATOF:.ROW=21:.SPN=57: FOR N=1 TO 28 STEP 3:.COL=N:.PTBL: 
NEXT N
 882 FOR C=1 TO 5
 883.ROW=22:.COL=1+INT (RND*9)*3: LET S=?SCV
 884 IF S=0 THEN GO TO 883
 885.ROW=21: FOR T=30 TO 1 STEP -4:.SPN=56:.PTBL: PAUSE T:.SPN=57:.PTBL: PAUSE T
: NEXT T
 886 FOR T=1 TO 10:.SPN=56:.PTBL: PAUSE 3:.SPN=57:.PTBL: PAUSE 3: NEXT T
 887.LEN=INT (RND*3)-1:.HGT=-1: FOR T=1 TO 22:.SP1=57:.SP2=56:.MOVE: PAUSE 3:.SP
1=56:.SP2=57:.MOVE: PAUSE 3: NEXT T: NEXT C:.ATON: RETURN 

In this screen helicopters with rotating rotor blades are seen to take off
and fly across a starry background.

Line 80	plots the stars on the screen and PUTs the planet sprite.

The text "ANIMATION" is placed in a window created in the subroutine at line
2000. The helicopters are animated and moved over the stars using the .MOVE
command. The sprite numbers of the two sprites are stored in SP1 and SP2,
and swapped after each execution by .MOVE.

Line 883 picks the helicopter to be flown at random using ?SCV (to see if
	the helicopter has yet to be flown). The helicopter is animated over
	the stars using MOVE.


THE .MOVE SCREEN

	Execution	variables to be set on entry.
	GOSUB 900	none.

 900 BRIGHT 0: INK 0: PAPER 6: BORDER 6:.HGT=24:.LEN=32:.ROW=0:.COL=0: CLS :.SET
V:.ATOF:.COL=18:.ROW=20:.SPN=33:.PTBL: LET L=8: LET H=3: LET C=0: LET R=19: LET 
P1=5: LET P2=0: GO SUB 2000: PRINT AT 20,1;".MOVE"
 901.ATOF:.SPN=14:.ROW=0: GO SUB 720:.ROW=3: GO SUB 720:.ROW=6: GO SUB 720:.ROW=
9: GO SUB 720
 902.ROW=0:.COL=0:.HGT=12:.LEN=32: FOR N=1 TO 80:.WR1V: NEXT N
 905.ROW=0:.COL=10:.HGT=18:.LEN=12:.NPX=-1: FOR N=1 TO 40:.WCRV: NEXT N


++				86

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


 906 FOR M=0 TO 15:.SET=M
 907 LET X=INT (RND*4): LET Y=INT (RND*4):.ROW=(Y*3)+5:.COL=(X*3)+10
 908 LET S=?SCV: IF S=0 THEN GO TO 907
 909.SP1=14:.SP2=14: GO SUB 920: FOR N=1 TO 30:.MOVE: NEXT N: NEXT M
 910 FOR M=0 TO 15:.SET=M: LET H=?HGT: LET H=H*-1:.HGT=H: LET L=?LEN: LET L=L*-1
:.LEN=L
 911 FOR N=1 TO 30:.MOVE: NEXT N: NEXT M
 912.ROW=0:.COL=10:.HGT=18:.LEN=12:.NPX=1: FOR N=1 TO 40:.WCRV: NEXT N
 913.ROW=0:.COL=0:.HGT=12:.LEN=32: FOR N=1 TO 80:.WL1V: NEXT N
 919 RETURN 

In this screen an array of invaders are scrolled into the middle of the
screen and then fly off, one at a time in different directions. Once all the
invaders have flown they reassemble the array and scroll off again. This
screen not only demonstrates the full use of .MOVE, but also the use of .SET
to store and recall the positions of the sprites stored in the various
variable sets.

Line 901 places the array of sprites on the screen by calling the subroutine
	at line 720 which was also used by the other invader array screen.
Lines 902 and 905 scroll the invaders, using .WR1V and .WCRV.

The invaders are then moved off at random after using ?SCV to find them on
the screen. A random number between -2 and 2 is stored in both HGT and LEN.
These values are checked to make sure they are not both zero which would
mean the sprite would not move.

 920.LEN=INT (RND*5)-2:.HGT=INT (RND*5)-2: LET L=?LEN: LET H=?HGT: IF L=0 AND H=
0 THEN GO TO 920
 921 RETURN 

Since a different variable set is used for each invader, the direction of
the invaders can be reversed by negating HGT and LEN, reassembling the array.

Lines 912 to 913 scroll the array off the screen.


THE SCROLLING OASIS LOGO ACROSS THE ATTRIBUTES SCREEN

	Execution	variables to be set on entry.
	GOSUB 930	none.

 930.SET=2:.HGT=4:.LEN=32:.ROW=10:.COL=0:.SPN=33: PAPER 0: BORDER 0: INK 7: CLS 
:.ATOF:.PTBL:.SET=1: FOR M=1 TO 9
 931 FOR N=1 TO 16 STEP 2
 932.COL=N:.ROW=3+N/2:.HGT=(17-N):.LEN=2*(17-N): PAPER INT (RND*6):.SETV: GO SUB
 940: NEXT N
 933 FOR N=15 TO 1 STEP -2
 934 .COL=N:.ROW=3+N/2:.HGT=(17-N):.LEN=2*(17-N): PAPER INT (RND*6):.SETV: GO SU
B 940: NEXT N
 935 NEXT M: RETURN 


++				87

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


In this screen a white Oasis logo is seen to scroll from left to right
across the screen over flashing attributes.

Line 930 places the logo (sprite 33) on the screen.
Lines 931 to 934 create a window of decreasing and then increasing dimensions.
	The PAPER colour is set to a random value while the INK colour remains
	white. A subroutine at line 940 is called each time, to scroll the
	logo using .WR1V.


THE HORIZONTAL SCROLLING GRAPH SCREEN

	Execution	variables to be set on entry.
	GOSUB 950	none.

 950 INK 7: PAPER 1: BORDER 1: BRIGHT 1: CLS :.ATOF:.ROW=3:.COL=9:.SPN=33:.PTBL
 951 LET P1=7: LET P2=4: LET L=30: LET H=7: LET R=7: LET C=0: GO SUB 2000
 952 LET P1=6: LET P2=5: LET L=22: LET H=3: LET R=19: LET C=4: GO SUB 2000: PRIN
T AT 20,5;"HORIZONTAL SCROLLING"
 955.LEN=28:.HGT=5:.ROW=8:.COL=1: LET X=92
 956 FOR M=1 TO 500: LET I=INT (RND*3)-1
 957 LET X=X+I
 958 IF X=112 THEN LET X=111
 959 IF X=71 THEN LET X=72
 960 PLOT 8,X:.SR1V: NEXT M: RETURN 

In this screen a graph appears to emerge from the left and scroll to the
right where it disappears. This is achieved by plotting on the left of the
scrolling window after every scroll operation.

Line 955 defines the window of length 28 and height 8. The original Y
	position for the pixel plotting is 92.
Lines 956 and 957 select a random number in the range -1 to 1 and this is
	added to the Y position for the plot to produce the random wavy line.
Lines 958 and 959 check that the pixel is never plotted outside the window
	that is being scrolled.
Line 960 plots the pixel and then scrolls the window using .SR1V. This
	sequence is repeated 500 times.


++				88

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE LAST JUMPING MAN SCREEN (THE CHESS BOARD)

	Execution	variables to be set on execution.
	GOSUB 970	none.

 970 INK 6: PAPER 0: BRIGHT 1: BORDER 0: CLS :.SET=7:.LEN=32:.HGT=4:.ROW=9:.COL=
0:.SET=0:.ATOF
 971 FOR Y=0 TO 16 STEP 4: FOR X=0 TO 28 STEP 4
 972.HGT=2:.LEN=2:.ROW=Y:.COL=X: PAPER 4:.SETV:.COL=X+2:.ROW=Y+2:.SETV: PAPER 1:
.HGT=1:.COL=X:.ROW=Y+2:.SETV:.COL=X+2:.ROW=Y+4:.SETV: NEXT X: NEXT Y
 973.SET=2:.HGT=4:.LEN=32:.SPN=32:.COL=5:.ROW=0:.PTBL:.COL=0:.SET=3:.ROW=4:.COL=
20:.SPN=32:.PTBL:.HGT=4:.LEN=32:.COL=0:.SET=4:.SPN=32:.ROW=16:.COL=28:.PTBL:.HGT
=4:.LEN=32:.COL=0:.SET=0
 975.ROW=20:.COL=0:.SPN=60:.ATON:.PTBL:.ATOF:.SET=0:.ROW=9: FOR I=-33 TO 32 STEP
 4:.COL=I
 976.SPN=7:.PTBL: GO SUB 980:.SPN=8:.PTBL: GO SUB 980:.SPN=9:.PTBL: GO SUB 980:.
SET=7:.SR8V: GO SUB 980:.SET=0:.SPN=10:.COL=I+2:.PTBL: GO SUB 980:: NEXT I
 977.ATON: RETURN 

In this screen the Jumping Man moves across the screen which is being
patrolled by 3 scrolling chess pieces

Lines 971 and 972 build the chequered pattern out of attributes, with their
	INK colours set to yellow and the paper colours set to CYAN, BLUE
	and BLACK.
Line 973 places the sprites on the screen and define the windows around them.
Lines 975 and 976 animate the little man calling a subroutine at line 980
	which will scroll the 3 chess pieces by swapping between the variable
	sets.

 980.SET=2:.WL1V:.SET=3:.WR1V:.SET=4:.WL1V:.SET=0: PAUSE 2: RETURN 


++				89

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


THE TORTOISE EATING THE PLANTS SCREEN

	Execution	variables to be set on entry.
	GOSUB 990	none.

 990 INK 4: PAPER 0: BORDER 0: CLS :.COL=9:.ROW=3:.SPN=60:.PTBL:.ATOF:
 991 PAPER 4:.LEN=32:.HGT=6:.ROW=12:.COL=0:.SETV
 992.SPN=4:.ROW=9: FOR N=4 TO 31 STEP 2:.COL=N:.PTBL: NEXT N
 993.ATON:.ROW=10:.SPN=1:.COL=0:.PTBL
 994 FOR N=4 TO 31 STEP 2:.ROW=9:.HGT=3:.LEN=2:.COL=N:.NPX=-1: FOR G=1 TO 24:.SC
RV: NEXT G
 995 BRIGHT 0: INK 5: PAPER 0:.SETV:.COL=N-4:.LEN=6: FOR G=1 TO 16:.WR1V: NEXT G
: NEXT N
 996 PRINT AT 8,28;"BURP": PAUSE 50: PRINT AT 8,28,"    ":.MIRV
 997.LEN=32:.ROW=9:.HGT=4:.COL=0: FOR N=1 TO 256:.SL1V: NEXT N
 998.ATON: RETURN 

In this screen the tortoise is seen to walk from left to right eating the
plants as it goes along.

Line 992 places the plants (sprite 4) on the screen.
Line 993 places the tortoise (sprite 1) on the screen.

The plant directly in front of the tortoise is scrolled down. The attributes
of the tortoise are set in front of it and the tortoise is scrolled forward
on to the next plant. This process is repeated until the tortoise has
reached the end of the screen where it is mirrored and then scrolled all the
way back.


THE TEXT WINDOW SUBROUTINE

	Execution	variables to set on entry.
	GOSUB 2000	L = the length of the window.
			H = the height of the window.
			R = ROW position.
			C = COL position.
			P2 = the paper colour of the shadow.
			P1 = the paper colour of the window.

2000 .LEN=L:.HGT=H:.ROW=R+1:.COL=C+1: PAPER P2: INK 9:.SETV
2001 .ROW=R:.COL=C: PAPER P1:.SETV
2002 LET C=C*8: LET R=175-(R*8): LET H=H*8-1: LET L=L*8-1
2003 PLOT C,R: DRAW L,0: DRAW 0,-H: DRAW -L,0: DRAW 0,H
2004 RETURN

This subroutine is used to create the coloured windows in which the titles
of the various screens are placed. The window is in fact cleared twice, the
first time with an offset of one character to the right and down to produce
the shadow effect. The colour of the shadow is defined by the variable P2.
The main window colour is defined in the variable P1.


++				90

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
