Free Hero Mesh

Artifact [f2091cdda2]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.

Artifact f2091cdda2130607906da54aac4e615b8f73b16f:


[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

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.

{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>)
  Set the background colour, from 0 to 255. The default value is 1.

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

(<message> <code...>)
  Defines a default message code for all classes which do not specify
  their own code for this message.


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

* Sound: A sound.

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.

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.

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 : int8
  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.

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.

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

Shape : int8 [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 : int8 [c]
  Defines what directions the object may be shoved, where bit0 means east,
  bit2 means north, bit4 means west, and bit6 means south.

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.

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.

Some instructions are block instructions; see the next section.

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.

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

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.

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.

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.

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.

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

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.

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

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.

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.

MaxInventory  ( number -- )
  Results in an error and loss of game if the number of different
  inventory items exceeds the given number, otherwise no effect.

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.

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.

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.

NewY  ( oldx dir -- newy )
  Advance the number in the direction as though it is a Y coordinate.

nip  ( x y -- y )

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

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.

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.

QueueTurn  ( key -- ) **
  Queue another turn after this one, using the specified key code, which
  must be a number from 0 to 255. The extra turn is not entered into the
  replay list and does not increase MoveNumber, but otherwise will act
  like any other turn. Popup messages are not removed; they will be
  retained, and these extra turns execute the input phase as though there
  is no popup quiz.

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

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.

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.

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.

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.

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.

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.


=== Substitution codes ===

%c
  Display a single character whose code is the low 8-bits of the value.

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

%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; they have different purposes.)

ARRIVED
  

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.

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.

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.

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.

CREATED
  

DEPARTED
  

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
  

END_TURN
  

FLOATED
  

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.

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
  

MOVED
  

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
  


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

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.

bit22 *
  Prevents movement regardless of Height, but may still allow sliding.

bit23 *
  Reserved for future.

bit24 *
  Reserved for future.

bit25 *
  Reserved for future.

bit26
  Available for your own use; preserved across restarts.

bit27
  Available for your own use; preserved across restarts.

bit28
  Available for your own use.

bit29
  Available for your own use.

bit30
  Available for your own use.

bit31
  Available for your own use.


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