 Magazine: Ahoy!
 Issue No.: 55
 Date: July 1988
 Pages: 13-14
 Transcribed by Patrick Kellum <patrick@ygw.bohemianweb.com>

                           --------------------------

                        PROGRAMMING YOUR OWN TEXT GAMES

                         Part II of III: Think Modules

                           By Cleveland M. Blakemore

    Ingenuity lies not in further complicating definitions and concepts, but in
reducing the number of contradictions and terms to the fewest possible true
sets.  Any given system design must begin with the sum of its parts, and then
define these parts.

 This is the essential theory behind "black box" system design, or modular
programming.  We begin by describing what we want the system to do, then
breaking this down into the necessary steps to accomplish it.  Whether you are
pursuing a personal goal or creating a computer program, you will find that this
approach is always the most effective.

 Last month we published a short text adventure called Lost Dutchman's Mine. 
In this installment we will examine this program in detail and demonstrate how a
series of modules (or subroutines) can be tied together into one cohesive system
that is greater than the sum of its parts.  None of the routines by themselves
would constitute a game - but working in tandem, they create an interactive
adventure.

 If we wanted to describe the player's purpose in Lost Dutchman's Mine in one
sentence, we could say:

 "To move around within a network of locations, collect various objects,
return them to a specific location, and win the game."

 This is the simplest way to define the program's operation.  In last month's
column, I advised designing your adventure on three seperate pieces of paper
before touching the keyboard.  Page one of my scenario for Lost Dutchman's Mine
read like this:

 "The object of the game is to wander around within a series of caves,
collecting up three treasures as you go.  When you have all three objects, you
return them to a specific base location, drop them, and win the game."

 On page two I listed the obstacles I wanted to hamper the player's efforts:

 "1. A timber woolf guards the entrance to a burial mound where one of the
treasures is buried.  The player must find the gun and bullets to kill the wolf.

 "2. A secret word is required to pass from the base location to the caverns.
(Kind of like PLUGH in Colossal Caves.)  The secret word is written inside a
matchbook cover. 

    "3. A whistling spirit guards the entrance to the caverns.
The player must blow on an empty 7-UP bottle to scare the spirit away.

 "4. The burial mound is submerged under water.  The player must find and
open a reservoir lock through which the mound room can be drained.

 "5. A shovel is needed to dig up the third treasure (Dutchman's nugget).

 "6. The player must also light a torch, drop enough equipment to fit through
a narrow crack, and escape from the room after he opens the reservoir lock."

 You may have noticed that a lot of these ideas are taken from other
adventure games, many of them classic puzzles.  I wanted them to be familiar
enough that the game could be solved without too much trouble.  I could just as
easily have made the game much harder.

 On the third and final page, I drew a map detailing all nine locations in
the game, complete with references to the objects that would be found there, and
the puzzles specific to those spots.

 Using the modular approach, I broke the program down into seven discrete
boxes.

 * Initialize arrays and variables
 * Read in data
 * Get command
 * Find verb in command
 * Find noun in command (if any)
 * GOSUB to appropriate subroutine pertaining to verb
 * Data lines

 Modules 3, 4, and 5 could all be considered part of the parser, the routine
that gets and analyzes player input.  I define them seperately here to make
clear what goes on inside the routine.

 The first thing I typed in, as always, were lines 1530-1610.  These lines
contain descriptions of the nine locations in the game.  I immediately followed
with comments to accompany each, in lines 1630-1670.  These commonts are
specific observations in each location.  For example, the gas station has a
"metal plaque above a glass shelf."

    Then, using the third page of my notes (the map) as a guide, I typed in the
data for an array of nine dimensions, each dimension having six elements.  This
dimension will be known as D(9,6).  The six elements consist of the directions
North, South, East, West, Up, and Down. This is a numerical array, and the
number in each element indicates the location to which that direction connects.
Any non-zero number is a pathway; otherwise there is no exit in that direction.
I did not type in directions for the gas station, because it is only accessible
by use of the formentioned "magic word."

 In the fashion of any sensible hacker, I jumped to lines 120 through 210 and
designed a data loader.  Once I made sure that the arrays were dimensioned
properly in line 120, I read them in a couple times in lines 190 and 210 just to
make sure everything was going smoothly before I continued.  This type-n-run
approach is the hacking method, and it works.  Trust me.

 Now for the tough part.  I had to figure out all the verbs and nouns that
would be needed for the parser's vocabulary.  In lines 1800-1850 I tried to give
the program a reasonable dictionary of words to work with for player input.  An
advanced parser would recognize far, far more then this simple collection of
words.

 Again, I skipped back to the beginning and made sure these strings loaded in
correctly before going on.

 Lines 1870 through 1900 are detailed descriptions of the objects that can be
carried in the player's inventory.  Although an object might be referenced by
the parser as "diamo," it will be described on the screen as a "glowing
diamond."  This gives character and atmosphere to the adventure.

 Line 1920 is a list of numbers that tells the program where to place objects
initially.  The first number indicates the location, the second is the object
number itself in the inventory.The -1, -1 at the end of the line signals the end
of the data.

 Lines 1940-1970 are end of game messages, for when the player is killed or
is victorious.  If the player is killed, these lines help tell him where he made
his mistake.

 With this, I completed the data lines, the major stumbling block of any
adventure game.  Although I made many changes afterwards and altered these lines
considerably before finishing, these lines gave me something to work with, the
meat of the text adventure.The remaining program portions manipulate the data
loaded in from here in many ways, but it is in these lines that the game gets
its substance.

 Important variables to be defined are CL(Current Location) and the arrays
O(9,8) and I(8).  The former is an array that tells what objects are in what
rooms, and the latter is the player's inventory array.I(8) refers directly to
the eight objects listed in line 1840, the objects in the game which can be
carried.  Any non-zero number in element I(1), for example, would indicate that
the player is carrying the torch.  However, a -1 would mean the torch is
burning, while a 1 would mean it is out.  I also set up meaningful flag names in
line 150.  These flags indicate the status of certain items.

 In lines 340-540, I fleshed out the parser routines.First the directions,
then once the program is recognizing them correctly and responding, I introduce
the other verbs.  It is better to make sure that all directions are functiong
correctly first before continuing, because a flaw that shows up later might take
a lot of work to repair.Make certain that the directions in the game correspond
indentically to your map.  It is very common to make errors here.  I often get
East and West mixed up while typing them in.

 Line 340 gets the player's input.  If he enters nothing, the program checks
again.  Line 370 checks for a single character input (either a direction or the
letter "i" for inventory) and acts accordingly.  Since the six compass
directions match up with the six single character commands perfectly, I just
reduced any of these terms to a number between 1 and 6, subtracting 7 if
necessary.  I can then use this number to reference the corresponding element in
direction array D(9,6).  Once a match is found for the verb, the number is
placed in the variable V.

 The verb is the important part.  We use the verb to jump to the subroutine
that designates the action, so we must have a verb.  The noun, on the other
hand, is not always necessary for many actions, and so our parser only looks for
it.  If it finds one, it places the number of the noun into the variable Nbefore
branching off to our routine.  The subroutine can then check this variable to
see if the player is referencing the correct object.For example, if the player
gives the command to dig, we check the variable N to determine whether or not he
wants to dig in any particular spot, as in DIG MOUND.  If N=0, we simply print a
standardized message that reads "YOU DIG FOR A WHILE BUT YOU DON'T FIND
ANYTHING."

 After the parser has both these variables, V  and N, assigned with values,
it drops through to lines 570-580, the branches.  These lines will steer the
program flow into the correct verb actions that alter program variables and the
game environment.

 These lines run from 700-1520, accomplishing every possible action that the
player is permitted to take in our adventure.If you study them carefully, the
variables are self-explanatory and it should be readily apparent that they act
on values to change location inventory, specific flags (mound full-empty, wolf
dead-alive, etc.), and print messages for the player's benefit.

 After program flow returns from these subroutines, the main parser program
executes a series of critical checks in lines 600-690.  These flags count
elapsed time in the current location and check on the player's status relative
to certain non-player characters and events.  For example, if the player is in
room 4 for more than four turns with the spirit, he is going to get it good. 
The same goes for being in a river full of water too long or beside a hungry
wolf.

 The check for a win is in line 600.  This line checks if a variable called
WINGAME has been set yet by the drop subroutine.  If the player drops all three
treasures in location zero, this flag will be set upon returning from the
routine, telling the main program that the player has succeeded.

 With as little work as all this, an adventure game was born.  We have a
full-fledged story, with a plot, characters, and suspense.  Next month, we'll go
over the specifics of the way the parser functions, and methods we could use to
upgrade the routine so that it could recognize complete sentences.

 Until then, remember - stop wrestling with the program as a whole and break
it down into modules.  You cannot move mountains unless you do it one bucket of
dirt at a time!

EOF
