A brief summary of A-code, version 12
A-code is the adventure-writing language developed by Dave Platt for the
adv550 superset of the original Adventure, and subsequently developed by
Mike Arnautov, in working on the adv660 superset and later on the adv770
one.
Contents
Introduction
A-code is not intended to be a general purpose programming language and its
strengths lie in being tailored specifically for programming purely
text-based interactive fiction games. Each game created with the A-code
system is a stand-alone package, requiring no separate game
engine/interpreter. As an added bonus, with a little care it is possible to
ensure that any game saves are
upward compatible and thus can be used even
after the game has been modified/extended (a feature of particular use in
beta-testing!).
The current implementation of the language has only been used for writing
extensions of the original Adventure, and hence its parser is limited to
dealing with commands which can be reduced to (a series of) verb/noun
commands. (See the section on the
current A-code parser.)
On the positive side, that implementation is sufficiently UTF8 compliant
to allows games to be written in some languages and character sets other than
English/Latin.
Technically, A-code is a Polish notation (i.e. "prefix", or "operator
[argument [...]]") language, so its statements take the form of, e.g.
"set door, oiled".
The original version by Dave Platt was organised
as a "munger", translating A-code source into tokenised pseudo-binary, and an
interpreter, interpreting the pseudo-binary at run time. This was an
economical arrangement, but as versions grew in size, its performance on a
multi-user machine gradually became less satisfactory. (We are talking mid-80s
here! :-))
This is why the current implementation of A-code takes a different route. It
consists of an A-code to C translator (".acd -> .c" or just acdc!) and a C
kernel which gets compiled and loaded with the translated code. The overall
size of the program is larger, but the performance is very much better.
Now that computer speeds have increased dramatically, it would probably
make sense to replace this translation-based implementation with a virtual
machine, akin to Platt's original implementation.
A-code style and version numbering
The current version of A-code departs in some significant ways from Platt's
original version of the language, but maintains full backward compatibility
with it. This is achieved by an optional explicit declaration via the STYLE
directive of the major version number of A-code being use by game source. The
significance of the major A-code version in save game compatibility.
- Style 1 is Dave Platt's original A-code of Adv550
- Style 2 is Make Goetz's slightly different A-code of Adv580
- Styles 3 to 9 were development stages of Mike Arnautov's Adv660
- Style 10 is the A-code version of the finalised code of Adv660
- Style 11 was for a while the A-code of Mike Arnautov's Adv770, until
save game compatibility got broken by some technical developments.
- Style 12 is the current A-code of Adv770
If not explicitly declared, the default style is assumed to be the
currently highest one supported by the A-code engine being used.
A note on conventions and notation
All A-code documentation uses the following notation:
- A-code statements are case insensitive. This documentation uses upper case
except when providing code snippets – that is just to make such statements
to stand out against other text.
- A-code lexical elements (tokens) are separated by spaces and/or commas. By
convention, the operator (the first token) is separated from its arguments
simply by a space (or several spaces), while its arguments are separated by
commas followed by a space (or spaces). E.g. "APPORT BOTTLE,
YLEM".
- Angled brackets (< and >) are used to denote a generic name or
value, to be substituted for as appropriate. Thus, e.g., "SET
<varname>, <value>" is a generic form of statements such as,
e.g., "SET COUNT, 1".
- Square brackets ([ and ]) are used to indicate optional arguments. For
example "LOCAL <varname1> [, <varname2> [...]]
"
indicates that more than one local variable can be declared in a single LOCAL
statement.
- Ellipsis ([...] or just ...) as in the above example, is used to show that
the preceding element can be repeated.
- Curly brackets ({ and }) are
used to denote mandatory items permitting some alternatives, such as "SET
<entity>, {<entity2>|<state>|<constant>}".
- The word "entity" is used as a collective noun for any
declared elements, which are not mere synonyms for numerical constants.
Source file naming.
All A-code source file must have the mandatory suffix .acd. However,
in using A-code tools or when using the A-code INCLUDE directive to
include another source file, this suffix may be omitted – it will be
automatically added by the software.
A-code program structure.
At the highest conceptual level, an A-code program falls into four
distinct parts:
- Header statements giving game information, (optional)
- Declarations of game-specific constants, entities and procedures (also
optional)
- Code to be executed once, on game's invocation (mandatory, but may be
empty)
- The main code loop, usually prompting the player for commands, and
processing those commands (mandatory)
Thus the simplest A-code program looks like this:
init # There is actually no initial code
repeat # Main loop...
stop # ... consisting simply of the instruction to terminate the game
And here is the obligatory Hello World code:
init
say "Hello world!"
repeat
stop
In practice it is often convenient to have more than one INIT and REPEAT
sections, which are executed in the order of their declaration.
Major (or declarative) directives fall into three categories: header ones,
translator directives (or pragmas) and entity declarations. With a single
exception, they can occur in any order. All major A-code directives
(translator instructions and declarators) must start in column one. All other
lines of A-code source must be offset from the beginning of the line by one or
more tabs or spaces.
Other source lines are either parts of declaration, or lines of code. The
latter have the form of a minor directive (a.k.a. opcode), possibly followed
by some arguments. Code line tokens are separated by commas and/or spaces. The
convention of using comma-space separators is not mandatory.
A-code lexical items
A-code lexical items fall into three categories:
- Major directives (or opcodes)
- Minor directives (or opcodes)
- Ad hoc modifiers to minor directives
Major directives come in three flavours:
- Header statements describing game name, author, date etc...
- Pragmas, which affect the way the game source is treated by any software
processing it (e.g. an instruction to include a separate source file in place
of the INCLUDE pragma).
- Declarations of game elements, such as location, objects, procedures
etc. Forward declarations are allowed! That is, a game entity may be
referenced before it is declared.
Minor directives are, with one exception (the LOCAL opcode, declaring local
variables of a procedure) instructions for performing some action
(e.g. SET STATUS, 1) and are used to write A-code procedures.
Types of declared elements
Elements manipulated by A-code are variables, objects, places, texts,
words, procedures, flags, states and constants. All declared elements are
global in scope, except for local variables and procedure arguments, both of
which are local to the relevant procedure.
Some elements (specifically flags, states and constants) are merely
synonyms for integer values. Procedures (or procs) are a category of their
own. All other elements are entities in their own rights and are referred to
collectively as entities in this document.
In its current implementation, A-code makes no distinction between
vocabulary verbs and nouns, allowing e.g. "cage" to be treated as
either, depending on context. However, the basic form of a player command
is verb optionally followed by a noun. Thus in the context of parsing
player commands "verb" and "noun" will be used, referring
respectively to the first and second words of player command.
Any source line, which is not a part of a text or a place.object
description is considered to be terminated by a hash (#) sign. Thus # can be
used to provide comments, including in-line comments. (This convention holds
for A-code version 10 and higher -- earlier versions had different convention
for comments.)
Declared element names are subject to these rules:
- All names are case-independent.
- Names may not contain blanks or other "white space" characters
(such as tab, end-of-line etc.).
- Unless UTF8 encoding is being used, all names must start with an alpha
character, a dot or a question mark.
- Unless UTF8 encoding is being used, The rest of the name characters may
be any of: an alpha character, a digit, dot (.), dash (-), underscore (_)
shriek (!), single
quote ('), ampersand (&) and forward slash (/).
All declared (or automatically declared) elements other than
states, flags or constants are automatically assigned a "reference
number", or refno for short. You do not need to worry about
specific refnos, but it is useful to understand that (a) they exist and (b)
how they are assigned.
Refnos are assigned separately for each type of entity, consecutively in
the order in which elements are declared in the source code. Thus e.g.
objects will have consecutive refno value, even if their declaration is
interspersed with declarations of other entities. Refnos can be
thought of as "addresses" of relevant entities and, indeed, can be
used as such.
Unlike other entities, texts can be declared nameless. Such texts can be
accessed and manipulated via refno offsets from the nearest preceding named
text. (Note, however, that this feature is deprecated in favour of using text
switches.) In-line texts are also permitted. See the A-code texts description later in this
document.
Entities other than vocabulary words also have attributes other than their
assigned refnos. They have a value (a short integer) and a bit-screen
of binary flags. Objects, places and texts have further attributes
appropriate to their type. These will be covered when describing declarations
of such entities.
All entity values are automatically initialised to zero and all flags are
automatically set to false on program start-up.
Places and vocabulary words can have (and generally do) have procedures
associated with them via the AT and ACTION major directives (see below).
Flags
Flags are binary yes/no properties (bits in entity bitscreen), referred to
by symbolic names. A flag's value is simply a bit-screen offset. There are
three separate categories of flags. One is defined for objects, one for places
and one for variables. Each entity has its own instance of the
appropriate kind of a flag set. There are no limits on the number of flags in
a flag set.
Even within a given set, each individual flag can have several different
names, allowing for the greater legibility of the source. Since alternative
names are usually required for variable flags, several different variable flag
sets can be defined (as opposed to only one for each the object and the place
flag sets). The actual variable flag set is simply the biggest of these, with
individual flags having synonymous names as defined in different set
definitions. Don't worry if this makes little sense - it will eventually.
Constants
A-code constants come in several flavours, but fall into two simple types:
numerical (integer values only) and symbolic. Where a integer value has been
given a symbolic name, this can be used interchangeably with the actual value
it names.
The various constant flavours are:
- Numerical integer values (signed short integers)
- Symbolic names of such values, declared as CONSTANT for ease of
reading game sources.
- Some entities (places, objects, variables and texts) each have a state
(a.k.a. value) associated with them. These can be named by using STATE
declarations. The only difference between a state and a symbolic constant is
that the former cannot be negative.
- Some entities (namely objects, places and variables), also carry a
bitscreen of binary flags. Symbolic names should be given to individual flags
via FLAGS declaration – these are effectively just symbolic names for
bitscreen offsets (necessarily non-negative).
Flag names differ
from state names in some important ways. Firstly, there can be only one set of
flags associated with locations, whereas a number of multiple flag sets can be
declared for objects and variables. Secondly, the distinction between object,
place and variable flag sets is used as part of syntax checks. Thirdly, the
system uses flag declarations to work out sizes of bitscreen required
respectively by objects, places and variables.
- Finally, there are compound constants. These are deprecated.
See the deprecated features section for a brief
explanation.
Variables
Variables are symbolically named entities, each with a state and an
instance of the variable flag set. There are some mandatory variables (e.g.
HERE, see below), but any number of additional variables can be declared by
the programmer. Words entered on the command line are available through the
special mandatory variables ARG1 and ARG2 (and ARG3, currently used for
handling of EXCEPT, but available for a future parser use of holding command
instrument). This generally restricts A-code to simple verb/noun commands,
even though the parser makes this less then obvious, permitting apparently
complex commands such as e.g. DROP ALL BUT LAMP AND ROD THEN EXIT (see the parser section for an explanation of the way
player commands get parsed).
It is important to understand that the ARGn variables are unlike any
others. They have the appropriate player command word associated with them
regardless of the actual variable value (unless the value is -1, meaning "no
word"). This makes error handling possible, because variable value can be sat
by the parser to an appropriate error code, while embedding the variable in a
text to be displayed, actually embeds the corresponding command word.
A special form of variable declaration is an array. In A-code this
has a very limited, simple meaning: declaring an array of n elements declares
a variable of the given name, followed by n-1 anonymous variables. (See below
on handling of anonymous entities).
An automatic indirection occurs for some A-code directives when
manipulating variables into which "addresses" (refnos) of other entities have
been loaded. Generally speaking this happens for non-arithmetical manipulation
of variables.
Texts
Texts are named, nameless, or in-line entities representing a piece of
text. Any amount of text can be associated with a text entity. Generally
multi-line texts are considered to be unformatted, line wrapping and filling
being done by the A-code kernel at run time. However, A-code texts are more
than just textual strings. The section on
A-code texts gives their full description.
Procedures
A-code procedures are unusual in that there can be any number of procedures
sharing the same name. Such procedure groups are executed in the order of
their occurrence in the source (i.e. in the order of their refnos).
Procedures come in 5 varieties:
- Initialising ones, declared as INIT. These form a procedure group, which
gets executed on game startup.
- Main loop, declared as REPEAT. These form a procedure group executed
repeatedly after the INIT procedure group execution is completed.
- "Free-standing" declared as PROC (or PROCEDURE). These
procedures are all named. Procedure arguments (if any) are specified on the
declaration line after the procedure's name. If two or more form an
identically named procedure group, they must all have the same number of
arguments.
- Associated with a place and declared as AT (as in "at
such-and-such-place"). Their names are in fact names of relevant
locations. No arguments are allowed.
- Associated with a vocabulary word and declared as ACTION. The name of such
a procedure is the vocabulary word in question (or equivalently, any of its
synonyms). Arguments are allowed and, perhaps surprisingly, procedures in the
same procedure group will have different arguments and even different number of
arguments. See the minor directive ACTION below for details.
Places
Places are symbolically named entities, each with a state, an instance of
the place flag set, up to three different unnamed texts (brief, long and
detailed descriptions) and a "hook" for unnamed chunks of A-code to be
associated with the place. By default symbolic place names are not available
in the player vocabulary, but each such name can be specifically forced into
the vocabulary by prefixing the name in the place declaration with a plus sign
(+). Any number of synonyms can be defined for a place name, though of course,
there is no point doing this unless such names are forced into the player
vocabulary. All properties of texts (described above) apply to place
descriptions.
Objects
Objects are also individually named (with any number of synonymous names)
and once again, have to their name a state and an instance of the object flag
set each, plus up to three different descriptions (inventory, long and
detailed), but no A-code. Object descriptions also obey the rules common to
any kind of text. Object names (and synonyms) do get entered into the player
vocabulary by default, but it is possible to exclude any specific object name
by prefixing the object name in its declaration with a minus sign (-).
Words (a.k.a. verbs, a.k.a. nouns)
Words have symbolic names (with synonyms) and each is associated with one
or more chunks of A-code. By default, verb names are added to the vocabulary,
but again, any specific name can be excluded. It is sometimes useful to have
"dummy" verbs for internal house-keeping, but not available to the player.
This is again achieved by prefixing the verb name with a -, in the verb
declaration.
As noted above, some of the entity names are automatically or selectively
added to the player vocabulary.
To summarise, vocabulary words consist of: all explicitly defined
words/verbs/nouns and their synonyms, all object names and their synonyms not
explicitly excluded and some those place names which are explicitly included.
The vocabulary section gives a full
description of A-code vocabulary.
Major A-code directives
Major directives are either declarations or translator instructions. They
must start in the first column of a line – that's how they are recognised in
the first place, since everything else must be indented. The indentation depth
is arbitrary – the convention of 9 leading spaces and subsequent indents of
three spaces at a time is not mandatory.
Pragmas
Firstly, there are two major directives, which are in fact translator
instructions:
- INCLUDE <file>
- read commands from indicated file until end of file,
then revert to reading from the previous file. Include files may be nested
down to 10 levels.
- INCLUDE? <file>
- conditional include – includes the file if it exists. If it does not
exist, this directive is simply ignored. Given the fact that A-code permits
forward declarations and supports procedure groups, this pragma can be used
for optional addition of new commands or modification of existing commands
– a feature used extensively by Adv770 to provide the optional Wizard
(debug) mode.
Secondly, there are six game information directives, all of them optional.
- NAME <game-name>
- names the game (a.g. adv770). If not specified, the game's name is taken
to be the name of the file given to the acdc translator, less the .acd
suffix.
- VERSION <version>
- specifies game's version. Traditionally this has the format of two numbers
(major and minor versions) separated by a dot (.), however, this format is not
enforced. If omitted, the current year is used as the game's version.
- DATE <date>
- gives a free-format specification of the date of this version of the
game.
- AUTHOR <author-name>
- name the game's author (also free format).
- STYLE <style>
- specifies the A-code style, i.e. the major version number of A-code in
which the game is written. If used, directive must precede any non-header
directives. If omitted, style is set to the major version of the acdc
translator used to convert the game's A-code source into ANSI C.
Style
1 is reserved for Dave Platt's original code of Adv550. Style 2 is similarly
reserved to Mike Goetz's Adv580 (an expansion of Adv550). Styles 3 to 9 are
not in use. Style 10 is reserved for Adv660.
- UTF8
- signals use of the UTF8 character encoding in the game's A-code
source. This directive is only required if the game uses UTF8 characters
in its entity names or vocabulary words.
(There are also a couple of header directives (GAMEID and DBNAME) which are
obsolete and only supported in style 10, i.e. in Adv660.)
Declarations
The remaining major directives are all declarators.
Other than the flags, states and constants, all declared entities are
associated with a "reference number" (refno) and are internally referenced
by A-code only by this number. The reference numbers of entities of
the same kind (e.g. objects, places, texts, variables...) are guaranteed to
be lumped together into an unbroken numerical interval, with their reference
numbers incrementing by one in the order in which the entities are declared.
To reiterate: within each declarative category (e.g. objects, places, texts)
entities are stored sequentially in the order of declaration and hence can
be referenced via refnos by numerical offsets from other entities.
It is not necessary for the game author to be aware of the reference numbers
of declared entities, but it is helpful to be aware of this arrangement in
general terms.
Reference numbers are used to achieve indirection in A-code. They can be
loaded into variables, which are then recognised by most opcodes as
"indirectors" so that the opcode is actually applied to the entity whose
reference number the variable stores. This does not apply to arithmetical
opcodes, making it possible to do "reference number arithmetic". This
allows, for example, referencing nameless texts by offsets from other named
texts, and has other uses too. It is not necessary to know the
"reference number" of an entity, in order to load it into a variable.
- FLAGS {VARIABLE|OBJECT|PLACE}
-
starts the declaration of a flag set of the appropriate kind (variable,
object or place). It is followed by any number of indented lines, each
declaring a symbolically named flag in the set, optionally followed on the
same line by synonymous names. Only one object and place set declarations
are permitted, but any number of variable set declarations are allowed.
(They are equivalent to a single declaration with flags declared on
corresponding lines being synonymous with each other).
- STATE [value] statename [...]
-
is used to declare symbolic names for entity states. It makes "statename"
synonymous with the value preceding it, or with zero, if the value is
absent. A STATE directive can be followed by any number of indented lines of
the format " [value] statename", which declare further state names to be
synonymous with the corresponding value, if given, or with the value of
"statename" defined on the preceding line plus 1. Note that the STATE
directive deliberately does not specify which entities the defined
statenames relate to, allowing for partial state sequences to be shared by
different entities. "Value" can be a number, a previously declared constant,
a previously declared entity (in which case the "reference number" of the
entity is used) or several such, combined into a simple expressions with
plus (+) and/or minus(-) signs, without any separating blanks.
- CONSTANT [value] constname [...]
-
This directive is in fact exactly synonymous with the STATE directive. It is
used simply to indicate that the symbolic constants being defined are
general purpose constant and not entity state names. The two are completely
interchangeable.
- TEXT [textname]
-
declares a piece of text, which may be associated with a text name or be
"anonymous" (available only by offset from some named text). The TEXT
directive is followed by one or more lines of text, which must not
start in column 1 (anything starting in column 1 is taken to be a major
directive -- it follows, that all leading spaces are ignored). A-code texts
are very rich entities. Please see the section
on A-code texts for details.
- FRAGMENT textname
-
Identical to the TEXT directive, except that the text is not terminated by a
new line. I.e. it is a text fragment.
- PLACE [+]placename [...]
-
declares a location. By default, "placename" is not entered into the player
vocabulary, unless prefixed with a '+' (which does not count as a part of
the name). Synonymous names can be declared on the same line.
-
Each location declaration is optionally followed by a piece of text
(following all the text rules described above), comprising up to two
different descriptions – the brief one and the full one – and
terminated by a major directive. Insofar as these do description components
occur – they occur in that particular order. The brief description (if
any) immediately follows the PLACE line and is terminated by a text line
starting with a '%' or a major directive. The full description (if any)
starts with a line beginning with '%' and is terminated by the next major
directive.
-
If the full description is missing and the brief one is present, the full
one defaults to the brief one. It is possible for a location to have no
description at all. The '%' delimiter is not itself considered to be a part
of the description. If a text switch is encountered in a description being
displayed, the current state of the location is used as the switch
qualifier. Thus for example
PLACE +TUBE
You're in lava tube at top of chimney.
%You're at the top of a narrow chimney in the rock. A cylindrical tube
composed of hardened lava leads south and northwest[/, from where
comes some ][/silvery /day/orange ][/light, providing a dim
illumination to this place].
-
All special trickery described in the A-code
texts section applies to place descriptions as well.
- OBJECT [-]objname [[=]objname ...]
-
declares an object. By default, "objname" is entered into the player
vocabulary, unless prefixed with a '-' (which does not count as a part of
the name). Synonymous names can be declared on the same line. These can be
prefixed with a '=', indicating their re-mapping to the last synonym not so
prefixed, which, in fact may be a string (see the example below), which
is not itself entered into the game's vovabulary.
-
Each object declaration is optionally followed by a piece of text (following
all the text rules described above), comprising up to three different
descriptions – the inventory one, the full one and the detailed one -
and terminated by a major directive. Insofar as these three description
components occur – they occur in that particular order. The inventory
description (if any) immediately follows the OBJECT line and is terminated
by a text line starting with a '%', '&' or a major directive. The full
description (if any) starts with a line beginning with '%' and is terminated
by a line beginning with a '&' or by the next major directive. The
detailed description (if any) starts with a line beginning with a '&'
and is terminated by the next major directive. E.g.
OBJECT "nest with eggs in it", =NEST, =EGGS
Nest with golden eggs
%There is a large nest here, full of golden eggs!
&The nest holding the eggs is lined with some sort of bird down - might
be goose, but I am not sure. The eggs themselves gleam dully in the
light with the unmistakable gleam of pure gold.
-
If the full description is missing and the inventory one is present, the
full one defaults to the inventory one. If the detailed description is
missing, it defaults to the full one, if that is present, or to the
inventory one, if the full one is absent and the inventory one present.
-
It is possible for an object to have no description at all. The '%' and
'&' delimiters are not themselves considered to be a part of the
description. If a text switch is encountered in a description being
displayed, the current state of the object is used as the switch qualifier.
-
All special trickery described in the A-code
texts section applies to place descriptions as well.
- NOISE word [...]
- NOISE declares words to be ignored when parsing player's input.
- VERB [{-||}]verbname [synonyms]
-
Declares a word "verbname" (optionally with synonyms), which is (by default)
entered into the vocabulary available to the player. The optional minus sign
prefixing the principal verb word stops the verb being available in the
vocabulary. Such dummy verbs have two separete uses. I only the principal
name is given, the word is useful for range checking within the vocabulary
and bracket groups of verbs of a similar kind (e.g. movement directions).
Synonyms to such excluded words can be used in replacing words that have to
be know to the kernel (such as AND, THEN or AGAIN) with non-English
alternatives. See the internationalisation
section for details.
VERB is currently synonymous with NOUN and
WORD. Adjectives and prepositions are not currently supported. Distinction
between different word types are up to the game's code.
- ACTION verb [objname]
- The major directive ACTION is used to associate chunks of A-code (procedures) with
individual verbs. More than one procedure can be assigned to the same verb and
they are executed in the order of their declaration. If the optional object
name is given, that particular action procedure is skipped, unless the object
in question features in player's command.
- VARIABLE variable [...]
- defines one or more variables. Note that variables defined on one line
like this are not synonymous. By convention, related variables tend to
be defined in a single VARIABLE directive.
- ARRAY arrayname constant
- defines a consecutive block of variables of the size given by the
constant. The first of these is named by the array name, the rest are
anonymous – accessible only via refno offsets from the array's base
- PROC procname [arg ... ]
- defines a chunk of A-code (a set of executable code) called "procname".
The procname can be followed by a list of arguments, which are passed by value
when the procedure is called. The subsequent lines contain the code, terminated
by the next major directive.
- AT placename
- defines code to be executed when the player is at the indicated place -
the following lines contain the actual code. More than one AT procedure may be
defined for a particular place – they are executed in the order in which they
are declared in the A-code source.
- INITIAL
- defines once-only code to be executed at initialisation time. Multiple
INITIAL commands may be used and are executed in the order encountered.
- REPEAT
- defines the main action-processing code that is executed during each
player input. After the INITIAL code has been executed, the REPEAT statements
are executed. Once the last REPEAT statement is executed, the program loops
back and starts again with the first.
Each of the above "major directives" must appear in column 1. A major
directive embraces all following lines up to but not including the next
major directive statement (i.e., all lines in which column 1 is blank) or
the end of the source file in which it occurs.
Special entities and flags
Not all entities or flags need to be declared explicitly. Some are
"automatic" and some are "optional"
"Automatic" means that the entity is declared automatically.
Automatic entities may be explicitly declared by the program, but if so, must
be of the correct type. If an entity of that name is declared as some other
type, this is treated as a compilation/translation error.
"Optional" means that the entity may but need not be declared by
the program. If declared, it has a special meaning. An entity of that name but
of a different type is treated as a compilation/translation error.
INHAND automatic location
Use: contains all objects currently
carried by the player; contents are maintained by the kernel but can be also
accessed and modified by the game's code.
STATUS – automatic variable
Use:
set by the kernel to indicate the number of words in the player's
latest command.
Can be set by the program to various values in order to pass information
to the kernel.
Possible values:
BADSYNTAX – automatic state
Use: set by the kernel if the current player command
cannot be parsed.
NO.MATCH – automatic state
Use: set by the program to indicate that no abbreviation
or approximate matching is to be performed on the next player command.
NO.AMATCH – automatic state
Use: set by the program to indicate that no approximate
matching is to be performed on the next player command.
value -1
Use: set by the kernel to signal game restore on
start-up.
Flags:
FULL.DISPLAY – optional flag
TERSE.DISPLAY – optional flag
MOVED – optional flag
Use: set by the kernel whenever player's location changes.
JUGGLED – optional flag
Use: set by the kernel if player's inventory has changed.
PLS.CLARIFY – optional flag
Use: set by the game's code in order to trigger orphan
processing of next player input; cleared by the kernel as a part of
orphan processing. (See the description of the
A-code parser for an explanation of orphan processing of commands.)
HERE – automatic variable
Use: set by the kernel to the refno of the player's
current location.
THERE – automatic variable
Use: set by the kernel on a change to player's location
to the refno of the location prior to the change.
ARG1 – automatic variable
Use: set by the kernel to the refno
of the player command's verb
Possible values:
BADWORD – automatic state
Use: set by the kernel if the word is not understood.
AMBIGWORD – automatic state
Use: set by the kernel if the player's word can be an
abbreviation of more than one vocabulary word.
AMBIGTYPO – automatic state
Use: set by the kernel if the player's word can be
matched as a typo in more than one way
SCENEWORD – automatic state
Use: set by the kernel if the player's word is not found
in the vocabulary but matches a word (in excess of three characters) in the
latest location description or in a text displayed since
the last move.
ARG2 – automatic variable
Use: set by the kernel to the refno of
the player's noun (if any) or zero otherwise.
States: (as ARG1)
ARG3 – automatic variable
Use: At present used solely for EXCEPT
processing. If player's command is of the form "<verb> ALL EXCEPT
<list>", ARG3 may be set by the kernel to BADWORD, AMBIGWORD or
AMBIGTYPO, if appropriate.
CONTEXT – optional variable
Use: avoid use of the QUERY minor
directive in game builds which require single-turn operation (see the
section on A-code game build modes). Value:
If non-zero, indicates the current command to be a response to a query, the
value (as set by the program) indicating the nature of the query.
Flags:
PROMPTED – automatic flag
Use: set by the kernel if the player has been
prompted.
ENTNAME – optional variable
Use: when processed by the SAY
directive, shows the symbolic name of the entity to which ENTNAME is set
to point.
Value: a pointer to a named entity set by game's code.
Use of ENTNAME has the two side-effects:
-
It stops the dot character ('.')
acting as a player command separator, permitting reference to entity names
containing this character.
-
It a player command word is not found in the games vocabulary, game entity
names are also searched by the parser; only exact matches are accepted
– no abbreviations and no typo matching.
The variable is intended for game debugging
in the wizard mode. See the section on
debugging A-code games.
TYPO – optional text
Use: enables single-typo matching of player commands
against the games vocabulary.
The TYPO text must contain a switch of 4 (or a multiple of four) components.
It is used by the kernel to explain a typo match to the player. Regardless
of the number of components, it must be declared as
FRAGMENT CYCLE TYPO
The first three components in each foursome must contain one word holder
(#). The four switch components (in any of the switch quads if there are more
than 4 components) are used by the kernel as follows:
- Shows original player word that got typo-corrected
- Shows the typo-corrected version for what the player gave
- Shows the full non-abbreviated matched word if typo-corrected version is
an abbreviation.
- States that the corrected version is assumed
Here is an example from Adv770:
FRAGMENT cycle TYPO
[Sorry, the word "#" is not familiar to me./ I'll just assume you
meant "#"/, i.e. "#"/./
Regretfully, I don't have "#" in my dictionary./ But I do know
"#"/, as in "#"/, so I'll assume you meant that./
The word "#" is not one I know./ Let's assume you meant "#"/,
meaning "#"/./
I wonder what "#" might be.../ I guess it could be mistyped
"#"/, i.e. "#"/, so I'll assume that was what you meant.]
UNDO and REDO optional verbs.
Use:
Their presence activates the A-code undo/redo facility,
enabling players to undo a specified number of last commands and, if
necessary, undo some or all of this undoing. This is described in
the section dealing with undo/redo.
UNDO.STATUS – optional variable
Use: set by the kernel to indicate the number of commands
undone or re-done, which need not be the number requested by the player.
If the variable is declared, the below flags are declared automatically:
UNDO.INFO – automatic flag
Use: Can be used by game code to note that player has
been advised of rules for using undo; set to off by default and
ignored by the kernel.
UNDO.TRIM – automatic flag
Use: maintained by the kernel: if set, the level of
undo/redo was found to be excessive and had to be trimmed to match the
existing undo history.
UNDO.INV – automatic flag
Use: maintained by the kernel: if set, the player's
inventory has changed as the result of undo/redo.
UNDO.BAD – automatic flag
Use: maintained by the kernel: if set, undo/redo failed.
DWARVEN – optional variable
Use: If set to non-zero, all text
output by the game is shifted circularly one position up in the alphabet and
all player input is shifted one position down. If set to zero, any portion of
game text delimited by % signs is output shifted one position up.
PROMPT – reserved optional variable
Use: none at present. Reserved for
specifying non-standard prompt.
SCHIZOID an automatic object flag
Use: Indicates that the object is to
be treated as present in its current location, and also in the
immediately succeeding one (i.e. the one with the refno one higher).
Minor A-code directives (a.k.a. opcodes)
The actual A-code code consist of minor directives (or opcodes) followed by
their arguments (if any). A line of code cannot have more than a single opcode
line.
The following is a list of the available opcodes and a quickie description
of what they do. As noted previously, in some cases if an argument is a
variable, it is automatically de-referenced – i.e. the operation
indicated by the opcode is applied not to the argument but to the entity
referenced by the argument. Any such opcode arguments are denoted by a
trailing asterisk in the following summaries.
Local variables
- LOCAL varname [varname...]
- Declares correspondingly named
variables local to a procedure. It must immediately follow either the major
directive declaring the procedure in question, or another LOCAL declaration.
Local names pre-empt any identically named global variables. Local variables
are dynamically initialised to zero value and zero bitscreen whenever the
procedure is entered. They do not exist outside the procedure.
Local variables are not a part of the data set saved/restored by saving
or restoring a game image. Thus they can be used to preserve some values
over a game restore, instead of using the (now obsolete) EXEC 6 and
EXEC 7.
Conditionals
All conditional structures have the basic form of
conditional, some code, FIN
conditional, some code, ELSE, some code FIN
where the immediately following block of code is executed if the
conditional is true, and the block following ELSE (if present) is executed if
it is false.
In order to avoid deeply nested indentation in source code, A-code
also features OTHERWISE, analogous to C's "else if" or Perl's elsif. Thus
some condition
some code
ELSE
some condition
some code
ELSE
some condition
some code
FIN
FIN
FIN
can be equivalently written as
some condition
some code
OTHERWISE
some condition
some code
OTHERWISE
some condition
some code
FIN
The following conditionals are available:
(A quick reminder: the value of a place or an object, is its state;
however, variables (local or global) can be "pointers", i.e. have the refno of
some entity is loaded into them. In the below, variables, which are in fact
pointers are represented as "varname*".)
value of a variable is either just that value or (if indirection is indicated
- IFEQ {entname1|const1}, {entname2|const2}
- True if the value of the first argument is equal to the value of the
second argument.
- IFNE {entname1|const1}, {entname2|const2}
- True if the value of the first argument is not equal to the value of the
second argument.
- IFLT {entname1|const1}, {entname2|const2}
- True if the value of the first argument is less then the value of the
second argument.
- IFLE {entname1|const1}, {entname2|const2}
- True if the value of the first argument is less then or equal to the value
of the second argument.
- IFGT {entname1|const1}, {entname2|const2}
- True if the value of the first argument is greater than the value of the
second argument.
- IFGE {entname1|const1}, {entname2|const2}
- True if the value of the first argument is greater than or equal to
the value of the second argument.
- IFINRANGE {entname|constant} {entname|constant}
{entname|constant}
- True if the value of the first argument is greater or equal to that of the
second argument, but less or equal to the value of the third one.
- CHANCE {entname|constant}
- True with the probability of n%, where 'n' is the value of the
argument.
- IFHAVE {objname|varname}* [{state|flagname}]
- True if the player is holding the specified object. If the second argument
is supplied, the object also has to be in the specified state or have the
specified flag set.
e.g. if THING is a variable,
LDA THING, BOTTLE
IFHAVE THING
will be true if and only if the bottle is in the player's inventory. Of
course,
IFHAVE BOTTLE
will have the same effect in this particular example.
- IFHERE {objname|varname*} [{state|flagname}]
- True if the specified object is at the same location as the player. If the
second argument is supplied, the object also has to be in the specified state
or have the specified flag set.
- IFNEAR {objname|varname}* [{state|flagname}]
- True if the specified object is held by the player or is in the same
location as the player. If the second argument is supplied, the object also
has to be in the specified state or have the specified flag set.
- IFFLAG {entname|varname*} flagname
- True if the specified entity has the corresponding flag set. If a flagless
entity is specified, the test returns FALSE.
- IFAT {placename|varname*} [...]
- True if the player is currently at the one of the specified locations.
- IFLOC {objname|varname1}*, {placename|varname2*} [...]
- True if the object specified by the first argument is at one of the the
specified locations.
- IFIS varname, {objname|placename|varname*} [...]
- True if the named variable is a pointer to one of the specified objects
or locations.
- IFKEY word [word]
- True if all specified words appear in the player's command.
- IFANY word [word...]
- True if any of the nominated words appear in the player's command.
- QUERY {textname|varname*}
- Displays the nominated text, which should be a yes/no question, and gets
player response. Set to true if the answer is yes and false otherwise.
CAUTION this directive is incompatible with library and
single-turn modes (and thus incompatible with the HTML/JavaScript build, which
uses the library mode). If such modes are to be supported, use the CONTEXT variable mechanism instead.
- IFHTML
- True if the game is running in a mode in which its output is formatted
as HTML.
- IFCGI
- True if the game is running in a cloud via a CGI interface.
- IFDOALL
- True if the game is processing a DOALL command loop.
- IFTYPED
- True if the player actually typed the string given as an argument, as one
of the command words.
Thus for example
IFTYPED W
will be true only if the player typed W rather than WEST, even though
W is interpreted as WEST.
- IFNEEDCMD
- True if there are no more pending simple commands to process, i.e. the
player is about to be prompted for a new command. This is useful e.g. to avoid
interrupting processing of a compound command with a spontaneous offer of
help.
Logical operators
Now for some logical operators, to string the tests together, creating
"compound" conditions. Note that tests are executed in the order in which they
are encountered, with no precedence rules for operators and no bracketing.
So, conceptually, A and B or C and D is understood as ((A and B) or C) and D.
This may be unusual, but is, in fact surprisingly natural (or at least I
found it so :-)).
- AND
- "And" the test results so far with the following test.
- OR
- "Or" the test results so far with the following test.
- XOR
- "Xor" the test results so far with the following test.
- NOT
- Invert immediately following test.
Logically enough, here are delimiters for conditional code.
- ELSE
- Execute the following code, up to the next FIN, if the latest
(compound) condition returned false.
- OTHERWISE
- An equivalent of "else if" in C or elsif in Perl. Useful for
avoiding deeply nested if-then-else constructs.
- FIN
- Delimits the code associated with the most recent (compound) condition.
Can be used interchangeably with EOI.
Iteration
Next come the opcodes to do with iteration.
- ITOBJ varname [{placename|varname*}] [objflag]
- Execute the following code up to the matching FIN repeatedly, with the
value of the nominated "loop variable" becoming a reference to objects
satisfying the optional location and/of flag/state constraints (or all object,
if no constraints specified) in the order of their declaration.
- ITPLACE varname [{placename1|varname1*}, {placename2|varname2*}]
- Execute the following code up to the matching FIN repeatedly, with the
value of the nominated "loop variable" running through the specified range of
locations (default all declared locations) in the order of their
declaration.
- ITERATE varname, {entname1|varname1*|const1}, {entname2|varname2*|const2}
- Execute the following code up to the matching FIN repeatedly, with the
value of the nominated "loop variable" running through all values from
entname1 to entname2 inclusive. If either of the two range delimiting entnames
is a variable, its value is used as the appropriate loop boundary (this may
but need not be the reference number of some other entity). If either is a
constant, the value of the constant is used. Otherwise the reference number of
the nominated entity is used.
- NEXT
CONTINUE
- Skip the rest of the iteration block and proceed with the next iteration
loop.
- BREAK
LAST
- Break out of the innermost iteration block.
- DOALL [{placename|varname*}] [objflag]
- DOALL starts
off a do-all loop, in which the REPEAT cycle is repeated, but instead of
querying the player for input, input is constructed out of the verb in ARG1
and the next object fitting the specified criteria. The loop is terminated
either when no more objects fit the criteria or when the FLUSH directive is
executed.
- FLUSH
- Abort the do-all loop if one executing and flush the command line buffer
Execution flow control
- CALL {procname|placename|verbname|varname*}
- Execute code associated with the named entity, which may consist of one or
more separate, identically named chunks of code. These are executed in the
order of their declaration, until either none left or one of RETURN, QUIT
or QUIT-implying opcodes is executed in one of them.
- PROCEED
- Terminate the execution of the current procedure. If the procedure is one
of a group of procedures of the same name, the next procedure in the sequence
(in the order of declaration) is executed.
- RETURN
- Terminates the execution of the current procedure and of all procedures
within the group of procedures of the same name
- QUIT
- Abort execution of the current procedure and restart the REPEAT loop at
the first REPEAT procedure.
- STOP
- Terminate the whole program immediately.
Moving player and objects
- APPORT {objname|varname*} {placename|varname2*}
- Transport the indicated object to the indicated location.
- GET {objname|varname*}
- Transport the indicated object into the player's hands. Equivalent to
"APPORT {objname|varname*}, INHAND".
- DROP objname*
- Transport the indicated object (presumed to be in player's hands (location
INHAND) to the same location as the player).
Equivalent to
IFAT {objname|varname*}, INHAND
APPORT {objname|varname*} HERE
FIN
- GOTO {placename|varname*}
- Transport player to the indicated location.
- MOVE [word [...]] {placename|varname*}
- If no word list supplied or if any of the supplied words appear in the
player's command, transport the player to the indicated location and
restart the main loop (the REPEAT loop).Equivalent to (if a word list is
present)
IFANY [word [...]]
GOTO {placename|varname*}
QUIT
FIN
- SMOVE [word [...]] {placename|varname1*} {textname|varname2*}
- If no word list supplied or if any of the supplied words appear in the
player's command, transport the player to the indicated location and display
the indicated text, then restart the main loop. If a word list is present,
equivalent to
IFANY [word [...]]
SAY {textname|varname1*}
GOTO {placename|varname2*}
QUIT
FIN
Generating and manipulating output
There are several directives for producing text output. All of them can be
"qualified" for the purposes of "#" and "$" substitution and/or of the text
switch mechanism. The VALUE qualifier is mandatory, but both SAY and QUIP can
be used with a single argument. If the argument is an object or a place
(possibly indirectly pointed to through a variable), the current state value
of the object or place is used as the implicit qualifier. See
the section on A-code texts for a full a
explanation.
- SAY {entname|varname*} [{entname|constant}]
-
Display text associated with the specified entity (text, object, place or
any of these indirected through a variable). General rules for displaying
texts are covered in the section on A-code
texts. However, objects and locations can have up to three separate
texts applying to them. Please see major directives OBJECT and PLACE
as well as the minor directive DESCRIBE.
- RESAY {entname|varname*} [{entname|constant}]
- Just like SAY, except that any text accumulated but not yet displayed is
discarded first.
- QUIP {entname|varname*} [{entname2|constant}]
- Like SAY, but perform a QUIT having output the text
- RESPOND word [word [...]] {entname|varname*} [{entname2|constant}]
Like QUIP, but null effect unless one of the listed words is present in the
- player's command.
- APPEND {entname|varname*} [{entname|constant}]
- Like SAY, but it first eliminates any trailing line feeds (if any) in the
output accumulated so far and replaces them with a single blank. That is, it
appends its text to the preceding paragraph.
- DESCRIBE {placename|objname|varname*}
- Outputs the longest available description of the indicated object
or location.
- VOCAB {objname|placename} [flagname] [textname]
VOCAB word {objname|placename} flagname [textname]
VOCAB [textname]
- Used for displaying context-sensitive vocabulary. The first of the above
three formats displays either primary name of the object or place in question,
or the text specified as the last argument, unless the flagname argument is
present and the flag in question is not set for that object or place. For
example:
VOCAB CAGE, SEEN
VOCAB DWARF, SEEN, DWARF.VOC
The second format applies to words which are neither places nor objects, but
their listing should be regulated by a flag setting of some object or place.
For example:
VOCAB CHASM, SW.OF.CHASM, BEEN.HERE
The display, if any, is prefixed with a comma and a space, except for the
first word displayed. The count of words displayed is reset to zero by a VOCAB
directive with no arguments or with just the textname argument.
- TIE textname [textname2...] [entname|textname]
- Ties the value of the text (or texts) to that of the indicated entity
or text. (See the A-code texts section
for an explanation of text values.) The effect is that the value(s) of text(s)
being tied are automatically kept in step with the value of the entity or text
given as the last argument.
Arithmetical operations
- SET entname {entname|constant}
- Set the value of the entity given as the first argument, to the value of
the constant or entity given as the second argument. Note that no
indirection occurs with this opcode. If the first argument is an "indirector"
variable, SETting it reverts it to an ordinary variable. Use the DEPOSIT
opcode to SET with indirection.
- ADD entname {entname|constant}
- Increase the value of the entity supplied as the first argument, by the
value of the constant or entity supplied as the second. Note, that no
indirection takes place!
- SUB entname {entname|constant}
- Decrease the value of the entity supplied as the first argument, by the
value of the constant or entity supplied as the second. Note, that no
indirection takes place!
- MULTIPLY entname {entname|constant}
- Set the value of the nominated entity to its original value multiplied by
the value of the second argument. Note, that no indirection takes
place!
- DIVIDE entname {entname|constant}
- Set the value of the nominated entity to its original value divided by the
value of the second argument. Note, that no indirection takes
place!
- INTERSECT entname {entname|constant}
- Set the value of the nominated entity to the bit-wise "and" of its
original value and the value of the second argument. Note that no
indirection takes place!
- NEGATE entname
- Set the value of the nominated entity to its original value negated. Note,
that no indirection takes place!
Randomisation
- RANDOM entname {entname|constant}
- Set the value of the entity indicated by the first argument to an integer
chosen randomly from the interval between zero (inclusive) and the value of
the entity or constant given as the second argument (exclusive). E.g. RANDOM
CLOCK 10 will set the value of CLOCK at random to an integer number from 0 to
9. Note that no indirection takes place.
- RANDSEL varname, entname1, entname2, [...]
RANDSELECT varname, entname1, entname2, [...]
- Selects at random (i.e. with equal probability) one of the listed
entities and makes its first argument into a pointer to that entity.
- CHOOSE entnam {entnam2|constant2} {entnam3|constant3}
- Set the value of the entity indicated by the first argument to a random
integer from the interval indicated by the second and the third arguments. If
these latter arguments are both constants or variables, their values are used
to determine the interval boundaries. However, for any entities other than
variables, the reference numbers of the two entities are used instead. The
randomisation is inclusive of the interval boundary values. E.g. CHOOSE VAR1
20 29 will set the value of VAR1 to a random integer between 20 and 29
inclusive, while CHOOSE VAR1 FIRST.QUIP, LAST.QUIP (where the two "quips" are
not variables but text names) will load into VAR1 the reference number of
an entity (text in this case) randomly chosen from between FIRST.QUIP and
LAST.QUIP inclusive (there may well be some unnamed texts between these
two).
- RANDOMISE {objname|placename}, constant
- Set state of the object or place to a random value between the base lower
bound indicated by the constant (usually 0), and the highest numbered text
switch component in any of the object's or location's description.
Refno manipulation
- LDA varname, entname
- Make the variable specified by the first argument "indirect" to to entity
specified by the second.
- EVAL varname varname
- Set the value of the variable specified by the first argument to the value
of the entity "indirected" through the second argument. Please note that no
check is made to verify that the second argument "indirects" anything
meaningful.
- DEPOSIT varname {varname|constant}
- Set the value of the entity "indirected" by the first argument to the
value specified by the second. Note that no check is made whether the first
argument truly indirects to some other entity.
- LOCATE varname objname*
- Make the indicated variable into an "indirector" for the location
currently holding the indicated object.
Manipulating flags
- FLAG entname flagname
- Switch on the flag identified by "flagname" in the instance of the
appropriate flag set belonging to the indicated entity.
- UNFLAG entname flagname
- Switch off the flag identified by "flagname" in the instance of the
appropriate flag set belonging to the indicated entity.
Communicating with the machine environment
- EXEC {varname|constant}, varname
- Perform a special action, indicated by the value of the first argument,
and return the result in the value of the variable given as the second
argument. This opcode is to do awkward things, which are not allowed for in
A-code opcode definitions or are far easier done in C than in A-code. All
these special actions are performed in the adv00.c procedure special(). As
supplied the following actions can be selected by the appropriate value of the
first argument: the value
- dump game to disc (obsolete – use SAVE FILE instead)
- restore game from disc (obsolete – use RESTORE FILE)
- delete saved game(obsolete – use DELETE FILE)
- Obsolete – Adv550 legacy only (flush game cache)
- Obsolete – Adv550 legacy only (get prime time flag)
- save value of a variable (obsolete – use local variables instead)
- restore value of a variable (obsolete – use local variables instead)
- get number of minutes since restored game saved
- set the value (pointer!) of ARG1
- set the value (pointer!) of ARG2
- pretend player said "X X" instead of "X"
- check for end of player's (possibly compound) command (obsolete –
use IFHAVECMD instead)
- (spare)
- retrieve a persistent data flag (should be part of IFFLAG?)
- store a persistent data flag (should be part of FLAG?)
- delete a persistent data flag (should be part of UNFLAG?)
- save current location of all objects (should be part of SAVE?)
- retrieve saved location of an object (should be part of RESTORE?)
- toggle output text justification
- set screen width (in fixed font characters)
- set page margin (in fixed font characters)
- set screen height (in lines)
- save player's command (obsolete – use SAVE COMMAND instead)
- restore player's command (obsolete – use RESTORE COMMAND instead)
- (spare)
- (spare)
- {spare)
- recover from failed restore
- swap ARG1 and ARG2
- (spare)
- (spare)
- check object being on the exception list
- check existence of a memory save
- list available saved games
Any number of other special action may be defined, but codes up to and
including 100 are reserved for future use by the engine.
Get and manipulate player input.
- INPUT [{textname|varname*}]
- Input and parse a command, setting the mandatory variables ARG1 and ARG2
to the supplied verb and noun respectively. If only a single word is given and
the mandatory flag PLS.CLARIFY of the mandatory variable STATUS is set, the
supplied word is combined with the last (incomplete) command.
Note that the player is queried for input only if we have run out of the
last command line. There are three circumstances under which the player is not
prompted:
- He gave several commands separated by full stops or semicolons and we
have not processed the last one yet.
- The last processed command consisted of a verb followed by several nouns
and we haven't yet finished applying the verb to all the nouns. This case does
not preclude case (a) also applying!
- We are in a doall loop, applying the verb of the last processed command to
all objects satisfying the criteria of the DOALL opcode, which started the
loop – and there is at least one more object to process. Again, this
case does not preclude either of the two preceding cases applying
simultaneously.
If the optional argument is supplied, the nominated text is displayed,
before accepting player's input. Whether or not this happens, if the last
printed text was a "fragment", it is pushed out as the prompt and padded with
a space, if required. If the last message was not a fragment, the player is
prompted by the standard linefeed and question mark prompt. Note that this
allows you to have any prompt you like, instead of the standard one.
- FAKEARG [{entname1|varname1*}] [{entname2|varname2*}]
- If player's command refers to an entity referenced (possibly indirectly)
by the first argument, pretend that the reference was to the entity referenced
by the second argument. This directive does not, however, alter the words of
the command.
- FAKECOM [{entname1|varname1*}] [{entname2|varname2*}]
- Like FAKEARG, except that the relevant word in the player's command is
also modified, in case it is echoed back at the player.
- VERBATIM {ARG1|ARG2}
- Replaces the word string associated with ARG1 or ARG2 respectively, with
whatever the player actually used, which got interpreted as whatever word
string that is to be replaced.
- UNDO
- If undo is permitted, undo the number of commands specified by
player command's second word, which may be (a) a number to undo a specific
number of commands, (b) ALL to undo all commands since the last restore, or
(c) UNDO to undo the immediately preceding UNDO. The UNDO_TRIM flag
of the UNDO_STATUS variable is set or cleared appropriately.
- REDO
- Only accepted immediately after an UNDO command. REDO reverts the undoing
of the specified number of commands, which may be given as (a) a number or (b)
ALL which is equivalent to UNDO UNDO. The UNDO_TRIM flag of the UNDO_STATUS
variable is set or cleared appropriately.
- DEFAULT [{placename|varname*}] [objflag]
- If no object has been specified in the player's last command (i.e. if the
value of STATUS is 1), check whether there is an object at the nominated
location (default HERE) and, optionally, has the nominated flag set. If no
such object exists, this directive has no effect. If only one object satisfies
the criteria, ARG2 is set as if the player had explicitly nominated that
object. If more than one object fits the criteria, ARG2 is set to AMBIGWORD.
In either case, the value of STATUS is increased from 1 to 2.
Saving and restoring (file, memory or command)
- SAVE {FILE|MEMORY|COMMAND} varname
- SAVE FILE saves the current state of the game in a file nominated by the
command text string associated with ARG2. SAVE MEMORY creates or replaces
an in -memory save image (this gets written off to disk in ADVLIB and CGI
modes). SAVE COMMAND saves player's parsed command, so that the game
can ask a yes/no (or other) question, without relying on the QUERY directive,
since this directive is not compatible with ADVLIB or CGI modes.
The variable specified by the <varname> argument returns zero on success.
Non-zero return indicates failure.
- RESTORE {FILE|MEMORY|COMMAND} varname
- Restores file, memory image or player command saved by the SAVE directive.
The variable specified by the <varname> argument returns
zero on success. Non-zero return indicates failure.
- DELETE {FILE|MEMORY} varname
- Deletes respectively a saved file nominated by the second word of the
player's command, or the saved memory image (which also can be a file, in an
ADVLIB or CGI modes).
The variable specified by the
<varname> argument returns zero on success. Non-zero return indicates
failure.
Debugging minor directives .
- CHECKPOINT
- SAYs its location (file name and line number) in the A-code
source.
- DUMPDATA
-
Dumps game data to STDERR or to the log file if one is being written to. If
a second command word is given, it is taken to indicate the type of
value-bearing entites to be shown. Possible values are "objects",
"locations" or "places"), "variables" (or "vars") and "texts" – all of
these being abbreviable to a single character. The command is handled by the
kernel and hence types of dump need not be in the game's vocabulary. Most
likely use of this directive is in optionally included code – see the
debugging section for debugging use of
optional includes.
Obsolete and/or deprecated lexicals and directives
These directives are still supported for compatibility with old versions of
A-code. Some are supported only for style 1 of A-code (i.e. only for Platt's
original source).
- Compound constants
-
- A compound constant is a text string with no spaces, where names of simple
constants or entitynames are joined by plus and/or minus
signs.E.g. LAST.DEFLECTOR-FIRST.DEFLECTOR+2 evaluates as the
value of LAST.DEFLECTOR minus the value of FIRST.DEFLECTOR plus 2. For entity
names the value used in the calculation is the refno of that entity. In this
example from Adv550, the two symbolic names happen to be text names.
- SYNON {value|symbname}, synon [...]
- Used to define symbolic name for constants or synonyms for already defined
symbols.
- BISET {entname|varname*}, flagname
BIS {entname|varname*}, flagname
- Obsolete synonym of FLAG.
- BITST {entname|varname*}, flagname
-
BIT {entname|varname*}, flagname
- Obsolete synonym of IFFLAG.
- BICLEAR {entname|varname*}, flagname
BIC {entname|varname*}, flagname
- Obsolete synonym of UNFLAG.
- LABEL procname
- Synonymous with PROC.
- NAME entname, qualifier
- Synonym of SAY, except that the qualifier is mandatory.
- DEFINE placename
- Add the placename to player's vocabulary. The recommended way of doing
this is by prefixing the placename with the + sign in its declaration
- EOI
- Closes an iteration loop. Use FIN instead!
- EOF
- Used in Platt's code as a short-hand for an arbitrary number
of successive FINs.
- DBNAME database-name
- Defines the name of the data file.
- TITLE title
- Older synonym of DBNAME.
- KEYWORD word [...]
- If all indicated words (or their synonyms) appear in input, execute the
following code, up to the next major directive; otherwise PROCEED.
- HAVE {objname|varname*} [...]
- If all indicated objects are held by player (at location INHAND), execute
the following statements up to the next major directive; otherwise PROCEED.
- HERE {objname|varname*} [...]
- If all indicated objects are at the same location as the player
(specified by the variable HERE), execute the following code, up to the next
major directive; otherwise PROCEED. There was no corresponding opcode in the
original A-code.
- NEAR {objname|varname*} [...]
- If all indicated objects are either held by the player (at location
INHAND) or at the same location as the player (as specified by the variable
HERE), execute the following code up to the next major directive; otherwise
PROCEED.
- AT {placename|varname*} [...]
- If the player is at (any of) the indicated location(s), execute the
following code, up to the next major directive; otherwise PROCEED. Don't worry
about the name of this opcode clashing with the AT major directive – they
exist in different name spaces, major directives being recognised by starting
in column one. Note that the "place" may be an object!
- ANYOF word [...]
- If the player typed any of the indicated words in the command being
processed, execute the following code, up to the next major directive;
otherwise PROCEED. If successive lines have the ANYOF opcode, they are merged
internally into a single ANYOF directive. If any of indicated words are in
command do following; else PROCEED
- VALUE entname* [{entname|constant}]
- Like SAY, but replace '#' with value of the qualifier, rather than the
qualifying entity name.
- SVAR {varname|constant}, varname
- Set value of the variable nominated in the second argument, according to
the value of an environmental variable (or condition) indicated by the value
of the first argument. Supported only for the sake of Platt's original
code of Adv550, which uses SVAR 4 and SVAR 5 to regulate timing of
game restores.
A-code history
The A-code language was created by Dave Platt in early 1980s for the
purpose of writing his classic 550 expansion of the original Adventure. It was
subsequently expanded by myself in mid 1980s when merging Platt's Adventure 3
(now known as Adv550 ) with Luckett's and Pike's AdventureII (now known as
Adv440) into Adv660 (well... into Adventure4, upgraded to Adventure4+, now
known as Adv660).
I embarked on further expanding Adv660 into Adv770 in 1998, one of the
purposes of the exercise being to explore further possibilities for improving
A-code. The final result was the considerably improved Acode12. The history section describes the history of the
language in greater detail.
|