home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Unsorted BBS Collection
/
thegreatunsorted.tar
/
thegreatunsorted
/
misc
/
part3.doc
< prev
next >
Wrap
Text File
|
1985-11-16
|
22KB
|
429 lines
3-1
The Generic Adventure Game System
Copyright 1985 by Mark J. Welch 415-564-1066 (voice)
415-664-2811 (modem)
The GAGS source code (briefly explained, not included)
--------------------
[ The GAGS source code is available to registered users of GAGS
for $25; source code purchasers must also sign an agreement not
to distribute or share the source code. For information,
contact Mark J. Welch, P.O.Box 2409, SF, CA 94126.]
The Generic Adventure Game System is broken into fourteen
"modules," each structured as a Turbo Pascal "include" file.
Initially, the entire program was in one source code file. The
tremendous size of the parser led to its being broken out as a
separate module. Soon, other groups of procedures were also
removed from the main program file so that I could edit and print
smaller pieces at a time, and so that Turbo could handle the
files (Turbo Pascal can only process files up to 64K).
As my Programming Methodology professor pointed out four
years ago, it is also much easier to track down bugs when you
only modify one module at a time. Naturally, I should've started
the project by defining the separate modules, and I should have
drawn out pseudo-code, so that the program was better structured.
These bad habits might explain the 'C' I got in that class....
The twelve modules are:
-- the parser (PARSE.MOD);
-- the execution module (EXECUTE.MOD) which interprets the
user's parsed command line, with three sub-modules EXECSUBS.MOD,
SPECIALS.MOD, and SAVEREST.MOD;
-- the initialization module (INIT.MOD), which zeros out all
the arrays and reads the data file;
-- the declaration module (DECLARE.MOD), which contains all the
global type, constant, and variable declarations;
-- a command-line parameter checking module (PARAM.MOD);
-- a title-printing module (TITLE.MOD) which also contains
several useful tools;
-- a creature-animation module (ANIMATE.MOD), which executes
any actions creatures take (i.e. attacking the player);
-- two tools modules (GENTOOLS.MOD and SPCTOOLS.MOD) which contain
procedures and functions used by more than one other module;
-- a module to describe and list the player's location
information (DESCRIBE.MOD);
-- and the main program (ADVENT.PAS) which INCLUDEs the other
modules.
3-2
Summary:
The parser is quite straightforward: it takes a command line
string, and breaks it into words; it massages the words, tries to
eliminate unimportant words, throws away adjectives if they match
following nouns, and locate from one to four important sentence
elements: a verb, a noun, a preposition, and an object of the
preposition. These are passed back to the main program.
The main program immediately 'executes' the user's
deciphered command (unless a syntax error was discovered in the
parser); the execute module simply decides which verb was used
and calls the procedure appropriate to that verb or class of
verbs.
Whenever a change is made to the program, several modules
must usually be changed. For example, to add a new field to nouns
(say, 'NUKEABLE'), the declaration of the nouns record must be
changed to add the field; the initialization procedure must
assign it a default value ('true'?) and must also check to see if
the noun declaration in the data file changes its 'default'
value; and any appropriate changes must also be made to the
execute module. In this case, the logical intent would be to also
add a verb 'NUKE' and of course also add a procedure in the
execute module called 'nuke' with a parameter of what noun to
destroy. That verb would have to be added in the initialization
module (INIT_VERBS procedure) so the parser recognizes it; and an
appropriate check would be made in the nuke procedure to see if
conditions are met. Nuke might activate a special, which means
the nuke procedure would call the 'special' procedure if the
proper conditions are met.
3-3
GAGS - A Generic Adventure Game System
Copyright 1985 by Mark Welch
--------------------------
In More Detail: The Parser
--------------------------
Definition: The PARSER examines each word in an input sentence
to determine whether it is a valid part of speech in the context of
other words in the sentence.
Background:
In some software, the input is quite fixed. In spreadsheets or
word processors, for example, a fixed list of commands are
available, and no general flexibility is permitted (although
multiple ways might be offered to accomplish the same task).
In some early adventure games, two-word commands were the
limit. "TAKE BOOK" was the way you picked up a book. Sometimes
synonyms were offered ("GET", for example). More complex sentences
were sometimes permitted ("THROW AXE AT DWARF"), but it's a much
easier programming task if the syntax is fixed. For this last
reason, the word "the" was a latecomer to adventure games.
Of course, what you really want is a way to say "Take the
small red key from the second dwarf and put it in the blue box
under the rug" and have the program figure out what you want. GAGS
can't do that, for several reasons. It can, however, accept some
fairly long sentences and concepts more complex than "THROW AXE."
One acquaintance suggested that a really good adventure game
should understand a sentence like "Dive under the fallen branch and
roll to the left, grabbing the laser pistol as you rise, and sever
the dwarf's leg by ricocheting a laser shot off of the pickup's
mirror." I'll leave that as an exercise to the reader.
What does a parser need to do?
A parser breaks up a sentence into parts of speech. Let's
think about that for a minute, using the previous sentence as an
example.
"A parser breaks up a sentence into parts of speech."
/ | | | | |
article/ subject^ ^verb ^object ^prep ^obj.of prep
Instantly, most people can recognize the subject and the verb.
"Parser" is the noun, and "breaks up" is the verb. Or is "breaks"
the verb? "Up" is a preposition...but here it's an adverb. Gee, the
English language is complicated.
Already we have a problem: some words can serve as multiple
parts of speech and can only be parsed by checking context. There
are rules to English, but they're complex and filled with
exceptions. Many programmers are working hard to develop "Natural
Language Interfaces" to computers, so people can get computers to
perform complex tasks without having to know how to program a
computer. Very few of those "natural language interfaces" can
accept a complex sentence, and most -- like GAGS' parser -- limit
their knowledge to a certain task so context problems are reduced
and the rules can be made more limited.
(continued)
3-4
(the parser, continued)
In writing this game, I wasn't interested in AI or complex English
or anything like that. I just wanted to allow people to enter
understandable sentences, like "put the red key with the blue globe." How
to do that?
I cheated, to start. The first thing my parser does is strip
out extraneous words, words that always (I hope) add no real
meaning to a sentence. "The" and "a" are removed. So is "go", since
that has no meaning unless it's followed by a direction. GAGS wants
a verb to come first in the sentence, and will choke if there isn't
one.
GAGS' Parser
------------
The Parse procedure first breaks the sentence up into words
(an array of strings), arbitrarily counting any non-alphabetic
character as a word separator. (Actually, the real check is for
ASCII characters from 'A'..'z'.)
It then strips out any words which are "extras." A strange
effect is that no check is made to see if the sentence really made
sense before it was "stripped" of extra words. The sentence
"The Put the the red the gun the in the the the wooden the bookcase"
becomes
"Put red gun in wooden bookcase."
The parser then immediately begins scanning the sentence,
left-to-right. The first word must be a verb now. If it is, the
program moves on to the next word (or exits when it finds no more
words). The program expect the second word to be a noun. If it's
not a noun, it checks to see if it is an adjective with a noun
following it. If neither is true, it checks the possibility that
the second word might just be a preposition ("Look in bookcase").
If the second word wasn't a preposition, the third word is checked
as a preposition. The following word(s) is/are again checked as a
noun or an adjective-noun pair.
A more "correct" parser could check for a verb, and then check
to make sure that any articles ("the" or "a") are positioned
properly with nouns, and that words like "please" or "now" are
located logically.
Four strings are returned from the parser: a verb, a noun, a
preposition, and another noun as the object of the preposition.
Also, if any error was discovered (a word not recognized, or a
missing verb), a boolean variable 'syntax_error' is set to 'true.'
3-5
GAGS - A Generic Adventure Game System
Copyright 1985 by Mark Welch
---------------------------------
Possible Source Code Enhancements
---------------------------------
Modifying the Source Code: Some Suggestions
-------------------------------------------
There are probably an infinite number of ways you can modify
the source code to GAGS to make it a more enjoyable game. In many
ways, my original coding was too simple to permit a full-featured
game. Changes to the game range from relatively simple and painless
additions to some extremely complex modifications which could mean
rewriting huge portions of the code. In fact, I'm open-minded
enough to realize that some efforts would involve rewriting the
entire game or starting from scratch.
Enlarging the Game
------------------
As shipped, GAGS can handle up to 200 rooms, 100 creatures, and
100 objects. These limits permit the game to run snugly in a 192K
IBM PC, or quite comfortably in a 256K system. If you have more
memory than that, you might want to expand these limits. All the
changes would be in the declaration module (DECLARE.MOD), where
you'd need to simply re-define the first and last numbers of each
range (creatures, rooms, and nouns).
"On-Line Help"
--------------
One verb you might want to add is "help." A help procedure might
do one of several things: it might simply read in a file and
display it on the screen; it might prompt for the user's specific
help question (or you might patch the parser so the user could
type "help scream" or whatever); or it might try to offer
context-sensitive help ("The reason you can't go north is that
the banshee blocks your way. Banshees often let you pass if you
give them yogurt").
Specials
--------
Although several methods of invoking "specials" have been
provided, you might want to add more by defining new verbs to
activate them. Or, you might modify the "Take" procedure to
invoke a special; this would involve a fairly aggressive
rewriting of that procedure. You might want to modify the
procedures in which a creature is killed to search for text to
display, rather than the stock "creature is killed" message; you
might even want to leave a dead body in the room after a creature
is killed. Keying user-defined verbs to specials would be ideal.
(continued)
3-6
(Enhancing GAGS, continued)
Adding Verbs
------------
Probably the simplest thing to do is add a verb to the game. In
the latter stages of development, I was able to add new verbs in
about ten minutes, plus the time it took to write a procedure to
execute the verb's desired actions. Adding a verb was designed to
be the easiest task because I started the game with one verb
("Look") and added new verbs at the rate of about one per night
of development and debugging.
To add a verb, you must modify the Init_Verbs procedure so
that the parser recognizes it as a valid verb, and you must add
the new verb to the multiple if..then..else statement in the
Execute procedure so that Execute performs the action you desire
from the verb's invocation.
If you want to add synonyms, this involves merely calling
whatever procedure already exists. If you want to create a new
procedure, you have Execute call it and then write the procedure.
I added the "Scream" procedure in this way in a total of fifteen
minutes, and then created two synonyms ("shriek" and "shout") in
five more minutes. Of course, the Scream procedure doesn't do
anything to modify variables; more complex procedures will
involve some fairly complex actions and testing. When you write a
new procedure, you'll usually want to test to see if the desired
action can be performed, and whether the things being acted upon
are present.
Two verbs called for by several beta-testers but not
implemented are "shoot" and "fire," which would be useful in
games with guns.
Multiple Nouns with the Same Name
---------------------------------
One thing Infocom adventures provide are multiple nouns with the
same name, like "brass key" and "bronze key." While GAGS
currently doesn't provide this, it wouldn't be too difficult to
modify it to do so. The parser would pass along the noun, but the
Noun_Number procudure currently returns only the number of the
first noun with the specified name. You could have Noun_Number
check to see if the adjective matches (which would involve having
the parser return the adjective along with the noun, verb,
preposition, and object) and resolve unanswered ambiguities by
asking, "Which <noun> do you mean, the <first_adj> one or the
<second_adj> one?"
Alternately, the parser could be left to resolve the
ambiguity and could then return a noun NUMBER instead of the
actual noun name. This last approach could also save some
processor time since the noun's number is accessed during both
the Is_Noun and the Noun_Number functions. Of course, returning a
noun number instead of a name would require a major rewrite of
the program.
(continued)
3-7
(Enhancing GAGS, continued)
Creature Animation
------------------
With a fairly small effort, creatures in the game could be
"animated" -- that is, made to move from room to room within the
game. This involves modifying the ANIMATE module by adding new
procudure(s) and making calls to them from the animate procedure.
The procedure could check a new field in the creature record and
thus decide what sort of motion is called for (none, random, or
intelligent). It might merely have the creature follow the player
once encountered, or might invoke random behavior. Perhaps
creatures could pick up items the player has discarded (or thrown
at the creatures), and even use them as weapons against the
player or as tools to their own goals. There are some fascinating
possibilities here.
Turn/Time Sensitivity
---------------------
In the same manner -- a module executed from the main program --
the game could support time or number-of-turn sensitivity. For
example, the game might seal off an area of the game after a
certain time, and trap the player inside (or outside). Or a
creature might be added to the game after a certain time period.
Perhaps the player could be chased more aggressively by creatures
as time passes, or even chased at a rate commensurate (sp?) with
his or her skill level, so experienced adventurers who breeze
through many rooms quickly are instantly set upon by all the
beasts available. The player might also collapse from hunger if
s/he hasn't eaten food in a certain number of turns. Again, the
limits for this addition are virtually limitless, but all require
some modification of several procedures.
Adding Verbs in Data Files (User-defined verbs)
--------------------------
When I first began designing GAGS, I had hoped to allow new verbs
and their actions to be defined in the data file, so that anyone
could add new verbs. I decided that although the idea was
conceptually sound, the difficulty of the task made it not worth
the advantage. Additionally, an additional level of game design
complexity would be added.
I think that permitting "special" verbs to be defined in data
files is still a possibility, and though not at all a simple
task, it would not be a lifelong effort. Essentially, my approach
would be to add a new "special" procedure -- or more than one --
but leave the verb names undefined. Then, when the data file was
read in, the verb names could be plugged into place and tested
against. If the specified conditions of the special were in
place, and the verb was typed, a standard "special" could be
executed.
3-8
Attempts to reduce the size of GAGS
===================================
The program already makes extensive use of overlay files,
due to Turbo Pascal's 64K code segment limit. I noticed only
about a 5-second slowdown in the game's initialization when I
began using overlays. Since the total of the .COM file and the
overlay files is about 75K, it's probably relatively simple to
reduce the code size to under 64K and avoid the use of overlays,
but I don't find a pressing need and prefer not to worry about
the RAM needed by each feature I add.
Rough minimum size: 59K
-----------------------
Before GAGS grew to its present size, in an effort to further
reduce the RAM needed, I tried adding more overlays in several
areas. First, the main modules (execute, the two initialize
procedures, title, and the parser) were overlaid. This, of
course, means a disk access every turn since the parser and
execute procedures alternate. Then I overlaid as many of the
EXECSUBS procedures as possible, breaking them into two or three
overlays to avoid some disk swapping.
I then reduced the size of the arrays: to 10 creatures, 25
nouns, and 70 rooms. This reduced the program's reported maximum
heap size to 64K exactly.
I then installed my machine as a 128K IBM PC, and attempted to
run the object file with varying amounts of memory allocated to a
print buffer (in 1K increments).
The program, as quickly overlaid and compressed, will execute
with a 43K print buffer installed, or in 85K of RAM. The
operating system reserves 26K of the 85K; the program itself,
with its data areas and such, thus takes up 59K.
The main program .COM file was under 20K, as distinct from the
51K file generated without use of overlays. However, even with
all the overlays above, the standard 200-room/100-creature/100-
noun data would not fit in 128K, so there are no real savings
except possible space reserved for other resident programs in a
192K machine.
These size figures were obtained before a number of GAGS'
functions were added or enhanced; GAGS is probably about 10-20%
larger now than it was then. Reducing GAGS to run in a 64K CP/M
system is almost impossible, and would certainly involve too much
performance degradation to be worth the effort.