A-code vocabulary structure and handling have some unusual features,
motivated by my desire to make IF games more player-friendly and less
'mechanical' in their responses to player commands. This document deals
specifically with vocabulary handling, rather than with the more general topic
of player command parsing. See the parser
section for parsing details.
There are four specific areas in which A-code vocabulary handling is unusual. These are:
By default, all vocabulary words are automatically abbreviated to the
shortest unambiguous length. For example, if the vocabulary contains
KICK and no other word beginning with K, then KICK is automatically
abbreviable as any of K, KI and KIC. If, however, the vocabulary also
contains KILL (and no other word beginning with KI), then KICK is only
abbreviable to KIC, and KILL to KIL.
There are, of course, command words which must not be abbreviated:
this is particularly true for any magic words. E.g. we do not want X
to mean XYZZY! This is catered for in vocabulary declarations by
prefixing the non-abbreviable word with an exclamation mark:
This does not, however, eliminate all unwanted abbreviations. For
example, a player may wish to save a game under some arbitrary name,
which just happens to be a legitimate abbreviation of some vocabulary
word. Clearly, the intended name should not be expanded to the
vocabulary word in question.
This problem is solved by permitting some vocabulary verbs to be
marked as "special" in that other words in the command are
taken verbatim, as entered by the player (except for the case, which is
always normalised to lower case). For historical reasons, instead of
such special verbs being flagged individually, at present (A-code
version 12) they are grouped in one block of verb declarations:
The '-' sign preceding "first.special" and
"last.special" indicate that these are pseudo-verbs, not to be
added to the game's vocabulary. This is an extension of the same
convention in declaring object names.
To cater for any other instances in which abbreviation expansion is
not wanted, setting the mandatory STATUS variable to the built-in value
of NO.MATCH suppresses expansion for the duration of one command
cycle.
As a further wrinkle, for object names, abbreviation matching is performed
only if the object in question is either carried by the player or is in the
same location as the player. This prevents game secrets being inadvertently
revealed by being too generous in interpreting player's command.
See the section on command
parsing for an explanation of A-code's response to ambiguous
abbreviations.
Approximate matching
My typing is terrible. From seeing many player logs I know that I am
not alone in this. That's why by default A-code enables automatic
approximate matching of words entered by the player against words in the
game's vocabulary. This feature is activated by the game declaring a text
named TYPO, the assumed purpose of which is to report typo matching. This is
necessary because otherwise typo correction can look distinctly baffling
to players.
If a single typo is sufficient to transform an
unknown word type by the player into a unique, non-abbreviated
match in the vocabulary, that match is accepted as the
player's command word. Here by a typo I mean a single character dropped,
a single character interpolated, a single character substituted by
another character or two adjacent characters swapped around. Thus, for
example GET BOTTEL will be understood as GET BOTTLE.
Note, however, that approximate matching is attempted instead of, rather
than in addition to unique abbreviation matching, if no unique abbreviation is
found. Thus if BOTT is a unique abbreviation of BOTTLE, then GET BOTT will be
understood, but GET BORT will not. That's because BORT differs from BOTTLE by
three typos rather than one: mistyped R instead of T and two missing letters L
and E at the end.
Clearly enough, the same problems arise here as with abbreviation
matching. These are dealt with by the same mechanisms. No approximate
matching in the following circumstances:
- word declared as non-abbreviable
- word accompanies a verb declared as "special"
- word refers to an object not yet seen by the player
- the STATUS variable is set to NO.MATCH or NO.AMATCH (duration one
command cycle)
See the section on command
parsing for a detailed explanation of A-code's responses to
approximately matched commands.
Synonyms and sub-synonyms
Traditionally, IF game vocabulary is a 2D structure, consisting of
list of lists of synonyms. Thus, for example, using A-code notation
verb get, take
verb drop, release
declares two vocabulary terms, both of which are denoted by two
synonymous words. From version 10, A-code adds a third dimension: any
individual word in the traditional structure may be associated with a
list of sub-synonyms. For example, in Adv770 the full definitions of
get and drop are as follows:
verb get, =g, =reach, carry, take, =t, pickup, keep, hold, catch,
grab, =grip, clutch, steal, capture, tote, scoop
verb drop, =dr, =discard, =fall, =abandon, free, =release, =let
The '=' sign preceding a word indicates that word to be a sub-synonym
of the last preceding word not prefixed with '='. So G and REACH are
sub-synonyms of GET, but CARRY is not.
This additional vocabulary structure is motivated by my preference
for responding to player commands rather more explicitly than is
traditionally the case. Thus instead of the standard and rather
mechanical "Taken." in response to GET CAGE, I like the game
to respond with "You get the cage.". But there is a very
obvious snag to this: G CAG should not result in "You g the
cag."
While the expansion of "cag" to "cage" is handled
by the abbreviation processing feature of the parser, "g" is
declared explicitly as a vocabulary word, so does not get expanded as an
abbreviation. If there were no other verbs beginning with g, it would
not be necessary to include "g" as a verb synonym – the
abbreviation processor would do the expanding, but that's not a
realistic solution. Hence the declaration of "g" as a
sub-synonym of "get", which instructs the A-code engine to
echo the latter if the command verb is to be echoed.
Vocabulary listing
To my mind, one of the most irritating features of many IF games is the need
to guess what words may or may not be present in the game's vocabulary. A-code
offers an intelligent way of making the vocabulary listing available to
players, without revealing things players should not as yet know about. This
is achieved by the minor directive VOCAB, which is a kind-of fancy wrapper
around the SAY directive. The full syntax of the directive is as follows:
VOCAB {<OBJECT>|<PLACE>|<WORD>} [, {<PLACE>}] [,
{<FLAG>}] [, {<TEXT>}]
The first argument is the vocabulary word to be conditionally included in a
vocabulary listing. The optional second and the third arguments specify
conditions under which the word is to be included. The fourth argument, also
optional, specifies the text to be shown instead of the word given by the 1st
argument. Each vocabulary word shown to the player is prefixed with a comma
followed by a space. A special form of the directive
VOCAB [<TEXT>]
is used to signal the start of a sequence of VOCAB directives. It can
optionally display a text, but its main purpose is to suppress the
comma-and-space lead of the following vocabulary list.
As an example, here are some VOCAB commands from Adv770
- vocab voc.lead
- A special form, signalling the beginning of a vocabulary
listing in order to suppress the leading comma before the first word
to be shown; in this example a text name is given as an argument, so
the voc.lead message will be also displayed.
- vocab axe
- The word axe is shown unconditionally.
- vocab alarm, seen
- The word alarm is shown if the
seen bit of the alarm object is set.
- vocab bones, bones.room, been.here
- The word bones is shown if
the player has been at the bones.room location.
- vocab eggs, seen, eggs.voc
- The text eggs.voc (in this case "eggs (nest)")
is shown if the object eggs has been seen.