Game engine

The game engine interprets PLAYER commands in the context of the WORLD described by the current GAME FILE. Every time the PLAYER issues a command, the engine looks up the corresponding action or movedef defined in the GAME FILE (or recognizes a special command), executes any tests specified by the action's condstatement, and when it finds a test that matches the current GAME STATE it executes the associated WDL statement directives. Those directives may change the state of the world (e.g., by changing variable values), may move the PLAYER, may print messages to the screen, may issue WARNINGs or ERRORs, or may end the game. By chaining together sequences of such tests and directives, surprisingly complex game scenarios can be achieved.

The specific semantics of the WDL, as implemented by the Zurk game engine are:

NAMEs
ROOMs, ACTIONs, and OBJECTs all are assigned unique NAME strings. Each NAME MUST be unique in a single GAME FILE - no two ROOMs can share the same NAME, nor can a ROOM and an OBJECT share the same name. Each NAME can be declared only once (via a Room, Action, etc. command), though it may be referenced more than once (via a RoomRef, etc. command). It is an UNRECOVERABLE ERROR to reference a NAME that has not been declared, though the reference is allowed to precede the declaration in the GAME FILE. That is, a NAME, say ObjA, can be referenced (ObjRef(ObjA)) on lines 93, 112, 153, and 198 of a GAME FILE, but be declared on line 138.

The exceptions to the uniqueness rule are the NAMEs associated with VARIABLEs and MOVEs. The same VARIABLE NAME or MOVE NAME may be reused in different contexts. These cases will be described in detail below, under Variable and Move.

In addition to the NAMEs that are declared in the GAME FILE, there are a small number of built-in, special-purpose NAMEs:

Player
The NAME of the data structure corresponding to the PLAYER. This special NAME allows WDL statements to reference characteristics of the PLAYER such as Player.location.
Inventory
The special LOCATION associated with the PLAYER. The INVENTORY is a list of OBJECTs carried by the PLAYER. An OBJECT's location can be assigned to be Inventory or can be tested against Inventory. While Inventory is the name of a LOCATION, the PLAYER cannot occupy the INVENTORY location (that would be just silly).
location
The NAME of a special VARIABLE associated with every OBJECT and with the PLAYER. The location variable stores a reference to the LOCATION (ROOM or Inventory) of the object.
Motility
The NAME of a special VARIABLE associated with all OBJECTs other than the PLAYER. The meaning of this VARIABLE will be described further below, under Object.

Room and RoomRef
These statements declare and reference a ROOM (i.e., a LOCATION at which the PLAYER can be at some time during the game), respectively. A ROOM has the following properties:
NAME
See NAMEs, above.
description
String giving the description of the ROOM. The description is printed whenever the PLAYER enters the ROOM or when the PLAYER gives the look command with zero arguments.
objset
The set of OBJECTs currently in the ROOM. OBJECTs may be added to or removed from the ROOM as a result of PLAYER actions. Note that if the LOCATION of an OBJECT is updated, the objsets for all affected ROOMs MUST also be updated. E.g., if the PLAYER picks up a rose OBJECT from the garden room, then rose.location would be set to Inventory, while the rose would removed from garden's objset.
moveset
The set of MOVE commands that are available to the PLAYER in this ROOM. The moveset effectively defines the interconnectivity of the LOCATIONs in the world, by describing the neighbors of a ROOM.

Variable
This statement declares a VARIABLE. Unlike ROOMs, OBJECTs, and ACTIONs, a VARIABLE may be declared more than once in a GAME FILE. Specifically, each VARIABLE is attached to an OBJECT, and the fully qualified name of the VARIABLE is objname.varname. The fully qualified name of a VARIABLE MUST be unique. E.g., OBJECTs ObjA and ObjB can both have instances of the VARIABLE VarA, but their fully qualified names are ObjA.VarA and ObjB.VarA, respectively. No OBJECT can contain two instances of the same VARIABLE.

Object and ObjRef
These statements declare and reference an OBJECT, respectively. An OBJECT is a thing in the environment and can either be MOBILE (can be picked up and moved by the PLAYER) or SESSILE (cannot be picked up or moved). An OBJECT has the following properties:
NAME
See NAMEs, above.
description
String giving the description of the OBJECT. The description is printed whenever the PLAYER picks up the OBJECT (adds it to the PLAYER INVENTORY) or gives the look command with this OBJECT as an argument.
Motility
Special variable possessed by all OBJECTs. An OBJECT can be either Motile (meaning that it can be added to the INVENTORY or dropped in an arbitrary ROOM) or Sessile (meaning that it is immobile and cannot be picked up or relocated).
varset
(optional) An OBJECT can contain a set of VARIABLEs, allowing state to be associated with the OBJECT. In WDL, the state of a VARIABLE v associated with OBJECT o can be tested or set via o.v. If o does not have a variable named v, it is a RECOVERABLE ERROR to query or attempt to set that variable. If the attempt to access o.v is the result of a PLAYER command, then a WARNING should be issued to the PLAYER and the current command halted. If the access to o.v is detected at GAME FILE load time, then an UNRECOVERABLE ERROR should be issued to the PLAYER indicating that the GAME FILE is corrupted. If the access is detected at GAME FILE load time in the ParserTest module, then an UNRECOVERABLE ERROR should be issue and the load abandoned.

Action
An ACTION is a command that the PLAYER can execute, along with a set of conditions and outcomes for each condition. The notion is that the same ACTION can have different results depending on the GAME STATE when it is executed. E.g., an attempt to leave a ROOM through a door might fail when that door is closed (door.closed=true), or an ACTION might only be applicable when taken from a certain ROOM (Player.location=garden). Each ACTION is characterized by the following properties:
NAME
See NAMEs, above. The ACTION NAME is specified by the first argument to the ACTION declaration statement.
arity
The arity of an ACTION is the number of arguments that that action takes. E.g., an ACTION with an arity of 3 takes three arguments when the PLAYER types it in: aName argA argB argC. Each argument is mapped to a numerical argument ID in the body of the action: the first argument becomes $1, the second becomes $2, etc. The ACTION arity is specified by the second argument to the ACTION declaration statement.
condstatement
The condstatement determines the possible outcomes of the ACTION when executed in different GAME STATEs. A condstatement is essentially an arbitrarily long list of boolean expressions, each of which is associated with a list of outcome statements. When the ACTION is invoked, each of the boolean expressions are evaluated in turn. Testing stops the first time an expression is found to evaluate to true; at that point, the corresponding list of outcome statements is executed, in order. The boolean expressions and the outcome statements can test and set the current GAME STATE by referring to variables either by fully qualified name (e.g., objA.varC) or by argument reference (e.g., $2.varC). The statements can also refer to the special OBJECT Player, the special variables location or Motility, or the special value Inventory.
Move
The Move statement declares a move that is possible from some ROOM. Every MOVE must be associated with a ROOM, and different ROOMs can have MOVEs with the same name (but different conditions and outcomes). The outcome of a move describes how the GAME STATE changes when the PLAYER executes that MOVE. Like ACTIONs, MOVEs support conditional execution and outcomes. Unlike ACTIONs, MOVEs do not have arity - every MOVE is of arity 0 and accepts no arguments. It is a RECOVERABLE ERROR and should result in a WARNING for the PLAYER to provide an argument to a MOVE command.

MOVEs possess the following properties:

NAME
See NAME, above. Note that different ROOMs can declare MOVEs with the same NAME, so MOVE NAMEs are non-unique.
condstatement
The outcome(s) of a specific MOVE are described by its condstatement in exactly the same way as outcomes are handled for ACTIONs. See condstatement under Action, above, for the precise semantics.
Special WDL commands
The WDL language also provides the following directives which control the game engine itself or cause output to be displayed.
print
Displays a message to the PLAYER by printing its string argument to STDOUT. This string output MUST be wrapped at word boundaries at the 75 column mark. (I.e., the text string is wrapped at the last word boundary before the 75 column mark.) Otherwise, the string argument to the print command MUST be printed literally.
error
Displays an ERROR message to the PLAYER, by printing its string argument to STDERR, and then terminates the game and exits the Zurk engine. This statement is to be used by a GAME FILE designer to indicate an UNRECOVERABLE ERROR. Any text printed in addition to the string argument to the error statement MUST be human-consumable. The exit from the Zurk game MUST be clean and not cause the corruption of any GAME FILEs or other durable state.
warn
Displays a WARNING message to the PLAYER by printing its string argument to STDERR. Unlike error, however, warn indicates a RECOVERABLE ERROR and game play MUST continue uninterrupted. This statement is used to indicate that the PLAYER has executed an illegal command, provided the wrong number of arguments to a command, etc. The warn statement MUST NOT cause the corruption of any GAME STATE, any GAME FILEs, or any other durable state.
end
Terminates the game. The game termination MUST be clean and MUST NOT corrupt any GAME FILEs or other durable state.

Terran Lane 2005-02-28