A brief summary of A-code, MLA version 11.03

(Document date 07-Oct-2000)

NB: this description is by now incomplete; I will try to find the time to add other features introduced during the development of adv770. Though to be honest, it really needs a complete re-write! In any case, the best way to learn A-code is to study A-code sources, as I did. MLA 18 Dec 2001.

NB: The up-to-date description of A-code texts is now available as a separate document. MLA 27 Oct 2015.

Contents


Introduction

A-code is the adventure-writing language developed by Dave Platt for the adv550 superset of the original Adventure, and subsequently developed by myself, in working on the adv660 superset.

A-code is not intended to be a programming language and hence as a programming language it is fairly primitive. Its strength are elsewhere - in supporting features such as text-switches or text-nesting. It also comes with a pre-programmed "skeleton" adventure template. This is written in A-code and implements lots of basic adventuring functionality, so that on the one hand you can get on with the meaty bits of your adventure straight away, while on the other if you want to give the standard parts a much more customised look, you can easily do that too. As a further bonus, each game created with the A-code system is a stand-alone package, requiring no separate game engine/interpreter.

Technically, A-code is a Polish notation (i.e. "prefix", i.e. "operator [argument [...]]") language. 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 Adventure4 grew in size, its performance on a multi-user machine gradually became less satisfactory. (We are talking mid-80s here! :-)

This is why this 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.

A-code is a deceptively simple language. Many of its features are quite primitive (e.g. global variables only, no procedure arguments...), but don't let this fool you. It is admirably suited to its purpose, making adventure development a much easier task than many other such tools. This is particularly true of this version, which comes with a pre-programmed "skeleton" adventure, already containing all generic adventure code for you to add to or modify.


A-code components

A-code source consists of (surprise!) declarations and code - in that order! Forward references are not allowed. Declarations declare a variety of entities and code manipulates them. Entities manipulated by A-code are variables, verbs, objects, places, texts, procedures, flags, values and words. All entities have the global scope. I.e. there are NO local variables or procedure arguments. (No longer the case, A-code 11 now supports local variables and procedure arguments.)

Entity names are subject to these rules:

  1. All names are case-independent.
  2. All names must start with an alpha character, a dot or a question mark.
  3. The rest of the names characters may be any of an alpha character, a digit, or any of dot (.), dash (-), underscore (_), shriek (!), single quote ('), ampersand (&) and forward slash (/).

Flags are binary yes/no properties, referred to by symbolic names. There are three separate sets of these. One set is defined for objects, one for places and one for verbs/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. Some flags are mandatory, (e.g. the object SCHIZOID flag, see below) but any number of additional ones can be declared in any of the three flag sets.

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.

Some entities (places, objects and variables) each have a state (a.k.a. value) associated with them. A state is simply a short signed integer. To enhance the legibility of A-code source, specific state values can be given symbolic names, e.g. making it possible to test a lamp against being "lit" instead of having the value of, say, 1).

More generally, numbers (signed short integers) can be used within A-code source interchangeably with symbolic constants. Compound symbolic constants, defined on the basis of numbers or previously defined constants, are also allowed for some special purposes.

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. Yes, you've spotted it! This restricts A-code to simple verb/noun commands. Which makes A-code adventures more difficult to devise, but easier to play. Not that expanding the syntax to verb/object [/instrument] would be very difficult.

Texts are named or nameless 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. Texts can contain text "switches" which allow them to be context dependent. A text switch cannot be nested in another switch (that would be meaningless!), but otherwise can occur anywhere within the text, and having components of any length. Its format is [string0/string1/string2...] and must contain not less than two strings (possibly empty). When displayed, text can be qualified by the value of a constant, a variable, an object or a place. If the qualifying value is n and the text contains text switches, only string-n of every switch is displayed. If the qualifier value is higher than the number of strings in the switch, the last string of the switch is printed. This allows texts (and for that matter object and place descriptions, which too are texts), to be context dependent.

Another feature of A-code text is the processing of the # symbol. In a text qualified by a value, each occurence of the # will be replaced either by the numerical value in question or, depending on the directive used to display the text, if the qualifier is a verb or an object, by the primary word associated with the verb or object.

As noted, A-code kernel does its own text formatting and filling at run- time. However, if a text line has a forward slash as it first non-blank character, the rest of the line will be displayed verbatim as a separate line of output.

Finally, text nesting. While braces on directive lines indicate comments, within text they signal inclusion of another previously defined piece of text, which in itself may have further nesting. The syntax is {text_name}, where text_name is either the symbolic name of a piece of text, or a variable referring to text. (See below for the A-code indirection mechanism.)

Chunks of A-code are just that - named or unnamed chunks of A-code. They can be separate procedures or can be associated with verbs or places.

You may be wondering how does one refer to nameless entities of any sort? A-code groups together all entities of one class in the order of their declaration, allowing one to reference nameless ones by offsets from named entities of the same class. Essentially, you can view a sequence of nameless entities as an "array" associated with the last declared named one.

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 +. 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 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 -.

Verbs 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.

There is no restriction on the length of symbolic names, but only the first 16 characters are significant. Names may include any "reasonable" printing ASCII characters.

As noted above, some of the entity names are automatically or selectively added to the player vocabulary. To summarise: all verb names and their synonyms (except if otherwise indicated), all object names and their synonyms (unless otherwise indicated) and some place names and their synonyms (where specifically requested).

Vocabulary words can be abbreviated by player to the minimal unambiguous length. Nevertheless, If a word used by the player is echoed via a text qualified by either the ARG1 or ARG2 variable, the full matching dictionary word is displayed. It is also possible to enforce remapping of vocabulary words. E.g. it may be kind to allow the player to refer to an object by several different synonyms, yet always echo back only one of these. E.g. a matchbox could be referenced as matchbox or just box, but you may wish "get box" to result in "You get the matchbox.". To do this, use the declaration

OBJECT   MATCHBOX, =BOX

where the "equal" sign prefixing "BOX" is not a part of the synonym but specifies that if a player says "BOX", "MATCHBOX" should be assumed instead.

An automatic indirection occurs for some A-code directives when manipulating variables into which "addresses" of other entities have been loaded. Generally speaking this happens for non-arithmetical manipulation of variables.

Except within texts, casing is irrelevant - all keywords and opcodes are internally lowercased. The uppercasing of the A-code source is merely conventional.


A-code program structure

All declarations must precede any executable code. Forward referencing is not allowed. Within these restrictions, major (declarative) directives 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. The convention of starting all "other" lines in column 10 is not mandatory.

Directive, symbolic names and numerical values can be separated by commas and or spaces. The convention of using comma-space separators is not mandatory.


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.

There are three translator instructions:

  • LIST
    start echoing A-code source being translated

  • NOLIST
    stop echoing A-code source

  • 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.

The remaining major directives are all declarators. Within each declarative category (e.g. objects, places, texts) entities are stored sequentially in the order of declaration and hence can be referenced by numerical offsets from other entities.

Other than the dbname, flags, states and constants, all declared entities are associated with a "reference number" 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. It is not necessary for the programmer 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.

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). Any line with an asterisk in column 1 is considered to be a comment and is ignored. Comments may be placed on major-command and opcode-control lines (but not on text-string lines) by starting the comment portion of the line with a left-brace ('{') - the closing of a comment with a right brace ('}') is conventional but not mandatory.


Mandatory places, variables and flags

From MLA A-code version 10 onwards these are not so much "mandatory" as "reserved". If they are not defined, the acdc converter will define them automatically. It will only complain if your A-code source defines them to be of a wrong type.

  • FLAG VERB
  • FLAG OBJECT
  • FLAG PLACE
    These three flags are common to all three kinds of flag sets. Their values are maintained automatically and they are used to decide what kind of entity one is dealing with.

  • PLACE INHAND
    This is the location of all objects the player is carrying.

  • VARIABLE HERE
    Stores the reference number of the current location of the player.

  • VARIABLE THERE
    Stores the reference number of the last location of the player.

  • VARIABLE STATUS
    The value of this variable indicates the number of words in the players command being executed (not the whole command line!). As things stand, this value can be only 1 or 2.

  • FLAG JUGGLED
    Variable set flag. Set automatically for the variable STATUS whenever the player picks up or drops something.

  • FLAG MOVED
    Variable set flag. Set automatically for the variable STATUS whenever the player changes his location.

  • FLAG FULLDISPLAY
  • FLAG DETAILDISPLAY
    Variable set flags. Changing their settings in the STATUS variable changes the verbosity of descriptions.

  • VARIABLE ARG1
    Stores the verb part of the player's command.

  • VARIABLE ARG2
    Stores the object part of the player's command.

  • FLAG SCHIZOID
    If set by the program, the object will appear in two places - its current location and the place with the reference number one higher than that of the current location. Handy for implementing objects like doors, bridges etc...

  • VERB AGAIN
    If used on its own, repeats the previous (possibly compound) command line. If embedded in a complex command line, causes the last atomic command (other than AGAIN) to be re-executed.

  • OBJECT ALL
    Allows A-code program to understand commands like GET ALL and DROP ALL


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.

First, tests with the "if" group terminated by a major opcode

  • 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* [...]
    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* [...]
    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* [...]
    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*|objname*} [...]
    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

The next lot are also tests, but their "if" groups must be terminated by the "FIN" opcode (or the deprecated "EOF" opcode).

  • IFEQ {entname1|const1}, {entname2|const2}
    Execute the following code up to the next ELSE or FIN (or EOF), if the value (state, if object or place) of the first argument is equal the value (state) of the second argument.

  • IFLT {entname1|const1}, {entname2|const2}
    Execute the following code up to the next ELSE or FIN (or EOF), if the value (state, if object or place) of the first argument is less then the value (state) of the second argument.

  • IFGT {entname1|const1}, {entname2|const2}
    Execute the following code up to the next ELSE or FIN (or EOF), if the value (state, if object or place) of the first argument is greater than the value (state) of the second argument.

  • IFAT {placename*|objname*}
    Execute the following code up to the next ELSE or FIN (or EOF), if the player is currently at the indicated location (which may be in fact an object!).

  • CHANCE {entname|constant}
    Execute the following code up to the next ELSE or FIN (or EOF), with the probability of n%, where 'n' is the value of the argument.

  • IFHAVE objname* [{state|flagname}]
    Execute the following code up to the next ELSE or FIN (or EOF), if the player is holding the indicated object. If the second argument is supplied, the object has to be in the indicated state or have the indicated flag set.

  • IFHERE objname* [{state|flagname}]
    Execute the following code up to the next ELSE or FIN (or EOF), if the indicated object is at the same location as the player. If the second argument is supplied, the object has to be in the indicated state or have the indicated flag set. This is a new directive, not present in the original A-code.

  • IFNEAR objname* [{state|flagname}]
    Execute the following code up to the next ELSE or FIN (or EOF), if the indicated object is held by the player or is in the same location as the player. If the second argument is supplied, the object has to be in the indicated state or have the indicated flag set.

  • BITST entname*, flagname
  • BIT entname*, flagname
    Execute the following code up to the next ELSE or FIN (or EOF), if the indicated entity has the corresponding flag set. Remember that only objects, places, verbs and variables have flags to their names. If a flagless entity is specified, the test returns FALSE.

  • IFKEY word
    Execute the following code up to the next ELSE or FIN (or EOF), if the nominated word appears in the player's command being processed.

  • QUERY textname*
    Display the indicated text and request a yes/no answer. Execute the following code up to the next ELSE or FIN (or EOF) if the answer is "yes". The answer is case insensitive and can be abbreviated.

  • IFINRANGE {entname|constant} {entname|constant} {entname|constant}
    Execute the following code up to the next ELSE or FIN (or EOF), if the first argument lies in the inclusive interval defined by the second argument (lower bound) and the third argument (upper bound). For the purposes of this opcode, if an argument is a variable, the value of the variable is used, if it is a constant, the constant value is used, otherwise the reference number of the indicated entity is used.

  • IFIS varname, entname
    Execute the following code up to the next ELSE or FIN (or EOF), if the indicated variable references the indicated entity.

  • IFLOC objname*, {placename*|objname*}
    Execute the following code up to the next ELSE or FIN (or EOF), if the object nominated by the first argument is located at the place indicated by the second argument (which in itself may be an object).

Now for some logicals, 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. Test which cannot affect the result are not evaluated.

  • 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 (or EOF), if the latest (compound) condition returned false.

  • FIN
    Delimits the code associated with the most recent (compound) condition. Can be used interchangeably with EOI.

Next come the three iterative opcodes together with the iterative loop terminator.

  • ITOBJ varname [objname1*, objname2*]
    Execute the following code up to the next EOI or EOF repeatedly, with the value of the nominated "loop variable" running through the specified range of objects (default all declared objects) in the order of their declaration.

  • ITPLACE varname [placename1*, placename2*]
    Execute the following code up to the next EOI or EOF 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|constant1}, {entname2|constant2}
    Execute the following code up to the next EOI or EOF 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
    Skip the rest of the iteration block and proceed with the next iteration loop.

  • BREAK
    Break out of the innermost iteration block.

  • EOI
    Delimits the code executed by the most recent iteration opcode (ITPLACE, ITOBJECT, ITERATE). Can be used interchangeably with FIN.

Other execution flow control opcodes.

  • CALL {procname|placename|objname|verbname}
    Execute code associated with the named entity, if there is any. If there is more than one (doesn't apply to procedures, of course), execute them in the order of their declaration, until either none left or the QUIT opcode is executed in one of them (be it explicitly or implicitly).

  • PROCEED
    Terminate the execution of the current chunk of A-code. Equivalent to returning from a procedure in C.

  • QUIT
    Terminate the execution of the current chunk of all current chunks of A-code (they may be nested by various CALLs) and restart the REPEAT loop at the first REPEAT procedure.

  • STOP
    Terminate the whole program immediately. Now for instructions to move objects and player.

  • APPORT objname* {placename*|objname*}
    Transport the indicated object to the indicated location (which itself may be an object!).

  • GET objname*
    Transport the indicated object into the player's hands. Equivalent to "APPORT objname* INHAND".

  • DROP objname*
    Transport the indicated object (presumed to be in player's hands (location INHAND) to the same location as the player. indicated by the variable HERE). Equivalent to "APPORT objname* HERE".

  • GOTO placename*
    Transport player to the indicated location.

  • MOVE [word [...]] placename*
    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 QUIT.

  • SMOVE [word [...]] placename* textname*
    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 QUIT.

There are three directives for producing text output. All three can be "qualified" for the purposes of # substitution and/or 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 implied qualifier

  • SAY entname* [{entname|constant}]
    Display text associated with the specified entity (text, object, place or any of these indirected through a variable), possibly modifying the text with the value of the qualifying entity/constant; any embedded # signs are replaced by the name of the qualifying entity, while text switches are governed by qualifier's value.

  • QUIP entname* [{entname|constant}]
    Like SAY, but perform a QUIT having said the text

  • VALUE entname* [{entname|constant}]
    Like SAY, but replace '#' with value of the qualifier, rather than the qualifying entity name.

  • VOCAB {entname|0}, 0, {flagname|0}, {textname|0}
    Used for displaying context-sensitive vocabulary. The second argument is not currently in use and must be supplied as 0. If a flagname is specified and the corresponding flag of the entity is not set, the directive is ignored. Otherwise the first dictionary entry for the entity is displayed, or if a textname is specified, the corresponding text is displayed rather than the dictionary word. The display, if any, is prefixed with ", ", except for the first word displayed. The count of words displayed is reset to zero by a VOCAB directive with 0 as the first argument, which has no other effect.

These opcodes are used to alter values and flag settings.

  • 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!

  • 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.

  • 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, say 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.

  • 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.

  • BISET entname*, flagname
  • BIS entname*, flagname
    Switch on the flag identified by "flagname" in the instance of the appropriate flag set belonging to the indicated entity.

  • BICLEAR entname*, flagname
  • BIC entname*, flagname
    Switch off the flag identified by "flagname" in the instance of the appropriate flag set belonging to the indicated entity.

Finally two opcodes for communication with the machine environment.

  • 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. The mappings between the first argument value and the environmental variable or condition required is quite arbitrary and is performed by the code (if any) of the procedure svar() in advcustom.c. The value returned through the second argument of SVAR is equally arbitrarily decided upon by the same routine. As supplied, A-code does not use the SVAR opcode. If you have a need to - it's up to you.

  • 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 advkernel.c procedure special(). As supplied the following actions can be selected by the appropriate value of the first argument: the value

    1. dump game to disc
    2. restore game from disc
    3. delete saved game
    4. switch to Dwarvish
    5. switch to English
    6. save value of an A-code variable over a game restore (only one variable value can be saved - usually used to preserve the wizard status)
    7. restore value saved by (6)
    8. get number of minutes since restored game dumped
    9. stick value of second argument into variable ARG1; do not alter second argument!
    10. stick value of first argument into variable ARG2; do not alter first argument!
    11. not used (reserved for ARG3 in the future!)
    12. (spare)
    13. (spare)
    14. (spare)
    15. (spare)
    16. Game-start restore
    17. Memory save
    18. Memory restore

    Any number of other special action may be defined, but codes up to and including 100 are reserved for future use by the engine.

  • DEFAULT [place*] [objflag]
    If no object specified set the object to the first one satisfying supplied criteria - being at a specific location and optionally having a specific object flag "on"; if no place specified the current value of the mandatory variable HERE is assumed as the place specification.

  • DOALL [place*] [objflag]
    Just like DEFAULT, but instead of setting the command object, 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

Oh yes, as an afterthought, perhaps something to communicate with the player.

  • INPUT [textname*]
    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 PLSCLARIFY 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:

    1. He gave several commands separated by full stops or semicolons and we have not processed the last one yet.

    2. 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!

    3. 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.

That's it! Mind you, you won't understand A-code from this description alone. Go and read the A-code source.


The most common A-code error

Just a quick word on the most common error one makes in using A-code. It is dreadfully tempting to forget that ARG2 holds a pointer rather than a value and to write "IFEQ ARG2, value", by analogy with "IFEQ object, value". This is WRONG. The correct code would either refer to ARG2 by its object name (we often know by that time which particular object ARG2 points to) or use EVAL: "EVAL variable, ARG2" followed by "IFEQ variable, value".


Obsolete directives

These obsolete directives are supported for compatibility with old versions of A-code. They are honoured only in old-style A-code, i.e. when the A-code source does not start with a DBNAME directive. (Well, not strictly true, actually, but it's not safe to assume otherwise.)

  • SYNON {value|symbname}, synon [...]
    Used to define symbolic name for constants or synonyms for already defined symbols.

  • 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.

  • EOF
    Delimits code associated with all pending (compound) conditions and iterations. EOF is simply a shorthand for the appropriate sequence of FINs and EOIs. Probably not supported at all - old-style or no old-style! Jolly well replace it with the explicit sequence of terminators whenever you find it, OK?

  • TITLE title
    Older synonym of DBNAME.

To the A-code page
To the Mipmip home page
Feel free to leave a comment!
Mike Arnautov (03 January 2017)