[TODO: This document is incomplete]
This document describes how class definitions are working.
=== Syntax ===
The following kinds of tokens are available:
* Open and closing delimiters: These are ( and ) and no spaces are
required around it. They are used for grouping in many places.
* Plain name: A plain word with no sigil. The set of valid plain names is
fixed, and they are all explained in the rest of this document.
* Number: Can be in decimal, or in hexadecimal with a 0x prefix, or in
octal with a 0o prefix. The "x" or "o" must be in lowercase, but the
hexadecimal digits can be uppercase or lowercase. Decimal numbers may be
optionally preceded by a - or + sign.
* Qualified name: A name with a sigil prefix. See below for the list of
possible sigils and their meanings. In all cases except key names, you can
define your own qualified names.
* String: A string literal with quotation marks around it. A string may
contain escapes, which use a backslash followed by whatever text is being
escaped; see below section for the list of string escapes.
Names can contain the following characters:
0123456789-+_?.*/
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
Plain and qualified names may also optionally be prefixed by an equal
sign and/or a comma; their purpose is explained later. If you have both,
the equal sign comes first and then the comma.
Name sigils are:
$ Class
@ Global variable
' Key code
: Label
% Local variable
# User message
! User sound
& User function
^ User flag
Comments are also allowed; these start with a semicolon (outside of a
string literal) and end at the next line break.
=== Escapes ===
\0
Makes further text black (default).
\1
Makes further text blue.
\2
Makes further text green.
\3
Makes further text cyan.
\4
Makes further text red.
\5
Makes further text purple.
\6
Makes further text yellow.
\7
Makes further text white.
\b
Draws a horizontal rule.
\c
Makes further text centred.
\iCLASS:NUMBER\
Displays a picture. Give the class name (without $ at first) and a
colon and the zero-based index number of the picture in that class.
This is then followed by another backslash. The picture may span
multiple lines; it will automatically move the text to make room.
\l
Makes further text left aligned (default).
\n
Line break.
\qX
Make a "quiz button". Any string containing this command is a "quiz
string", and there are special behaviours involving quiz strings. The
X should be replaced by any digit or uppercase letter; that will be
displayed, and if clicked, it represents that key code.
\xXX
Hexadecimal escape, where XX is a hexadecimal number from 01 to FF,
and displays a graphic character with the given PC character code.
=== Preprocessor ===
Free Hero Mesh includes a macro preprocessor, which you may use if wanted.
All preprocessor commands are in braces; that constitutes a preprocessor
token, which may contain other tokens as arguments.
Other preprocessor tokens include the macro separator token, which is
written as a vertical bar, and a macro argument token, which is one or
more backslashes followed by a number from 1 to 255.
For user-defined macros, one argument can be either many tokens inside of
parentheses (the parentheses are part of the argument), a single token, or
a macro separator token (omitted from the expansion) followed by any number
of further tokens to make up the last argument.
Built-in macros include:
{+ <numbers...>}
Addition. The result is 0 if no arguments are specified.
{- <number> <number>}
Subtraction.
{* <numbers...>}
Multiplication. The result is 1 if no arguments are specified.
{/ <number> <number>}
Division.
{append <string> <tokens...>}
This works like {define} but adds to an existing definition rather than
replacing the definition.
{band <numbers...>}
Bitwise AND. The result is -1 if no arguments are specified.
{bit <numbers...>}
The numbers are in range 0 to 31 and denote bit positions; the result is
a number with only those bits set.
{bnot <number>}
Bitwise complement.
{bor <numbers...>}
Bitwise OR. The result is 0 if no arguments are specified.
{bxor <numbers...>}
Bitwise XOR. The result is 0 if no arguments are specified.
{call <string> <tokens...>}
Call a macro dynamically.
{cat <tokens...>}
Makes a string by concatenating several tokens together. Sigils are
omitted, macro separator tokens are removed, and numbers are converted
to decimal. Strings are also allowed.
{define <string> <tokens...>}
Define a macro. The inner tokens are not expanded yet; they will be
expanded during each use. A macro argument token with a single backslash
expands to the argument in that position, while a macro argument tokens
with multiple tokens becomes the token with one less backslash. It is
permitted to redefine existing macros as well as new ones.
{include <string>}
Include text from another file into this one. You cannot use {include}
inside of another macro or in a macro argument.
{mod <number> <number>}
Modulo.
{version <number>}
Expands into nothing. The number must be zero, otherwise it is an error.
Future versions of Free Hero Mesh may change this.
It is possible to implement a tag system in this preprocessor, which makes
it Turing complete. For example:
{define "skip" {call \2}}
{define "1" {skip \1|"3"|"3"|"2"|"1"|"H"}}
{define "2" {skip \1|"3"|"3"|"1"}}
{define "3" {skip \1|"3"|"3"}}
{define "H" \1}
{call "2"|"1"|"1"}
Note: Macro names are entirely independent from token names.
=== Global definitions ===
These are the global definitions in the class definition file.
(Animate <limit>)
Set the limit for logical animations, from 1 to 255. The default is 32.
(Background <number> [<number>])
Set the background colour, from 0 to 255. The default value is 1. You
can optionally specify a second number, which is the background colour
for the inventory; if not specified, uses the same colour for both.
(CollisionLayers <userflags...>)
Define user flags as CollisionLayers bits; the first defined flag is
bit0. Up to 8 flags can be defined in this way.
(Misc4 <userflags...>)
Define user flags as Misc4 bits; the first defined flag is bit0. Up to
32 flags can be defined in this way.
(Misc5 <userflags...>)
Define user flags as Misc5 bits; the first defined flag is bit0. Up to
32 flags can be defined in this way.
(Misc6 <userflags...>)
Define user flags as Misc6 bits; the first defined flag is bit0. Up to
32 flags can be defined in this way.
(Misc7 <userflags...>)
Define user flags as Misc7 bits; the first defined flag is bit0. Up to
32 flags can be defined in this way.
(Synchronize <slot> <length> <speed>)
Define an animation slot for synchronized animation. The slot number can
be 0 to 7, the length is the number of images in the sequence, and the
speed is the number of centiseconds between frames.
(Volume <number>)
Define the maximum allowed volume for an object to move diagonally
between two other objects. The default value is 10000.
($<name> <definitions...>)
Define a class. See the section about class definitions for details.
(@<name> <value>)
Define a global variable and its initial value.
(@<name> Array <rows> <columns>)
Define a global variable whose value is a reference to a new array, with
the specified dimensions. The maximum number of rows is 64, and the
maximum number of columns is 1024, and the maximum number of cells in
all arrays in total is 65534. All elements are initialized to zero when
the level starts.
(<message> <code...>)
Defines a default message code for all classes which do not specify
their own code for this message.
(&<name> <code...>)
Define a user-defined function. User-defined functions may take any
number of inputs from the stack and leave any number of outputs on the
stack, but may not access user-defined local variables. (It may still
access standard local variables, and all global variables, though.)
=== Class definitions ===
Within a class definition, the following definitions can be used. See also
the section about variables; many of these definitions are used to specify
the initial value for variables of objects of this class.
Outside of code blocks, named constants are not normally interchangeable
with the numbers having the same value.
<userflag>
Set a user flag bit in the definition of Misc4, Misc5, Misc6, Misc7, or
CollisionLayers of this class. You must previously define this user flag
as a global definition.
Abstract
(Not implemented yet.)
(Arrivals InPlace)
This is an abbreviation for (Arrivals 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0).
(Arrivals <numbers...>)
Define the Arrivals variable for this class. This is twenty-five numbers
each of which is either zero or one. They are meant to be on five lines
of five numbers each, making a 5x5 matrix, where the centre means this
object's location.
(Climb <number>)
Define the Climb variable for this class.
(CollisionLayers <numbers...>)
Define the CollisionLayers variable for this class. The format is the
same as for Misc4 (see below), but only the low 8-bits are usable.
Compatible
Sets the Compatible flag for this class. This changes some features for
compatibility with Hero Mesh, and would not normally be used for new
puzzle sets made with Free Hero Mesh.
,Compatible
Sets the Compatible flag for this class, but removes the restriction of
some variables limited to 16-bits.
(DefaultImage <list...>)
Each entry is either a number of an image in this class, or two
numbers in parentheses giving a range of images, or () to indicate
that there are no default images. This specifies which images can
be used in objects of this class which are initially present on
the level (placed in the editor). If () is used, then this class
is not available in the editor. If there is no (DefaultImage) block,
all images are available. The (Image) block must come before this one.
(Density <number>)
Define the Density variable for this class. If you want the Density to
be different in the editor, specify the value to use in the editor here,
and then change the Density value in the INIT block.
(Departures InPlace)
This is an abbreviation for (Departures 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0).
(Departures <numbers...>)
Define the Departures variable for this class. The format is the same as
for the Arrivals variable; see above.
(EditorHelp <strings...>)
A help message to display in the level editor; normally, this would
explain what values are expected for Misc1, Misc2, Misc3, and Dir.
Each string is one line of text.
(Hard <number>)
Define the hardness of this object on all four sides.
(Hard <pairs...>)
Define the hardness per direction. Each pair is in parentheses, and is
a direction (E, N, W, or S) followed by a 16-bit number. If any
direction is not specified, then the hardness is zero in that direction.
(Height <number>)
Define the Height variable for this class.
(Help <strings...>)
A help message for the game player, which would normally explain what
this object does. Each string is one line of text.
(Help Misc1)
Similar to (Help) but tells it to display a level string referenced
by the Misc1 of this object.
(Image <strings...>)
Specify strings with the names of images. The first string is the
name of the image numbered 0, next for the image numbered 1, etc.
Input
Set the Input flag for this class. This causes it to receive a KEY
message during the input phase of each turn.
Invisible
Set the Invisible flag for this class.
(Misc4 <numbers...>)
Specify any combination of numbers and/or bit constants. Defines the
Misc4 variable of this class to be the bitwise OR of the listed numbers.
Although this variable may have any value at run time, the definition in
a class is limited to numbers.
(Misc5 <numbers...>)
Define the Misc5 variable for this class; see Misc4 above for details.
(Misc6 <numbers...>)
Define the Misc6 variable for this class; see Misc4 above for details.
(Misc7 <numbers...>)
Define the Misc7 variable for this class; see Misc4 above for details.
Player
Set the Player flag for this class.
Quiz
If specified, the internal variables of objects of this class cannot
normally be examined by the player. However, the player can override
this definition at run time; you cannot rely on it. Class codes cannot
read the value of this flag.
(Shape <number>)
Define the shape of this object on all four sides, where 0 means flat,
1 means slanted to left, 2 means slanted to right, and 3 means slanted
both left and right.
(Shape <pairs...>)
Define the shape of this object per side, similar to the (Hard) block.
(Sharp <number>)
Define the sharpness of this object on all four sides.
(Sharp <pairs...>)
Define sharpness per direction, as for the (Hard) block.
Shovable
Set the Shovable variable for this class to 0x55 (meaning it is shovable
in all four directions).
(Shovable <dir...>)
Set this object to be shovable in the specified directions, which can be
any absolute direction.
(Shovable <number>)
Set the Shovable variable to the specified 8-bit number. (You cannot set
the initial value of any other bits; they are always clear.)
Stealthy
Set the Stealthy flag for this class.
(Strength <number>)
Define the Strength variable for this class.
(SUBS <code...>)
Make a code block with no entry point. This isn't very useful, but it
is provided for compatibility with Hero Mesh.
(Temperature <number>)
Define the Temperature variable for this class.
VisualOnly
Set the VisualOnly flag for this class.
(Volume <number>)
Define the Volume variable for this class.
(Weight <number>)
Define the Weight variable for this class.
(<label> <code...>)
Make a code block whose entry point is the specified label.
(<message> <code...>)
Make a code block whose entry point is the specified message.
(<key> <code...>)
Add a code block for key dispatch. This cannot be combined with a KEY
message in the same class; it causes the KEY message to be automatically
defined for this class. If this class has the Input flag and the first
instruction is not IgnoreKey, then it is entered into an internal list
of key codes to not ignore. Otherwise, the automatic KEY messages (for
all classes with them, not only this one) will have the effect of the
IgnoreKey instruction when an unrecognized key is specified. You can
still call the KEY message by yourself; Arg1 is the key code, and if
Arg3 is true then the implicit IgnoreKey will not be executed (although
any explicit IgnoreKey will still work).
=== Data types ===
The following data types are available:
* Number: A 32-bit integer. Whether it is treated as signed or unsigned
depends on the context. In some cases, it is used as bit field data.
* Class: A class name with a $ prefix.
* Message: A message name. User-defined message names have a # prefix;
standard message names have no prefix.
* Object: A reference to an object. There are no literals of this type.
* String: A string in quotation marks. There are no string manipulation
functions; the only thing that can be done with a string is to display it,
or to compare if one string matches another.
* Sound: A named sound effect. Values of this type cannot be compared with
anything, even other values of the same type.
* Mark: There is only one value of this type; it is used to delimit lists
of values on the stack.
* Array: A reference to an array. You cannot allocate arrays at run time;
the available array memory is fixed at compile time, subject to the global
array definitions.
Some things are not their own types, and are other uses of numbers:
* Null: A null class or null object is represented as zero.
* Boolean: When a boolean is required as input to some instruction, zero
is false, and most other values (of any type) are true, except for sounds
which cannot be used as booleans at all. When an instruction produces a
boolean value as output, true is one and false is zero.
* Key: A key code for input (not necessarily the same as the physical key
with that label). See the list in the below section.
* Direction: Can be absolute or relative. For absolute directions, zero is
east, and increasing numbers go counterclockwise 45 degrees each, up to
seven for southeast. Relative directions start at eight for forward and
otherwise work similarly (increasing numbers go counterclockwise).
=== Constants ===
The following constants are available. Some of them are numeric constants
and using them pushes numbers to the stack, and they are interchangeable
with the corresponding numbers where instructions are expected.
Absolute directions:
E = 0
NE = 1
N = 2
NW = 3
W = 4
SW = 5
S = 6
SE = 7
Relative directions:
F = 8
LF = 9
L = 10
LB = 11
B = 12
RB = 13
R = 14
RF = 15
Bit constants:
bit0 to bit31 = numbers with a single bit set
Animation constants:
STOP = 0
ONCE = 1
LOOP = 2
OSC = 8
OSCLOOP = 10
Standard messages:
ARRIVED
BEGIN_TURN
COLLIDE
COLLIDEBY
CREATE
CREATED
DEPARTED
DESTROY
DESTROYED
END_TURN
FLOATED
HIT
HITBY
INIT
JUMPED
KEY
LASTIMAGE
MOVED
MOVING
PLAYERMOVING
POSTINIT
SUNK
Input constants:
'BACK = 8
'TAB = 9
'CENTER = 12
'ENTER = 13
'SHIFT = 16
'CTRL = 17
'BREAK = 19
'CAPSLOCK = 20
'SPACE = 32
'PGUP = 33
'PGDN = 34
'END = 35
'HOME = 36
'LEFT = 37
'UP = 38
'RIGHT = 39
'DOWN = 40
'DELETE = 46
'0 = 48
'1 = 49
'2 = 50
'3 = 51
'4 = 52
'5 = 53
'6 = 54
'7 = 55
'8 = 56
'9 = 57
'A = 65
'B = 66
'C = 67
'D = 68
'E = 69
'F = 70
'G = 71
'H = 72
'I = 73
'J = 74
'K = 75
'L = 76
'M = 77
'N = 78
'O = 79
'P = 80
'Q = 81
'R = 82
'S = 83
'T = 84
'U = 85
'V = 86
'W = 87
'X = 88
'Y = 89
'Z = 90
'NUMPAD0 = 96
'NUMPAD1 = 97
'NUMPAD2 = 98
'NUMPAD3 = 99
'NUMPAD4 = 100
'NUMPAD5 = 101
'NUMPAD6 = 102
'NUMPAD7 = 103
'NUMPAD8 = 104
'NUMPAD9 = 105
'MULTIPLY = 106
'DECIMAL = 110
'DIVIDE = 111
'F9 = 120
'F10 = 121
'F11 = 122
'F12 = 123
'NUMLOCK = 144
'SCRLOCK = 145
'SEMICOLON = 186
'EQUALS = 187
'COMMA = 188
'MINUS = 189
'PERIOD = 190
'SLASH = 191
'TILDE = 192
'OBRACKET = 219
'BACKSLASH = 220
'CBRACKET = 221
'QUOTE = 222
Standard sound constants:
ANHH
BANG
BEDOINGNG
BEEDEEP
BOOOM
BOUNCE
BRRREEET
BRRRT
BUZZER
BWEEP
CHEEP
CHYEW
CLICK
DEEP_POP
DINK
DOOR
DRLRLRINK
DYUPE
FAROUT
FFFFTT
FROG
GLASS
GLISSANT
HAWK
HEARTBEAT
JAYAYAYNG
KEWEL
KLECK
KLINKK
LOCK
OLDPHONE
POUR
POWER
RATCHET1
RATCHET2
RATTLE
SMALL_POP
SPLASH
STEAM
TAHTASHH
THMP_thmp
THWIT
TICK
UH_OH
UNCORK
UNHH
VACUUM
WAHOO
WHACK
YEEHAW
=== Variables ===
These are the variables which each object has. Some are marked [ro] below
because they are read-only. In all cases, you can put , in front to access
a different object rather than self and = in front to write that variable
(unless it is read-only). You can also access some of these variables also
on classes instead of objects; these are always read-only. The variables
which are available on classes too are marked [c] below.
Some variables list one type, and some list two. If there are two types,
"int16/int32" means any number written to it is truncated to 16-bits in
compatible mode, but the full value is retained in incompatible mode. The
16-bit number is treated as unsigned, so it is zero-extended to 32-bits.
The notation "int16/any" means the same thing, except that the variable
is not limited to numbers; non-numbers are never truncated.
A few variables require a direction on the top of the stack, above the
value if you are writing. These are marked [d] below. These are really
four variables, one for each direction (not counting diagonals).
If you use the comma prefix to refer to another object, the object to
refer to is always below the direction and/or value to write on the stack
(if there are any such values).
In incompatible mode, many "physics" variables are treated as signed.
Most of these variables are state-changing; writing to them is not allowed
on the same turn as IgnoreKey. Exceptions are Distance and KeyCleared.
%xyz : any
A user-defined variable. This variable cannot be accessed on other
objects other than this one. You can give it any name with a percentage
sign at first. User variables are initialized to zero, and need not be
declared anywhere.
^xyz : bool [c]
A user-defined flag, which is one bit in Misc4, Misc5, Misc6, Misc7, or
CollisionLayers. If it is CollisionLayers, then it is read-only; other
flags are read/write. User defined flags must be defined first (globally)
before they can be used. Unlike user-defined variables, you can access
user-defined flags on any object.
Arrivals : int32
Only the low 25-bits are used. Each bit which is set indicates that it
cares if other objects arrive around it at that relative location, where
bit0 is two paces northeast, bit1 is to the west of that, etc, and then
bit4 two paces northwest of this object, and bit5 starts on the next
row to the south, etc, and bit12 is this object's location.
Arrived : int32
When an object arrives in the location where this object cares about
arrivals (according to the Arrivals variable), the corresponding bits
are set in the Arrived variable. If this value is nonzero, then it will
also send a ARRIVED message during the trigger phase. You can write all
bits of this variable, but only the low 25-bits can be read back; if you
write a nonzero number with only the high bits set, then it will still
be triggered but will be read back as zero.
Busy : bool
If any object has either the Busy or UserSignal variable set, then the
player input is blocked, and the turn may continue. Use this to control
the timing of effects in LASTIMAGE blocks.
Class : class [ro]
The class of this object.
Climb : int16/int32 [c]
In order for this object to move, this object's Climb must equal or
exceed the Height of all objects at the target location, otherwise it
is prevented from moving.
CollisionLayers : int8 [c] [ro]
Any set bit means no other object with that same bit set in this field
may exist at the same location.
Compatible : bool [c] [ro]
The compatibility flag. Class definitions imported from EKS Hero Mesh
always set this flag; in new puzzle sets it is normally not set.
Density : int16/int32 [c]
Determines the order that objects are stacked within each cell. When an
object is moved or created, its Density is compared with the Density of
the objects already present at that location, in order to insert it into
the stack of objects there, at the top, bottom, or middle, where lesser
numbers mean closer to the top, and greater numbers are deeper. If there
are multiple objects of the same Density, the new one goes above others
with the same Density. If you change the value of this variable, it will
automatically float/sink the object if necessary in order to fit it into
the correct stacking order, sending FLOATED and SUNK messages.
Departed : int32
This is like Arrived but triggered for departures (as specified by the
Departures variable) rather than arrivals.
Departures : int32
This is like Arrivals but for positions where it is triggered by objects
leaving those locations rather than arriving there.
Destroyed : bool [ro]
It is set if this object has been successfully destroyed (but not yet
deleted from memory). You must use the Destroy or Assassinate command
in order to set this flag; you cannot set it by yourself. Unlike all
other variables, you can access this variable even for an object that
does not exist; it returns 1 in that case.
Dir : int3
The current direction. When it moves (without teleportation), it will
automatically be set to the direction it moved. You can also set this
by yourself. Relative directions are relative to this direction. If you
set this by yourself to a relative direction, then it will automatically
be set to an absolute direction, based on the previous value.
Distance : int16
When an object moves (including due to teleportation), the Manhattan
distance of the movement is added to the Distance variable. This is
reset to zero at the beginning of each turn.
Done : bool [c]
This flag is used to determine whether or not to find the object in a
for/next loop. It automatically clears all Done flags at the beginning
of each turn and at the entry of each for/next loop, so usually you do
not need to set this by yourself.
Hard : int16 [c] [d]
See Sharp.
Height : int16/int32 [c]
Used to block the movement of other objects; see Climb for details. In
order for HIT and HITBY messages to work, Height must be positive.
Image : int16
The index number of the picture to display. The (Image) block in the
class definition specifies which picture to display for each index
number, where the first picture is zero. The actual picture being
displayed may differ if an animation is in progress, and no picture
will be displayed at all if the Invisible flag is set, although this
variable still remains available in such circumstances.
Inertia : int16/int32
This determines how much "left over" Strength an object has to move.
Normally, when an object tries to move, its Inertia is set to the
Strength of the object which is moving, and then the Weight of the
objects moved are deducted from Inertia. Normally you do not need to
set this value by yourself nor to read it, but you might use it in the
HIT or HITBY messages to affect how much it can push, or to check the
Inertia after the movement is complete to see what is left over.
Invisible : bool [c]
If set, then this object is not displayed on the screen. However, it
is still present in the level and does everything else that a visible
object will do.
KeyCleared : bool
The game engine does nothing with this except to automatically clear it
between turns, so that you need not do by yourself.
Misc1 : int16/any
The game engine does not use this variable; use it for your own use. The
Misc1-Misc3 variables can be defined for each individual object in the
level editor; normally they are zero. In the level editor, they can only
be defined as a 16-bit number, a class, a message, or a string; at run
time they can be set to any value.
Misc2 : int16/any
The game engine does not use this variable; use it for your own use.
Misc3 : int16/any
The game engine does not use this variable; use it for your own use.
Misc4 : int16/any [c]
The game engine does not use this variable; use it for your own use.
Misc5 : int16/any [c]
The game engine does not use this variable; use it for your own use.
Misc6 : int16/any [c]
The game engine does not use this variable; use it for your own use.
Misc7 : int16/any [c]
The game engine does not use this variable; use it for your own use.
Moved : bool
After a Move instruction successfully moves this object, it will set
this flag. During the trigger phase, it will send the MOVED message
to all objects which have moved; you can set or clear this flag by
yourself if you want to cause it to trigger even though it didn't
move or to not trigger even though it did move.
Moving : bool
This flag indicates that a deferred movement is scheduled for this
object. The direction of movement is specified by the Dir variable.
Player : bool [c] [ro]
If this object is the player. This is used implicitly as the From of
some messages sent by the game engine, and has a few other purposes.
(Normally, a level should have exactly one object of such a class,
although this is not mandatory; any number (including zero) is allowed.)
Shape : int16 [c]
Defines the shape of the object, which is used when one object tries to
move into another one that it can't climb over. The low 2-bits are for
east, next 2-bits for north, next 2-bits for west, and finally the high
2-bits are for south. Each of these 2-bit values can be 0 for flat (no
sliding), 1 for slanted to the left, 2 for slanted to the right, and 3
for slanted both left and right. (Left and right are when "facing" that
side of the object.)
ShapeDir : int2 [c] [d]
Allows accessing the individual 2-bit parts of Shape.
Sharp : int16 [c] [d]
When one object tries to move into another object, the Hard and Sharp
values for the sides that are touching will be compared. If the Sharp
value for one is greater than the Hard of the other, then the object
with insufficient Hardness is destroyed.
Shovable : int16 [c]
Defines what directions the object may be shoved, where bit0 means east,
bit2 means north, bit4 means west, and bit6 means south. Bit1, bit3,
bit5, and bit7 can be used for diagonal shoving. Higher bits are
reserved for future and should not be used.
Stealthy : bool [c]
If this flag is set, then the Arrived and Departed variables of other
objects are not automatically set when this object moves.
Strength : int16/int32 [c]
When this object's code tries to move this or other objects by the use
of the Move instruction, the Strength must be greater than or equal to
the total Weight of all objects being moved, or else it won't move.
Temperature : int16/int32 [c]
The game engine does not use this variable; use it for your own use.
UserSignal : bool
This variable has the same effect as Busy; see Busy for details. It is
still a separate variable though.
UserState : bool [c]
The game engine does not use this variable; use it for your own use.
VisualOnly : bool [c]
If set, this object is ignored by most operations, although it can still
receive messages, and ObjClassAt can still find it. If the Compatible
flag is also set, then VisualOnly also has the effects of Stealthy.
Volume : int16/int32 [c]
If an object tries to move diagonally, it will not be able to move if
the sum of its Volume and the largest Volumes at the orthogonally
adjacent cells that it is moving between is greater than the limit
(which is normally 10000, but you can redefine it globally). See the
documentation about moving objects for further details.
Weight : int16/int32 [c]
Determines how much Inertia is required to move this object (and is used
up once it has moved, or if it failed to move it). See Strength.
Xloc : int8 [ro]
The 1-based X coordinate of this object. To move the object, use any of
the instructions for movement; it cannot be moved by directly assigning
the new coordinates to these variables.
Yloc : int8 [ro]
The 1-based Y coordinate of this object (1 is at the top of the screen).
=== Instructions ===
For some instructions, a comma prefix means to operate on another object,
while the lack of the comma means to operate on itself; for some other
instructions, a comma prefix means to use signed instead of unsigned
arithmetic. An equal sign prefix usually means to write instead of read.
Anywhere an instruction is allowed, it may be one of these instructions, or
it may be a constant value, or reading/writing a variable (see the above
section about variables specific to objects), or a block instruction (see
the next section for block instructions).
Many instructions are state-changing instructions; these instructions are
marked with ** in the summary line. Such instructions are not allowed to be
used on the same turn as the IgnoreKey instruction.
<function>
Call a user-defined function (the name starts with a ampersand).
<global> ( -- any )
Read a global variable.
=<global> ( any -- ) **
Write a global variable.
<label>
Define a label. Labels are local to the current class. (Label names
always start with a colon.)
=<label>
Go to a label. (Put the colon after the equal sign; this instruction,
and the one below, are using a double sigil.)
,<label>
Call a label as a subroutine; when it returns, comes back to here.
. ( x -- )
+ ( in1 in2 -- out )
Add two numbers together.
- ( in1 in2 -- out )
Subtract in2 from in1.
* ( in1 in2 -- out )
Multiply two numbers together.
,* ( in1 in2 -- out )
Signed multiply in1 by in2.
/ ( in1 in2 -- out )
Unsigned divide in1 by in2 producing the quotient.
,/ ( in1 in2 -- out )
Signed divide in1 by in2 producing the quotient.
_ ( -- mark )
Add a mark to the stack.
a? ( any -- bool )
True if the value is an array reference, or false if it is any other
type. Error if it is a sound.
Animate ( flag start end delay -- ) **
Start or stop an animation for this object. This also sets the Image
variable equal to the start value. The flag can be STOP to stop an
animation, ONCE to play the animation once (and to queue a LASTIMAGE
event if the animation isn't changed before that happens; note that
the message is sent even before the animation is actually visible),
LOOP to play it in a loop, or OSCLOOP for an oscillating loop. The
delay between frames is in centiseconds; the start and end are the
image numbers in this class, and may be ascending or descending.
AnimateDead ( x y class start end delay -- )
Create a dead animation, at the specified coordinates. Give the class
to use the pictures of, and the start and end image number, and the
delay between frames in centiseconds. This will draw the animation on
the screen without being associated with any object; this animation is
purely visual and does not affect the game state. The animation will
play once and then it will disappear.
Arg1 ( -- value )
The first message argument.
=Arg1 ( value -- )
Allows setting the first message argument. This will last until the
current message returns, and does not affect further messages sent; it
allows Arg1 to be used as a mutable local variable.
Arg2 ( -- value )
The second message argument.
=Arg2 ( value -- )
Allows setting the second message argument. This will last until the
current message returns, and does not affect further messages sent; it
allows Arg2 to be used as a mutable local variable.
Arg3 ( -- value )
The third message argument. If the message was sent with only two
arguments, then this value is zero by default.
=Arg3 ( value -- )
Allows setting the third message argument. This will last until the
current message returns, and does not affect further messages sent; it
allows Arg3 to be used as a mutable local variable.
ArrayCell ( array row column -- array )
Make a reference to a single cell of an array. The new reference is
treated as a reference to a 1x1 array, which aliases the original array.
Coordinates are zero-based.
ArraySlice ( array start count -- array )
Make a slice of an array. The new reference aliases the original array.
Coordinates are zero-based.
Assassinate ( -- ) **
Destroy this object without sending any messages. The object is marked
as destroyed, but its variables are still accessible until the garbage
collector runs (during the trigger step for combatible objects, and
during the cleanup step for all objects). Assassination always succeeds,
so there is no result value to indicate success or not.
,Assassinate ( obj -- ) **
Destroy the given object without sending any messages.
band ( in1 in2 -- out )
Bitwise AND.
(bit <numbers>) ( -- number )
Make a number with only the specified bits set, given numbers 0 to 31.
bnot ( in -- out )
Bitwise NOT.
bor ( in1 in2 -- out )
Bitwise OR.
Broadcast ( class message arg1 arg2 -- count )
Send a message to all objects of the specified class (or to all objects
of all classes if the specified class is zero), in the reverse order of
the creation of the objects. The result value is the number of objects
of that class.
(Broadcast <class>) ( message arg1 arg2 -- count )
An alternative syntax for Broadcast (needed only for compatibility with
EKS Hero Mesh).
BroadcastEx ( class message arg1 arg2 arg3 -- count )
As Broadcast but with three message arguments.
BroadcastSum ( class message arg1 arg2 -- total )
As Broadcast but the result is the sum of the return values rather than
the number of objects. If a return value is a class or object, it is
treated as 1. Other non-numeric return values are errors.
BroadcastSumEx ( class message arg1 arg2 arg3 -- total )
As BroadcastSum but with three message arguments.
bxor ( in1 in2 -- out )
Bitwise XOR.
c? ( any -- bool )
True if the value is a class, or false if it is any other type. Error if
it is a sound.
chain ( any -- bool )
If given an object of the same class as the current object, selects that
object as the current object and continues executing the code with that
object instead. This new current object is not saved if you return from
a function or a subroutine call. If it successfully chained, then the
result is false. If given an object of a different class, an object that
doesn't exist, or anything other than an object, then it does nothing
and the result is true.
Chebyshev ( obj -- number )
Calculate the Chebyshev distance between this object and the specified
object. If the specified object is zero, then the result is also zero.
,Chebyshev ( obj1 obj2 -- number )
Calculate the Chebyshev distance between thie two specified objects. If
either specified object is zero, then the result is also zero.
Coloc ( obj -- bool )
True if this object and the specified object are in the same place, or
false otherwise. Always false if the object is destroyed, or if one
object is in the bizarro world and the other one isn't.
,Coloc ( obj1 obj2 -- bool )
True if the two specified objects are in the same place, or false
otherwise. Always false if the object is destroyed, or if one object
is in the bizarro world and the other one isn't.
CopyArray ( src dest -- ) **
Copy one array to another. It is OK if the two references overlap.
Create ( class x y image dir -- obj ) **
Creates a new object at the specified location, and returns it. The
result is zero if the class is zero, the coordinates are out of range,
the object cannot be created due to the CollisionLayers, or if the new
object is destroyed before its CREATE message returns.
cz? ( any -- bool )
True if the value is a class or zero, or false if it is neither a class
nor zero. Error if it is a sound.
DelInventory ( class image -- ) **
Delete an item from the inventory; see SetInventory for more details.
Delta ( in1 in2 -- out )
Subtracts the smaller input from the larger (unsigned).
Destroy ( -- value ) **
Destroy this object. The variables can still be accessed after it is
destroyed until it is garbage collected. This calls the DESTROY message;
the return value will be the result of this instruction, and if it is
false then it is destroyed, and if true then the destruction fails.
,Destroy ( object -- value ) **
Destroy the specified object (as Destroy but for any object).
DotProduct ( array array -- any )
Compute the dot product of two arrays. Any nonzero number times a class,
message, or object will shortcut and return that class, message, or
object; zero can multiply by any value of any type to make zero; a class
by an object will return that object if the class is correct; an object
by a message will send that message to that object, and add the return
value to the running total, or stop and return that value if the return
value isn't a number.
dup ( x -- x x )
eq ( in1 in2 -- bool )
Test if they are equal. Sounds cannot be compared, but you can compare
values of any other type. Strings compare as equal if they contain the
same text. Object references are only equal if they refer to the same
object; objects which no longer exist still compare correctly. Values
of two different types are never equal to each other.
eq2 ( in1 in2 in3 in4 -- bool )
Test if in1 is equal to in3 and in2 is equal to in4. Comparison works
the same way as the "eq" instruction.
Finished ( -- number )
Returns the value of an internal flag which tells it that the beginning
and ending phases should be skipped. This is a 8-bit number; zero means
don't skip them, and any other number means it does. When the game engine
sets this automatically, it normally sets it to 1, but "-1 FlushClass"
during the input phase sets it to 255. When you set this value by
yourself, you can use any 8-bit number.
=Finished ( number -- )
Write to the Finished variable. Only the low 8-bits are used. When set to
nonzero then the beginning and ending phases are skipped (see above), but
if IgnoreKey is used, then all phases are skipped, regardless of the
value of this flag.
flip ( mark ... -- mark ... )
Reverses everything above the mark on the stack.
FlushClass ( class -- ) **
Resets the Arrived, Busy, Departed, Inertia, Moved, and UserSignal flags
of all objects of the specified class to zero. If the class is -1, then
all objects are flushed in this way, and during the input phase, it also
skips the beginning and ending phases if the class is -1.
FlushObj ( -- ) **
Resets this object's Arrived, Departed, Inertia, Moved, and UserSignal.
,FlushObj ( obj -- ) **
Resets the Arrived, Busy, Departed, Inertia, Moved, and UserSignal flags
of the specified object only.
From ( -- obj )
The object which send the message to this object. In some cases, this
will be zero instead of a valid object.
ge ( in1 in2 -- bool )
Test if first input is greater or equal to second input (unsigned).
,ge ( in1 in2 -- bool )
Test if first input is greater or equal to second input (signed).
GetArray ( array row column -- value )
Read a value from an array. Coordinates are zero-based.
GetInventory ( class image -- value true | false )
Read from the inventory, with true if it exists or false if not.
gt ( in1 in2 -- bool )
Test if first input is greater than second input (unsigned).
,gt ( in1 in2 -- bool )
Test if first input is greater than second input (signed).
HeightAt ( x y -- height )
Finds the greatest height among objects at the specified location.
IgnoreKey ( -- )
There is no effect outside of the input phase. During the input phase,
indicates that this input is not part of the solution, so it will not
be entered into the replay. It is an error to ignore inputs which do
cause state changes. Pop-up messages are still allowed, and unlike in
EKS Hero Mesh they will not break replayability; the key to dismiss a
non-quiz popup is not entered into the replay list, and the key to
dismiss a quiz popup will be treated as a non-quiz input. IgnoreKey
also causes the rest of the turn after the input phase to be skipped.
in ( x mark ... - bool )
Check if x is equal to any of the values above the mark; equality is
tested the same as the "eq" instruction.
InitArray ( array value -- ) **
Fill all cells of an array with the specified value.
IntMove ( dir -- bool ) **
Similar to Move but do not initialize Inertia at all; use the current
value of Inertia instead.
,IntMove ( obj dir -- bool ) **
Similar to ,Move but do not initialize Inertia at all; use the current
value of Inertia instead.
is ( x y -- bool )
Where x is a class or object or zero, and y is a class, check that it
is an object of that class, is the same class, or is a subclass of the
class. If y is zero, then it is always true unless x is zero.
JumpTo ( x y -- bool ) **
As MoveTo but sends JUMPED message to that object after it has been
successfully teleported.
,JumpTo ( obj x y -- bool ) **
As ,MoveTo but sends JUMPED message to that object after it has been
successfully teleported.
Key ( -- number )
During the input phase, the key input. During other phases, zero.
land ( in1 in2 -- out )
Logical AND.
le ( in1 in2 -- bool )
Test if first input is less or equal to second input (unsigned).
,le ( in1 in2 -- bool )
Test if first input is less or equal to second input (signed).
Level ( -- number )
The level code value for this level. The game engine does nothing with
this value, but you can use it in class codes if you wish. (For puzzle
sets converted from EKS Hero Mesh, this is the zero-based level number;
a few badly designed puzzles use it. In Free Hero Mesh, you can set it
to whatever 16-bit number you wish in the level editor, and then use it
as an additional parameter for the puzzle.)
lnot ( in -- out )
Logical NOT.
Loc ( -- x y )
The X and Y coordinates of this object; same as "Xloc Yloc".
,Loc ( obj -- x y )
The X and Y coordinates of the specified object; same as "dup ,Xloc
swap ,Yloc" (but more efficient).
LocateMe ( -- )
Makes the current object especially visible. This is meant to help the
player to notice where the "Hero" object is more easily, but you can use
it to make other objects noticeable too if that is appropriate.
lor ( in1 in2 -- out )
Logical OR.
LoseLevel ( -- )
Ends all execution and results in loss of game.
lsh ( in shift -- out )
Left shift. If the shift amount is out of range 0-31, all bits are
shifted out, and the result is zero.
lt ( in1 in2 -- bool )
Test if first input is less than second input (unsigned).
,lt ( in1 in2 -- bool )
Test if first input is less than second input (signed).
lxor ( in1 in2 -- out )
Logical XOR.
m? ( any -- bool )
True if the value is a message, or false if it is any other type. Error
if it is a sound.
Manhattan ( obj -- number )
Calculate the Manhattan distance between this object and the specified
object. If the specified object is zero, then the result is also zero.
,Manhattan ( obj1 obj2 -- number )
Calculate the Manhattan distance between thie two specified objects. If
either specified object is zero, then the result is also zero.
max ( in1 in2 -- out )
Whichever input number is greater (unsigned).
,max ( in1 in2 -- out )
Whichever input number is greater (signed).
MaxInventory ( number -- )
Results in an error and loss of game if the number of different
inventory items exceeds the given number, otherwise no effect.
min ( in1 in2 -- out )
Whichever input number is lesser (unsigned).
,min ( in1 in2 -- out )
Whichever input number is lesser (signed).
mod ( in1 in2 -- out )
Unsigned divide in1 by in2 producing the remainder.
,mod ( in1 in2 -- out )
Signed divide in1 by in2 producing the remander.
Move ( dir -- bool ) **
Move this object in the given direction (which may be absolute or
relative to the current direction). The result will be true if the
move is successful or false if it failed. See the section about
movement for details.
,Move ( obj dir -- bool ) **
As Move but moves a specified object rather than necessarily this one.
Move+ ( dir -- bool ) **
Similar to Move but adds Strength to Inertia without resetting Inertia.
(The reason this exists is for compatibility with a bug in EKS Hero
Mesh; you probably do not need to use this yourself.)
,Move+ ( obj dir -- bool ) **
As Move+ but for a specified object.
+Move ( dir -- bool ) **
Schedules a deferred move for this object in the specified direction
(which may be absolute or relative). Some things are checked at this
time, while other things are checked at the time that the movement will
be made; its working is different from non-deferred movements. The
result is true if the move was scheduled or false if it isn't. (Note:
Do not confuse +Move with Move+; they are unrelated.)
,+Move ( obj dir -- bool ) **
As +Move but for a specified object rather than necessarily this one.
-Move ( dir -- bool ) **
Cancel a deferred move in the specified direction, and possibly also
other things that are shoved by it. The result will be true if it was
scheduled and successfully removed, or false otherwise.
,-Move ( obj dir -- bool ) **
As -Move but for a specified object rather than necessarily this one.
MoveNumber ( -- number )
The current move number. This is initially zero, and is advanced after
each input phase (before the beginning phase).
MoveTo ( x y -- bool ) **
Teleports this object to the specified coordinates; the MOVING message
(and PLAYERMOVING if applicable) are sent to check if it is allowed.
This also updates the Distance variable, and will deal with arrivals and
departures, and send FLOATED and SUNK messages as appropriate.
,MoveTo ( obj x y -- bool ) **
As MoveTo but for a specified object, not necessarily this one.
Msg ( -- message )
The current message being processed.
n? ( any -- bool )
True if the value is a number, or false if it is any other type. Error
if it is a sound.
ne ( in1 in2 -- bool )
As eq but the result is inverted (like "eq lnot").
neg ( in -- out )
Multiply by negative one.
NewX ( oldx dir -- newx )
Advance the number in the direction as though it is a X coordinate. If
the direction is north or south, leaves it alone, but if it is east or
west then it is increased or decreased by one. The output is never less
than zero nor exceeding the playfield width by more than one.
NewXY ( oldx oldy dir -- newx newy )
NewX and NewY together.
NewY ( oldy dir -- newy )
Advance the number in the direction as though it is a Y coordinate.
nin ( x mark ... - bool )
Check if x is unequal to any of the values above the mark; this is the
same as "in lnot".
nip ( x y -- y )
o? ( any -- bool )
True if the value is an object (whether or not it has been garbage
collected), or false for any other type. Error if it is a sound.
ObjAbove ( -- obj )
The object above this one (0 if this one is at the top). "Above" means
it overlaps this object, not upward on the screen (north).
,ObjAbove ( obj -- obj )
The object above the specified object (0 if there isn't any).
ObjBelow ( -- obj )
The object below this one (0 if this one is at the bottom). "Below"
means this object overlaps it, not downward on the screen (south).
,ObjBelow ( obj -- obj )
The object below the specified object (0 if there isn't any).
ObjBottomAt ( x y -- obj )
Find the object on the bottom at the specified location. The result will
be zero if that location is vacant or out of range.
ObjClassAt ( class x y -- obj )
Find the bottom-most object of the specified class at that location. If
there is no object of that class, then the result is zero. This function
will find objects with the VisualOnly flag set as well as clear. You may
specify zero instead of a class, in which case it finds nothing. Any
other number, or any other value that isn't a class, is an error.
ObjDir ( dir -- obj )
Find the top-most object in the cell one step in the specified direction
from this object.
,ObjDir ( obj dir -- obj )
Find the top-most object in the cell one step in the specified direction
from the specified object.
ObjLayerAt ( layers x y -- obj )
Find an object with the given CollisionLayers bits set at that location.
If you specify multiple bits, it finds one with any of those bits. (It
is not possible for there to be more than one such object.)
ObjMovingTo ( x y -- ... )
Push on the stack all objects scheduled to move to the specified X and Y
coordinates. There may be zero or more such objects; you can add a mark
to the stack in order to delimit this list (it won't do so automatically,
since you may be putting multiple lists together).
ObjTopAt ( x y -- obj )
Find the object on the top at the specified location. The result will be
zero if that location is vacant or out of range.
over ( x y -- x y x )
oz? ( any -- bool )
True if the value is an object or zero, or false if it is neither an
object nor zero. (Even if the object has been garbage collected, it is
still true.) Error if it is a sound.
pick ( index -- any )
Copy a value from the specified index from the top of the stack, where 0
means the top of the stack, 1 means the one below, etc.
PopUp ( value -- )
Displays a popup message. Normally, the value is a string, but it can be
another type, and it will try to display it. If the text contains any \q
commands, then dismissing the popup message will send a KEY message to
the object which created the popup message. If there is already another
existing popup message, only the first one set up will be displayed, and
the others will be ignored. IgnoreKey also affects what happens when a
popup message is dismissed; see IgnoreKey for details.
(PopUp <number>) ( string args... -- )
Displays a popup message, like PopUp does. However, this one allows the
string to contain substitution codes; see the section below about what
substitution codes are allowed in popup messages. Each substitution code
consumes some number of arguments, from bottom to top. The number of
arguments must be 0 to 32.
Rel ( dir -- dir )
Resolves a relative direction to an absolute direction.
,Rel ( obj dir -- dir )
Resolves a relative direction to an absolute direction, using the
direction of the specified object as the base. If zero is specified
instead of a valid object, thent the result is the same as the input.
ret ( -- )
Exit the current subroutine. If this is a message block, it must either
leave the stack as it is, or leave it but with one extra value pushed
which will be the return value from the message call. (This is implied
at the end of a code block.) For a user defined function call, or a
subroutine call, these restrictions are not applicable.
rot ( x y z -- y z x )
-rot ( x y z -- z x y )
rsh ( in shift -- out )
Logical right shift. If the shift amount is out of the range 0-31,
then all bits are shifted out and the result is zero.
,rsh ( in shift -- out )
Arithmetic right shift. If the shift amount is out of the range 0-31,
then all bits are shifted out; the result will be -1 if the input is
negative, or 0 otherwise.
s? ( any -- bool )
True if the value is a string (which may be either a string in the class
codes or a string in the level), or false if it is any other type. Error
if it is a sound.
Seek ( obj -- dir )
Returns the direction from this object to the specified object. If that
object is in the same place as this one, returns F. If zero is specified
then it is an error.
,Seek ( obj1 obj2 -- dir )
Returns the direction from obj1 to obj2. If the two objects are in the
same place, returns F. If either object is zero, then it is an error.
Self ( -- obj )
The reference to the current object.
Send ( message arg1 arg2 -- value )
Similar to ,Send but this object sends the message to itself.
,Send ( obj message arg1 arg2 -- value )
Send a message to the specified object.
SendEx ( message arg1 arg2 -- value )
Similar to ,SendEx but this object sends the message to itself.
,SendEx ( obj message arg1 arg2 arg3 -- value )
Send a message to the specified object.
SetArray ( array row column value -- ) **
Write a value to an array. Coordinates are zero-based.
SetInventory ( class image value -- ) **
Sets an inventory item with the specified class and image number to the
specified value (which must be a number). If there is no inventory item
with that exact class and image, an inventory item will be added,
otherwise the existing one is updated to the new value. Inventory values
are always unsigned 16-bit numbers.
Sound ( sound interruptflag -- )
Play a sound; if the interrupt flag is zero then it does not interrupt
existing sounds but otherwise it does. It is not an error if the values
of the arguments are not valid.
swap ( x y -- y x )
Synchronize ( slot startimage -- ) **
Start a synchronized animation. Give the slot number of the animation,
and the starting image number. The length and speed are defined in a
global definition, and the animation is always a non-oscillating loop.
Target ( -- bool )
Check if Arg1 and Arg2 are the coordinates of this object. It is an
error if either Arg1 or Arg2 are not numbers.
,Target ( obj -- bool )
Check if Arg1 and Arg2 are the coordinates of the specified object. It
is an error if either Arg1 or Arg2 are not numbers.
tmark ( any -- any true | false )
If the input is a mark, then it is removed and the result is false.
Otherwise, the value remains and true is added above it on the stack.
Trace ( obj arg1 arg2 -- )
If tracing is enabled, sends the three values and some other information
on stdout. If tracing is disabled, does nothing. This is intended to be
used for debugging class codes.
tuck ( x y -- y x y )
VolumeAt ( x y -- volume )
Finds the greatest volume among objects at the specified location.
WinLevel ( -- )
Ends all execution and accepts the input sequence that resulted in the
current game state as a valid solution. (In other words, the goal of the
game is to find a sequence of inputs that result in the execution of a
WinLevel instruction, without causing any errors or executing LoseLevel.)
XDir ( dir -- newx )
Finds the X coordinate of the cell in the specified direction.
,XDir ( obj dir -- newx )
Finds the X coordinate of the cell in the specified direction of the
specified object.
XYDir ( dir -- newx newy )
Finds the X and Y coordinates of the cell in the given direction.
YDir ( dir -- newy )
Finds the Y coordinate of the cell in the given direction.
,YDir ( obj dir -- newy )
Finds the Y coordinate of the cell in the specified direction of the
specified object.
=== Block instructions ===
These are block flow controls. They include bodies of other instructions.
begin <body> again ( -- )
Executes <body> an unlimited number of times; it will only stop once some
command inside of the loop jumps out, returns, or results in an error.
begin <body> until ( -- ) ( bool -- )
Executes <body>, and then pops one boolean from the stack; if false, then it
will be repeated, but if true then it stops.
begin <part1> while <part2> repeat ( -- ) ( bool -- ) ( -- )
Executes <part1>, and then pops one boolean from the stack; if true, then it
will execute <part2> and then repeat; if false then it jumps out of the loop
and does not execute <part2>.
for <body> next ( upflag x y -- ) **
It starts by saving the inputs into an internal variable (each class has its
own such variables, and they are separate for each instance of the word "for"
in the program, but they will interfere if the same loop is reentrant on the
same object or other objects of the same class), and then resetting the Done
flag of all objects at the given (x,y) coordinates. If upflag is false, then
it starts at the top, and if true, starts at the bottom. At the beginning of
the <body>, the found object is on the stack; you can then use or store it.
Once "next" is reached, it finds the next object and goes back.
if <truepart> [el <cond> if <truepart> ...] [else <falsepart>] then ( bool -- )
Takes a boolean value from the stack. If true, then <truepart> is executed;
otherwise it tries the other parts; "el" means to execute <cond> and take
another boolean, and continue; "else" means always do this if none of the
previous parts match.
mbegin <body> repeat ( -- any ) ( -- )
The "mbegin" instruction is a shortcut for "begin tmark while", and it has
the same behaviour.
=== Substitution codes ===
%c
Display a single character whose code is the low 8-bits of the value.
%C
The low 3-bits of the argument specifies the colour of the text. If it
is not a number, then the colour is unchanged.
%d
Display a signed decimal number.
%i
Display a picture. Consumes two arguments, being first a class and then
the image number. If either argument is not valid, displays nothing. The
picture may take up multiple lines of space; the lines will be moved
farther apart to make room if necessary.
%R
Display a roman number.
%s
Display a string. If the value is not a string, it will display it as
whatever type it is.
%u
Display a unsigned decimal number.
%x
Display a unsigned hexadecimal number in lowercase.
%X
Display a unsigned hexadecimal number in uppercase.
%%
Display a percentage sign; does not consume an argument.
=== Messages ===
This section describes when the various standard messages are sent to
objects, and what return values are expected. (Do not confuse CREATE with
CREATED, or DESTROY with DESTROYED, or COLLIDE with COLLIDING; they have
different purposes.)
(Some standard messages are in the names.js file but not used; do not use
them in your own code, since their names and meaning may change later. The
ones listed here are (probably) considered stable, and their numeric value
(used in level files) will (probably) remain unchanged.)
ARRIVED
Sent during the trigger phase if the Arrived value is nonzero. Arg1 is
the saved Arrived value. The Arrived variable will usually be set
automatically; see the section about variables.
BEGIN_TURN
Sent to all objects during the beginning phase (the phase after the
input phase). From is an object with the Player flag (if there is any),
Arg1 and Arg2 are the X and Y coordinates of that object, and Arg3 is
the most recent return value from a KEY message. The beginning phase may
be suppressed; if it is, then the ending phase is also suppressed.
BLOCKED
When scheduling deferred movement, if the moving object is blocked by
another object, then the moving object sends this message to the object
which is blocking it. From is the object attempting to move, Arg1 and
Arg2 are that object's coordinates, and Arg3 is 1 for +Move or 0 for
-Move. Of the return value, bit0 clears the Moving flag (causing the
move to fail), and bit1 causes it to not send any more BLOCKED messages.
COLLIDE
Received when this object is trying to move into a location where there
is a collision, so it can't move there. Of the return value, bit0 means
to prevent the movement (even if the objects are moved out of the way or
destroyed in order to make room), bit1 means to not send any COLLIDEBY
messages, and bit2 means to pretend the move attempt was successful even
if it isn't successful. Even if bit0 is set, that won't prevent sending
COLLIDEBY messages unless bit1 is also set. Arg1 and Arg2 are the X and
Y coordinates that it is trying to move to, and Arg3 is the collision
bits which are conflicting.
COLLIDEBY
Received when another object is trying to move into the location of this
object or trying to be created in the same location as this object, if
there is a collision in the CollisionLayers values of those two objects.
Of the return value, bit0 means to prevent the movement, bit1 means to
not send any more COLLIDEBY messages, bit2 means to pretend the movement
attempt is successful even if it isn't (there is no effect for creating
objects; this bit is meaningful only for moves), and bit4 means that if
necessary, it will try to destroy this object to make room. From is the
object attempting to move here, and Arg1 and Arg2 are its location (if
attempting to create an object, then From, Arg1, and Arg2 are all zero).
Arg3 is the class of the object being moved or created.
COLLIDING
Called when deferred movement is being performed if the move cannot
occur due to a collision with some other object. From is the object
that it is colliding with, Arg1 and Arg2 are its location, and Arg3
is the type of collision (0 if this object is trying to move into a
stationary object, 1 if another object is trying to move into this
stationary object, 2 if two objects are trying to move into the same
space, or 3 if two or more objects forming a loop are trying to move
into each other). There is no guarantee that this will only be called
once; sometimes it will be called multiple times for a single collision
or for multiple collisions with the same objects. (TODO)
CONFLICT
Called during scheduling of a deferred move if it is already currently
scheduled to move but in a different direction. Arg1 is the direction
that it is trying to schedule the move in. If the return value is false
then the schedule fails; if true, then it succeeds.
CREATE
Sent when the object is created by the Create instruction. This is done
after the object is created, but before sending any other messages. The
From is the object that created it. The return value will be used as the
Arg3 of the SUNK and CREATED messages it might send if appropriate. From
is the object which executed the Create instruction to create it.
CREATED
Sent to all objects whose Arrivals care about objects in the location
where an object has just been created. From is the newly created object,
Arg1 and Arg2 are the X and Y coordinates where the object was created,
and Arg3 is the return value from the CREATE message.
DEPARTED
Sent during the trigger phase if the Departed value is nonzero. Arg1 is
the saved Departed value. The Departed variable will usually be set
automatically; see the section about variables.
DESTROY
Received when the object is about to be destroyed. Arg3 is the reason:
0 for the Destroy or ,Destroy instruction, 1 due to this object moving
into something sharp, 2 due to something sharp moving into this one,
or 3 for a conflict with CollisionLayers. The return value is false to
allow it to be destroyed or true to keep the object.
DESTROYED
Sent to all objects whose Departures care about objects in the location
where an object has just been destroyed (if its VisualOnly flag isn't
set). From is the object which has just been destroyed. Arg3 is the
reason, as for the DESTROY message.
END_TURN
During the trigger phase, if no objects are busy, then the ending phase
will be executed next. This message is sent to all objects during the
ending phase (unless the ending phase has been suppressed). Arg1 is the
phase number; this is initially zero at the beginning of each turn, but
after each ending phase completes, this number is incremented. If the
return value is true, or if this object has Arrived, Busy, Departed,
Moved, or UserSignal variables set to nonzero, it will not suppress the
next ending phase. Otherwise, if this is not the case for any of the
objects checked, it will suppress the ending phase for the rest of this
turn (although other phases may still work).
FLOATED
This message is used in three cases. If an object's Density variable is
changed, then as each pair is being exchanged, it sends the FLOATED
message to the object which now has less density. From is the object
which it has been exchanged with. The return value is used as the Arg3
of the corresponding SUNK message. The other case this is used is when
an object moves or is created but is not the least dense object at that
location. In this case, From is the object which has been moved or
created, Arg3 is the return value of the corresponding SUNK message,
and the return value is not used. (The FLOATED and SUNK messages have
nothing to do with floating and sinking in water.)
HIT
Indicates that this object is trying to move into another one; that
other object is the From value of the message. Arg1 and Arg2 are the
X and Y coordinates of that object, and Arg3 is the current hit value
(see below). The return value is ORed with the hit value to make the
new hit value.
HITBY
Indicates that this object was hit by another object that was trying to
move, where From is the object trying to move, Arg1 and Arg2 are the X
and Y coordinates of that object, and Arg3 is the current hit value, and
the return value is ORed with the hit value to make the new hit value.
The return value may also be an object in order to warp; see the section
about hit values below, which also explains warping.
INIT
Sent to all objects when the level is initialized. Objects which are
created during this time will not receive INIT messages, but they will
receive POSTINIT messages.
JUMPED
Sent after a successful teleport by the JumpTo instruction. Arg1 and
Arg2 are the previous X and Y coordinates, and Arg3 (not From) is the
object that caused the move.
KEY
During the input phase, it sends this message either to all objects with
the Input flag set, or to only the current quiz object if there is one
(whether or not it has the Input flag). Arg1 is the key code (the Key
instruction can also be used), Arg2 is the return value of the previous
KEY message (0 for the first one), and Arg3 is zero for normal input or
one for a quiz. The return value is passed as Arg2 for the next object.
LASTIMAGE
Called during the trigger phase if this object has a one-shot logical
animation whose logical timer has expired. New animations played during
or after this time will retain any existing visual animation, but the
new logical animation replaces the old one. However, there is a maximum
number of animations that may be sequenced together in this way.
MOVED
Sent during the trigger phase to all objects which have the Moved flag
set; this flag is cleared before sending the message, so if it moves
again it will remember that it moved again. It will not send this
message again during the same trigger phase, even if the Compatible
flag is set; it will wait until all other objects have been processed
during the same trigger phase first. Arg3 is the phase number (see the
description of END_TURN for details). The Moved variable will usually
be set automatically; see the section about variables for details.
MOVING
Called when the object is about to be moved (whether due to Move,
MoveTo, JumpTo, or any other reason). From is the object that caused
the move, and Arg1 and Arg2 are the target X and Y coordinates. If the
return value is true, then the move is aborted.
PLAYERMOVING
If an object with the Player flag is about to move, then after the
MOVING message is sent, PLAYERMOVING is sent to all objects. From is
the object which is moving, Arg1 and Arg2 are where it will be moved to,
and Arg3 is the From of the MOVING message. If the return value is true,
then the move is aborted.
POSTINIT
After all INIT messages are sent when the level is initialized, then it
will send POSTINIT to all objects. Objects which are created during this
time will not receive POSTINIT messages.
SUNK
This message is used in three cases. If an object's Density variable is
changed, then as each pair is being exchanged, it sends the SUNK message
to the object which now has more density. From is the object which it
has been exchanged with. Arg3 is the return value from the corresponding
FLOATED message. The other cases this is used is when an object moves or
is created but is not the least dense object at that location. In this
case, From is zero, and the return value is not used. For creation, Arg3
is the return value of the corresponding CREATE message; for movement,
Arg3 is always zero. (This has nothing to do with sinking in water.)
=== Hit values ===
This section describes the bits of the return value of the HIT and HITBY
messages; these values are also used as the Arg3 of those messages.
Some descriptions below are marked with an asterisk. If the Compatible
flag is set for the object that returned this value, then all bits with
the asterisk in the below descriptions are masked out (bit15 is only
masked out for Compatible objects for diagonal movement).
bit0
Do not send the HITBY message to the target object.
bit1
Do not destroy either object due to hardness/sharpness.
bit2
Do not attempt to shove the target object.
bit3
Abort the move attempt immediately. Do not send any more HIT or HITBY
messages, do not check hardness/sharpness, and do nothing else either.
bit4
Do not send the HITBY message to the target object or to any further
objects at the target location.
bit5
Do not destroy either object due to hardness/sharpness, nor should any
further objects at the target location be destroyed due to sharpness.
bit6
Do not attempt to shove the target object, nor attempt to shove any
other objects at the target location.
bit7 *
Do not attempt sliding.
bit8
Abort after sending the HITBY message.
bit9
Abort after hardness/sharpness checking.
bit10
Abort after attempting shoving.
bit11
Set by the game engine if the move attempt has been restarted due to
bit15 being set during the previous attempt.
bit12 *
If the move attempt fails, pretend it was successful, even though the
object hasn't actually moved. This means that the result of Move will
be 1 and that the MOVED message will trigger; it does not trigger any
ARRIVED, DEPARTED, FLOATED, or SUNK, nor does it set Distance.
bit13 *
Abort before actually moving the object and before trying sliding.
bit14 *
Do not set the Moved flag even if successful.
bit15 (*)
Try again after trying shoving (whether or not the shoving is
successful). If it tries to shove an object and it is successful, then
it will automatically set this bit and automatically try again.
bit16
Set by the game engine if it is attempting sliding.
bit17 *
Do not actually move the object. It still does everything else, but when
it is time to move the object, just assume it is successful without even
trying. Things that Move and JumpTo have in common aren't done.
bit18 *
Do not restart, even if bit15 is set.
bit19
Set by the game engine if the requested movement is diagonal.
bit20 *
If set, then when the movement attempt is restarted (due to bit15 set),
the direction will be reread from the object's Dir variable.
bit21 *
Allows the object to move regardless of Height. The game engine sets
this bit if currently the Climb/Height is OK for moving.
bit22 *
Prevents movement regardless of Height, but may still allow sliding.
bit23 *
If this bit is set, then do not consider any further objects at the
new location of the shoved object after successfully shoving, and
instead restart the movement immediately.
bit24 *
Allows sliding to the left regardless of Height; the other attributes
still need to be correct (unless bit26 is set). The game engine sets
this bit if the Climb/Height is OK for moving.
bit25 *
Allows sliding to the right regardless of Height; the other attributes
still need to be correct (unless bit27 is set). The game engine sets
this bit if the Climb/Height is OK for moving.
bit26 *
Allows hitting to the left regardless of Shape, Volume, etc. In order
to actually move when sliding to the left, both bit24 and bit26 must
be set, and bit7 must be clear.
bit27 *
Allows hitting to the right regardless of Shape, Volume, etc. In order
to actually move when sliding to the right, both bit25 and bit27 must
be set, and bit7 must be clear.
bit28 *
This bit is set by the game engine if a warp has occurred. See the below
description of warping. You can also set this bit by yourself, and it
persists across restarts. If this bit is set, the moving object's
direction is updated after the movement if it is successful.
bit29 *
Reserved for future.
bit30
Available for your own use.
bit31
Available for your own use.
The return value of HITBY can also be an object instead of a number. In
this case, a warp occurs. The movement is restarted, using the specified
object as the origin of the movement, and that object's direction as the
direction of movement.
=== Pattern matching ===
Where an instruction is expected, you can have pattern matching. This can
be (P <pattern...>) or (,P <pattern...>) where the first one uses the
current location, and the second kind uses the position and direction of
the specified object as the matching. It pushes the found object to the
stack, or pushes zero if the pattern does not match.
<class>
Match an object of the specified class.
<dir>
Move in the specified direction. (This does not move any objects; it
only moves the cursor for pattern matching.) The direction can be
relative to the current direction (initially the Dir variable of the
origin object) or absolute.
<message>
Send the message to all objects at the current location. From is the
position from which pattern matching started. Arg1 is the direction.
Arg2 is the currently matched object (which may be zero). If the
return value is zero, it continues normally; if one, the match fails;
if two, it continues without sending more messages at this location;
if an object, sets the matched object and current location.
<userflag>
Match an object with the specified flag.
,<userflag>
Fail if there are any objects having the specified flag here.
+
Push the matched object to the stack.
-
Push zero to the stack.
*
Update the current choice point with the location and direction.
_
Push a mark to the stack.
again
End a block with begin or if, allowing it to occur more than once; it
is repeated until it no longer matches. If the first word is begin,
then it must match at least once; if it is if, then it can match zero
or more times. The match is greedy; it will match as much as possible.
begin
Begin a block.
Climb
Fail the match if the origin object cannot climb here.
(Climb <number>)
Fail the match if the height here is greater than this number.
cut
Discards the most recent choice point.
else
Delimits alternatives within a block.
Four
Try four directions (E, N, W, and S).
Eight
Try all eight directions.
Height
Fail the match if the origin object can climb here.
(Height <number>)
Fail the match if the height here isn't greater than this number.
if
Begin a block that can optionally match.
next
Unconditionally fail the current attempt and try the next choice.
ObjAbove
Match the object above the currently matched object.
ObjBelow
Match the object below the currently matched object.
ObjBottomAt
Match the object at the bottom of this location.
ObjTopAt
Match the object at the top of this location.
then
Ends a block started with begin or if.
Trace
Used for debugging.
=== Compatibility ===
Compatible objects have the following differences from the default:
* VisualOnly implies Stealthy.
* If the current quiz object is Compatible, The effect of "-1 FlushObj"
is implied at the beginning of the turn (before the input phase), except
that Inertia is not reset.
* Some bits are masked out of the return value from HIT and HITBY.
* Many variables are limited to 16-bits.
* Moving objects is not allowed during LASTIMAGE processing.
* The way that the trigger phase works is different.
* In the ARRIVED and DEPARTED messages, Arg1 is always zero.
* Diagonal shoving is not possible.