REALMS OF INTERACTION
part 3 of 5
by Alan Davis
from ZX Computing, July 1986

Part 3: Alan Davis' adventure writing series continues,
with Merlin and co. starting to pick up objects.

I want to begin this month by reminding you of a few (immortal?) words
from the first article in the series: "However we approach it, we must
create the illusion that they (the independent characters) are
behaving in a purposeful way." Note well the word "illusion" here -
because of course the whole business of creating independent
characters is really a kind of sleight-of-hand on the part of the
programmer. The key to success in this doesn't necessarily lie in the
use of incredibly sophisticated artificial intelligence techniques,
but rather in the programmer's ability to capture the imagination and
sympathy of the player.

What we need to aim for is a program which prompts the player to
believe that there is more going on "beneath the surface" than meets
the eye, and there are several ways we can approach this. For a start,
each character should at least seem to be aware of any other
characters he encounters - perhaps by chatting away to one of them
occasionally, as might happen in real life. In this way we can
periodically remind the player that the goings-on in our imaginary
world are not wholly dependent on his participation; that as far as
the inhabitants of the world are concerned he's just another
character, neither more nor less important than the rest.

Another thing we can do is to make our characters seem aware of
objects in their surroundings. For example, they should be capable of
picking up objects or discarding them of their own accord. Perhaps
they might mention their possessions in conversation; in a sensible
way. And if we can arrange for something a little out of the ordinary
to happen now and then, well so much the better.


Character building

Now if we're going to attempt this sort of thing, our program needs to
have rapid access to three essential kinds of information. It must be
possible to find out, at any time: (a) which characters are present at
the current location; (b) which objects are present; and (c) which
objects are currently being carried by any given character. Of course
you could do all this in BASIC without any difficulty, but unless
you're willing to write an adventure involving only a very small
number of characters and objects, the repeated use of all the
necessary program loops will lengthen the response time of your game
to a desperately ponderous degree. The obvious answer is to add just a
dash of machine code to deal with these three specific routines -
which brings us to the meat of this month's ramblings.

If you look back at last month's article, you'll see that in our
miniature world there are six characters (if we include Merlin - the
player-controlled character) and eight objects, whose names are stored
in sequence in two string arrays. Of course, in a full-blown adventure
you'd want more than this; it's the basic principles of the business
that we're involved with at present, and the actual number of objects
etc. is irrelevant. Our first job is to decide on some method of
storing position information for each one of these. This means storing
two numbers for each character or object, corresponding to the BASIC
variables, io and jo, that we used last month to define Merlin's
position on the map. We'll call these i and j respectively. Because
all our scanning of these data lists is going to be done from machine
code, the sensible thing to do is to store them as a sequence of bytes
above RAMTOP.


M/C routines

Listing 1 is the assembly language program which provides us with the
three routines we need. The position data for the characters begins at
the label FKLC (64831). The first two bytes give Merlin's map
coordinates (i at 64831 followed by j at 64832) and of course we'll
need to update these from BASIC as you move Merlin about when the
program is running. The next two bytes hold Timbril's map coordinates,
and so on. Incidentally, the DEFS 20 instruction simply reserves extra
space so that, if you wish, you can add more characters of your own later.

Position data for the objects starts at label OBLC (64863) and is
stored in the same way as for the characters apart from one important
difference. You'll notice that some of the numbers here are greater
than 100. These are objects which are being carried by one of the
characters. When an object is being carried, we arrange for its i
coordinate, the first byte of the pair, to be 100 + (numeric code of
character holding it). So an object carried by Merlin has an i
coordinate of 101; one carried by Timbril has i=102 and so on. Again,
I've left some spare bytes for you to add further objects if you wish.

Right, now to the routines proper. Listing 1 provides three routines
which I've called WHO, WHAT, and LIST, whose USR call addresses are
64720, 64782, and 64900 respectively. Their jobs are as follows:

WHO - this scans through the position data for the characters to find
which ones are present at Merlin's current location.

WHAT - this does the same for the objects.

LIST - this scans through the object position data and finds the
objects carried by the character whose code is held in the byte at
address 64945 (labelled CHAR in Listing 1).


Information

So, how do we extract this information from within our BASIC program?
Simple. Suppose we want to know about the characters present. If we
call the routine using LET m=USR 64720, then the variable m will hold
the number of characters present, and the numeric codes of these
characters will be found in the bytes from 64811 onwards (labelled
PRES in Listing 1). All the other routines work in the same way,
except that for the LIST routine you must first POKE 64945 (CHAR) with
the code of the character involved. Thus, POKE 64945,1: LET m=USR
64900 will give us Merlin's inventory as a sequence of "m" codes
stored in successive addresses starting at 64811 (PRES).

If you decide eventually to add a few characters or objects, then
you'll need to change the loop counter for each of the three routines,
in lines 40, 380, and 900 of Listing 1 (though it's probably best to
wait until you have the next two articles before trying this). For the
three people over there in the corner who still don't have an
assembler program, Listing 2 gives a BASIC program which will POKE the
code into memory, check it, and save it to tape.

Now we have our routines, what next? The most exciting bit comes next
month, but we can certainly find a use for them here and now. Load in
last month's auto-running BASIC module and BREAK. Then load in the new
bytes from this month and add to the program the lines of BASIC in
Listing 3. Line 9998 replaces an existing line so that you can save
the complete updated program and bytes by typing GOTO 9998.

To assist the intelligibIlity of the program, the various addresses
relating to the machine code are assigned to named variables in lines
8010/8020. (It's much more convenient to bash in a line like POKE
char,1: LET m=USR list than to have to keep looking up the numbers.)
Line 50 defines a new function which enables the program to string
together a list of objects in a coherent way before printing to the
screen. Lines 260/270 will enable you to take Merlin's inventory by
pressing the "I" key and demonstrate the use of the LIST routine.
Lines 1060/1100 add a list of characters present to the location
descriptions, and demonstrate the use of the WHO routine. Note also
the two POKEs which update the position data for Merlin as you move
him between locations. Finally, lines 1110/1160 add a list of the
objects present to the location descriptions, demonstrating the WHAT
routine in action.

Once you've typed everything in and saved it, type GOTO 8010 to get
the program running (not RUN!). If all is well, Merlin should be
carrying a staff when you give the "I" key a prod. And as you move him
about he should encounter all the other characters and an assortment
of objects lying around here and there.

Of course the other chaps still won't do anything, but now we have
everything we need. The stage is set, the cast assembled, and next
month the mayhem begins ...

