\input texinfo                              @c -*- texinfo -*-
@set VERSION 1.30
@setfilename enigma-ref.info
@settitle Enigma Reference Manual
@documentencoding US-ASCII
@documentlanguage en
@titlepage
@title Enigma Reference Manual
@subtitle for version @value{VERSION}
@author Daniel Heck (old API v 0.92)
@author Petr Machata (old API v 0.92)
@author Ralf Westram (old API v 0.92)
@author Ronald Lamprecht
@author Andreas Lochmann
@author Andreas Abraham
@end titlepage

@defindex ob
@defindex at
@defindex ms

@c Macro for pdf(tex) and html reference
@ifhtml
@macro yref {name}
@ref{\name\}
@end macro
@end ifhtml

@iftex
@macro yref {name}
\name\
@end macro
@end iftex

@contents

@ifnottex
@node Top
@top

This manual describes the internals of
@uref{http://www.nongnu.org/enigma/,Enigma} version @value{VERSION}, in particular how to
build new levels using Lua and how to interact with the game engine.
@end ifnottex

@menu
* Running Enigma::              Running Enigma
* Levelpack Basics::            Addition and managing of levels in packs
* Level Basics::                Introduction to level description
* Enigma Paradigm::             Principles of world, objects and messages
* Lua API::                     Describing a level with all its objects and interactions
* Common Attributes and Messages::  What all objects support
* Floor Objects::
* Item Objects::
* Stone Objects::
* Actor Objects::
* Other Objects::               Wires, Rubberbands and Gadgets
* Libraries::                   Supplemental Functions and Features
* Advanced Features::           Resolvers, Scrolling, Flood, Fire, etc.
* Extension Development::       Resolver, Library Development
* Guidelines and Hints::        Tips and Recommendations for Levels to be included in Enigma
* Compatibility::               Engine Mode and Version Compatibility
* Object Index::
* Attribute Index::
* Message Index::
* Function Index::
* Concept Index::
* Renaming Index::              Old API to new API translation hints
@end menu

@node  Running Enigma
@chapter Running Enigma

Hopefully, after successfully installing and playing some first levels, you may be interested in
some information about how we have configured Enigma, how you can optimize Enigma to your
needs, and the purpose of some options and attributes within Enigma.

This first chapter should give you some valuable information about these questions, and provide
some basic knowledge you will need to manage level packs, levels or write your own levels, as
described in the following chapters.

@menu
* Locating Resources::
* Startup Switches::
* User Options::
* Inventory Console::          Command and document text history
* Level Info::
* Handicap and PAR::           Background to score evaluation and HCP
* User Sound Sets::            How to create and install sound themes
@end menu

@node Locating Resources
@section Locating Resources

For reasons of backup, system changes, special configurations, level additions and hopefully
your own new levels, you may need to know where Enigma stores the resources and how you
can control them.

Enigma maintains several paths for control of load and storage of files. You
can list these paths either in the help submenu paths, or by starting Enigma
with the switch @option{--log} (@pxref{Startup Switches}) and looking at the
console output.

@table @asis
@cindex preferences path
@item @b{Preferences Path}
This is the path to the file that stores your preferences concerning application
options. This file is usually located at your @env{HOME} directory. For @env{HOME}-less
Windows users, it is stored in the @samp{Application Data\Enigma} directory. Since it is the
third version in the history of Enigma, the file is named
@samp{.enigmarc.xml} by default.

We recommend that you backup this file, although it contains only a few data that you can
quickly reconfigure.

Since these preferences are quite specific for the operating system and configuration, you will
use a different version on each Enigma installation you have.

Mainly for Enigma developers, a switch exists @option{--pref} (@pxref{Startup Switches})
to rename this preferences file. By starting Enigma with a renamed preferences
file, a developer can temporarily use a complete separate configuration for
testing purposes without the danger of destroying his main configuration. The
developer may use it to start Enigma with a plain standard configuration for
testing purposes, too.

In all cases, a leading @samp{.} will hide the preferences filename.

@cindex user path
@item @b{User Path}
This is the main path to the user's Enigma data. All updates, user-installed levels and user-
written levels, the user's scores, history and usually the user's screenshots and level previews,
are stored at this path.

A backup of this directory is mandatory!

The standard location is the directory @samp{.enigma} in your @env{HOME}
directory. For @env{HOME}-less Windows users, it is the folder
@samp{%APPDATA%\Enigma}, what resolves to the subfolder
@samp{Application Data\Enigma} on XP/2000 or @samp{AppData\Roaming\Enigma} on
Vista/Windows 7 located within your user data folder.

This standard location of the user path is the location of logging and error
output files, too.

You can define your own path within the @ref{User Options}. By doing so, you can store your
Enigma user data on a memory stick or on a shared partition, and use them alternatively from
two Enigma installations.

@cindex user image path
@item @b{User Image Path}
This is a second path to the user's Enigma data, which you can use to access images such as
screenshots and thumbnails of levels. Usually this path is identical to the main @samp{User
Path}.

Just in case you make many screenshots and have limited resources on the main
@samp{User Path}, you may want to store the images on another path. You can
define your own path within the @ref{User Options}.

@cindex system path
@item @b{System Path}
This path gives you the location of all system resources that are distributed with Enigma. Here
you will find the levels, libraries, etc. This is a first class address to look for examples if you start
writing your own levels.

@cindex resource paths
@item @b{Resource Paths}
This is a list of paths. The program looks up each version-independent resource on all paths in
this list, and loads from the first occurrence.

User data precedes system data; this way, updates on your user data path will win. Have a look
at this list if you are observing a difference between a source and the runtime behavior. You may
have looked at a file that another file had hidden on a preceding path in this list.

@cindex l10n path
@cindex localization path
@item @b{l10n Path}
This path shows the directory that contains the localization data.

@end table

Please note that some resources, like levels, may be zipped. In this case, a
resource that you expect to find at @samp{dirname/filename} may be stored in a zipfile
named @samp{dirname.zip}. The path of the file within the zip can be either
@samp{dirname/filename} or @samp{./filename}. In case a resource is provided
in zipped and unzipped form, the plain file stored in a directory wins, since Enigma
assumes it to be an update to the zip.

@node Startup Switches
@section Startup Switches

Besides starting Enigma by clicking on an installation-provided icon or start
menu entry, you can start Enigma from a shell or commandline. This allows you
to add a selection of startup switches that are valid for just a single run.

For repeated usage of constant startup switches you can create a desktop icon
or start menu entry and append the startup switch to the target string of the
Enigma application executable.

The following list explains the supported user options. If an option is listed with a long name
preceded by two minus signs, and with a one-character abbreviation preceded by one minus
sign, use one of the notations, not both together; for example,
@samp{--data path} or @samp{-d path}.

@table @asis
@item @b{-@w{}-assert}
A switch for Enigma developers that forces all debugging assertions, even
expensive ones, to be evaluated. The additionally evaluated checks look like
@samp{ASSERT(noAssert || long_lasting_check(), XLevelRuntime, "remark");}.

@item @b{-@w{}-data -d path}
A switch for Enigma developers that allows you to add an additional path to the
resource paths that precedes the system path (@pxref{Startup Switches}). A
developer can test an Enigma compilation, without installation, by calling it
from the shell with the current working directory on the main directory via
@samp{src/Enigma -d ./data}.

@item @b{-@w{}-help -h}
Just lists the available startup switches to the output and terminate.

@item @b{-@w{}-lang -l lang}
A switch that allows you to override any other language preference. The language
is given in the common 2-character sequence as @samp{fr} for French or @samp{ru}
for Russian.

@item @b{-@w{}-log}
This switch turns on logging of internal information to the standard output.
Windows users will find a file called @samp{Output.log} in the standard
@samp{User Path} folder. An additional file @samp{Error.log} lists severe
error messages.

The output will, for example, list the paths described in @ref{Locating Resources}.

@item @b{-@w{}-nograb}
A switch for Enigma developers that causes Enigma not to grab the mouse. You can hardly
play a level in this mode, but it makes it possible to debug the
application in its core parts.

@item @b{-@w{}-nomusic}
Start Enigma without playing background music.

@item @b{-@w{}-nosound}
Start Enigma with sound being switched off.

@item @b{-@w{}-pref -p filename}
The name of an alternative preferences file without the leading dot for hidden
filenames. This switch is a pure Enigma developer support feature, as described
in @ref{Locating Resources}.

@item @b{-@w{}-pref -p dirpath}
The path of an alternative directory that contains the standard named preference
file @samp{.enigmarc.xml}. If no preference file exists or the directory does
not yet exist they are created. On creation of the preference file the user data
path is set to the given dirpath per default. This allows to store all Enigma
user data in a single directory that can be stored anywhere, e.g. on a USB stick.
You always need to call Enigma with the above switch to use this new set up.
Remember that a path with spaces needs to be quoted.

@item @b{-@w{}-redirect}
Redirect the @samp{stdout} and @samp{stderr} to files named @samp{Output.log}
and @samp{Error.log} on the standard user path (@pxref{Locating Resources}).
For Windows this option is always @code{true}, but the usage of this option
is useful on any operating system if Enigma is started via a desktop icon or
a menu button.

@item @b{-@w{}-robinson}
Disable all connections to the internet. No automatic updates will take place
and all user initiated requests that would require an internet connection will
fail with an error message.

@item @b{-@w{}-showfps}
Show the framerate (FPS) during the game.

@item @b{-@w{}-version}
Just print the version number to the output and terminate.

@item @b{-@w{}-window -w}
Start Enigma in window mode instead of screen mode.

@end table

Enigma interprets all further arguments supplied on the commandline as level file
addresses. You can use absolute or relative addresses to level files stored
on your computer. Adding url's to levels stored in the Internet is also possible.

A Unix user may start Enigma with the following command:

@code{enigma --log ~/mylevel.xml http://somewhere.com/netlevel.xml}

A Windows user may start Enigma from the command line (please adjust the Enigma
installation path):

@code{C:\Programs\Enigma\enigma.exe --log demo_simple.xml}

You will find these levels in the levelpack called @samp{Startup Levels}, which is
only visible by default if you supplied levels on the commandline.

@node User Options
@section User Options

@table @asis
@item @b{Ratings update}
Please retain this option on the value @samp{Never} until release of Enigma 1.00.

@item @b{User name}
Enter your user name, which Enigma will attach to your scores. Please look at
the Enigma home page for user names already in use and choose a new, unique name.
You can change your user name at anytime without losing any of your
scores.

@item @b{User path}
This textfield allows you to define an arbitrary directory for your Enigma user
data as described in @ref{Locating Resources}.

Deletion of the string resets the path to the default.

Enigma activates the new path when you leave the options menu. Though it stores all files
directly to the new path, and will still find files on the old path, you may want to quit Enigma
immediately and first copy/merge the old directory to the new location. This copy of your old
data is necessary, since with the next start, Enigma will locate user data at the new location
exclusively.

@item @b{User image path}
This textfield allows you to define an arbitrary directory for your Enigma user
image data as described in @ref{Locating Resources}.

Deletion of the string resets the path to the default.

Enigma activates the new path when you leave the options menu. Though it has stored all files
directly to the new path and files will still be found on the old path, you may want to quit
Enigma immediately and first copy/merge the old directory to the new location. This copy of
your old data is necessary, since with the next start, Enigma will locate user data at the new
location exclusively.

@end table


@node Inventory Console
@section Inventory Console

The lower right window area that usually shows the inventory items and scrolls
the texts of activated document items allows the user to reread previous
document texts, to enter textual commands and to reissue previous commands.

You can issue a command by usage of the keyboard. Just enter the command string
and activate the command by a finishing @key{return} stroke. The following
commands are supported:

@table @asis
@item @b{help}
List all public available commands.
@item @b{abort}
Abort level and return to level selection menu. Same as @key{Alt X}
@item @b{April 1st}
Just a joke.
@item @b{cheats}
List level developer cheat commands for fast testing.
@item @b{collision}
Developer cheat that disables collisions between stones and marbles or pearls.
Once used no score will be recorded if the level is successfully finished.
@item @b{easy}
Restart level in easy difficulty mode.
@item @b{find} search_string
Searches levels in all levelpacks that contain matching string in either
the level's title, author's name or the file name.
@item @b{god}
Developer cheat that protects the actors assigned to the current player like
the activation of an @ref{it_umbrella} does. Once used no score will be
recorded if the level is successfully finished.
@item @b{hunt}
Switch to world record hunting mode. Same as toggling the left most button
in the level selection menu to the world icon.
@item @b{info}
Show info about level like the levelpack, position within levelpack, the file
location, the title, author, version and the level internal id.
@item @b{jumpto} levelpack,position
Directly start the given level. The levelpack is identified by its title. The
position is the number within the levelpack. E.g. @code{jumpto Enigma IV,33}.
@item @b{nohunt}
Switch off the world record hunting mode. Same as toggling the left most button
in the level selection menu to the marble icon.
@item @b{regular}
Restart level in regular difficulty mode
@item @b{restart}
Restart level in currently selected difficulty mode.
@item @b{suicide}
Kill actors, but continue level if possible. Same as @key{F3}.
@end table

Both, the commands and the displayed document text have a history. You recall
the history by usage of the up and down arrows.

@itemize @bullet
@item @b{inventory} --> jump to start
@item @b{command #10}, oldest command in history
@item @b{command #9}
@item @dots{}
@item @b{command #2}
@item @b{command #1}, last executed command
@item @b{command under edition}, just if the last edited command has not been executed
@item @b{inventory} <-- start
@item @b{document #1}, last viewed document
@item @b{document #2}, previous viewed document
@item @dots{}
@item @b{document #n}, first viewed document
@item @b{level title, subtitle, author}, as shown on level start
@item @b{inventory} --> jump to start
@end itemize

Starting with the inventory item display the up arrow shows the previously
submitted commands. Just by another @key{return} you can reissue a command.
The history will be resorted with the last command at the position direktly
above the inventory. You can edit history commands anytime like you can insert
a new command. If you do not finish a command by a @key{return} the string will
still be recorded and presented as the first command above the inventory. The
command history is persistent.

The document history can be recalled by usage of the down arrow. All level
documents previously displayed can be redisplayed. Additionally the initial
level info displayed on the level start can be read again.

Both histories revolve to the item inventory when the up or down keys are
used beyond the oldest command or message.

@node Level Info
@section Level Info

@cindex levelinspector
For every level, Enigma manages more data than can be displayed in the level menu. You can
view them all with the levelinspector. You can call this special menu from within the level menu
by right or control clicking on the level icon.

Besides title and author, Enigma provides information concerning a public rating of the level,
different score values of interest, details on the level version, the level file location and more.
Additionally, the levelinspector allows you to enter personal annotations for a level. You can
review any screenshots you made for this level directly from the levelinspector, too.

@menu
* Public Ratings::
* Scores::
* Versions::
* Private Annotations and Ratings::
* Screenshots::
@end menu

@node Public Ratings
@subsection Public Ratings

Most levels are rated within five different categories:
@itemize @bullet
@item
int = Intelligence

@item
dex = Dexterity

@item
pat = Patience

@item
kno = Knowledge of Enigma

@item
spe = Speed and Speed control

@end itemize

To distinguish the ratings from their everyday-meanings, we use the following abbreviations for
the ratings. Each of these categories takes values between 1 (easy) and 5 (difficult), except kno,
which can also be 6 (unique mechanism).

Please bear in mind that it's not simple to retain the
following definitions in each of nearly 750 cases, so there
might be (will be) deviations from them in single levels.

@strong{Intelligence (int)}

This rating is intended to measure the creativity, planning and analytic requirements needed to
solve the level. Intelligence is a very difficult concept in itself, and thus at first not easy to rate or
to grasp. Consequently, a fixed definition of the five rating-degrees not only helps, but is
essential in the rating process. So, assume you know everything about the single elements of a
level. Then ask yourself these questions:
@itemize @bullet
@item
Can I see the solution at once? Yes -> int 1

@item
Do I only have to orient myself, for example, testing the exits of wormholes or to see the
function of a switch? -> int 2

@item
Is there a standard algorithm to solve the problem, like in a maze, or
searching for a hidden item? -> int 3

@item
Neither trial-and-error nor standard algorithms work; is it a simple
kind of code or does it require advance planning? -> int 4

@item
Is it a difficult code, pattern or causal chain? -> int 5

@end itemize

High values for intelligence are typically puzzles.
int-ratings do not accumulate; the most difficult puzzle
itself already determines the rating.

@strong{Dexterity (dex)}

You can solve many levels either by accuracy or by patience. In our context, we do not mean
dexterity in the sense of accuracy to avoid impatience, but accuracy to avoid death. So it focuses
on the lethal positions in a level, not only death-stones and abysses, but also casualties like
pushing a stone accidentally into an unreachable corner.

@itemize @bullet
@item
It doesn't matter what I touch, this level is damn-proof. -> dex 1

@item
Well, there are lethal positions I shouldn't move the level into, but
they are not difficult to overcome. -> dex 2

@item
Comparable to a single row with an abyss left and right. -> dex 3

@item
Comparable to pushing a stone to the right with an abyss on
the left, or a single row with death-stones left and right. ->
dex 4

@item
Needs lots of attempts to succeed. -> dex 5

@end itemize

In contrast to the int-rating, dex might accumulate: A level with many situations,
each of dex 3, can add up to dex 4 or even 5. This way, you can achieve dex 5.
Rotors in a level also contribute to dex and to the
speed-rating, spe. Thus, levels with a high dex-spe-combination are
mostly action-driven, whereas a high dex-pat-combination typically is
a dangerous maze.

@strong{Patience (pat)}

Patience is a relatively subjective rating, and refers mostly to ``felt time'', how long it felt to
complete the level. So two levels with same mechanics can have different pat-values, e.g., if one
level has a nicer design or shows the progress of the level in some way, like the number of
opened oxyds. It explicitly includes having to restart the level repeatedly; not the time in the
lower left corner or the score is crucial, but the complete ``felt time'' needed to solve the level,
starting from the first look at it.
@itemize @bullet
@item
I solved the level right after understanding it. -> pat 1

@item
I needed some time, but it wasn't boring. -> pat 2

@item
Okay, it took some minutes, but the landscape is nice @enddots{} -> pat 3

@item
I know what to do, but it doesn't seem to end. -> pat 4

@item
This level really requires discipline. -> pat 5

@end itemize

A high number of oxyds can heighten the pat-value and also lower it: If the player has to
traverse the level several times to open matching pairs of oxyds, it is definitely pat-heightening.
However, if oxyds are arranged to mark the progress of the player, and act as a kind of small
reward within the level, they can lower the pat-value. It's the same with a high number of doors:
The arrangement is the critical factor.

High pat-values are typically mazes. In combination with int 3, a high
pat-value can indicate a hidden item or a hollow stone. pat-values
involve the whole level, so they can't accumulate.

@strong{Knowledge of Enigma (kno)}

The kno-rating mostly takes on the function and interactions of single
objects in the game, like stones, floors, items, and actors. However,
in some cases it also deals with special techniques. The guideline is
the ``Advanced Tutorial'', which defines kno 3. kno 4 corresponds to
standard objects that aren't shown in the tutorial; kno 5 requires a
deeper knowledge of the game internals. Finally, kno 6 indicates
special mechanisms, that are seldom encountered or unique. The overall kno-rating
of a level equals that of the most difficult object or technique (and
thus is non-accumulative):
@enumerate
@item
Moving a single marble on normal floors, normal walls, oxyds,
stones that look like oxyds, death-stones, water, an abyss, documents,
using the inventory, static gravity, visible gradients.

@item
Pushing stones, simple Sokoban-tricks, bridge-building in water
and an abyss, connected puzzle-stones, moving more than one marble,
meditations, grates, rotors and tops, hidden gradients, triggers and
switches, doors, holes (not made by dynamite), swamp, floppies and
st-floppy, keys and locks, coins and slots, cracks, timer-stones.

@item
Different floors can have different friction and mouseforce, space,
ice, inverted floor, some stones sink while others swim, black grates
that hold rotors and tops away, dynamite, dynamite-breakable stones,
spade, boulders, magic-wand to change boulder-direction, boulders sink
into an abyss, sheets of glass, spoon, actors and items may hide under
movable stones, small not-killer whiteballs, coloured one-way-streets,
actorimpulse-stones (``bumpers''), rotors can fly over an abyss,
quake-stones, swords and knights, lasers, static and movable mirrors,
item- and coin-transformations by pushing stones over them and by
using lasers, umbrellas protect in an abyss, hammer and breakable stones
(although not in the tutorial).

@item
Bridge-building in swamps, rubber-bands, rubber-band-stones,
scissor-stones, unconnected puzzle-stones, exploding puzzle-stones,
turning puzzle-stones (with and without a magic wand), springs (both
types, on the floor and hole-kind springs like in ``Upstream
Journey''), thieves, three-part shogun-stones, invisible stones,
hollow stones, chameleon-stones, items hidden under chameleon stones,
stones that aren't what they seem (e.g., fake-death-stones), wormholes,
magnets, using F3 for a restart to solve a level, yin-yangs,
one-color-, yin-yang- and inverted yin-yang-stones, stones breakable
by only one color, killer-balls, swap-stones, brush and paintable
stones, changing one-way-streets with a magic wand, changing stones to
glass with a magic wand, impulse-stones (movable, static and hollow),
black and white bombs, bomb-stones, fire, extinguishers,
rotator-stones, yellow anti-swapping stones, mines, flags, seeds,
weights, putting objects under one-way-streets and other hollow
stones, electric stones, turnstiles, mailing and pipes, rings (single
and multiplayer), volcanos, bags, randomizers (as possible effect of a
switch), horses (the actors) and horse-passing stones, pins, bananas, cherries
can make you invisible, surprise-item.

@item
Cracks, floor-springs, wormholes, etc., are all items, seeds can grow
inside stones, the laser is blocked by all items, killer-balls don't sink
in water, ``Space Meditation''-kind collisions, holding down the
mouse-button, invisibility lets you go through glass, jumping over
lasers @enddots{}

@item
Spitter-stones, surprise-stones, levels like ``Enigris'' or ``Flood
Gates'' @enddots{}

@end enumerate

kno 6 does not necessarily mean that this level is difficult to
understand; the unique mechanism or object might also be very
intuitive, like in ``Flood Gates''.

@strong{Speed and speed control (spe)}

The spe-value corresponds not only to the maximum speed a level
requires (like you need to run away from a rotor), but also the
degree of control a player has over his mouse while moving it;
excellent examples for this are ``Mourning Palace'' and the middle
part of ``Sacrifice''. This involves moving the mouse at a constant
velocity for a long time, as well as correctly estimating the speed
that's needed in a certain task, like shattering a sheet of glass.

@enumerate
@item
No time limit.

@item
You shouldn't stop for too long. For example, something slow might
be chasing you.

@item
There is an appropriate time limit or speed control task. This can
be a single, not-too-fast rotor in an open area.

@item
Don't stop! Examples include difficult timing-tasks as well as a single
fast rotor or several slower ones.

@item
Hurry Up! Whereas spe 4 is meant to be difficult, but obviously
solvable in not too many attempts, spe 5 is everything beyond this.

@end enumerate

The spe-rating again is cumulative, since many slow rotors can add up
to spe 3 or 4, or a combination of many slow time-switches to be
pressed in a certain order can create a horrible task. In contrast to
the other categories, for which the average is near 3 (or between 3
and 4 for kno), most levels are definitely
spe 1. So, the spe-rating is more a supplement to the three
core-ratings int, dex and pat.

@strong{Combinations of ratings}

Sometimes, it can be interesting to have a single value to measure the difficulty of a level. To
calculate such a universal rating, a simple possibility is choosing a linear combination of the 5
single ratings, weighted with appropriate weights. These weights should correspond to the
difficulty a single category adds to the universal difficulty. Yet you should also choose these
weights carefully to avoid number-theoretic obstructions (e.g., when all weights are even except
for the spe-rating, then there will be a visible difference in the distribution of even and odd
universal ratings, which can be very misleading). A working, and very interesting linear
combination, is the following, which has been applied in the reordering process:


@example
universal difficulty  =  7*int + 6*dex + 4*pat + 3*kno + 4*spe - 23
@end example

This has a special property, in that it takes relatively broad and continuously distributed values
between 1 (all ratings 1) and 100 (all ratings 5, kno 6) and emphasizes the most difficult
categories, intelligence and dexterity. However, some very low or very high values cannot
appear in this combination, such as 2 or 99. Other combinations lead to full but narrow, or to
broad but noncontinuous spectra.

@node Scores
@subsection Scores

The score columns show your and some comparison values for the difficult and
for the easy mode, if the levels supports it.

The world record is the best score that was retransmitted to the Enigma team.
The world record holders are listed below.

The PAR value is the ``professional average rating'' of the level. It is the harmonic average of all
scores that Enigma players have retransmitted. However, we take into account only scores from
players who have solved a certain number of levels. Opposed to the world record, which will be
very difficult to gain, the PAR value is a much more realistic aim for an ambitious player. If you
are equal or better than PAR, the levels are marked with a speeding blackball within the level
menu.

The author's value is another reference score. Most authors are not keen on holding the world
record of their own levels. However, they will likely know the fastest way to solve the level. If
your score is much higher than the author's score, a simpler solution to solve the level may
exist.

The solved number is the number of players who solved this level in the given
score version.

The solved percentage is the relation of the number of players who solved this
level to the number of players who retransmitted scores. Actually, we take into
account only those players who could have solved the level. For example, players
who did retransmit scores before the level was written, without updating
afterwards, are not taken into account. A low percentage is a hint that a level
is not easy to solve.

@node Versions
@subsection Versions

The version column shows detailed information about the level. Read the chapter Level
Basics node @pxref{<version>} and @pxref{<modes>} for an explanation of the
values.

For you as a player, the @samp{Score} version number can be interesting.
A level you had solved with a certain score may appear with a red triangle in the level menu in
an updated Enigma release of the level. Although the level menu displays the medals showing
that you solved the level, it will not display the score values anymore. This is due to an
incompatible level update that requires a new solution with different, incomparable score
values. The author will increase the score version number in such a case.

@node Private Annotations and Ratings
@subsection Private Annotations and Ratings

This textfield allows you to enter an annotation for a level that you can review
on later replays. Note that the current textfield is limited (it may not allow you to enter all
characters, and needs the mouse cursor to remain within its boundaries). Yet it should work for
entering short annotations that may be very useful later.

Enigma stores annotations in your private applications @samp{state.xml} file. It permits one
annotation per level, independent of the level version.

You may rate the levels, too. Just click on the ratings button. Values go from
0 to 10 with an additional @samp{-} for abstention. 0 stands for a poor level
that you think is not worth playing, 5 for an average level and 10 for the
ultimate, best levels. Try to use all values in your ratings.

Enigma stores the ratings with the scores and evaluates them anonymously. Enigma displays
the resulting average rating of all users, for your information. Note that different ratings are
possible for different score versions of the same level, because levels may improve as a result of
suggestions by users. If you do not re-rate a new version of a level, Enigma inherits your rating
from a previous version.

@node Screenshots
@subsection Screenshots

While playing a level, you can make screenshots by pressing @key{F10}. You can make
several screenshots in sequence for documentation purposes. Enigma will store each
with a unique image filename. Using the level inspector, you can view the screenshots directly
from within Enigma. Just click on the screenshot button to
view the first image.

Because any buttons would disturb the view of a screenshot, all functions are keyboard
commands. Press @key{F1} to get a help screen. @key{ESC} returns to the level inspector.
@key{Page Up} and @key{Page Down} will show the previous and next screenshot.
If you scroll down behind the last screenshot, the ``missing'' screenshot file is named.
This may be a useful hint as to where to search the other screenshot files on your
@samp{user image path} (@pxref{Locating Resources}).

@node Handicap and PAR
@section Handicap and PAR

As PAR (@pxref{Scores}) describes the difficulty of a level, the handicap @samp{hcp}
describes your ability to solve levels in PAR. The handicap is always related
to a levelpack or group of levelpacks. You can see your handicap for each levelpack in the level
menu, if you select the PAR mode by clicking on the lower
left button until the speeding black marble appears. The value is displayed in
the upper right corner, with the number of levels you solved in PAR.

The handicap is similar to the golfer's handicap. A low value is better than a
high value. If you solve all levels exactly in PAR, your handicap will be 0. If
you are even better than PAR, your handicap will be negative. Players can use
this value to compare their overall abilities.

Just for those of you that want to know the details of this score rating system
of PAR and handicap, here is some additional information, which others may skip and
continue with the next chapter @ref{Levelpack Basics}.

We request all users to send their scores. All scores are evaluated for world
records and counts of level solution rates and numbers.

However, for the PAR calculation, we take into account only scores from users who have solved
more than a certain percentage of levels (currently about 10% of the levels). For every level, we
calculate the harmonic average of the scores of these
@samp{professionals}. We take professionals who did not solve a level into account with the
10-fold world record score. The harmonic average calculates as

harm.avg. = N / (sum_[j=1..N] 1/score_j) )

It weights small (short) times with a greater weight than large (long) solution times.

The handicap is a sum of values that describe your scores in relationship to the PAR value of a
level. Since it has to take into account that you have no score at all or that no PAR value exists,
we apply some exception rules to the addends:

@multitable @columnfractions .1 .15 .75
@item @bullet{ } @tab + 1.0 @tab for each unsolved level
@item @bullet{ } @tab + log10(score/par) @tab for each solved level with existing par if score >= par
@item @bullet{ } @tab + 0.7 @tab as upper limit for each solved level with existing par if score >= par
@item @bullet{ } @tab + log2(score/par) @tab for each solved level with existing par if score < par
@item @bullet{ } @tab - 3.0 @tab as lower limit and as value for levels without par
@end multitable

Note that each score that is better than PAR results in a negative addend and
thus reduces your handicap. For a levelpack with 100 levels, the handicap will
be in the range of +100 to -300. For levelpacks with more or fewer levels, Enigma
will scale the sum by a factor 100/size to result in comparable handicap values.
Handicaps are stated with one digit behind the decimal point.


@node User Sound Sets
@section User Sound Sets

(The following information accounts only for Enigma 1.01 and above.)
Sound effects are triggered by so-called @samp{sound events}. These sound
events usually have a name (like @samp{dooropen}) and an associated location
(the coordinates of the door) which affects the way a sound effect is
played. The collection of all sound files, their assignment to sound events,
and some additional information how to play them is called a @samp{sound set}.

You can use own sound files to create own sound sets for Enigma, and choose
among them in the options menu (entry @samp{Sound set}). You can distribute
these sound sets under your own choice of license and install sound sets from
other users. There is no internal limit for the number of installed sound sets.

The sound event is converted into a real sound effect using tables, you can
find such tables in the @samp{data/sound-defaults.lua} file and in the empty
sample file at @samp{reference/soundset.lua}. Each entry in these tables is
either a string like @samp{enigma/st-coinslot}, which is interpreted as the
file @samp{soundsets/enigma/st-coinslot.wav} with some default properties, or a
list of sound attributes enclosed in curly braces. Sound events triggered by a
@ref{sound} message are converted the same way. Here is an example of such an
entry:

@example
dooropen = @{ file="my_soundset/open-door", volume=0.9, priority=4 @},
@end example

The meaning of these attributes is as follows:

@itemize

@item @samp{file}
Path and name of the sound file for this event, without the @samp{.wav}
extension.

@item @samp{volume}
The sound volume: 1.0 is default, 0.0 is silent.

@item @samp{priority}
If many effects are active at the same time, high-priority
effects can replace lower-priority effects. Use an integer
between 1 and 10 (default 1). This property does not yet
work with Enigma 1.01.

@item @samp{global}
Either @samp{true} or @samp{false}.  If true, no stereo effects are
applied and there is no attenuation.  Used for menu sound,
level end sounds, etc. Default is @samp{false}.

@item @samp{loop}
@samp{true} or @samp{false}. If true, the sound repeats infinitely
until canceled. Default is @samp{false}.

@item @samp{damp_max}, @samp{damp_inc}, @samp{damp_mult}, @samp{damp_min}, @samp{damp_tick}
Parameters for sound damping.  Sounds from noisy objects like light passengers
are damped to reduce the noise.  For this, the sound event's frequency is
estimated.  @samp{damp_max} calibrates the maximal damping factor (high means
quiet), @samp{damp_inc} how fast the damping accumulates, @samp{damp_mult} is an
overall factor, @samp{damp_min} defines a lower bound for the damping entries
(beyond which they are removed from memory) and @samp{damp_tick} the factor
that's applied all 0.1 seconds.  See @samp{sound.hh} for details.
Defaults: 10.0, 1.0, 1.0, 0.5, 0.9.

@end itemize

To design a new sound set, proceed as follows:

@enumerate

@item
Create a new folder containing a copy of the sample file @samp{soundset.lua}
and the wav files you want to use.

@item
Move this new folder into Enigma's "soundsets" folder in your user path.
(Possibly you have to create it.) The directory structure should look
something like this:

@example
(user path)/soundsets/my_sounds/
                               /soundset.lua
                               /high_pitch.wav
                               /soundfile_13.wav
                               ...
@end example

@item
Run Enigma and choose @samp{My Soundset} in the options menu.  Since this file's
sound set does not map any sound effect to a wav file, you should hear nothing.

@item
Edit the contents of @samp{soundset.lua} to your liking.  You can access the
default sound files, e.g.:

@example
...
coinsloton = @{ file="enigma/st-coinslot" @},
...
@end example

When using own sound files, remember to add the subfolder, like in

@example
...
coinsloton = @{ file="my_sounds/soundfile_13" @},
...
@end example

No extension ".wav"! It's added automatically. Make sure that the
extension is in lower case letters.

@item
Replace @samp{MY_SOUNDSET} by a suitable variable name, and @samp{My Soundset}
by the name you want to see in the sound options menu.  Remember to
make it short enough to fit on the button.  The three identifiers variable,
button name, directory name need not have the same names, but it eases the life
of other developers to give them similar names that uniquely determine the
sound set.

@end enumerate

Remember to choose the sound set in the options menu anew each time you change
its name.  And always shut down Enigma before changing sound sets, new sounds
are not recognized during runtime.

Feel free to zip and distribute the whole directory containing your
sounds and the @samp{soundset.lua} file. You can install a downloaded zipped
sound set simply by unpacking it and placing it into the
@samp{soundsets}-subdirectory of your user path. Make sure that the
@samp{soundset.lua} is always exactly one subdirectory below @samp{soundsets}.
Deinstall a user sound set simply by deleting its directory. Renaming the
directory does not suffice -- you have to rename the @samp{soundset.lua} if you
want to hide a sound set from Enigma. This can be advantageous if you use
interdependent sound sets (sound sets that share sound files) and want to
deactivate just one of them.

@c ===================  Levelpack Basics  =======================

@node  Levelpack Basics
@chapter Levelpack Basics

Knowing the basics of running Enigma, you may wonder how levels are organized in
levelpacks and how you can add levels or complete levelpacks to Enigma.

@cindex crossreference
@cindex crossindex
@cindex levelpack
@cindex index
Levelpacks are sorted collections of levels that consist of an index and optional
attached level sources. Not all level sources of a levelpack have to be included
within the levelpack itself. A levelpack can crossreference levels stored in
other levelpacks. If a levelpack has no level sources of its own and consists only
of crossreferences, we speak of a crossindex, since just a single index file represents the
levelpack.

These definitions suit all versions of Enigma well. However, up to Enigma 0.92, levelpacks
needed to be manually edited, and the registration of levelpacks was a little bit cryptic. Thus, we
decided to rewrite the complete levelpack system for Enigma 1.0, and tried to make it versatile
and easy to use. We did set up the following aims:

@itemize @bullet
@item
an @samp{Auto} levelpack that allows level addition by drag and drop of the
level source

@item
levelpack addition simply by copying the files to the userpath

@item
autodetection of all levelpacks without editing any registration files

@item
commandline-supplied levels as a standard levelpack

@item
a @samp{History} levelpack with crossreferences of last-played levels

@item
level search results as a levelpack of crossreferences

@item
zipped levelpacks that are just archives of levelpack directories and their files

@item
grouping of levelpacks in the menu

@item
integrated composer to create and modify new levelpacks

@item
updates of levelpacks without updating Enigma itself

@item
automatic conversion of Enigma 0.92 levelpacks

@end itemize

Some of these features work seamlessly. You can use them immediately from the
levelpack menu. For others, you may need to know where to place files. We will
explain these details in the following sections:

@menu
* Getting Started with Levelpacks::
* Converting 0.92 Levelpacks::
* Zip Levelpacks::
* Grouping and Sorting Levelpacks::
* Creating New Levelpacks::
* Modifying and Deleting Levelpacks::
* Composing Levelpacks::
@end menu

@node Getting Started with Levelpacks
@section Getting Started with Levelpacks

One of the outstanding features of Enigma is its extensibility by new levels.
And the community of users usually provides us several new great levels every week.

Adding a new level that you receive as an XML file is very simple. Locate the
subdirectory @samp{levels/auto} on your @samp{user path} (@pxref{Locating Resources}).
Just copy the level file to this folder and restart Enigma. The new level will be
part of the @samp{Auto} levelpack, and you can play it like any other level.

Please note that Enigma displays erroneous or incompatible levels with an error icon in the level
menu. Of course an attempt to run such a level will result in an error message. Look at the level
metadata with the levelinspector
(@pxref{Level Info}) to identify the required compatibility version, and contact
the author via the address in case of level code errors.

A second way to run new levels is to add the address of the level files to the
commandline (@pxref{Startup Switches}). This way you can play levels that are stored
anywhere, and you may even use url addresses of levels stored on the internet. Levels added to
the commandline are accessible via the @samp{Startup Levels}
levelpack.

If you want to run an old-fashioned Lua level that someone wrote for Enigma 0.92 or earlier,
you may try to start it via the commandline. These old levels miss necessary metadata for auto
detection. However, commandline-supplied levels are treated as temporary levels available just
for a single run of Enigma; reasonable defaults substitute the missing data. The level will
probably run, but scoring and copy, paste and linking of such levels is not possible.

Besides single new levels, the community may provide you with complete levelpacks, too. These
levelpacks may occur as directories with levels, zip archives or single XML files. You can install
all of them simply by copying the files, but we have to distinguish the three formats.

You must copy levelpacks distributed as directories, with level files and an index file in them, to
the subdirectory @samp{levels} on your @samp{user path}
(@pxref{Locating Resources}).

You must copy levelpacks distributed as zip archives to the subdirectory
@samp{levels} on your @samp{user path}. You do not need to unpack the zip,
although it is possible, as described in the section @ref{Zip Levelpacks}.

You must copy levelpacks that are distributed as a single XML index file to the subdirectory
@samp{levels/cross} on your @samp{user path}.

All new levelpacks should be accessible via the levelpack
menu after restarting Enigma.

That is all you need to know to be able to add new levels and levelpacks for
testing and playing. If your main interest lies in writing your own levels, you may
want to proceed directly to chapter @ref{Level Basics}. The rest of this chapter
explains how to arrange and sort existing levels in your own levelpacks.

@node Converting 0.92 Levelpacks
@section Converting 0.92 Levelpacks

With the changes of the levelpack index format, converting old levelpacks is necessary. Although
the main work is done automatically just by starting Enigma, a few special cases remain that
need manual preparation. Further on, after the autoconversion, some cleanup may be useful.

If you formerly maintained your levelpacks within the Enigma system levels directory, you
should now copy your own levelpacks from the old Enigma version to the @samp{user path}
subdir @samp{levels} (@pxref{Locating Resources}). The @samp{user path} exists on all
systems, and since Enigma 1.00 will never write to the system levels directory, it will perform
updates and conversions only on the @samp{user path}. If you
registered your levelpacks on the system levels directory within the @samp{index.lua}
file, you need to copy these registration lines to the @samp{index_user.lua} file,
which you should store on your @samp{user path}.

If you maintained several of your own levelpacks, Enigma 0.92 allowed you to keep them
in several subdirectories of the @samp{levels} directory. However, since it also allowed you to
keep all level files and different indices in the @samp{levels} directory
itself, you will run into trouble with the auto conversion, because Enigma 1.00 allows only one
levelpack with attached level files per directory.
In this case, we recommend a step-by-step conversion: in every step, provide only one old index
for conversion. Enigma will convert this index to a new @samp{index.xml}.
Move this new index, together with all levels, to a subdirectory and convert the
next levelpack.

A last special case occurs if you had an old index stored in @samp{levels} that
referenced level files in different subdirectories of @samp{levels}. Since Enigma 0.92 did not
have a concept of cross-references, and Enigma 1.00 requires that you store all level files
attached to a levelpack in a single subdirectory, the conversion algorithm needs to guess the
correct subdirectory. It simply takes the subdirectory of the first level. If this does not fit, you
may need to clean up your 0.92 levelpack prior to conversion.

Enigma should convert all other standard levelpacks without problems. It only performs the
conversion once. As soon as the new @samp{index.xml} exists, only this
index is used. Thus, after a careful check, you may remove the old @samp{index.txt}.
We recommend keeping a backup of the old index until you have completely switched to
Enigma 1.00.

If you used a levelpack of your own in the zip format, you will find a subdirectory named with
the base name of the zip archive in your user @samp{levels}
directory. Enigma stores the converted @samp{index.xml} within this directory. You
may want to exchange the old @samp{index.txt} in the zip with the new index.
Afterwards you can delete the subdirectory, since Enigma will load the index directly
from the zip archive.

After converting your levelpacks, we strongly recommend that you update your own
levels to the new XML format, as described in @ref{Level Basics}.

@node Zip Levelpacks
@section Zip Levelpacks

Besides the classic levelpack format of a subdirectory of @samp{levels} with
an @samp{index.xml} and several level files, Enigma 1.00 provides a compatible
zip archive format. This zip allows you to reduce resources and to ease distribution
of levelpacks.

The compatibility is 100%. If you have a classic subdirectory levelpack, you
can simply zip the complete subdirectory and name the zip with the name of the
subdirectory, plus the standard @samp{.zip} suffix. Now you can completely remove the
subdirectory; Enigma autodetects the levelpack and it is fully playable. Even cross-references
into this levelpack will not be broken!

On the other hand, Enigma allows you to expand every zip levelpack to a subdirectory with
index and level files. Again, everything runs and no cross-references are broken.

If you keep both, the files contained in the subdirectory precede files in the zip
archive. Thus, Enigma stores updates of single files in subdirectories in parallel
to existing zip archives.

@node Grouping and Sorting Levelpacks
@section Grouping and Sorting Levelpacks

As the number of levelpacks increased, it became necessary to sort and group the
levelpacks in the menu. We tried to provide a useful set of default groups
and default assignment of the distributed levelpacks to these groups:

@itemize @bullet
@item
@b{Enigma} - levels that are written just for Enigma

@item
@b{D@'ej@`a-vu} - levels that you may have seen before

@item
@b{Sokoban}

@item
@b{Facets} - special sortings and views of the levels above

@item
@b{User} - personal levels and levelpacks like History, Autofolder generated by the
system for the user.

@item
@b{Development} - templates and unfinished levels from the Enigma Team

@item
@b{All Packs}

@end itemize

Still, this is just a proposal. You are free to rename the groups, add new groups and change the
assignments of the levelpacks. As in other parts of Enigma, you can right or control click on the
group and levelpack buttons.

The group configuration menu allows you to rename and reposition a group. You
can choose any name that is not a duplicate, that is not enclosed in square brackets
and differs from @samp{Every Group}. Note that you may not be able to enter as many
characters as you are used to. Sorry for this inconvenience.

The levelpack configuration menu allows you to assign a pack to a group. The
group list contains two special entries: @samp{[Every Group]} and another name
enclosed in square brackets. Selecting the first pseudogroup displays the levelpack in every
group. This is the default assignment of the @samp{Startup Levels} group. The second square
bracket-enclosed name is the default group of the
levelpack itself. It is a hint for you and allows you to reassign a levelpack
to the default group even if meanwhile you have deleted the group.

@node Creating New Levelpacks
@section Creating New Levelpacks

To create a new levelpack, you simply select the group to which you want to add
the new pack. This is most likely the @samp{User} group. Right or ctrl click on
the group and simply click on the @samp{New Levelpack} button. Enigma will call the
levelpack configuration menu, which allows you to enter all the important data for the creation
of a levelpack.

First you should enter a name for the levelpack. You are limited to characters
that can be used for filenames, too. You may use alphanumerical characters A-Z, a-z, 0-9 and
space, underscore and hyphen. Note that you may rename the pack
later for a better or more suitable display name (@pxref{Modifying and Deleting Levelpacks}).

Later, you should decide whether you want a levelpack that can contain level
sources or just a crossreference levelpack. The first one is useful for storing
your own self-written levels or levels that you download from the internet.
You may use the crossreference levelpacks for your favorite collections, where you simply
reference existing levels of other levelpacks with your own personal sorting.
You set the selected type with the @samp{Level types} button, which uses symbols
for references and carbon copies.

The @samp{Default Location} is a number that determines the sorting location
within levelpack groups, if you have not resorted the levelpack manually
(@pxref{Grouping and Sorting Levelpacks}). This default value is relevant only
if you distribute your levelpack and want to ensure that the users will find
your levelpack at a proper location. The value given after creating a new
levelpack should work well in most circumstances.

You may declare yourself as owner or creator of the levelpack. This is just a
string for identification purposes.

Finally, when you have completed the configuration, you can create the levelpack by
clicking @samp{OK}. Enigma will create the levelpack on your @samp{userpath}
(@pxref{Locating Resources}).

If you decide not to create a new levelpack, just click @samp{Undo}. Enigma will not create or
change anything in this case.

If you want to set up the new levelpack immediately, you can click directly on
@samp{Compose Pack}. Enigma will create the levelpack, and you can use the composer to fill
it with levels.

@node Modifying and Deleting Levelpacks
@section Modifying and Deleting Levelpacks

To modify a levelpack, right or ctrl click on its button in the levelpack menu.
You will see the metadata for all levelpacks. However, an @samp{Edit Metadata} button will
appear only for your own levelpacks, which Enigma stores on your @samp{userpath}.
Clicking on it allows you to edit the metadata.

Renaming the levelpack is possible, but Enigma will not change the filenames anymore. It will
use the new name as the logical levelpack name that shows up in Enigma.

Other attributes that you can modify include the @samp{Default Location} and the
@samp{Owner}.

Note that changing the levelpack type later is not possible. You must create a new levelpack of
the proper type and copy the levels by using
@ref{Composing Levelpacks}.

We do not provide a levelpack deletion function to avoid unintended loss of levelsources.
Still, the deletion of a levelpack is as simple as deleting the complete levelpack
directory on your @samp{userpath}. For crossreference levelpacks, you simply need to
delete the index XML file on the @samp{levels/cross} subdirectory of your
@samp{userpath}.

@node Composing Levelpacks
@section Composing Levelpacks

You can change the levels of a levelpack by using the levelpack composer. You call it
by right or ctrl clicking on the levelpack button in the levelpack menu, then
clicking on the @samp{Compose Pack} button in the levelpack configuration menu.

The composer looks similar to the levelmenu, but it provides other functionality. Enigma lists
all commands in the F1 help menu. First, if you compose your own levelpacks, you may note
that the levels are bordered red. This is a warning, since you can modify these levelpacks.
System levelpacks (the distributed Enigma levelpacks) will border the levels in gray, since you
can use the composer only for copying levels to the clipboard.

The clipboard allows you to select levels in one or several levelpacks and to
insert these levels as reference or as copy to your own levelpacks. First, clear
the clipboard by @samp{Shift delete}. Then select any levels you want from within the
composer levels, and add them by @samp{Shift click}; or use @samp{F6} to add all
levels from the current levelpack to the clipboard. They will appear
in the upper text lines in the composer. Return to the levelpack where you want
to add the levels. Select the level behind which you want to add the levels. Use
@samp{F8} to insert the levels of the clipboard as references. If you edit a
levelpack that can take level copies, you may use @samp{F9} to insert the levels
of the clipboard as file copies.

As soon as you modify the levelpack, a small red triangle in the upper left corner
signals the modification. Leaving the composer via the @samp{OK} button finalizes all
changes. Leaving the composer via the@samp{Undo} button reverts all changes.

Besides adding levels, you can delete levels by using the @samp{delete}
button. Note that Enigma will delete the level files themselves if you delete a level
that is not just a reference. Be careful with all levels that have the document
icon on their preview. You can revert deletions with the @samp{Undo} button.

You can resort all levels with the @samp{alt left arrow} and @samp{alt right arrow}.
The new sorting appears immediately, and you can save it by using the @samp{OK} button.

You can use the @samp{F5} button to update the index from the levels. This is very useful if
you edit levels yourself. The levelpack will notice changes in title, revision, easy mode support
etc. Enigma updates all levels of the levelpack at once.

By using the Auto levelpack and the composer, you can set up levelpacks of your own levels, as
follows: Create a new levelpack, add the level files to the @samp{auto}
folder, restart Enigma, add the levels from the @samp{auto} folder to the clipboard,
use the composer to insert the levelpack to your levelpack as a copy, and delete the
unused level file copies from the @samp{auto} folder.

Outside the composer, you can use @samp{F6} in a normal level menu as well. This way
you can swiftly create level packs from search results: Make sure the clipboard is
empty, enter your search criteria in the search menu, start the search, press
@samp{F6}, create a new level pack, go to its composer, and press @samp{F8}.

@c ===================  Level Basics  =======================

@node  Level Basics
@chapter Level Basics

Now that you have played some levels of Enigma, you may have noticed that Enigma is quite a
dynamic game with versatile levels. Thus, it is not astonishing that it is impossible to describe
such levels with a static approach of a simple object map like Sokoban. Some levels, like mazes,
generate their layout and look different each time you play them. Other levels provide a dynamic
behavior during the play; i.e., switches may open doors only in certain circumstances. To
comply with these demands, we have integrated the powerful lightweight C extension language
@url{http://www.lua.org, Lua} as of version 5.1.4 into Enigma.

Up to Enigma 0.92, two different level formats did exist. One was a XML-like format, primarily
designed for external level editor programs. Because its static object map description part was
inconvenient for manual editing, many authors never used it. The second format was plain Lua
code that used an interface of Enigma Lua functions to add objects and callback functions.
Nearly all authors used this second format, but it had a small drawback:
you could store metadata for the level (like the author name, license info, and last but not least,
the level name itself) only as unformatted Lua comments, and you had
to reinsert it manually into the level-package indices.

With the post-0.92 XMLification of Enigma, we achieved full XML support by integrating
Apache Xerces, and were wondering how to get rid of the old level format drawbacks and how to
add some compelling new features:

@itemize @bullet
@item
a single format with optional parts - use only those parts you need

@item
no major changes or any limitations for Lua level authors

@item
keep all author-supplied metadata in the level

@item
enable plug & play for users - copy the level from the author and play it
without manual index edition

@item
support of various encodings, such as US-ASCII, UTF-8, UTF-16, Windows-1252

@item
internationalization of levels - allow authors to add strings in their native
language and supply translators with all translatable level strings and comments
from the authors' how-to-translate.

@item
add a release and dependency management for levels and libraries

@item
add level update and upgrade support for levels and libraries

@item
substitute the old XML format with a versatile editor interface

@item
keep the format open to future extensions

@end itemize

Let us have a first view on complete simple @samp{Hello World} level in the new format:

@example
<?xml version="1.0" encoding="@var{UTF-8}" standalone="no" ?>
<@i{el}:@b{level} xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="@i{http://enigma-game.org/schema/level/1 level.xsd}" xmlns:@i{el}="@i{http://enigma-game.org/schema/level/1}">
  <@i{el}:@b{protected} >
    <@i{el}:@b{info} @i{el}:@b{type}="@var{level}">
      <@i{el}:@b{identity} @i{el}:@b{title}="@var{Demo Simple}" @i{el}:@b{id}="@var{20060210ral001}"/>
      <@i{el}:@b{version} @i{el}:@b{score}="@var{1}" @i{el}:@b{release}="@var{1}" @i{el}:@b{revision}="@var{2}" @i{el}:@b{status}="@var{stable}"/>
      <@i{el}:@b{author}  @i{el}:@b{name}="@var{Ronald Lamprecht}"/>
      <@i{el}:@b{copyright}>@var{Copyright @copyright{} 2006,2009 Ronald Lamprecht}</@i{el}:@b{copyright}>
      <@i{el}:@b{license} @i{el}:@b{type}="@var{GPL v2.0 or above}" @i{el}:@b{open}="@var{true}"/>
      <@i{el}:@b{compatibility} @i{el}:@b{enigma}="@var{1.10}"/>
      <@i{el}:@b{modes} @i{el}:@b{easy}="@var{false}" @i{el}:@b{single}="@var{true}" @i{el}:@b{network}="@var{false}"/>
      <@i{el}:@b{score} @i{el}:@b{easy}="@var{-}" @i{el}:@b{difficult}="@var{-}"/>
    </@i{el}:@b{info}>
    <@i{el}:@b{luamain}><![CDATA[
@i{ti}["@var{ }"] = @{"@b{fl_lawn_b}"@}
@i{ti}["@var{#}"] = @{"@b{st_box}"@}
@i{ti}["@var{o}"] = @{"@b{st_oxyd}"@}
@i{ti}["@var{@@}"] = @{"#@b{ac_marble}"@}

@i{wo}(@i{ti}, " ", @{
    "@var{####################}",
    "@var{#                  #}",
    "@var{#  o      @@     o  #}",
    "@var{#                  #}",
    "@var{####################}",
@})
    ]]></@i{el}:@b{luamain}>
    <@i{el}:@b{i18n}/>
  </@i{el}:@b{protected}>
</@i{el}:@b{level}>
@end example

You may notice that the XML portion contains all the metadata that the level author is
accustomed to supplying with a level. The XML part is like a formula that you can copy from a
template and fill out.

The Lua code is embedded in the XML. The only limitation to the Lua portion is that it reserves
@samp{]]>} for the end mark, and you would have to substitute it with
@samp{]] >}. No further restrictions.

Since the example above includes all mandatory XML parts, we should achieve our aim to avoid
major changes for Lua level authors.

You can find the example above in the @samp{Exp} levelpack grouped in
@samp{Development}.
The source code is located on the system path subdirectory
@samp{levels/enigma_experimental}
(@pxref{Locating Resources}).

If you make your first coding experiments on a copy of this level, either add your
copy to the auto folder (@pxref{Getting Started with Levelpacks}), or use it as
an argument on the command line (@pxref{Startup Switches}).

Of course we must look at the details of the format and explain the optional
parts:

@menu
* Getting Started with Levels::
* XML Level structure::
* Info metadata::
* LUA code::
* Internationalization (i18n)::
* Usage::
* Update and Upgrade::
* Library Files::
* Multilevel Files::
@end menu

@c ----------------- Getting Started with Levels --------------------
@node Getting Started with Levels
@section Getting Started with Levels

Most likely you are keen on understanding the basic principles of placing
objects in a level. Here is a very simple level description that can also serve
as a starting-point for new landscapes.  (In fact, this is the first welcome
level in levelpack Enigma I, so you can try it out right away.)

@example
 1    @i{ti}["@var{ }"] = @{"@b{fl_gravel}"@}
 2    @i{ti}["@var{#}"] = @{"@b{st_box}"@}
 3    @i{ti}["@var{O}"] = @{"@b{st_oxyd}"@}
 4    if @i{wo}["@b{IsDifficult}"] then
 5        @i{ti}["@var{Q}"] = @{"@b{st_quake}", @b{name}="@var{quake}"@}
 6        @i{ti}["@var{T}"] = @{"@b{st_timer}", @b{interval}=@var{10.0}, @b{target}="@var{quake}"@}
 7    else
 8        @i{ti}["@var{Q}"] = @i{ti}[" "]
 9        @i{ti}["@var{T}"] = @i{ti}[" "]
10    end
11    @i{ti}["@var{@@}"] = @{"@b{ac_marble_black}", @var{0.0}, @var{0.5}@}
11
12    @i{wo}(@i{ti}, " ", @{
13	"@var{####################}",
14	"@var{#                  #}",
15	"@var{#                  #}",
16	"@var{#  O            O  #}",
17	"@var{#         @@        #}",
18	"@var{#                  #}",
19	"@var{#        QT        #}",
20	"@var{#                  #}",
21	"@var{#                  #}",
22	"@var{#  O            O  #}",
23	"@var{#                  #}",
24	"@var{#                  #}",
25	"@var{####################}"@})
@end example

The resulting level looks like this inside the game:

@image{images/first_level, 150mm}
@ignore
      <img src="welcome.png" alt="The first level" width="75%" height="75%"></para>
@end ignore

Let's now turn to a line-by-line analysis of this program:

@example
 1    @i{ti}["@var{ }"] = @{"@b{fl_gravel}"@}
 2    @i{ti}["@var{#}"] = @{"@b{st_box}"@}
 3    @i{ti}["@var{O}"] = @{"@b{st_oxyd}"@}
@end example

First we declare some keys for objects we like to use in our level map. We
just add each key to our @i{ti} tiles repository and assign an object tile
description that consists of the object kind name in these simple cases. The
two character prefix of the kind name shows us the basic object type like floor,
item, stone, actor, etc.

@example
 4    if @i{wo}["@b{IsDifficult}"] then
 5        @i{ti}["@var{Q}"] = @{"@b{st_quake}", @b{name}="@var{quake}"@}
 6        @i{ti}["@var{T}"] = @{"@b{st_timer}", @b{interval}=@var{10.0}, @b{target}="@var{quake}"@}
 7    else
 8        @i{ti}["@var{Q}"] = @i{ti}[" "]
 9        @i{ti}["@var{T}"] = @i{ti}[" "]
10    end
@end example

The welcome level provides two modes, the regular difficult one and an easy one.
As the regular difficult one differs just in two additional stones we add two
mode specific tile declarations.

In the difficult mode we assign two stone definitions. Each provides the
stone kind and additional attributes. The @samp{st_quake} is the stone that
closes oxyd stones when being hit or toggled. We just name it, to be able to
reference it later on. The second stone is a timer that should get active
every 10 seconds and should send a toggle message to its target, our oxyd
closing @samp{st_quake}. As we did name this stone we can reference it here
as target by its name.

@example
11    @i{ti}["@var{@@}"] = @{"@b{ac_marble_black}", @var{0.0}, @var{0.5}@}
@end example

Now we just need to declare our actor. It is a black marble that should not
be placed at the left upper corner of a grid but in the mid of the left
border of a tile grid. Actually we just want to center it within the level.
As a one screen sized level has the extension of 20 x 13 we need the offsets
given above.

@example
12    @i{wo}(@i{ti}, " ", @{
13        "@var{####################}",
14        "@var{#                  #}",
15        "@var{#                  #}",
16        "@var{#  O            O  #}",
17        "@var{#         @@        #}",
18        "@var{#                  #}",
19        "@var{#        QT        #}",
20        "@var{#                  #}",
21        "@var{#                  #}",
22        "@var{#  O            O  #}",
23        "@var{#                  #}",
24        "@var{#                  #}",
25        "@var{####################}"@})
@end example

Now we can create the world simply by providing a map. We just need to call
@samp{wo}, our world handle, provide it our tile resolver, the key of the
default floor and a map of tile keys.

You will find all conceptional background information in chapter
@ref{Enigma Paradigm} and more examples and syntax information in chapter
@ref{Lua API}. But first you should take the time to get aware of the XML
based level metadata.


@c ----------------- XML Level structure --------------------
@node XML Level structure
@section XML Level structure

Let us start with a complete overview of all existing top XML element nodes. The
following level skeleton contains optional elements that are beyond level basics.
We include these elements for completeness:

@example
<?xml version="1.0" encoding="@var{UTF-8}" standalone="no" ?>
<@i{el}:@b{level} xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="@i{http://enigma-game.org/schema/level/1 level.xsd http://enigma-game.org/schema/editor editor.xsd}" xmlns:@i{el}="@i{http://enigma-game.org/schema/level/1}" xmlns:@i{ee}="@i{http://enigma-game.org/schema/editor}">
  <@i{el}:@b{protected}>
    <@i{el}:@b{info} @i{el}:@b{type}="@var{level}">
      <!-- required elements omitted -->
    </@i{el}:@b{info}>
    <@i{el}:@b{elements}/>
    <@i{el}:@b{luamain}><![CDATA[
    ]]></@i{el}:@b{luamain}>
    <@i{ee}:@b{editor}/>
    <@i{el}:@b{i18n}/>
  </@i{el}:@b{protected}>
  <@i{el}:@b{public}>
    <@i{el}:@b{i18n}/>
    <@i{el}:@b{upgrade}/>
  </@i{el}:@b{public}>
</@i{el}:@b{level}>
@end example

The first line is the XML declaration. It is fixed besides the encoding
specification. Enigma supports on all platforms, at least @samp{US-ASCII},
@samp{UTF-8}, @samp{UTF-16}, @samp{ISO-8859-1}, @samp{windows-1252}.
Enter your encoding and make sure that your editor saves the level in this encoding.
On some editors, you can start in ASCII mode, copy the level skeleton with a
different encoding declaration, like UTF-8, save the level still in ASCII mode
and reopen the file.  The editor may then detect the XML declaration and switch
automatically to the given encoding. Note that unless you enter
international strings in the level, you do not have to bother with the encoding
at all. You can choose UTF-8 in this case.

Some additional remarks for XML newbies: The XML markup tags are quite similar
to HTML. But XML requires a corresponding
end tag @samp{</element>} for each start tag @samp{<element>}. For elements that have
only attributes and no content,
you can and should use the alternative empty element notation @samp{<element/>}.
Note that when we define an element as empty or state that no content is allowed,
not a single whitespace, not even a linebreak is allowed between start and end tag. Use the
empty element notation to avoid mistakes.

We use a pretty printing format with an indentation of 2. Each element starts on a separate line.
Elements with text content have the end tag on the same line. Only elements with subelements
have the end tag on a separate line with the same indentation.

This format is not mandatory. You can even insert linebreaks in text contents, within the marks,
and even within attribute values. But note: The basic rule is that each linebreak will be
substituted by a space during the XML parsing. Take this space into account to avoid mistakes,
or simply live with the long lines.

A namespace identifier prefixes all tag names and attribute names.  We
use @samp{el} as an abbreviation for Enigma levels. All tag names you can
manually edit use this prefix.

Finally, a short comment on the XML reserved characters, @samp{&} and @samp{<}.
These two characters are reserved as tag and entity starting characters. If you
need them in text contents or in attribute values, you must substitute
them by the entity sequences @samp{&amp;} and @samp{&lt;}. Additionally, you must enclose
attribute values with either @samp{"} or @samp{'}. Of course, you must substitute the
enclosing character used in attribute values, too. Use @samp{&quot}
and @samp{&apos}.

@b{Elements:}

@table @asis
@item @b{/level}, @i{required, single occurrence}
This is the root node. Only one instance of this node occurs per file. Like the first XML
declaration line, this second line is quite fixed. There are two versions. The simple 3-attribute
version, as used in the first example, and only level editor programs use the 4-attribute version
as above. For manual level
editing, just copy the simple version as the second line to your level file.

@b{Attributes:}

@table @asis
@item @b{xmlns:xsi}, @i{required, contents fixed}
Namespace definition for the schema. The contents are fixed to
``http://www.w3.org/2001/XMLSchema-instance''. The attribute tag @samp{xsi} must
match the prefix of the next attribute tag, and is standard.

@item @b{xsi:schemaLocation}, @i{required, contents fixed}
Location of the schemas used. The contents are the fixed Enigma level
namespace, followed by the schema location URL. Level editor programs will add
their namespace and their schema location URL, as in the second example above.

@item @b{xmlns:el}, @i{required, contents fixed}
Namespace definition for ``Enigma level''. We use @samp{el} as the namespace prefix
for all level element and attribute tags, as standard. The prefix used can be
arbitrary, but must match this attributes tag. The contents of the attribute is
fixed to the Enigma level namespace.

@item @b{xmlns:ee}, @i{optional}
Only level editor programs use this last namespace definition. For
example, we declared @samp{ee} as the namespace prefix for all editor element and
attribute tags.  The prefix you use can be arbitrary, but must match this attributes
tag. The contents of the attribute are the editor's namespace.

@end table

@item @b{/level/protected}, @i{required, single occurrence}

The protected node section contains all level data that derive from the author and
should not be modified by anyone else.

@item @b{/level/protected/info}, @i{required, single occurrence}

The info node section contains all level metadata. It is mandatory and described in
detail at section @ref{Info metadata}.

@item @b{/level/protected/elements}, @i{optional, single occurrence}

The elements node section is optional. It contains level description parts that
are given in a data-driven manner. Though the driving force is the support
for level editor programs, a level author may use any parts of this section he or she
likes.

@item @b{/level/protected/luamain}, @i{optional, single occurrence}

The luamain node section is the part to insert manually Lua level descriptions.
It is described in detail at section @ref{LUA code}.

@item @b{/level/protected/editor}, @i{optional, single occurrence}

The editor node section is an open extension area for level editor programs.
They can add any additional information in this section that they need.
Enigma simply ignores this node section.

@item @b{/level/protected/i18n}, @i{required, single occurrence}

The i18n node section contains English strings, native translations and comments
supplied by the author for the translators. This node section is mandatory
and described in detail at section @ref{Internationalization (i18n)}.

@item @b{/level/public}, @i{optional, single occurrence}

This public node section is an optional extension to the protected part. It
contains information that the author has not validated and may even be added
after the last author's review.

@item @b{/level/public/i18n}, @i{optional, single occurrence}

This public i18n section contains further translations supplied for the level. They
may derive from the author or other sources. The translators will
validate these translations, and they continue in use if the translators do not
supply corrected versions. See @ref{Internationalization (i18n)}.

@item @b{/level/public/upgrade}, @i{optional, single occurrence}

This upgrade node is part of the @ref{Update and Upgrade} system.

@end table

@c ----------------- Info metadata --------------------
@node Info metadata
@section Info metadata

The Info node contains all author-supplied metadata for the level. This is the
source of these data. All other parts of Enigma, such as level indices, simply contain
copies that will be automatically updated to the level's original data.

Let us look at all supported subnodes of info with typically used attributes:

@example
<@i{el}:@b{info} @i{el}:@b{type}="@var{level}">
  <@i{el}:@b{identity} @i{el}:@b{title}="@var{Demo I18N}" @i{el}:@b{subtitle}="@var{Translate or let it be translated}" @i{el}:@b{id}="@var{20060211ral002}"/>
  <@i{el}:@b{version} @i{el}:@b{score}="@var{1}" @i{el}:@b{release}="@var{1}" @i{el}:@b{revision}="@var{0}" @i{el}:@b{status}="@var{experimental}"/>
  <@i{el}:@b{author}  @i{el}:@b{name}="@var{Ronald Lamprecht}" @i{el}:@b{email}="@var{ral@@users.berlios.de}"/>
  <@i{el}:@b{copyright}>@var{Copyright @copyright{} 2006 Ronald Lamprecht}</@i{el}:@b{copyright}>
  <@i{el}:@b{license} @i{el}:@b{type}="@var{GPL v2.0 or above}" @i{el}:@b{open}="@var{true}"/>
  <@i{el}:@b{compatibility} @i{el}:@b{enigma}="@var{0.92}"/>
  <@i{el}:@b{modes} @i{el}:@b{easy}="@var{false}" @i{el}:@b{single}="@var{true}" @i{el}:@b{network}="@var{false}"/>
  <@i{el}:@b{comments}/>
  <@i{el}:@b{update} @i{el}:@b{url}="@var{http://@dots{}}"/>
  <@i{el}:@b{upgrade} @i{el}:@b{url}="@var{http://@dots{}}" @i{el}:@b{release}="@var{2}"/>
  <@i{el}:@b{score} @i{el}:@b{easy}="@var{-}" @i{el}:@b{difficult}="@var{-}"/>
</@i{el}:@b{info}>
@end example

@b{Attributes:}

@table @asis
@item @b{type}, @i{required}, values = @code{"level"}, @code{"library"}, @code{"multilevel"}
You may use the schema for single Enigma levels, libraries that contain level
description parts for reuse, and descriptions for multiple levels at once.

@samp{level} are all single level descriptions. It does not matter if you
edit them manually or with a level editor program, or which description elements you
use.

@samp{library} are level description parts that may be included in levels.
@ref{Library Files} consist simply of Lua code in the luamain node. Libraries
may make use of nearly all nodes besides the @samp{/level/protected/info/score}
and @samp{/level/*/i18n}, which both must be provided, but will not be evaluated.
Libraries are included in levels via the dependency node-element. See
@ref{<compatibility>}.

@samp{multilevel} are descriptions for multiple levels at once. The main purpose
is to support foreign game level formats, like the Sokoban level format, which
usually describes a whole set of level maps in a single file (@pxref{Multilevel Files}).

@item @b{quantity}, @i{optional}
The number of levels contained in a multilevel file (@pxref{Multilevel Files}).

@end table

@b{Contents - Elements:}

@table @asis
@item @b{identity}, @i{required}
The title, subtitle and the main level identification string. See @ref{<identity>}.

@item @b{version}, @i{required}
All aspects of the level @ref{<version>}.

@item @b{author}, @i{required}
All information provided about the author him- or herself. See @ref{<author>}.

@item @b{copyright}, @i{required}
The @ref{<copyright>} message for the level.

@item @b{license}, @i{required}
Information about the @ref{<license>} conditions.

@item @b{compatibility}, @i{required}
All information about @ref{<compatibility>} to Enigma releases, dependencies
from libraries, external data and the editor program that generated the level.

@item @b{modes}, @i{required}
The @ref{<modes>} that the level supports, such as difficulty, network and control.

@item @b{comments}, @i{optional}
Optional comments, such as credits, dedication and code comments. See @ref{<comments>}.

@item @b{update}, @i{optional}
@ref{Update and Upgrade}

@item @b{upgrade}, @i{optional}
@ref{Update and Upgrade}

@item @b{score}, @i{required}
The author's own @ref{<score>} of this level.

@end table

@menu
* <identity>::
* <version>::
* <author>::
* <copyright>::
* <license>::
* <compatibility>::
* <modes>::
* <comments>::
* <score>::
@end menu


@node <identity>
@subsection <identity>

The @samp{@b{identity}} element is required, since it provides the information for human
and system identification of the level.

@example
<@i{el}:@b{identity} @i{el}:@b{title}="@var{Demo I18N}" @i{el}:@b{subtitle}="@var{Translate or let it be translated}" @i{el}:@b{id}="@var{20060211ral002}"/>
@end example

@b{Attributes:}

@table @asis
@item @b{title}, @i{required}
The English title of the level. The string can contain arbitrary characters
that are displayable by Enigma's font and XML conformant. Just in case of
@ref{Multilevel Files} a trailing hash sign has a special meaning. Anyway please
make sure that the title is not too long, since Enigma will use it on the level
selection menu. Translations of the title can be provided in the
@ref{Internationalization (i18n)} sections.

@item @b{subtitle}, @i{optional}
An optional English subtitle. Used for title parts that are too long for the
main title, or for a short first hint. Enigma displays the subtitle on the level info
page and on the start of the level. Translations of the subtitle can be provided
in the @ref{Internationalization (i18n)} sections.

@item @b{id}, @i{required}
This is the central system identification string of the level that remains valid
for all time, independent of upcoming release updates. The id string should not
contain spaces, braces and wildcard characters, that means no character out
of @samp{*? ()[]@{@}}. Enigma's main demand on the id is that it is unique among
all levels created by all authors around the world and that it does not end on a
closing square bracket.

Since you can edit levels with any text editor or different special Enigma level
editors, there is no control about the uniqueness. Thus, we have to provide a
simple convention to avoid any possible id clashes:

@var{@b{YYYYMMDDuserNNN}}

Where @samp{YYYY},@samp{MM},@samp{DD} is the date of the creation of the first
experimental version, @samp{user} stands for a user-specific name and @samp{NNN}
for a random number. For example, my level called @samp{Houdini} has the id
@samp{20060816ral719}. Of course all levels created on the same day have to
differ in the random number part. The id is an Enigma level system id, and is
never exposed to users.

For backward compatibility, legacy levels keep their former filename as the
new level id, and do not fit in the name schema given above. Still, that does
not harm since the only requirement is the uniqueness.

@end table

@b{Contents:}

The element itself is empty - no content is allowed.

@node <version>
@subsection <version>

This element provides the versioning information for the system.

@example
<@i{el}:@b{version} @i{el}:@b{score}="@var{1}" @i{el}:@b{release}="@var{1}" @i{el}:@b{revision}="@var{0}" @i{el}:@b{status}="@var{experimental}"/>
@end example

@b{Attributes:}

@table @asis
@item @b{score}, @i{required}
The score version is given as a positive integer number. New levels start with
score version ``1''. New level versions need to increase the
score version number if the level modifications cause different solutions with
incomparable score values. Of course, level authors should be very restrictive
with such modifications.

During the development of a level, you should use the attribute @samp{@b{status}} to mark a
level as not released. When the author changes the @samp{@b{status}} to
@samp{released}, he has to check scoring compatibility and increase the score
version if necessary.

This attribute is the logical equivalence to the Enigma 0.92 @samp{index.txt} attribute
@samp{revision}.

@item @b{release}, @i{required}
The technical release version is given as a positive integer number. New levels
start with release version ``1''. You must increase the release version number if
the level modifications cause either technical incompatibilities with previous Enigma releases,
or the scoring version has been increased.

The primary cause for technical incompatibilities should be the compensation
of Enigma engine changes. Since such compensations will not run on the old Enigma
version, the level versions must be distinguished by a different release number.

In both cases, technical and scoring incompatibilities, the level file name must
be changed, too. This is necessary since different Enigma versions may be installed on some
systems at the same time. They have the need for both level versions at the same time. Internet
servers providing Enigma levels need to offer the different level release at the same time, too.

To enable people to assign different level release files to a level itself, we
strongly recommend the name convention for levels
@var{AuthoridentifierLevelnumber_Releasenumber.Suffix}, where the levelnumber is at
least 2 digits; for example, @samp{ral01_2.xml}

@item @b{revision}, @i{required}
The revision number is a simple, ever-increasing version number. Every published
version of the level should have a new revision number. The revision number is
independent from the scoring and release version number.

If Enigma finds two levelfiles in its data search paths with identical filenames,
id, score and release version, it will load the one with the higher revision number.
This feature guarantees that an older level revision stored on the user's
home level directory cannot supersede a new revision of a level distributed with a new
Enigma release. Online updates will check the level revision numbers, too.

Although the revision evaluates to a number, the attribute can take a second
string format as the literal keyword @samp{$Revision$}. This
@url{http://subversion.tigris.org/, Subversion} format allows level authors to
let their Subversion repository automatically insert the level revision number. They must simply
set @samp{svn propset svn:keywords "Revision" level.xml}
at their repository for every level file. Since the Subversion revision number is
ever-increasing, it fulfills our criteria. Note that Enigma does not require that revision
numbers be consecutive.

@item @b{status}, @i{required}, values = ``released'', ``stable'', ``test'', ``experimental''
This attribute describes the quality of the level during development. Enigma
uses the status to protect the score database from being spoiled by unplanned solution
scores. It will record scores only for levels marked as @samp{released}.

As a level author, if you start to change a released level, you should first change the
status back to @samp{experimental}. Then make your changes and test
the level. When you are definitively sure that you did not introduce any spoilers,
you can release the level again with a new revision and perhaps a new release or
score version number.

@end table

@b{Contents:}

The element itself is empty - no content is allowed.

@node <author>
@subsection <author>

The information about the author him/herself. Enigma requires the author element itself, but
all attributes are optional to allow an author to be anonymous. Please remember that level
administrators and translators may need to contact you as the author. So please provide a way
for them to contact you.

The author element node may look like:

@example
<@i{el}:@b{author}  @i{el}:@b{name}="@var{Ronald Lamprecht}" @i{el}:@b{email}="@var{ral@@users.berlios.de}" @i{el}:@b{homepage}="@var{http://myhomepage.domain}"/>
@end example

@b{Attributes:}

@table @asis
@item @b{name}, @i{optional}, default = ``anonymous''
The author's name as it will be displayed on the level info page and on the start
of the level. The name defaults to @samp{anonymous}.

@item @b{email}, @i{optional}
The author's email address or a newsgroup or forum he monitors. In general, this is a
hint as to how to communicate with him or her. The value will simply be displayed as a string on
the level info page.

@item @b{homepage}, @i{optional}
An address for the author or where the author publishes additional Enigma levels.
The value will simply be displayed as a string on the level info page.

@end table

@b{Contents:}

The element itself is empty; no content is allowed.

@node <copyright>
@subsection <copyright>

The standardized location for the author's copyright message:
@example
<@i{el}:@b{copyright}>@var{Copyright @copyright{} 2006 Ronald Lamprecht}</@i{el}:@b{copyright}>
@end example

@b{Attributes:}

none

@b{Contents:}

The author's copyright notice.

@node <license>
@subsection <license>

Of course, every author is free to choose the license conditions for his/her levels.
However, the author must state the conditions. Thus, this node element and its
attributes are required:

@example
<@i{el}:@b{license} @i{el}:@b{type}="@var{GPL v2.0 or above}" @i{el}:@b{open}="@var{true}"/>
@end example

@b{Attributes:}

@table @asis
@item @b{type}, @i{required}
A short license identifier of the license type, with an optional link address to
the license text or the string @samp{special}, if the author supplies his/her own
license as the content of this element.

@item @b{open}, @i{required}
A boolean statement, whether the chosen license fulfills the criteria of the
@url{http://www.opensource.org/, Open Source Initiative (OSI)}. Please note
that a value of @samp{false} may prevent your level from being distributed
with Enigma.

@end table

@b{Contents:}

You may add a complete license text as the contents of this element. Please
use the type attribute to identify the level.

@node <compatibility>
@subsection <compatibility>

@example
<@i{el}:@b{compatibility} @i{el}:@b{enigma}="@var{0.92}" @i{el}:@b{engine}="@var{enigma}">
  <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/natmaze}" @i{el}:@b{id}="@var{lib/natmaze}" @i{el}:@b{release}="@var{1}" @i{el}:@b{preload}="@var{true}" @i{el}:@b{url}="@var{http://anywhere.xxx/mypage/natmaze.xml}"/>
  <@i{el}:@b{externaldata} @i{el}:@b{path}="@var{./extfile}" @i{el}:@b{url}="@var{http://anywhere.xxx/mypage/extdata.xml}"/>
  <@i{el}:@b{editor} @i{el}:@b{name}="@var{none}" @i{el}:@b{version}="@var{}"/>
</@i{el}:@b{compatibility}>
@end example

@b{Attributes:}

@table @asis
@item @b{enigma}, @i{required}
The minimal Enigma release number required for compatibility.

@item @b{engine}, @i{optional}, values = ``enigma'', ``oxyd1'', ``per.oxyd'', ``oxyd.extra'', ``oxyd.magnum''; default = ``enigma''
The required engine compatibility mode that influences the behavior of various
objects. This attribute is evaluated only for levels. Libraries ignore this
attribute.
@end table

@b{Contents - Elements:}

The compatibility element itself contains only subelements as content.

@table @asis
@item @b{dependency}, @i{optional, multiple occurrence}
You can use this element to specify any Enigma-Lua library this level depends on. You can
specify several libraries by multiple occurrence of this element. If you configure a library to be
preloaded, the engine will load it before it loads or executes any level Lua code. The load
sequence of several libraries conforms strictly to the sequence of their dependencies elements.

@b{Attributes:}
@table @asis
@item @b{path}, @i{required}
The resource path of the library without its suffix or any release extension.
Enigma stores most libraries in the @samp{lib} subdirectory of its
@samp{levels} directory, in most cases the resource path will be like the one in
the example above: @samp{lib/ant}. This is the valid path for the library file
that may be either @samp{levels/lib/ant.xml} or @samp{levels/lib/ant.lua} or
@samp{levels/lib/ant_1.xml}.

However, libraries can also be totally level pack-specific. In this case, you may use
a relative resource path, such as @samp{./mylib} and store the library in the level
pack directory itself.

@item @b{id}, @i{required}
The version independent id of the library, as specified in the library metadata.
Enigma will check it on load of the library to avoid problems, and may use
it with the release number to detect relocated libraries.

@item @b{release}, @i{required}
Although different release versions of libraries must have different filenames, we require to
specify the library version.  Enigma will check it on load of the library to avoid problems, and
may use it with the release number to detect relocated libraries.

@item @b{preload}, @i{required}
A boolean statement that specifies whether the library should be preloaded. If
the library is not preloaded, you can still load it via Lua code statements. Yet
even those libraries must be declared since Enigma will check them on conformance.
You should always preload your libraries if you make use of the @samp{elements}
section.

@item @b{url}, @i{optional}
This optional attribute allows you to specify a backup address for the library.
This will be useful for using new libraries that are not yet distributed
with the system.

For the development and test phase of new libraries themselves, a developer can hand out test
levels with an empty @samp{library} resource path
attribute. The test levels will load the newest library version as published
at the given url.

@end table

@b{Contents:}

none.

@item @b{externaldata}, @i{optional, multiple occurrence}
You can use this element to specify any external text data file this level
depends on. You can specify several files by multiple occurrences of this
element. Files declared can be read via the Lua interface.

This feature should support levels that simulate foreign games like Sokoban
within Enigma. Due to copyrights and license conditions, the inclusion of such
data within a level or even the distribution with Enigma may not be possible.
However, distributing or downloading the data in the original unmodified format
may be legal.

@b{Attributes:}
@table @asis
@item @b{path}, @i{required}
The resource path of the external data file without its suffix @samp{.txt}. The
path has to be either of the format @code{"./name"} for an external data file
that is locally stored in the same folder as the level file, or will be saved
at this position when it gets downloaded. Or the path can be of the format
@code{"externaldata/name"} for shared external data files, that are referenced
by multiple level files stored at different folders. The external data file will
be locally stored or gets saved in the folder @code{"levels/externaldata"}. In any
case the local name of the external data file will have the suffix @samp{.txt}
to mark it readable but not executable for the local operating system.

@item @b{url}, @i{optional}
This optional attribute allows you to specify an internet download address for
the external data file. On first access a missing external data file will be
downloaded and a copy will be stored locally for further access.
@end table

@b{Contents:}

none.

@item @b{editor}, @i{optional, single occurrence}
Special level editor programs use this element to store information about themselves.

@b{Attributes:}

@table @asis
@item @b{name}, @i{required}
The name of the level editor.

@item @b{version}, @i{required}
A version number of the editor, given as a string.
.
@end table

@b{Contents:}

none

@end table

@b{Contents:}

none

@node <modes>
@subsection <modes>

The modes element allows the author to declare the supported and the default
modes of his level. Enigma's engine checks that the level is used in supported
modes.

@example
<@i{el}:@b{modes} @i{el}:@b{easy}="@var{false}" @i{el}:@b{single}="@var{true}" @i{el}:@b{network}="@var{false}" @i{el}:@b{control}="@var{force}" @i{el}:@b{scoreunit}="@var{duration}" @i{el}:@b{scoretarget}="@var{time}"/>
@end example

@b{Attributes:}

@table @asis
@item @b{easy}, @i{required}, values = ``true'', ``false''
If a level provides a second easy-difficulty mode, set this attribute to @samp{true}.
If only a one difficulty mode is supported, set this attribute to @samp{false}.

@item @b{single}, @i{required}, values = ``true'', ``false''
If a level provides a single player game as it is standard, set this attribute to
@samp{true}. Set this attribute to @samp{false} only if the level is a 2-player-network game.

@item @b{network}, @i{required}, values = ``true'', ``false''
If a level provides a 2-player-network game, set this attribute to @samp{true}.
If not, set this attribute to @samp{false}.

@item @b{control}, @i{optional}, values = ``force'', ``balance'', ``key'', ``other''; default = ``force''
This attribute defines the standard control mode of the level. You can play a level by using the
mouse to generate forces on the marbles, since it is the standard and was the only way up to
Enigma 0.92. Or you can play a level using the mouse, or other input devices to balance the
level-world with the marbles. Or you may use the keyboard with its cursor keys to move the
actor like in classic Sokoban games.

Although the user has always the last choice to define the input method he/she
currently wants to use, the author must define the standard control-mode that
the scoring system uses. Enigma will save and evaluate only scores achieved in the defined
control mode for high score lists.

@item @b{scoreunit}, @i{optional}, values = ``duration'', ``number''; default = ``duration''
This attribute defines the evaluation and display mode of score values. By the
default @samp{duration}, the score is interpreted as level solution time and displayed
in a @b{MM:SS} format. The @samp{number} mode displays scores as plain
numbers and lower numbers will be evaluated as better scores. This mode is appropriate
for counting pushes and moves.

@item @b{scoretarget}, @i{optional}, values = ``time'', ``pushes'', ``moves'', *; default = ``time''
The score target triggers the measuring of score values. @samp{time} will take the
solution time, @samp{pushes} counts the pushes of stones, @samp{moves} counts the
moves of the actor. Any other value will call a Lua function for score values.
The target is used as a short title for the score in user interface displays.

@end table

@b{Contents:}

none

@node <comments>
@subsection <comments>

The optional comments node allows the author to add a few comments and to determine how
they should be processed. Please note that internationalization support will not translate
comments.

@example
<@i{el}:@b{comments}>
    <@i{el}:@b{credits} @i{el}:@b{showinfo}="@var{true}" @i{el}:@b{showstart}="@var{false}">@var{Thanks to the author of my favorite libs}</@i{el}:@b{credits}>
    <@i{el}:@b{dedication} @i{el}:@b{showinfo}="@var{true}" @i{el}:@b{showstart}="@var{false}">@var{To a honorable or a beloved person}</@i{el}:@b{dedication}>
    <@i{el}:@b{code}>@var{some important general notes}</@i{el}:@b{code}>
</@i{el}:@b{comments}>
@end example

@b{Attributes:}
none

@b{Contents - Elements:}

The comments element itself contains only subelements as content.

@table @asis
@item @b{credits}, @i{optional, single occurrence}
The place to honor people who helped to make your level run.

@b{Attributes:}
@table @asis
@item @b{showinfo}, @i{optional}, default = ``false''
A value of @samp{true} will display the message on the level info
page

@item @b{showstart}, @i{optional}, default = ``false''
A value of @samp{true} will display the message on startup of the
level. Please use this feature only in rare cases.
@end table

@b{Contents:}

The credits message itself. It may be broken into several lines. Whitespace will
be collapsed before display.

@item @b{dedication}, @i{optional, single occurrence}
The place to dedicate the level to a honorable or a beloved person. Please use
this place instead of adding document-items within the level.

@b{Attributes:}
@table @asis
@item @b{showinfo}, @i{optional}, default = ``false''
A value of @samp{true} will display the message on the level info
page

@item @b{showstart}, @i{optional}, default = ``false''
A value of @samp{true} will display the message on startup of the
level. Please use this feature only in rare cases.
@end table

@b{Contents:}

The dedication message itself. It may be broken into several lines. Whitespace will
be collapsed before display.

@item @b{code}, @i{optional, single occurrence}

@b{Attributes:}

none.

@b{Contents:}

The main code comment, which may be an explanation of the @ref{<version>} status
or a to-do list. It may be broken into several lines. This comment will not be
processed.

@end table

@node <score>
@subsection <score>

In this node, the author should provide his own scoring values as hints and
a challenge for other players. All values are related to the control mode defined
in @ref{<modes>}.

@example
<@i{el}:@b{score} @i{el}:@b{easy}="@var{01:07}" @i{el}:@b{difficult}="@var{-}"/>
@end example

@b{Attributes:}

@table @asis
@item @b{easy}, @i{required}
The solution time for the easy mode. The format is either @var{@b{MM:SS}}, where
MM stands for the minutes, and SS for the seconds, or @var{@b{-}} if the author did
not yet solve the level him/herself. For levels with a score unit mode @samp{number},
the value would be the number of marble moves or pushes.

@item @b{difficult}, @i{required}
The solution time for the difficult mode. The format is either @var{@b{MM:SS}}, where
MM stands for the minutes, and SS for the seconds, or @var{@b{-}} if the author did
not yet solve the level him/herself. For levels with a score unit mode @samp{number},
the value would be the number of marble moves or pushes.

@end table

@b{Contents:}

@node LUA code
@section LUA code

This element takes any Lua code as a single chunk with nearly no limitations:

@example
    <@i{el}:@b{luamain}><![CDATA[
levelw = 20
levelh = 13

create_world( levelw, levelh)
draw_border("st-wood")
fill_floor("fl-leavesb", 0,0,levelw,levelh)

oxyd( 4,4)
oxyd( 14,4)

document(5,10,"hint1")
document(10,10,"hint2")
document(10,5,"Heureka!")
set_actor("ac-blackball", 4, 11)
    ]]></@i{el}:@b{luamain}>
@end example

@b{Attributes:}

none

@b{Contents:}

This element takes the main Lua code as its contents.

All other possible libraries that are declared as dependencies, and Lua chunks
supplied by XML elements are preloaded as described in @ref{<compatibility>}.
Generally there is no more need to use Lua functions like @samp{Require} to load
libraries. Just in case you need to control the point of execution were the
library must be loaded, you can declare the library with the attribute
@samp{el:preload="false"}. You should use the new function @ref{enigma.LoadLib}
to load the library.

The Lua code that is enclosed in a XML CDATA section. This limits the
Lua code not to use the reserved end marker @samp{]]>}. Any occurrence must be
substituted by @samp{]] >}.

On the other hand, the XML format extends the Lua capabilities to the use of
encodings. You may use Lua strings and comments with Umlauts, but Lua identifiers are still
limited to pure US-ASCII. The benefit is that you can use Umlauts and
other non-ASCII characters within it-document hints.

@c ----------------- Internationalization (i18n) --------------------
@node Internationalization (i18n)
@section Internationalization (i18n)

The internationalization of levels is a driving force behind the level
format changes. As you may have noticed, there are two @samp{i18n} elements, one
in the author's protected section and one in the public. Let us review how to use
them for internationalization of the three documents of our @samp{demo_i18n.xml}
level:

@example
  <@i{el}:@b{protected} >
    <!-- elements omitted -->
    <@i{el}:@b{i18n}>
      <@i{el}:@b{string} @i{el}:@b{key}="@var{title}">
        <@i{el}:@b{english} @i{el}:@b{translate}="@var{false}"/>
      </@i{el}:@b{string}>
      <@i{el}:@b{string} @i{el}:@b{key}="@var{subtitle}">
        <@i{el}:@b{english} @i{el}:@b{translate}="@var{true}"/>
        <@i{el}:@b{translation} @i{el}:@b{lang}="@var{de}">@var{@"Ubersetzten oder @"ubersetzten lassen}</@i{el}:@b{translation}>
      </@i{el}:@b{string}>
      <@i{el}:@b{string} @i{el}:@b{key}="@var{hint1}">
        <@i{el}:@b{english} @i{el}:@b{comment}="@var{Let 'right' be ambiguous: correct and opposite of left - if not possible choose correct">Read the right document}</@i{el}:@b{english}>
        <@i{el}:@b{translation} @i{el}:@b{lang}="@var{de}">@var{Lies das rechte Dokument}</@i{el}:@b{translation}>
      </@i{el}:@b{string}>
      <@i{el}:@b{string} @i{el}:@b{key}="@var{hint2}">
        <@i{el}:@b{english} @i{el}:@b{comment}="@var{the correct one and not the right positioned one}">@var{The right one, not the right one!}</@i{el}:@b{english}>
        <@i{el}:@b{translation} @i{el}:@b{lang}="@var{de}">@var{Das rechte, nicht das rechte}</@i{el}:@b{translation}>
      </@i{el}:@b{string}>
      <@i{el}:@b{string} @i{el}:@b{key}="@var{Heureka!}">
        <@i{el}:@b{english} @i{el}:@b{translate}="@var{false}">@var{Heureka!}</@i{el}:@b{english}>
      </@i{el}:@b{string}>
    </@i{el}:@b{i18n}>
  </@i{el}:@b{protected}>
  <@i{el}:@b{public}>
    <@i{el}:@b{i18n}>
      <@i{el}:@b{string} @i{el}:@b{key}="@var{hint1}">
        <@i{el}:@b{translation} @i{el}:@b{lang}="@var{fr}">@var{Lisez la document de droite}</@i{el}:@b{translation}>
      </@i{el}:@b{string}>
    </@i{el}:@b{i18n}>
  </@i{el}:@b{public}>
@end example

Two of the documents use key words to reference a string. The last one uses the
English string itself as the key. There are two additional reserved keys,
@samp{title} and @samp{subtitle}.

For each string we like to translate or have translated, we define a @samp{string}
subelement of the protected section and add a @samp{english} subelement to the
@samp{string} element itself. The @samp{string} element just takes a single
mandatory attribute, the key of the string. The @samp{english} element has a
single mandatory attribute @samp{translate} that defaults to @samp{true}, stating
the author's decision whether the string should be translated. If the author
does not want a string to be translated, he can and must simply add no @samp{string}
element for this string at all. Thus, the elements for the strings with the keys
@samp{title} and @samp{Heureka!} are optional and quite unusual.

@samp{title} and @samp{subtitle} display the English text in the @ref{<identity>}
element. All other strings referenced by keys need to add the
English text as the content of the @samp{english} element. @samp{hint1} and
@samp{hint2} are examples.

Because we chose quite ambiguous English texts, it is very likely that translators
who do not play the game but just translate the text, may deliver a wrong
translation. To avoid mistakes, a level author may add a @samp{comment} attribute
to the @samp{english} element. The translator receives this comment with
the English string as we will see later.

If the author is not native English-speaking, he should add his own @samp{translation}
subelement to the @samp{string} element. The @samp{translation} element has a
single mandatory attribute @samp{lang} that takes the 2-character language
abbreviation. The contents of the element is the translation itself.

All translations added in the protected section take precedence over any translator's
translation and will work directly after addition without waiting for a translator's
translation.

Last but not least, we have an @samp{i18n} element in the public section. This element
takes translation suggestions. The author may add them him/herself for other
languages he/she knows. They may be added by others on the way to the user,
or even by the user himself.

Translations in this section will work immediately after addition without
waiting for a translator's translation. However, available translations, provided by translators,
will precede them.

The format is identical to the protected section, with the exception that no
@samp{english} element may be provided. The @samp{key} attribute in the
@samp{string} element must match exactly the @samp{key} attribute in the corresponding
@samp{string} element in the protected section. One subtle difference exists,
due to technical and practical reasons. @samp{key} attributes in the public
section need to be XML identifiers; thus, you cannot provide public translations
for strings that use the English phrase as the key. Choose a keyword and provide
the English string in the public @samp{i18n} section to avoid these troubles.

The @samp{string} element in protected section and in the public section
must be unique concerning the attribute @samp{key} within the section. This means
you should add translations for all known languages for a string in @samp{string}
element in the protected and in the public section. The sequence does not matter.

Let us review what the translator receives for each string. Let us
start with @samp{hint2} for the German translator:

@example
#  @i{level}: "@var{Demo Internationalization}"
#  @i{author}: "@var{Ronald Lamprecht}" @i{email} "@var{ral@@users.berlios.de}"
#  @i{comment}: "@var{the correct one and not the right positioned one}"
#  @i{use}: "@var{Das rechte, nicht das rechte}"
#: po/level_i18n.cc:17
@b{msgid} "@var{The right one, not the right one!}"
@b{msgstr} ""
@end example

@samp{msgid} is the English string. @samp{msgstr} takes the German translation.
But the translator does not need to translate since the author provided the German translation
in the @samp{#  use:} line

As another example, @samp{hint1} for the French translator:
@example
#  @i{level}: "@var{Demo Internationalization}"
#  @i{author}: "@var{Ronald Lamprecht}" @i{email} "@var{ral@@users.berlios.de}"
#  @i{comment}: "@var{Let 'right' be ambiguous: correct and opposite of left - if not possible choose correct}"
#  @i{check}: "@var{Lisez la document de droite}"
#: po/level_i18n.cc:14
@b{msgid} "@var{Read the right document}"
@b{msgstr} "@var{Lisez le document de droite}"
@end example

Here the author gives the public translation in the @samp{#  check:} line. Since it
contains at least one mistake, the translator will correct it, as shown in the @samp{msgstr}
string.

@c ----------------- Usage --------------------
@node Usage
@section Usage

After all the theory, let's look at how to deal with the XML levelformat in
practice. Of course, you will not assemble all XML metadata from scratch for
every new level you write. You should use templates. You can start with any
existing level, for example, the @samp{demo_i18n.xml} supplied with this
documentation. Add your personal data to your template and store it as the basis for all new
levels you write.

Some level authors are very familiar with the Lua file format since their favorite editor supports
Lua files with syntax coloring. The XML file name and the XML elements will cause
their editor to use XML syntax coloring. Nevertheless, these authors are used
to supplying metadata in the header of their Lua levels as non-standardized Lua
comments; we decided to support a similar Lua-compatible XML format. We call it
``Lua commented XML'' since it simply comments out all XML lines with the Lua comment
@samp{--xml-- }. For example:

@example
--xml-- <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
--xml-- <el:level xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://enigma-game.org/schema/level/1 level.xsd" xmlns:el="http://enigma-game.org/schema/level/1">
--xml--   <el:protected >
--xml--     <el:info el:type="level">
--xml--       <el:identity el:title="Demo Simple" el:id="20060210ral001"/>
--xml--       <el:version el:score="1" el:release="1" el:revision="0" el:status="stable"/>
--xml--       <el:author el:name="Ronald Lamprecht"/>
--xml--       <el:copyright>Copyright @copyright{} 2006 Ronald Lamprecht</el:copyright>
--xml--       <el:license el:type="GPL2" el:open="true">GPL v2.0 or above</el:license>
--xml--       <el:compatibility el:enigma="0.92"/>
--xml--       <el:modes el:easy="false" el:single="true" el:network="false"/>
--xml--       <el:score el:easy="-" el:difficult="-"/>
--xml--     </el:info>
--xml--     <el:luamain><![CDATA[
levelw = 20
levelh = 13

@b{create_world}( levelw, levelh)
@b{draw_border}("@i{st-wood}")
@b{fill_floor}("@i{fl-leavesb}", 0,0,levelw,levelh)

@b{oxyd}( 4,4)
@b{oxyd}( 14,4)

@b{set_actor}("@i{ac-blackball}", 4, 11)
--xml--     ]]></el:luamain>
--xml--     <el:i18n/>
--xml--   </el:protected>
--xml-- </el:level>
@end example

Please note that each XML metadata line must start exactly with @samp{--xml-- },
8 characters, including the space at the end! An additional limitation of the
Lua-commented XML format arises from Lua's capability of handling character
encodings. You need to limit yourself to @samp{UTF-8} or, of course @samp{US-ASCII}
to successfully use the Lua-commented XML format. Please remember, that
although the XML part is Lua-commented, it must still be evaluated and thus must be
valid.

Every level stored in this Lua-commented XML format as a file with extension
@samp{.lua} can be used locally for command line use as well as in any level
package that is stored on the Enigma user's home directory. However, Lua-commented XML
levels cannot be stored on Internet servers or be updated online. Thus,
this format is good for level development, but you should convert the levels
to the pure XML format for distribution. Please note that Enigma looks for XML levels
first, and uses Lua levels only if it can't find an XML level.

Another use of Lua-commented XML levels is the format backward compatibility to
Enigma 0.92. If levels do not use new Enigma features, you can include
your levels in Enigma 0.92 level packages in this format.

Since you may need to convert levels several times between the XML and the Lua format,
we do provide tools for conversion: @samp{xml2lua} and @samp{lua2xml}. Both are
very simple Lua 5 scripts that you can execute as
@samp{lua xml2lua demo_simple.xml > demo_simple.lua} with a properly installed
Lua 5 version. On Unix systems, you can mark the scripts as executable and
simply call @samp{xml2lua demo_simple.xml > demo_simple.lua}.

Of course you can add the conversion algorithms as simple macros for your favorite
editor. Please publish any editor macros you write.

As you fiddle with the XML metadata, you may produce syntactical errors, of course.
You can validate your level by trying to start it with Enigma. XML errors are
output as Lua errors are. If the error messages are too long to read, you may
want to start Enigma from the command line with the option @samp{--log} and read the
messages printed to the command line or written to the file @samp{stdout.txt} on
the current working directory for Windows systems.

Of course, you can use any external XML validation tool, too. You just need to
copy the schema file @samp{level.xsd} on the same directory as the level itself.
Possible validation tools are the Xerces-C sample application
@samp{DOMPrint.exe -n -s -f -v=always level.xml} or validating editors, such as
@url{http://www.freexmleditor.com/, Exchanger XML Lite}. Such editors will provide
you with selections of all possible elements and attributes at each position.

@node Update and Upgrade
@section Update and Upgrade

Enigma is able to load new level versions since we provide all necessary
attributes in the @ref{<version>} element.

If Enigma loads a new level version, which differs just in the @samp{@b{revision}}, we speak of
an @samp{@b{update}}. You can perform updates automatically and replace old versions with
the updates, since the author guarantees them to be compatible in scoring and
dependencies. The author should provide a download address for automatic updates in the
protected info element:

@example
<@i{el}:@b{update} @i{el}:@b{url}="@var{http://myLevelServer.org/path/level_1.xml}"/>
@end example

@b{Attributes:}

@table @asis
@item @b{url}, @i{required}
A long-term valid, complete address for update downloads of this level in the same score and
release version.

@end table

If the author of a level introduces incompatibilities into the level, he increases the release
version of the level and stores it with a new filename. We call the download of such a new level
version an @samp{@b{upgrade}}.

To publish the availability of an upgrade release, the author should update the previous release
with a final revision that simply adds an upgrade element that announces the new release:

@example
<@i{el}:@b{upgrade} @i{el}:@b{url}="@var{http://myLevelServer.org/path/level_2.xml}" @i{el}:@b{release}="@var{2}"/>
@end example

@b{Attributes:}

@table @asis
@item @b{url}, @i{required}
A long-term valid, complete address for upgrade downloads of this level. A path
to the new file.

@item @b{release}, @i{required}
The release version of the upgrade.

@end table

Since the author cannot update all distributed levels himself to announce the availability of the
new release, we added another upgrade element in the public section. Level administrators can
use this element for the same purpose, with the same syntax, without modifying the author's
protected section.

@c ----------------- Library Files --------------------
@node Library Files
@section Library Files

Libraries are collections of Lua functions for reuse in many levels. To use a library, you must
declare it as a dependency, as described in @ref{<compatibility>}. Preloading the library is all
you have to do to use the library. Otherwise, you can use the function @ref{enigma.LoadLib} to
load the library at a certain point of execution.

Enigma provides several very useful @ref{Libraries}. You will find them on the system
path in the subdirectory @samp{levels/lib}. Most of them are documented in-line.
You will find a separate documentation file
@samp{doc/ant_lua.txt} for @samp{ant}.

In this section, we will concentrate on the aspects of writing and maintaining
libraries:

@menu
* Writing a Library::
* Maintaining a Library::
@end menu

@node Writing a Library
@subsection Writing a Library

Library files are nearly identical to level files. The main difference is the
attribute @samp{el:type} in the @samp{info} element, which you should set to
@samp{library}. You must provide all other elements and attributes as you
must for levels. Of course no scoring related attributes will ever be
evaluated and you should set them to default.

Libraries may depend on others, so you must provide an id and a release number.
Several releases of a library can coexist and you can update and upgrade them
if you provide the necessary information. Of course, libraries may contain document
strings that can be localized if you provide the @samp{i18n} elements.

The @samp{el:luamain} element takes the complete Lua code as it does for levels.
Let's look at the essential XML parts of a library:

@example
<?xml version="1.0" encoding="@var{UTF-8}" standalone="no" ?>
<@i{el}:@b{level} xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="@i{http://enigma-game.org/schema/level/1 level.xsd}" xmlns:@i{el}="@i{http://enigma-game.org/schema/level/1}">
  <@i{el}:@b{protected} >
    <@i{el}:@b{info} @i{el}:@b{type}="@var{library}">
      <@i{el}:@b{identity} @i{el}:@b{title}="" @i{el}:@b{id}="@var{lib/ant}"/>
      <@i{el}:@b{version} @i{el}:@b{score}="@var{1}" @i{el}:@b{release}="@var{1}" @i{el}:@b{revision}="@var{0}" @i{el}:@b{status}="@var{released}"/>
      <@i{el}:@b{author}  @i{el}:@b{name}="@var{Petr Machata}"/>
      <@i{el}:@b{copyright}>@var{Copyright @copyright{} 2002-2003 Petr Machata}</@i{el}:@b{copyright}>
      <@i{el}:@b{license} @i{el}:@b{type}="@var{GPL v2.0 or above}" @i{el}:@b{open}="@var{true}"/>
      <@i{el}:@b{compatibility} @i{el}:@b{enigma}="@var{0.92}">
        <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/natmaze}" @i{el}:@b{id}="@var{lib/natmaze}" @i{el}:@b{release}="@var{1}" @i{el}:@b{preload}="@var{false}">
      </@i{el}:@b{compatibility}>
      <@i{el}:@b{modes} @i{el}:@b{easy}="@var{false}" @i{el}:@b{single}="@var{false}" @i{el}:@b{network}="@var{false}"/>
      <@i{el}:@b{score} @i{el}:@b{easy}="@var{-}" @i{el}:@b{difficult}="@var{-}"/>
    </@i{el}:@b{info}>
    <@i{el}:@b{luamain}><![CDATA[
    @dots{}
    ]]></@i{el}:@b{luamain}>
    <@i{el}:@b{i18n}/>
  </@i{el}:@b{protected}>
</@i{el}:@b{level}>
@end example

@node Maintaining a Library
@subsection Maintaining a Library

Libraries may exist in different releases and revisions. Library versions that differ simply in the
revision, denote compatible versions. Library versions that introduce incompatibilities must
differ in the release number. However, since existing levels may depend on the legacy behavior
of the older release, you must maintain both library release versions and distribute them with
Enigma at the same time.

To coexist, these different library releases must follow a strict naming scheme. Every library has
a base name. In the example above it is @samp{lib/ant}.
The filename of a given release is the basename with the addition of an underscore and the
release number plus the suffix @samp{xml}. Thus, you must store release @samp{lib/ant} as
@samp{lib/ant_2.xml}.

If you look at the lib directory, you may wonder that Enigma stores most library files without
release number addition to the basename. This is due to 0.92 Lua level format compatibility
support. You can store one, and of course only one, release of each library without release
number addition to the basename. Enigma will load this version from pure Lua levels that do
not provide any information of the required library release.

If a library file with a complete filename is not present, the default library file without release
number addition will be loaded for XML load requests, too. Yet the future belongs to the new
naming scheme, and every new library should follow it from the beginning.

@c ----------------- Multilevel Files --------------------
@node Multilevel Files
@section Multilevel Files

Another concept of code reusage besides @ref{Library Files} are multilevel files.
The code contained in a single file generates several levels, called sublevels,
that appear as autonomous levels in a levelpack. Of course this concept is much
less flexible than the library concept as other level files can not reuse the
code. But you can write a multilevel if you wrote a lot of specific code for a
complex level that provides more than just two variants, which would be
otherwise presented as @samp{difficult} and @samp{easy} @ref{<modes>}.

But the main reason for multilevel files is the support of foreign game level
formats like Sokoban, which describe a whole set of levels in a single file.
Enigma imports these original files with just a few lines of code. It would be
inefficient, even though being possible, to write an Enigma level stub for
every level imported from a single foreign file.

But multilevel files have some restrictions. They use a single set of XML
level metadata. Thus these metadata must fit to all levels. The
@ref{<version>} will be identical as it reflects either the code version of the
native level or the version of the imported foreign file. But the other data
like @ref{<author>}, @ref{<compatibility>} and @ref{<modes>} have to match, too.
If they do not, you can not use a multilevel file.

Just the values for @samp{title} and @samp{id} will and have to differ for all
levels described by a single multilevel file. There exists special support for
multilevels to handle these attributes.

Let us look at all attributes and features of multilevels that differ from
standard level files.

First you have to declare in the @ref{Info metadata} element the type as
@code{"multilevel"} and to provide the quantity of generated levels. The
sublevels will be numbered from 1 to the given quantity.

In the element @ref{<identity>} you have to provide just one unique level id
value. Enigma will automatically append the string @code{"[1]"} for the first
sublevel, @code{"[2]"} for the second and so on. Thus every sublevel has an
unique id.

Additionally you should provide a base title for the levels in this metadata
@ref{<identity>} element. If your title ends with a hash @samp{#} sign Enigma
will autogenerate titles for the sublevels by appending the sublevel number to
the given common title string.

For individual sublevel titles the @ref{LUA code} has to provide the titles.
The title in the @ref{<identity>} element may not end on a hash sign and will
only be used as a default title base in case the @ref{LUA code} fails to
provide a sublevel title. Prior execution of the Lua code the global
attribute @ref{SublevelNumber} gets initialized. The Lua part has either way to
load the appropriate sublevel based on this number. Now it has additionally the
task to set the second special multilevel global attribute @ref{SublevelTitle}.


@ref{<compatibility>} externaldata



@c ===================  Paradigm  =======================
@node Enigma Paradigm
@chapter Enigma Paradigm

Now that you have learned about the formal declarative XML part of a level you
should be eager to understand the basic principles of the participants of an
Enigma level world. In this chapter we explain all the fundamental concepts and
the terms used in the following chapters that describe the level author's view
of a level.

Please note that we describe the features of the new API of Enigma 1.10. The
API of the earlier releases does not provide all the features and differs in
several aspects.

@menu
* The World's Structure::
* Object Description::
* Methods of Interaction::
* The Lifecycle of a Level::
@end menu

@c ----------------- The World's Structure --------------------
@node The World's Structure
@section The World's Structure

We speak of a level as the opus as a whole that describes the initial composition
of a gaming world and its dynamic behaviour during the game play. Let us look
at the participating objects in details.

@menu
* World's Shape and Coordinates::    Grid Positions and Tiles
* Object Layers::                    Floors, Items, Stones, Actors and Others
* World as an Object::               Global attributes and handle
* Unpositioned Objects::             Other objects like rubbers and gadgets
* Player and Inventory::             Yin and Yang
* Owned Objects::                    Objects temporary owned by others
@end menu

@c ----------------- World's Shape and Coordinates --------------------
@node World's Shape and Coordinates
@subsection World's Shape and Coordinates

Having played a few levels you will have noticed that every screen shows
quadratic tiles, 20 ones in the horizontal and 13 ones in the vertical direction.
Even if it is difficult for a player to map together all rooms and screens of a
large level, every level world has the shape of a rectangle in whole.
Nevertheless some parts may never be visible to the player due to walls of
stones or oceans of water.

@cindex onescreener
On the creation of a world the level author has to give its size in measure of
tiles. The given width and height of the world are fixed and cannot be changed
later on. A common size is 20x13 for a @dfn{Onescreener}. But there are no limits.
You can even build levels smaller than a screen. Note that for larger levels
you have to take into account that one tile row or column is usually shared
between two screens on scrolling. Thus a level of 2x2 screens has a size of
39x25 tiles, a 3x4 screen level has 58x49 tiles,...

@cindex position
Looking at the edges of all the tiles we get a grid that spans our world. We
define the upper left corner of our world as the @dfn{position} @{0,@ 0@}. The first
coordinate is the horizontal offset to the right, the second coordinate the
vertical offset to the bottom. For a Onescreener level the tile in the lower
right corner is located at position @{19,@ 12@}, whereas the corner itself is at
the position @{20,@ 13@} (Note that this point is actually not part of the level
anymore).

A position of an actor like the black marble needs to be given by two floating
numbers as coordinates like @{1.5,@ 2.5@} for an actor positioned in the center
of the tile that is one column right and two rows down of the upper left corner
tile.

@cindex grid position
But most objects like stones can only be placed on the fixed integral grid
positions. Even if you try to put a stone on @{1.5,@ 2.5@} it will be put on
the grid position @{1,@ 2@}. Thus we speak of a @dfn{grid position} if just the
integral part is taken into account. You may note that a tile is positioned
according to its upper left corner. Actually the upper and the left edge are
part of a tile, whereas the right and lower edge belong to the neighbour tiles.

@cindex tile
Finally let us look more precisely on the tile itself. On one grid position you
may place a floor, an item, a stone and even several actors. The combination
of all objects on one grid position is called a @dfn{tile}. It is a common
technique to declare these object combinations once in so called tile
definitions. As many grid positions share the same combination of objects these
tiles can be reused very efficiently.

@node Object Layers
@subsection Object Layers

@cindex layer
On every grid position you may set a floor, an item and a stone. But just one
of each. If you set a second stone the first one will be replaced. Floor, item
and stone have a unique physical arrangement with the floor always being below
an item and a stone always being on top of the others. Thus we speak of three
object @dfn{layers} - the floor layer, the item layer and the stone layer.

@cindex default floor
The floor layer has a unique prerequisite. Every grid position needs to be
covered by a floor. You can define a default tile which contains a
@dfn{default floor} that gets automatically set on every grid where you set
no other floor. Even if you @dfn{kill} a floor, that means removing a floor
without setting a replacement floor, a default floor will be set for you.

The floors provide two elementary features to the game: friction and adhesion.
The friction slows down actors and the adhesion enables you to accelerate
actors with your mouse. A floor may additionally cause a directed flat force
that gives the user the feeling of a slope. And last but not least a floor
may burn. A whole set of attributes let you control the details of the fire
behaviour.

The item layer is shared between items that an actor can pick up and items that
are static. The first category are items like keys, banana, etc. Static items
are bombs, landmines, triggers, hollows and items that will only be set by the
system itself like laserbeams, fire animations, ash, etc. As only one item can
be positioned on every grid position a marble can not drop an item on such a
static item. This is the technical reason that you can not intercept a laser
beam by dropping an item. But as a level author you are free to add any item
you like to the initial grid tile.

The stone layer is straight forward. The level author can choose a stone out
of the repository per grid. Of course most grid positions should be kept free
for the actors to move around. Even if most levels have a stone wall at the
border of the world that visually limits the area this is not mandatory. Without
a stone wall the marbles will be bounced at the physical boundary of the world.

The actors live in another layer that is not grid based. The actors can be
placed at any position. Actors that pass a stone will be displayed below the
stone.

@c ----------------- World as an Object --------------------
@node World as an Object
@subsection World as an Object

Friction, Brittleness, Modes and Co., Scrollmodes

@c ----------------- Unpositioned Objects --------------------
@node Unpositioned Objects
@subsection Unpositioned Objects

You should be missing at least one object, that can neither be assigned to a
single position nor to one of the above layers: rubberbands! In fact there are
many @ref{Other Objects} besides floors, items, stones and actors that are
unpositioned. Besides visible rubberbands and wires useful gadgets,
that help in plug and play composition of levels, can be added to the world.

All these other objects are full objects concerning the following chapters. But
you need to use the world's @ref{add} method to add them and you need to use
@ref{Object Reference} or @ref{Object Naming} to access them later on, as no
position driven access does exist.

@c ----------------- Player and Inventory --------------------
@node Player and Inventory
@subsection Player and Inventory

Enigma is conceptionally a game for 2 players. But nevertheless it can be played
by one user on a single computer by toggling the control between two virtual
players. We do call these virtual player's @code{YIN} and @code{YANG}, as the
first player controls in most cases a black marble, whereas the second
controls usually a white marble.

Each virtual player has its own inventory of up to 13 items. The leftmost
item of the inventory is called @samp{revealed}, as an item activation by a
mouse click does activate this item and on actor hits this item may cause
special actions.

The players inventories do exist outside of the rectangular world. Thus
any item being part of a player's inventory will report an invalid, out of world
position, that evaluates on an @samp{exists()} request to @samp{false}. You
can add items directly to inventories by the advanced world method @ref{add}.

Even though the actors are assigned to players they are quite independent
objects that live in one of the @ref{Object Layers}. Their relationship to
players is as follows:

Each virtual player can own and control one or several actors of any kind. That
means player @code{YIN} is not limited to a black @ref{ac_marble}, but may as
well control a white @ref{ac_pearl}, an @ref{ac_horse} or any other set of one
or several arbitrary actors.

Ownership and control of actors are two distinct aspects. Ownership of an actor
means that every item picked up by an actor ends up in the player's inventory and
items of the player's inventory can act on all owned actors. The control of an
actor by a player does just affect the movement of the actor by the users
force input. An actor may be controlled by a player without parallel ownership.
Another actor may be owned by a player without being controlled by it, thus
being a passive actor that depends on being pushed by others. An actor may even
be controlled by both players, but it can just be owned by one player or none.

The assignment of actors to players is solely configured by
@ref{Actor Attributes}.

When a single user plays Enigma he starts with the control over the player
@code{Yin}. By usage of yinyang objects he can toggle the control to the player
@code{Yang} and back again. Items @ref{it_yinyang} are added automatically for
network levels when played by a single user. They allow an arbitrary switch
between the players. The stones @ref{st_yinyang} do limit the user's ability to
switch between the player control.


@c ----------------- Owned Objects --------------------
@node Owned Objects
@subsection Owned Objects

Besides objects owned by a player and being part of his inventory, objects can
be temporary part of another object. The most obvious case is an item contained
in an @ref{it_bag}. Other samples are two @ref{st_shogun} stones pushed onto
the same grid position or for a short fraction of time a stone swapping the
position with an @ref{st_swap} or an @ref{st_pull}.

In any case the owned object will report the same position as the owner itself.
Even in case of some items contained in a bag that is itself part of another bag
all items will report the same position as the outmost bag. If this bag is part
of a player's inventory all items report an invalid position.

You can not directly enforce ownership by setting two objects to the same
position as this standard operation will kill and replace the old object by the
new one. Where possible, like in the case of a bag, you can add objects to
a container object by usage of the world advanced method @ref{add}.


@c ----------------- Object Description --------------------
@node Object Description
@section Object Description

Knowing where to place objects it is time to know how to select an object type,
how to specify the details of the object and how to reference it later on.

@menu
* Object Kind::
* Object Reference::
* Object Naming::
* Object Attributes::
@end menu

@node Object Kind
@subsection Object Kind

@cindex abstract kind
Up to now we have spoken about object kinds of floor @samp{fl}, item
@samp{it}, stone @samp{st} and actor @samp{ac}. All these kinds are called
@dfn{abstract}. You can check if a given object is of such a kind, but you can
not instantiate an abstract kind.

To create an object you need to give a specific kind name like
@samp{st_switch}. You will find all object kinds described in the chapters
starting with @ref{Floor Objects}. All these kind names with at least one
underscore can be instantiated.

Most kinds provide subkinds like @samp{st_switch_black} and
@samp{st_switch_white}. In case of the switches you get a color independent
switch if you do not append a suffix. In other cases like @samp{st_chess}
the super kind will result in a default @samp{st_chess_black} as no colorless
chess stone exists.

If you request an object for its kind it will always return the most specific
kind. This means that a fresh generated @samp{st_chess} returns the kind
@samp{st_chess_black}, whereas an @samp{st_switch} reports its name
unchanged.

Objects can change their kind by level code statements or by user actions. You
may set a color on a switch or a marble may cause a color change on a chess
stone by hitting it with a revealed wand. The object will report the new kind on
subsequent requests.

A few special object kinds do exist only for setting a new object. They are
usually named with a suffix @samp{_new}. These objects will never report their
initial kind name but change to a standard kind immediately.

If you are not interested in the specific subkind you can check an object for
conformity to any super kind. E.g. any switch stone of whatever color will
return true if checked for @samp{st_switch}.

@node Object Reference
@subsection Object Reference

Having set objects to the various layers a level author sometimes has the need
of referencing them later on. On callbacks the engine provides references to
sender objects. But the author can request any grid object anytime by its
position.

With an object reference, that is of a special Lua type @samp{object}, you can
request the objects on its current state and attributes, modify the
object, send messages or perform any supported methods of the object.

Objects can be grouped for efficient handling of common operations on
all affected objects. E.g. if you can send a message to a group of objects
all objects will receive the message in turn. The sequence of several objects
in a group is constant and guaranteed to be observed in processing common
operations.

As objects can seize to exist you have to be aware that the references are
volatile, too. You can check every object reference for existence. But in many
cases the validity of the reference is unimportant as Enigma 1.10 is very
tolerant on invalid object references access. The operations will simply be
ignored and requests will return default values.

As a general thumb rule you should request and keep object references just
for the time of a local call. As long as your level code is processed in
sequence without the running world simulation giving the player a chance to
kill objects by marble actions, objects should seize to exist just due to your
own direct statements.

To gain access to an object later on a subsequent call you can address it via
two methods. First you can address it via its position. But as many objects are
movable the position is not constant. Therefore you can address an object by
name. @xref{Object Naming}.

@node Object Naming
@subsection Object Naming

For addressing objects on a long term valid basis every object can individually
be tagged by a name. Assigning a name to an object is as simple as setting
the attribute @samp{name} with a unique string on this object. Of course you
can request an objects name by reading the attribute @samp{name}.

The name is a string that should be made up of characters @samp{a..z},
@samp{A..Z}, numbers @samp{0..9} and the underscore @samp{_}. Other special
characters are only allowed as far as they are explained in the following text.

@cindex auto naming
It is up to you to ensure unique names. Reuse of an already assigned name
will unname the prior object and assign the name to the new object. To simplify
the naming of larger groups of similar objects you can add the hash sign
@samp{#} as the last character to a name, e.g. @samp{mydoor#}. This causes Enigma
to add a unique random number to the given string. Thus an auto named object
will never unname another prior auto named object. But if you delete an
auto named object that has been named e.g. @samp{mydoor#103284} the number and
the same name may be assigned to another that is created later on.

All named objects are registered by the @dfn{named object} repository. The API
provides a variable @samp{no} that allows you to retrieve any named object, e.g.
@samp{no["mylaser_a"]}. You get an @ref{Object Reference} or @samp{nil}, if no
object is registered by the given name.

As you can auto name groups of objects you are allowed to use the wildcard
characters @samp{?} and @samp{*}. The question mark replaces a single
arbitrary character, the asterisk any number of arbitrary characters. E.g.
@samp{no["mydoor#*"]} retrieves all auto named @samp{mydoor} objects in a single
object group.

Many object attributes like @samp{target}, @samp{destination} need object
references to other objects. Besides a volatile @ref{Object Reference} you always
can provide a name string as a long term valid object reference. If the attribute
allows several objects to be given you can either give a group of object
references, a table of object names or an object name with wildcards. Thus
the string @samp{"mydoor#*"} is a valid target.

@cindex nearest object
Often switches are located near by their target object. As a major shortcut
you can reference the nearest object out of a group by prefixing its name
with an @samp{@@} character.

@example
ti["F"] = @{"st_floppy", target="@@door#*"@}
ti["D"] = @{"st_blocker", name="door#"@}
@end example

With this tile declaration you can describe arbitrary number of floppy switches
and nearby blocker doors in a world map all by the same two tile key characters.
Every floppy switch will target the nearest blocker door. If two targets are
given within the same distance the one located in the south will win. If the
targets are additionally horizontally aligned the one located in east will win.
In the rare case of objects located on the same position stones will precede
items, floors and actors. The chosen target or destination depends just on the
location of these objects and their type, but nothing else. Thus you can rely
on a stable selection mechanism. @ref{Nearest Object Clustering} may help you in
case of unexpected selected equidistant targets.

Auto naming and nearest object features help you to reduce the number
of needed tile declarations. Resolvers like @ref{res.autotile} and
@ref{res.composer} are another feature for reducing the need of tile declarations.

Another unique feature of object names is their late on access evaluation. This
allows you to reference an object prior to its existence. E.g. if you want to
set two vortices each declaring the other one as its destination, object names
are the favorite solution:

@example
wo[@{3,4@}]  = @{"it_vortex", name="vortex1", destination="vortex2"@}
wo[@{15,9@}] = @{"it_vortex", name="vortex2", destination="vortex1"@}
@end example

In general you will need to use object name references within any tile
declarations as none of the referenced objects will yet exist at the point of
tile declarations.

Objects do change over time. Doors do open, a chess may be recolored, a blocker
stone may shrink to a blocker item. This means that the kind of the objects
will change. But in many cases this means that the volatile object reference
will brake, too. For the sake of the level authors the identity of the object
will be transferred even if the reference gets invalid. And like the user
attributes the name is part of the object identity. Thus if you name an
@ref{st_blocker} and it shrinks to an @ref{it_blocker} you will retrieve this
item if you ask the name object repository for the named object.

When an object like a door is completely killed, e.g. by an @ref{it_seed},
it can no longer be targeted by active objects like switches. A still existing
reference to a no longer existing object does not cause problems on
@ref{Messages}. But what about the nearest object references? To avoid problems
due to killed objects the standard nearest object reference with just one
@samp{@@} as prefix is finalized on @ref{Level Initialization}. This means that
they get substituted by the unique name of the nearest of all existing objects
at a point of time when all objects have been created, but before the user takes
action and can incidentally kill a candidate.

But sometimes you may like a dynamic nearest object target or destination. One
that is evaluated when it gets accessed. By prefixing a name with @samp{@@@@}
the reference will not get finalized on initialization but remains dynamic.

@example
ti["c"] = @{"it_coin_s", "magic#"@}
ti["v"] = @{"it_vortex", destination="@@@@magic#*"@}
@end example

Setting three magic coins and one vortex in your map will teleport the marble
to the grid of that coin that is nearest to the vortex at the moment of
teleportation.

To avoid unexpected problems with invalid object references a few critical
objects are internally autonamed if the level author does not provide a name.
But these unique names should never interfere with the user assigned object
names.

@c ----------------- Object Attributes --------------------
@node Object Attributes
@subsection Object Attributes

One of the key concepts for the versatility of Enigma is possibility to fine
tune objects by means of attributes. The level author is not limited to a fixed
set of preconfigured objects as given by the object kind.

An attribute is a name, a string, with an assigned value. E.g.
@samp{obj["inverse"]=true} sets a single object attribute to a boolean value
and @samp{@{"it_magnet", range=6.5@}} describes a magnet item with an initial set
floating point attribute.

The scope of values is manifold. Most Lua types and a bunch of Enigma specific
types can be assigned:
@itemize @bullet
@item bool
@item int
@item double
@item string
@item nil, DEFAULT
@item position
@item object
@item group
@item tokens
@end itemize

If we speak of a bool value we do it in the sense of Lua 5, that means with the
possible values @samp{true} and @samp{false}.

Many enumerated values like orientations and colors are covered by the integer
numbers.

Of special interest is the value @samp{nil}. Just a few attributes make direct
use of the value @samp{nil}, e.g. "color" on some objects. If you set an
attribute to value @samp{nil} you do actually reset its value to the default
value. E.g. if you set the attribute "orientation" of @ref{st_boulder} to
@samp{nil} it will be set to its default, which is actually @samp{NORTH}, an
enumerated orientation value. A subsequent read of the attribute will return this
value. Just those attributes that allow a nil value will ever return @samp{nil}
on a read access. As a direct consequence these attributes always default to
@samp{nil}.

The authors of Lua did decide to prohibit the usage of @samp{nil} as a value
in Lua tables. As we make heavy usage of anonymous tables as object
declarations, you would not be able to set such attributes to @samp{nil}. You
would need to set such attributes explicitly. As a workaround we added a custom
value @samp{DEFAULT} that can be used anywhere to set attributes - even within
Lua tables.

@example
mySwitch["color"] = nil
mySwitch["color"] = DEFAULT
wo[@{3,6@}] = @{"ac_marble_black", player=DEFAULT@}
@end example

Note that @samp{DEFAULT} is not equal to @samp{nil}. They are different values
concerning Lua. They just result both in attributes reset to their default. If
you request a nil valued attribute you will always receive the Lua value
@samp{nil}. @samp{DEFAULT} will never be returned by the engine.

A group is an ordered set of @ref{Object Reference}s. As all contained objects
must exist this value is seldom used for attributes in object declarations.
But it is very useful for postprocessing of objects and for usage within
@ref{Callback Function}s.

The most complex attribute value type are the tokens. Their purpose is the
specification of one or many objects. As Enigma provides several means to do
that this value type combines and mix all possibilities. A token's value may
be a string, representing an object name, an object reference, a group or a
table with any of these basic types in any sequence and number. E.g. the
following right sides are all valid tokens for the attribute @samp{target}:

@example
obj1["target"] = "mydoor"
obj2["target"] = myobject
obj3["target"] = grp(ojb1, obj2, obj3)
obj4["target"] = @{"mydoor", myobject@}
obj5["target"] = @{grp(ojb1, obj2, obj3), "mydoor", myobject, "anotherdoor"@}
@end example

This versatility is useful to set tokens' attributes independent of the given
object reference types.

The chapter @ref{Common Attributes and Messages} and its followers describe
the existing object attributes in detail.

Besides these predefined attributes the level author can store own information
on objects for later retrieval. Any name starting with an underscore @samp{_}
can be used for level specific purposes. This prefix has been chosen as the
resulting names are still valid Lua names. Common usage patterns are switches
or triggers with callback functions. These functions provide the sender, the
switch or trigger, as an argument. If you attach the same function to number of
senders you can store the necessary context information within the sender.

The internal engine uses object attributes as well. Such inaccessible attributes
are named with a leading dollar sign @samp{$}. They may appear in the documentation
for C++ developers information. Level authors should ignore these attributes.

In some cases you may observe a different behaviour on setting an attribute
within the object definition and setting the same attribute while the object
is already on the grid. E.g. a door @samp{@{"st_door_h", state = OPEN@}} is
opened from the very beginning. Whereas @samp{mydoor["state"] = OPEN} on a
closed door will start opening the door. This takes a short time until the
door is really open. You find more details on these as aspects in the section
@ref{The Lifecycle of a Level}.

If you ever look into the C++ code you may wonder about the implementation of
attributes. They are not all directly stored in a map. Some of them are held
in object instance variables, other do not exist at all. Objects' attributes
are an abstract concept that unifies several internal features within a
common simple API for level description code. Within the C++ engine subtle
reasons like performance optimization forces a much more complex handling.

@c ----------------- Methods of Interaction --------------------

@node Methods of Interaction
@section Methods of Interaction

Having looked at the description of the initial object composition of a
level world we still need to understand how to configure the dynamic behaviour
of a level.

@menu
* Messages::             Asking objects to do something
* Target - Action::      Automatic reactions on an event
* Callback Function::    Lua hooks to react on events
* Object State::
@end menu

@c ----------------- Messages --------------------
@node Messages
@subsection Messages

You can generate an initially open door by setting its attributes. But how
can a switch stone open a door when it is hit by a marble? It simply sends
a message @samp{open} to the door. Another switch may send a message
@samp{on} to a laser or @samp{ignite} to an @ref{it_dynamite}. On explosion
the dynamite will in turn send automatically @samp{ignite} messages to the
neighbour grid positions.

Messages are a simple universal function or from the receiver object and the
Lua level authors point of view a "method". It takes two arguments - the message
name, a string, and an optional value. E.g.

@example
mydoor:message("open")
myboulder:message("orientate", NORTH)

mydoor:open()
myboulder:orientate(NORTH)
@end example

The last two examples are a common abbreviation of the first two ones.

Messages may return a value. But most messages just return @samp{nil}.

You can send any message to any object. Not supported messages are silently
ignored. This is the reason that an exploding dynamite can send @samp{ignite}
messages to its neighbours without knowing if the objects can be ignited at all.
Further on the dynamite has not to bother with the recipients of the messages.
Due to messages the sender and the receiver objects are totally decoupled
concerning the code base. Thus the level author just needs one method that
allows sending arbitrary messages to arbitrary objects.

You should not send a message during initialization of the level. You configure
the switch to send an @samp{open} message to the door by @ref{Target - Action}.
Within a Lua @ref{Callback Function} you may send messages during runtime to
any object.

All messages are listed and described in @ref{Common Messages} and the
subsequent chapters.

@c ----------------- Target - Action --------------------
@node Target - Action
@subsection Target - Action

@cindex target action paradigm
The "target action paradigm" is a classical object oriented method that allows
you to easily plug together objects. One object is triggered by a function
call or by an event like an actor hitting a stone, crossing over or applying an
item. You simply plug this object to another target object and tell it to send
an action message. Every time the first object is triggered it will send the
message to its target.

You configure such a target action by setting the attributes @samp{target}
and @samp{action} on the first object. E.g. a for a switch stone that should
open a door named @samp{mydoor} you can write:

@example
@{st_switch, target="mydoor", action="open"@}
@end example

Objects like the switch can be triggered on and off. Each time they will
perform the action. If you would like the door to open and close in turn to
the switch you need another action than @samp{open}. The universal message for
changing targets in their alternate states is @samp{toggle}.

@example
@{st_switch, target="mydoor", action="toggle"@}
@{st_switch, target="mydoor"@}
@end example

Now the door will toggle in sync with the switch between its open and closed
state. The message @ref{toggle} can be used quite independent of the target
object. In fact it is the default action message. As a default you may omit
the action in this case as it is demonstrated by the second example.

But keep in mind that toggling just changes the state of the target. If you
start with a switch in off state and an open door, the door will close when
the switch in turned on. They will not sync. If you configure two switches
both targeting the same door, you will have no clear relationship between the
switch states and the door.

As you remember messages can take a value. Action messages are no exception.
Every object sends its actions with a value, usually a bool value. A switch
sends a value @samp{true} if it just switched on, and a value @samp{false} if
it just switched off. The appropriate message for the door would be the
universal message @samp{signal}:

@example
@{st_switch, target="mydoor", action="signal"@}
@end example

Now the door will open when the switch is turned on and close if the switch is
turned off.

The message @ref{signal} takes an integer value of @samp{0} or @samp{1}.
Indeed the action value does not match. But in this as in many other cases
the messages and values are designed in a way that they are automatically converted to
the appropriated type. This compatibility is the basis for a seamless plugging
of objects.

In many cases authors face the task of triggering two or more objects by a
single object. @samp{target} and @samp{action} are both able to take
multiple values.  @samp{target} is of type tokens, as described in
@ref{Object Attributes}, whereas @samp{action} can be a string or a table
of strings.

@example
@{st_switch, target=@{grp(ojb1, obj2, obj3), "mydoor", myobject, "anotherdoor"@},
            action=@{"toggle",              "open",   "turn",   "close"@}@}
@end example

All objects described by a token receive the related message in the action
table. If not enough messages are listed the default action @samp{toggle}
will be sent.

Usually actions are performed at once. That is very important as the sequence
of actions if often essential. Consider an @ref{st_box} being pushed from one
@ref{it_trigger} to a neighboring one, or just an @ref{ac_marble} moving from
the first trigger to the neighboring one. In both cases it is important that
the first trigger is released prior the second one to be pressed. If this
sequence gets mixed up both triggers could be pressed by a single object for
a moment what could cause major shortcuts in a level. Thus all actions are
performed in the logical sequence and in a stable, repeatable sequence without
any random.

Action may be simple or sometimes be very complex world rearrangements. But in
any case you should @b{never ever} @samp{kill} the sender object. Killing the
sender can cause application crashes! Be aware that even chained actions are not
allowed to kill any prior sender object. Thus an @ref{it_trigger} that toggles
an @ref{st_switch} which in turn kills the first trigger is as critical as the
trigger killing itself. We do generally discourage you to kill any object
within its own action, as there is no dissolving animation and the WYSIWYG
user paradigm is violated, too. But if there is urgent need for reasons of the
level gaming logic you can perform the action in a secure, delayed mode. Just
add the attribute @ref{safeaction} with value @samp{true} to the self killing
sender object. The action will no longer be performed at once, but with a
minimum delay in a manner that will never cause crashes. But be aware that
even a minimum delay, which is still within the same timeslice, may disturb
the sequence of actions. This can cause unexpected logical results on the other
hand.

@c ----------------- Callback Function --------------------
@node Callback Function
@subsection Callback Function

@findex Callback Function
@cindex callback function
The most powerful extension to the @ref{Target - Action} paradigm that you can
think of are callback functions. Instead of a target object as receiver of an
action message you can supply an own @url{http://www.lua.org, Lua} function that
is called whenever the action is triggered.

@example
@{"st_switch", target="my_magic", action="callback"@}
@{"st_switch", target="my_magic"@}
@end example

The @samp{target} is the name of the function as a string. You may set the
@samp{action} to the string @samp{"callback"} for purpose of clarification,
but it is not necessary as you see in the second example. The engine identifies
the target to be of type of a Lua function and thus the action needs to be
a callback. But you should note and remember that it is up to you to ensure that
all object names and callback functions names are unique.

Let us look at the syntax of such a callback function

@example
function my_magic(value, sender)
    if value == true then
        wo[sender + @{1,0@}] = @{"it_coin_s"@}
    end
end
@end example

The function is called with two arguments. The first one is a value. The type
and contents depends on the issuing object, but in most cases it is a boolean
value. You will find the value described in the objects description. The second
argument is the reference of the calling object.

In the example we check if the @ref{st_switch} did just toggle to ON. If this
is given we take the switch, which is the sender, as a position and set a new
@ref{it_coin} to the grid east of it - a small bank automate that supplies money.

The @ref{Advanced Lua Examples} will show examples of real powerful callback
functions with a line by line comment.

Further usage and aspects of callbacks in the level's lifecycle are given in
the section @ref{Callbacks and Load Balancing}.

@c ----------------- Object State --------------------
@node Object State
@subsection Object State

A key concept for the ability to plug together objects like switches and doors
are the very simple state machines of these objects. Most objects are described
by simple machines with just 2 states like @samp{ON},@samp{OFF} or @samp{OPEN},
@samp{CLOSED}. These objects can be plugged together by just few common messages.
Further on these simple state machines are suited to the gamers who do not want
to read manuals but want to explore the objects by playing with just a few tests.

Even though states are usually named by appropriate uppercase names like above,
the states are integer numbers starting with @samp{0} usually related to the
default state. But some objects use another mapping due to historic reasons.
E.g. states that are orientation related use the state @samp{3} representing
@samp{NORTH} usually as the default and number the orientations clockwise down to
@samp{0} representing @samp{WEST}.

In most cases it is sufficient to perform a state independent common action
like @ref{toggle}. Even two stated objects can be easily synchronized by the
standard action @ref{signal}. But sometimes you may want to perform very state
specific actions. Let us look how this can be done.

E.g. let us take an @ref{st_fourswitch}, that has four states, and two
@ref{st_laser} which should be switched on and off. Both lasers should emit
their beams while the fourswitch is in 3 of its states. But one of them should
be off just while the fourswitch is in the @samp{EAST} state and the other
should be off just while the fourswitch is in the @samp{WEST} state.
This can be done by usage of state dependent target and actions:

@example
@{st_fourswitch, target_3="laser#2", action_3="on",
                target_2="laser#1", action_2="off",
                target_1="laser#1", action_1="on",
                target_0="laser#2", action_0="off"@}
@end example

Adding a number as suffix to @samp{target_} and @samp{action_} gives you
special target and action attributes that will take precedence over the general
@samp{target} and @samp{action} attributes if the state value equals the suffix
number. An alternative declaration would be:

@example
@{st_fourswitch, target=@{"laser#1", "laser#2"@},
              action_3=@{"nop",     "on"@},
              action_2=@{"off",     "nop"@},
              action_1=@{"on",      "nop"@},
              action_0=@{"nop",     "off"@}@}
@end example

Here we do address both lasers in all states. But one of them receives a
@ref{nop} message that stands for "no operation". In fact this message will
never be send. It is just a dummy message that we have need of for syntax
reasons in the case above.

Another example are two @ref{it_trigger} that switch a laser. An object pressing
the first trigger should switch the laser on, an object pressing the second
trigger should switch it off. But a trigger is two stated and performs one
action on being pressed and another on being released. Thus we want to block
the actions on trigger release events:

@example
@{it_trigger, name="on_trigger",  target="laser#1", action_1="on", action_0="nop"@}
@{it_trigger, name="off_trigger", target="laser#1", action_1="off", action_0="nop"@}
@end example

The blocking of @samp{action_0} is essential and can not be omitted, as
otherwise the default action would be performed. This would be a @samp{toggle}
message that would switch the laser.

As this useful default mechanism can sometimes be annoying you can switch off
the default message by setting the @ref{nopaction} attribute to true.

@example
@{it_trigger, name="on_trigger",  target="laser#1", action_1="on", nopaction=true@}
@{it_trigger, name="off_trigger", target="laser#1", action_1="off", nopaction=true@}
@end example

When an objects leaves a trigger the state @samp{0} action will be performed.
As neither @samp{action_0} nor @samp{action} is specified the default action
will be performed, which is now @samp{nop}.

If you ever look into the C++ code you may note that many objects do have much
more complex state machines than you expect from the level authors and gamers
view. This is due to running animations, timers, etc.. The C++ objects map their
complex internal state set to the much simpler external state set. This is the
main reason that some features that level authors request can not be provided
in the Lua API.

@c ----------------- The Lifecycle of a Level --------------------

@node The Lifecycle of a Level
@section The Lifecycle of a Level


Snapshot
Levelloading, Initialization, Runtime Callbacks,
Ending Conditions - the mystery of Oxyds and Meditation
@menu
* Library Preloading::
* Snapshot Principle::
* Level Initialization::
* Object Transformation::         Identity Transfer in case of Transformations
* Named Positions::               Positions as successors of killed Floors
* Callbacks and Load Balancing::
* Level Restart::
* Ending Conditions::             Meditation vs. Oxydpairs
@end menu

@c ----------------- Library Preloading --------------------
@node Library Preloading
@subsection Library Preloading

@c ----------------- Snapshot Principle --------------------
@node Snapshot Principle
@subsection Snapshot Principle

Most levels contain objects that take influence on each other. A switch might
toggle a door by @ref{Target - Action}, marbles may press a trigger, or a laser
might activate a laserswitch or transform a hammer into a sword. Of course it is
essential to know how to set up such objects to get the desired start
configuration without the objects changing unexpected on level initialization.

The snapshot principle is a simple thumb rule that you can rely on in describing
the level as a snapshot of object at a given point of time. Every object has just
to be configured as it should be at the given time. All interactions that would
take place in a running game do not take place while setting objects during
initialization.

E.g. if a switch toggles a door and the switch should be initially on and the
door should be initially open you describe the object with exactly these
attributes:

@example
@{"st_switch", target="mydoor", state=ON@}
@{"st_door", name="mydoor", state=OPEN@}
@end example

A laser that is initially on that illuminates a laserswitch needs an initially
active laserswitch. But of course no attribute exists that would allow you to
set a laserswitch active. The snapshot principle includes the rule that all
internal states are updated without external actions. This means that the
laserswitch will show up active without causing an action on its target.

@example
@{"st_laser", state=ON@}
@{"st_laserswitch", target="mydoor"@}
@end example

What about objects that transform on laser light. The snapshot principle keeps
the object from transforming during initialization. A hammer that is set in
an initially existing laser beam will not transform to a sword. It remains as
a hammer that will transform on any subsequent new laser light during the game.

Of course it cannot be allowed to describe impossible initial level states.
Objects like dynamite do explode immediately on a laser beam hit. Thus a
dynamite item in an initial laser beam is a fault that causes an exception.
The snapshot principle forces you in this case to set an explosion item instead
of the dynamite.

Some objects do process internal state transformations that cannot be configured
by attributes. But some of these states may be of interest on describing a
snapshot of a level. Where possible a special object subkind exists with a suffix
of @samp{_new}. These objects can be used in the initial level description to
set objects in special initial states. E.g. @ref{it_blocker} provides such a
special subkind. Note that these objects will never report their initial
subkind on a kind request as they come into existence as a standard object.


@c ----------------- Level Initialization --------------------
@node Level Initialization
@subsection Level Initialization

Knowing what has been preloaded and knowing exactly which objects we have to
set in which state, it is time to have a look on how your level code is
processed. The main issue is to guarantee that all parts referenced have been
set up properly in advance.

Prior execution of the first line of your code the world exists just as an
abstract handle, but not as grid array able to accept objects. Thus the first
lines of code should set up all @ref{Global Attributes} deviating from their
defaults. Even though many attributes can be set or changes later on and even
on runtime, there are some attributes like @ref{ProvideExtralifes} that take
only effect if being set prior world creation, or others like @ref{MaxOxydColor}
that must be set prior their first usage. Our recommendation is to collect all
global attribute settings at the very beginning of the level.

The second section of your level code should be the declaration of tiles. Being
just declarations these code lines do not set objects to the world. They just
depend on global attributes and may reference each other. Listing them all
together in a code section makes it easy to maintain the overview and to avoid
dependency conflicts.

If you use @ref{Resolvers} you should put their declarations in the next code
section as they may refer to tiles and global attributes and need to be set up
prior the world creation.

The central statement of every level is the @ref{World Creation}. It sets up
the world to its size and sets initial objects according to the given tile
declarations to the grid array. While you are free to add and change any of
these objects later on the size of the world is fixed and can not be changed.

Thus subsequent code lines should @ref{add} other objects, draw additional
maps of objects and finalize some objects. The most common statement for such
a finalization is the @ref{shuffleOxyd} method. It needs to know all
@ref{st_oxyd} to be able to color and shuffle them. Another finalization may
be a custom rendering of a maze, that extracts the maze shape out of the
level map (@pxref{res.maze}).

This post world creation code may well have the need of loops or even some
local used functions that need to be integrated to precede. Please keep such
functions near by their usage and within the same code section.

Another set of functions that you may want to add are @ref{Callbacks and Load
Balancing}. We recommend to append these functions as the last section as they
are not called within the level initialization itself.

But there is one very special exception. The @code{postinit()} callback is
called after the level initialization code has been processed and all subsequent
engine internal initialization has been finished. If this function is present
in a level it gets executed directly before the first mouse movement event gets
processed. Thus you can rely within this function that all objects are set up
in their final state. If you have need of such a postinit callback you should
put it after all the level intialization code and in front of other callback
functions that will be executed on subsequent events.

@node Object Transformation
@subsection Object Transformation

During runtime some Enigma objects do transform into other successor objects,
like an @ref{st_blocker}/@ref{it_blocker}, an @ref{st_brake}/@ref{it_brake},
an @ref{it_rubberband}/@ref{ot_rubberband}, an @ref{it_hammer}/@ref{it_sword},...

Even though the successor object may have other attributes, some attributes and
especially any user attributes should be maintained. In fact the objects name,
its target and action attributes and all attributes starting with an underscore
@samp{_}, the user attributes, are transferred to the successor object. Thus you
can rely on the successor to message the same target and you can access it
via its old name.

@node Named Positions
@subsection Named Positions

Many stones are movable and if the user can not push them, most may still be
swapped. Items may be picked up by actors or be killed in a burning fire. Thus
in most cases it is preferable to mark anchors or shapes in the floor. On every
grid position a floor object is guaranteed and they are much more stable than
other objects. But nevertheless a user may push an @ref{st_box}, an
@ref{st_puzzle} or other floor building stone on an @ref{fl_water} or
@ref{fl_abyss}. Furthermore a user may drop and ignite an @ref{it_bomb} that
destructs the floor leaving a new @ref{fl_abyss}. In all these cases you may
lose a named anchor or an essential part of a named grid area accessible as
an object group.

Thus for every named floor that gets killed its position is stored in a
repository under its name. You just need to retrieve the named positions
instead of the named objects if you want to get all affected floor positions.

@example
ti["~"] = @{"fl_water", "water#"@}
...
function sweet()
    wo[po["water#*"]] = @{"it_cherry"@}
end
@end example

Note that a request for a named position will include all positions of matching
named objects as well as those named positions derived from killed floors.

@c ----------------- Callbacks and Load Balancing --------------------
@node Callbacks and Load Balancing
@subsection Callbacks and Load Balancing

The most flexible feature for a level author to establish an unique behaviour
of his level are @ref{Callback Function}s.

@ref{Target - Action} kill warning
@ref{ot_timer}

global and res.*.function

@c ----------------- Level Restart --------------------
@node Level Restart
@subsection Level Restart

@c ----------------- Ending Conditions --------------------
@node Ending Conditions
@subsection Ending Conditions

Two essential questions remain to be answered. When and under which conditions
is a level successfully finished. How do I declare a level as being a
meditation level in opposite to a standard oxyd pair opening level.

In fact there is no 'meditation' flag, neither within the XML Level
@ref{Info metadata} nor as one of the @ref{Global Attributes}. That means there
is no formal distinction between both level 'types'. But there are two different
types of ending conditions. Both are checked permanently and whichever
is fulfilled first wins. Thus Enigma allows you to write true hybrid levels
that provide @ref{st_oxyd} as well as @ref{it_meditation} allowing the user
to solve the level by two totally different means.

The main way to end the game is to fulfill the oxyd pair opening condition:

The game is over when the user succeeds in opening all regular colored
@ref{st_oxyd}s by pairs.

This implies that there is at least one pair of regular colored oxyd stones
and that all oxyd colors appear in even number of instances. Whereas you will
always add at least one pair of oxyds for a standard level, you may simply loose
track of the number of instances. Therefore the engine will permanently check at
runtime that every oxyd color appears in an even number of instances. Any
violation causes an error. In case you will add or delete oxyd stones you
need to disable this checking by setting the global attribute
@ref{AllowSingleOxyds} to @code{true}. Now it is your reponsibility as an
author to ensure that the level remains solvable by adding or removing pairs
only.

The second way to end the game is to fulfill the meditation condition:

All @ref{ac_pearl}s must reside for at least one second within the uneven area
of an @ref{it_meditation}, all @ref{it_meditation} marked as @code{essential}
must be occupied and the number of @ref{ac_pearl}s must be equal to the number
of occupied @ref{it_meditation}s.

This implies again that there exists at least one @ref{ac_pearl} and that
no two pearls can reside within the same @ref{it_meditation}. There must be at
least the same number of @ref{it_meditation} as of @ref{ac_pearl}, but there may
be more @ref{it_meditation}s as long as they are not marked as being essential.
A surplus of @ref{it_meditation} can easily occur due to explosions of
@ref{it_dynamite}.

A level that should be solved by fulfillment of the meditation condition can
contain @ref{st_oxyd} and by setting @ref{AllowSingleOxyds} to @code{true} you
can add odd numbers of oxyd stones of a color. On the other hand you can add
@ref{ac_pearl} to a level that should be solved by fulfillment of the oxyd pair
condition. But you must carefully check that the user can not rest the pearls in
given @ref{it_meditation} or can create @ref{it_meditation} by @ref{it_dynamite}.
Marking more @ref{it_meditation} as @code{essential} than existing
@ref{ac_pearl}s can avoid shortcuts.

A level that is set up to allow the user to fulfill both conditions is called
a hybrid level. Of course it is a difficult task to provide equivalent solutions
for both approaches.

Independent of the condition type all actors marked as @code{essential} need to
be alive at the moment the condition is fulfilled. Mainly in existing legacy
levels but also in some very carefully designed future levels the author may
allow the user to sacrifice an actor to fulfill the condition by setting the
global attribute @ref{SurviveFinish} to @code{false}. In this case a marble
may shatter while the condition is fulfilled. Of course the essential actor
may not shatter in advance, because as soon as the shattering is over the
essential actor will cause a level restart, if it can not be resurrected.

@c ===================  Lua API  =======================
@node Lua API
@chapter Lua API

Knowing the basic principles of an Enigma level's world you now just need
the language glue to write your first level. Enigma levels are written in
the language @url{http://www.lua.org, Lua} as of version 5.1.4. This powerful
language gives you the ability to write most complex, dynamical levels, while
being nearly transparent on writing basic standard levels. Indeed there is no
reason to dig into this language at the very beginning.

With the second Lua API version, as of Enigma 1.10, we designed an optimized
way of describing levels in a very short and readable manner. Thus we would like
to introduce you to this API by giving several examples from a basic level to most
thrilling dynamic real Enigma levels. You should be able to start your first
experiments just after reading the first example with its explanations.

For your convenience we do color the Lua code part. Predefined Lua variables and
functions are colored in green. Enigma internal string constants as object kinds,
attribute or message names are colored in blue. Level specific variable names
and value constants are colored in magenta.

After the examples and a short overview the details of the language specific API
part are given, as you can expect it for a reference manual. Please note
that additional @ref{Advanced Features} are described in a separate chapter.

@menu
* Basic Lua Examples::
* API 2 Overview::
* Advanced Lua Examples::
* Introduction to Datatypes::
* Position::
* Object::
* Group::
* NamedObjects::
* PositionList::
* Positions Repository::
* Tile and Object Declaration::
* Tiles Repository::
* World::
* Functions::

@end menu

@c ----------------- Lua Examples --------------------

@node Basic Lua Examples
@section Basic Lua Examples

Let us look at two basic onescreener levels, that make use of all basic
techniques. While the first level is a little bit artificial, as it is designed
for demo purposes only, the second one is a quite dynamic real level out of
the Enigma levelpacks.

@menu
* Basic Example::
* Colored Turnstiles::         Enigma Levelpack VII, level #39
@end menu

@c ----------------- Basic Example --------------------
@node Basic Example
@subsection Basic Example

Let us view the source code. We did add a line count in the first two columns
for reference purpose within this section. These line count numbers are not part
of the source code itself!

@example
 1    <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
 2    <el:level xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://enigma-game.org/schema/level/1 level.xsd" xmlns:el="http://enigma-game.org/schema/level/1">
 3     <el:protected>
 4       <el:info el:type="level">
 5         <el:identity el:title="Basic Level" el:subtitle="" el:id="20080721ral513"/>
 6         <el:version el:score="1" el:release="1" el:revision="$Revision: 1170 $" el:status="experimental"/>
 7         <el:author el:name="Ronald Lamprecht" el:email="ral@@users.berlios.de"/>
 8         <el:copyright>Copyright @copyright{} 2008 Ronald Lamprecht</el:copyright>
 9         <el:license el:type="GPL v2.0 or above" el:open="true"/>
10         <el:compatibility el:enigma="@var{1.10}"/>
11         <el:modes el:easy="true" el:single="true" el:network="false"/>
12         <el:score el:easy="-" el:difficult="-"/>
13       </el:info>
14       <el:luamain><![CDATA[
15
16    @i{wo}["@b{ConserveLevel}"] = @var{true}
17
18    @i{ti}["@var{ }"] = @{"@b{fl_samba}"@}
19    @i{ti}["@var{.}"] = @{"@b{fl_abyss}"@}
20    @i{ti}["@var{~}"] = @{"@b{fl_water}"@}
21    @i{ti}["@var{#}"] = @{"@b{st_granite}"@}
22    @i{ti}["@var{X}"] = @{"@b{st_oxyd}"@}
23
24    @i{ti}["@var{L}"] = @{"@b{st_laser}", @b{orientation}=@var{EAST}, @b{state}=@var{ON}@}
25    @i{ti}["@var{M}"] = @{"@b{st_lightpassenger}", @b{interval}=@var{0.04}@}
26
27    @i{ti}["@var{P}"] = @{"@b{st_polarswitch}", @b{name}="@var{polar}"@}
28    @i{ti}["@var{T}"] = @{"@b{it_trigger}", @b{target}="@var{polar}"@}
29
30    @i{ti}["@var{^}"] = @{"@b{st_boulder}", "@var{boulder}", @b{orientation}=@var{NORTH}@}
31    @i{ti}["@var{F}"] = @{"@b{st_fourswitch}", @b{target}="@var{boulder}", @b{action}="@var{orientate}"@}
32
33    @i{ti}["@var{D}"] = @{"@b{st_door_d}", "@var{door}", @b{faces}="@var{ew}"@}
34    @i{ti}["@var{B}"] = @{"@b{it_blocker}", "@var{wall#}"@}
35    @i{ti}["@var{S}"] = @{"@b{st_switch}", @b{target}=@{"@var{door}", "@var{wall#*}"@}@}
36
37    @i{ti}["@var{v}"] = @{"@b{it_vortex}", "@var{left}", @b{destination}="@var{right}"@}
38    @i{ti}["@var{V}"] = @{"@b{it_vortex}", "@var{right}", @b{destination}="@var{left}"@}
39
40    @i{ti}["@var{O}"] = @{"@b{st_turnstile}", @b{flavor}="@var{red}"@}
41    @i{ti}["@var{E}"] = @{"@b{st_turnstilearm}", @b{orientation}=@var{EAST}@}
42    @i{ti}["@var{N}"] = @i{ti}["@var{.}"] .. @{"@b{st_turnstilearm_n}"@}
43
44    @i{ti}["@var{+}"] = @{"@b{fl_samba}", @b{checkerboard}=@var{0}@} .. ti(@{"@b{fl_wood}", @b{checkerboard}=@var{1}@})
45
46    @i{ti}["@var{1}"] = @{"#@b{ac_marble}"@}
47
48    if @i{wo}["@b{IsDifficult}"] then
49        @i{ti}["@var{=}"] = @i{ti}["@var{~}"]
50    else
51        @i{ti}["@var{=}"] = @i{ti}["@var{~}"] .. @{"@b{it_strip_ew}"@}
52    end
53
54    w, h = @i{wo}(@i{ti}, "@var{ }", @{
55        "@var{####################}",
56        "@var{#      ....++++++~ #}",
57        "@var{L   PM ..N.++~~~~OE#}",
58        "@var{#######  T~++++++. #}",
59        "@var{#     ^   ~++++++# #}",
60        "@var{#         =++++++X X}",
61        "@var{#         ~++++++# #}",
62        "@var{#~~~~~~~~~~~~~+++X X}",
63        "@var{#    ~   B   ~+++###}",
64        "@var{F    ~   B   ~+++++#}",
65        "@var{# 1  ~   B   #+++++#}",
66        "@var{S   v~V  B   D+++++#}",
67        "@var{####################}"
68    @})
69
70    @i{wo}:@b{shuffleOxyd}()
71
72     ]]></el:luamain>
73        <el:i18n>
74          <el:string el:key="title">
75            <el:english el:translate="false"/>
76          </el:string>
77        </el:i18n>
78      </el:protected>
79    </el:level>
@end example

The resulting level looks like this in the game

@image{images/ralD006_1, 150mm}

Let us now analyse the code line by line.

Lines 1 to 14 are the XML metadata of the level as described in
@ref{Level Basics}. The only line worth mentioning is
@example
10         <el:compatibility el:enigma="@var{1.10}"/>
@end example

You need to declare the level to be compatible to Enigma 1.10 or higher for
the new API 2 as described in this reference manual. A value less than 1.10
indicates compatibility to a previous Enigma release that did use the old API 1,
which should not be mixed up with the new API 2.

The Lua part starts with line 15:
@example
16    @i{wo}["@b{ConserveLevel}"] = @var{true}
@end example

Like most levels it starts with setting @ref{Global Attributes}. The handle of
our world is @samp{wo}. This object reference is preset
(@pxref{World as an Object}). Concerning Lua it is an @samp{userdata},
but most of its usage syntax is identical to that of Lua tables. Thus we access
an attribute by providing the desired attribute name in square brackets. As we
give a literal attribute name, we have to put it in double quotes @samp{"}. In
total this line requests the world to resurrect a killed actor as long as there
are enough extra lifes to conserve the running level (@pxref{ConserveLevel}).
In fact @samp{true} is the default value. So we could have left this line out.
But remember it is a demo level.

The second part of a level are the tile definitions as explained in
@ref{World's Shape and Coordinates}. Let us start with the most simple ones:
@example
18    @i{ti}["@var{ }"] = @{"@b{fl_samba}"@}
19    @i{ti}["@var{.}"] = @{"@b{fl_abyss}"@}
20    @i{ti}["@var{~}"] = @{"@b{fl_water}"@}
21    @i{ti}["@var{#}"] = @{"@b{st_granite}"@}
22    @i{ti}["@var{X}"] = @{"@b{st_oxyd}"@}
@end example

Again we use a handle @samp{ti} which is a preset object reference for the
tile definition repository. Like the world it is a Lua @samp{userdata}. And
we can access it like the world by giving the desired index in square brackets.
These indices are free to your choice. They have to be of a common character length
if they are referenced in the world map below. For a small level one character
keys are sufficient. You can use any ASCII character that Lua is aware of. That
means upper and lower case characters @samp{A-Z,a-z}, the numbers and special
characters besides backslash @samp{\} and double quote @samp{"}.

The assigned object definition are given as Lua anonymous tables, the curly braces,
containing in the most simple case just the desired @ref{Object Kind}. As it
is again a literal string, it has to be quoted. Without any further specification
the objects are taken in their default configuration as described in
@ref{Floor Objects} and following chapters.

@example
24    @i{ti}["@var{L}"] = @{"@b{st_laser}", @b{orientation}=@var{EAST}, @b{state}=@var{ON}@}
25    @i{ti}["@var{M}"] = @{"@b{st_lightpassenger}", @b{interval}=@var{0.04}@}
@end example

These two lines define objects with custom configuration. The @ref{st_laser}
should send its beam to the east and should start being switched on. The
@ref{st_lightpassenger} should move a little bit faster than usually. Both
times we just have to add comma separated additional attributes. The attribute
names are not quoted as they are followed by an equal @samp{=} sign.

@example
27    @i{ti}["@var{P}"] = @{"@b{st_polarswitch}", @b{name}="@var{polar}"@}
28    @i{ti}["@var{T}"] = @{"@b{it_trigger}", @b{target}="@var{polar}"@}
@end example

An @ref{st_polarswitch} named for reference usage (@pxref{Object Naming}).
The @ref{it_trigger} sets up a @ref{Target - Action}, the target being our
polarswitch. The action attribute is omitted. It defaults to the message
@samp{toggle}. Thus any actor or stone on top of the trigger makes the
polarswitch transparent, but switches it back to opacity when leaving
the trigger.

@example
30    @i{ti}["@var{^}"] = @{"@b{st_boulder}", "@var{boulder}", @b{orientation}=@var{NORTH}@}
31    @i{ti}["@var{F}"] = @{"@b{st_fourswitch}", @b{target}="@var{boulder}", @b{action}="@var{orientate}"@}
@end example

Another pair of objects that are coupled by @ref{Target - Action}. The
@ref{st_boulder} starts trying to move to north. This time we name the object
just by giving the name as the second comma separated string. We omitted the
attribute identifier @samp{name =}. This is a shortcut for this most common
attribute which requires the name to be given as the second value directly
after the object's kind.

The @ref{st_fourswitch} references the boulder as its target. We need to give
the action as well, as we want to make use of a special action that directly
steers the boulder according to the fourswitch orientation.

@example
33    @i{ti}["@var{D}"] = @{"@b{st_door_d}", "@var{door}", @b{faces}="@var{ew}"@}
34    @i{ti}["@var{B}"] = @{"@b{it_blocker}", "@var{wall#}"@}
35    @i{ti}["@var{S}"] = @{"@b{st_switch}", @b{target}=@{"@var{door}", "@var{wall#*}"@}@}
@end example

And another even more complex @ref{Target - Action}. We want a single
@ref{st_switch} to toggle a @ref{st_door} as well as set of @ref{it_blocker}s
at the same time. The gaming idea is that neither with switch on nor with switch
off the marble can pass both obstacles. The gamer needs to steer the boulder
through the blocker wall to pass these obstacles.

The setup of the door is simple. We just need to name it to be able to reference
it later on. We want to use several blocker objects and we need to name each
for reference purposes. We do this by appending a hash sign @samp{#} to its
name as described in @ref{Object Naming}. Every blocker gets a unique name.
The switch needs to list all these objects as its targets. This is done by
an embedded anonymous table given by the curly braces and comma separated
values. The first one is our door's name, the second one is a wildcarded string
that describes all our blocker objects. The asterisk stands for any suffix
that may have been added behind the hash in the process of autonaming of our
blockers.

@example
37    @i{ti}["@var{v}"] = @{"@b{it_vortex}", "@var{left}", @b{destination}="@var{right}"@}
38    @i{ti}["@var{V}"] = @{"@b{it_vortex}", "@var{right}", @b{destination}="@var{left}"@}
@end example

We want to use two @ref{it_vortex} that are connected to each other allowing
the marble to warp into both directions. We set up both vortices with a unique
name and add the attribute @samp{destination} referencing the other vortex' name.

Note that it is no problem to reference the right vortex in line 37 while it
is named later on in line 38. We are still just defining tiles and not creating
any objects at all.

@example
40    @i{ti}["@var{O}"] = @{"@b{st_turnstile}", @b{flavor}="@var{red}"@}
41    @i{ti}["@var{E}"] = @{"@b{st_turnstilearm}", @b{orientation}=@var{EAST}@}
42    @i{ti}["@var{N}"] = @i{ti}["@var{.}"] .. @{"@b{st_turnstilearm_n}"@}
@end example

Another object group is an @ref{st_turnstile} cluster with one arm disconnected.
The first two definitions are straight forward. But in line 42 we precede the
arm's definition by another tile reference. It is the abyss tile defined in
line 19. By concatenation, the two dots @b{..}, of a tile and an object
definition we can define a new tile that is composed of both objects. In this
case we define a turnstile arm on top of an abyss floor.

You may be wondering why we did not define floors for the other stone and item
tiles. We make use of the tile definition in line 18 that we will declare
later as the default floor for our level. Thus any tile declaration that does
not provide its own floor will set this default floor.

@example
44    @i{ti}["@var{+}"] = @{"@b{fl_samba}", @b{checkerboard}=@var{0}@} .. ti(@{"@b{fl_wood}", @b{checkerboard}=@var{1}@})
@end example

Just for fun we want to provide a checkerboard floor on the right side of our
level. This can be done by usage of the @ref{checkerboard} attribute. Again
we concatenate two object definitions for a single tile. Both are floors. That
means for each grid position we try to set both floor types, but just one meets
the checkerboard condition and will be set.

Please notice that we did convert one of the floor object definitions to a tile
definition by the function call @samp{ti()}. This is necessary as Lua does not
know how to concatenate two anonymous tables. One argument of the concatenation
has to be a tile.

@example
46    @i{ti}["@var{1}"] = @{"#@b{ac_marble}"@}
@end example

Finally we do need our marble. Unlike other objects it can be positioned
anywhere within a grid. The most common position is the center of the grid.
This is simply done by preceding the actor's kind by a hash sign @samp{#}.

@example
48    if @i{wo}["@b{IsDifficult}"] then
49        @i{ti}["@var{=}"] = @i{ti}["@var{~}"]
50    else
51        @i{ti}["@var{=}"] = @i{ti}["@var{~}"] .. @{"@b{it_strip_ew}"@}
52    end
@end example

We encourage every level author to provide an easy mode for the levels. This
is an example how to define mode dependent tiles. Like in line 16 we access
a world attribute. But this time it is a read access of @ref{IsDifficult}.
In easy mode we want an @ref{it_strip} on top of the water floor that allows the
marble to pass and press the trigger. In difficult mode there should be
no passage. Thus the special tile is identical to the water tile defined in
line 20.

@example
54    w, h = @i{wo}(@i{ti}, "@var{ }", @{
55        "@var{####################}",
56        "@var{#      ....++++++~ #}",
57        "@var{L   PM ..N.++~~~~OE#}",
58        "@var{#######  T~++++++. #}",
59        "@var{#     ^   ~++++++# #}",
60        "@var{#         =++++++X X}",
61        "@var{#         ~++++++# #}",
62        "@var{#~~~~~~~~~~~~~+++X X}",
63        "@var{#    ~   B   ~+++###}",
64        "@var{F    ~   B   ~+++++#}",
65        "@var{# 1  ~   B   #+++++#}",
66        "@var{S   v~V  B   D+++++#}",
67        "@var{####################}"
68    @})
@end example

After all tiles have been defined we can create our world simply by a map that
uses our tile keys. The first argument is our handle @samp{ti}, that defines
how the keys should be resolved. The second argument is the key of our default
floor. The third argument is the map as a table of strings, one for every line.

The world initialization returns the width and height of our world which are
calculated by the map's size.

@example
70    @i{wo}:@b{shuffleOxyd}()
@end example

After the world is created and all objects are set, we can do some final
postprocessing before the level starts to run. The most common task is the
shuffling of the oxyds, which is just a method call of @ref{shuffleOxyd} to
our mighty world object.

@c ----------------- Colored Turnstiles --------------------
@node Colored Turnstiles
@subsection Colored Turnstiles

As this level is part of the Enigma levelpacks we recommend that you play
the level first to get familiar with the used objects and their behaviour.

Now let us look at the essential Lua source code part of the level to understand
how such an idea can be realized with the new API

@example
@i{ti}["@var{ }"] = @{"@b{fl_sahara}"@}
@i{ti}["@var{#}"] = @{"@b{st_purplegray}"@}
@i{ti}["@var{@@}"] = @{"#@b{ac_marble_black}", "@var{marble_black}"@}

@i{ti}["@var{N}"] = @{"@b{st_turnstilearm_n}"@}
@i{ti}["@var{S}"] = @{"@b{st_turnstilearm_s}"@}
@i{ti}["@var{E}"] = @{"@b{st_turnstilearm_e}"@}
@i{ti}["@var{W}"] = @{"@b{st_turnstilearm_w}"@}
@i{ti}["@var{R}"] = @{"@b{st_turnstile}", @b{action} = @{"@var{open}", "@var{close}"@}, @b{target} = @{"@var{red}#*", "@var{green}#*"@}@}
@i{ti}["@var{G}"] = @{"@b{st_turnstile}", @b{action} = @{"@var{close}", "@var{open}"@}, @b{target} = @{"@var{red}#*", "@var{green}#*"@},
                           @b{flavor} = "@var{green}"@}
@i{ti}["@var{r}"] = @{"@b{it_blocker}", "@var{red}#"@} .. @i{ti}(@{"@b{fl_red}"@})
@i{ti}["@var{g}"] = @{"@b{it_blocker}", "@var{green}#"@} .. @i{ti}(@{"@b{fl_lawn}"@})

@i{ti}["@var{O}"] = @{"@b{st_oxyd}", @b{flavor} = "@var{d}", @b{oxydcolor} = @var{OXYD_GREEN}@}
@i{ti}["@var{o}"] = @{"@b{st_oxyd}", @b{flavor} = "@var{d}", @b{oxydcolor} = @var{OXYD_RED}@}

@var{w}, @var{h} = @i{wo}(@i{ti}, "@var{ }", @{
 -- 01234567890123456789
   "@var{#O#####O############}",
   "@var{#   r N g N rO##O#O#}",
   "@var{#WRE#WGE# R ####g#r#}",
   "@var{#   r N r S  r N   #}",
   "@var{#g#g#WG #g##r# REr##}",
   "@var{# # N S r    g S  gO}",
   "@var{#@@g RE#g#gWGE###g###}",
   "@var{# # S   g    r N  ro}",
   "@var{#r#r#WGE#r##g#WGEg##}",
   "@var{# N r S g N  r     #}",
   "@var{#WGE# RE# RE####r#g#}",
   "@var{#   g S r S go##o#o#}",
   "@var{#o#####o############}"
@})

@i{wo}:@b{shuffleOxyd}()
@end example

There are just four tile definitions that do all the dynamic actions. Let us
look first at the blocker item definitions:

@example
@i{ti}["@var{r}"] = @{"@b{it_blocker}", "@var{red}#"@} .. @i{ti}(@{"@b{fl-red}"@})
@i{ti}["@var{g}"] = @{"@b{it_blocker}", "@var{green}#"@} .. @i{ti}(@{"@b{fl-leaves}"@})
@end example
All blockers on red floors are autonamed with a name being composed of the
prefix @samp{red#} and a unique random number being added by the engine as
explained in @ref{Object Naming}. This allows us to address all these blockers
later on.

@example
@i{ti}["@var{R}"] = @{"@b{st_turnstile}", @b{action} = @{"@var{open}", "@var{close}"@}, @b{target} = @{"@var{red}#*", "@var{green}#*"@}@}
@i{ti}["@var{G}"] = @{"@b{st_turnstile}", @b{action} = @{"@var{close}", "@var{open}"@}, @b{target} = @{"@var{red}#*", "@var{green}#*"@},
                           @b{flavor} = "@var{green}"@}
@end example
Whenever the marble hits and turns an @ref{st_turnstile} it performs its actions
on the targets. Here the author makes clever usage of multitargets and
multiactions as described in @ref{Target - Action}. On every turn of a red
turnstile all objects named @samp{red#*}, that are all our blockers on a red
floor, will be sent a message @samp{open}, whereas all blocks on a green floor,
the second target group, receives the second action message @samp{close}. It is
essential to choose the @samp{open}, @samp{close} messages instead of
@samp{toggle}, as more than one red turnstile may be turned in sequence, but
just the first red turn should "toggle" all blockers. The next toggling should
occur on the first green turn following thereafter.

Hope you got the basic idea of the new API. You may well start with you first
level experiments. But you should return and read the following chapters with
overview and advanced examples to write even more fancy levels.

@c ----------------- API 2 Overview --------------------

@node API 2 Overview
@section API 2 Overview

Having analysed a first level it is time get an overview of the API 2
capabilities. Let us take a task driven approach by listing the different
possibilities and use cases by example.

@menu
* Types Overview::
* Position Tasks::
* Attribute Tasks::
* Object Tasks::
* Group Tasks::
* Tiles and World Tasks::
* Named Positions Tasks::
@end menu


@c ----------------- Types Overview --------------------
@node Types Overview
@subsection Types Overview

But first we need to introduce you to the special Enigma value types besides
the standard Lua types @samp{nil}, @samp{boolean}, @samp{string},
@samp{function} and @samp{table}:

@table @asis
@item @b{Types:}
@table @asis
@item @b{position:}@ @ @xref{Position}
A position within the world that can be described by an x and y coordinate.
@item @b{positions:} @i{preset variable:} @code{@b{po}}; @ @ @xref{Positions Repository}
The singleton type of the repository of all named positions.
@item @b{object:}@ @ @xref{Object}
An Enigma object like a stone, item, floor, other. Any object is a position, too.
@item @b{group:}@ @ @xref{Group}
A list of objects.
@item @b{namedobjects:} @i{preset variable:} @code{@b{no}}; @ @ @xref{NamedObjects}
The singleton type of the repository of all named objects.
@item @b{default:} @i{preset variable:} @code{@b{DEFAULT}}; @ @ @xref{Object Attributes}
The singleton type of default values that can be used instead of Lua's @samp{nil}
in anonymous table tile definitions.
@item @b{tile:}@ @ @xref{Tile and Object Declaration}
A description of one or several objects for a common grid position (floor, item,
stone, actor)
@item @b{tiles:} @i{preset variable:} @code{@b{ti}}; @ @ @xref{Tiles Repository}
The singleton type of the repository of all tile instances.
@item @b{world:} @i{preset variable:} @code{@b{wo}}; @ @ @xref{World}
The singleton type of the world that contains all objects.
@item @b{position list:}@ @ @xref{Named Positions}
A list of positions.
@end table
@end table

Please note the four handles @samp{po}, @samp{no}, @samp{ti} and @samp{wo}. You
have noticed two of them in the previous section @ref{Basic Lua Examples}. These
are four variables, that are preset prior the level code gets executed.

API 2 uses mainly two character names for frequently used variables and
functions to shorten the level code and to make it better readable. Authors
should try to use either single characters or names that are three characters or
longer for private variable names.

For the rest of this section let us assume that @samp{obj} is an object
reference of a stone, item or floor, which means that is of type @samp{object}.
And let @samp{pos} be a valid variable of type @samp{position}.

@c ----------------- Position Tasks --------------------
@node Position Tasks
@subsection Position Tasks

For reference details @pxref{Position}.

@table @asis
@item @b{Creating Positions:}
@example
@var{pos} = @i{po}(@var{7}, @var{3})         -- using function "po()" to generate a position object
@var{pos} = @i{po}(@{@var{7}, @var{3}@})        -- using a table position constant as argument
@var{pos} = @var{obj}              -- every object is a valid position
@var{pos} = @i{po}(@var{12.3}, @var{3.7})    -- a position within a grid (for an actor)
@end example
Absolute positions are created by the function @samp{po()}. But the most common
way should be the reinterpretation of an object as a position. This lets you
set other objects relatively to given ones.

@item @b{Position Constants:}
@example
@{@var{7},@var{3}@}     -- a valid position for all arguments and operations (@pxref{Caveats})
@end example
Anonymous tables with just two number values can be used in many cases directly as
a position constant. In case of errors, e.g. when operators are not well defined
like addition of two constants, which results in an attempt of adding two Lua
tables, use the function @samp{po()} to convert the constant.

@item @b{Coordinate Access:}
@example
@var{x}, @var{y} = @var{pos}.@b{x}, @var{pos}.@b{y}
@var{x}, @var{y} = @var{pos}["@b{x}"], pos["@b{y}"]
@var{x}, @var{y} = @var{pos}:@b{xy}()
@var{x}, @var{y} = @var{obj}.@b{x}, @var{obj}.@b{y}
@var{x}, @var{y} = @var{obj}:@b{xy}()
@end example
The x and y coordinate of a position or object can be read accessed like any
object attribute. A position or object method call by @samp{xy()} returns
both coordinate values at once. You can not set a position value by coordinate
write access. Objects need to be set to a new world position. New positions
can be calculated by position arithmetic.

@item @b{Position Calculation:}
@example
@var{pos} = @var{obj} + @{@var{2},@var{7}@}
@var{dpos} = @var{obj1} - @var{obj2}
@var{dpos2} = @var{2} * @var{dpos}
@var{dpos3} = @var{dpos} / @var{2}
@end example
Positions can be added or subtracted to get distance vectors. You can multiply
and divide them with any number.

@item @b{Center positions for set actors}
@example
@var{pos_centered1} = @var{pos} + @{@var{0.5}, @var{0.5}@}
@var{pos_centered2} = #@var{pos}
@var{pos_centered3} = #@var{obj}
@end example
Especially for positioning of actors you sometimes need the position of the
center of a grid. Of course you can get it by addition of a constant position.
But the @samp{#} operator applied on a position or an actor does the same in
a simpler way.

@item @b{Round a position to a grid}
@example
@var{grid_pos} = @var{pos}:@b{grid}()
@var{grid_pos} = ((@var{pos1} - @var{pos2})/@var{2}):@b{grid}()
@end example
A result of a position calculation needs sometimes to be rounded to integer grid
coordinates. This is done by the @samp{grid()} method.

@item @b{Position comparison}
@example
@var{pos_centered1} == @var{pos_centered2}
@var{pos_centered1} ~= @var{pos_centered2}    -- Lua's inequality operator
@end example
Position can be easily compared to equality.

@item @b{Position existence}
@example
@var{pos}:exists()
@end example
@samp{true} if a position is a valid position of the world. All positions
outside of the world return @samp{false}.
@end table

@c ----------------- Attribute Tasks --------------------
@node Attribute Tasks
@subsection Attribute Tasks

For reference details @pxref{Object}.

@table @asis

@item @b{Single Attribute Setting:}
@example
@var{obj}["@b{destination}"] = @i{po}(@var{7},@var{3})
@i{wo}["@b{Brittleness}"] = @var{7}
@end example
Object attributes as well as global world attributes can be set like Lua table
values. They can take values of special Enigma types like position, object or
group.

@item @b{Multiple Attribute Setting:}
@example
@var{obj}:@b{set}(@{@b{target}=@var{mydoor}, @b{action}="@b{open}"@})
@end example
You can set multiple attributes on any object at once with the object's @samp{set()}
method. The argument is an anonymous Lua table with the attribute names as keys
and assigned values of your choice.

@item @b{Requesting Attributes:}
@example
@var{value} = @var{obj}["@b{attr_name}"]
@var{value} = @i{wo}["@b{Brittleness}"]
if @i{wo}["@b{IsDifficult}"] then ... end
@end example
Attributes of objects and the world can be read like Lua table key values.

@item @b{Reset Attributes:}
@example
@var{obj}["@b{length}"] = nil       -- the default length, e.g. @samp{1}
@var{obj}["@b{color}"]  = nil       -- delete color attribute - no color
@var{obj}["@b{length}"] = @i{DEFAULT}   -- the default length, e.g. @samp{1}
@end example
Any object attribute can be reset to its default value, which is the attribute's
"delete" operation, by assigning it the Lua @samp{nil} or the Enigma
@samp{DEFAULT} value.

@end table

@c ----------------- Object Tasks --------------------
@node Object Tasks
@subsection Object Tasks

For reference details @pxref{Object}.

@table @asis
@item @b{Creating Objects:}
@example
@i{wo}[@var{pos}]  = @{"@b{st_chess}", @b{color}=@var{WHITE}, @b{name}="@var{Atrax}"@}   -- on grid pos
@i{wo}[#@var{pos}] = @{"@b{ac_bug}"@}              -- actor centered on grid pos
@i{wo}[@var{pos}]  = @{"#@b{ac_bug}"@}             -- actor centered on grid pos
@i{wo}[@var{pos}]  = @{"@b{ac_bug}", @var{0.3}, @var{0.7}@}    -- actor with offsets to pos
@i{wo}[@var{my_floor}] = @{"@b{it_magicwand}"@}    -- set a wand on top of a given floor object
@i{wo}[@var{pos}]  = @i{ti}["@var{x}"]                 -- tile based object definition
@end example
Besides map based object creation, that you saw in the previous basic examples,
you can create new objects on any world position directly. The world takes a
position, that may well be an object, as key argument. The new object is
described either by an anonymous Lua table, containing the kind string as first
value and additional attributes as key value pairs appended, or by a tile object.

@item @b{Object Naming:}
@example
@i{no}["@var{Atrax}"] = @var{obj}
@i{wo}[@var{pos}] = @{"@b{st_chess}", @b{name}="@var{Atrax}"@}
@i{wo}[@var{pos}] = @{"@b{st_chess}", "@var{Atrax}", @b{color}=@var{WHITE}@}
@end example
As explained in @ref{Object Naming}, the names are the only longtime valid
object references. You can explicitly name an object by assigning it at the
named object repository @samp{no} to the name as the key. But most times you
just supply the object's name as an object attribute. If you supply the name
attribute as the @b{second} value in the anonymous table you can omit the
key @samp{name =} part as a common abbreviation.

@item @b{Object Autonaming:}
@example
@i{wo}[@var{pos}] = @{"@b{st_chess}", @b{name}="@var{Atrax}#"@}
@end example
As explained in @ref{Object Naming} you can append a hash sign @samp{#} to a
name and use the resulting string for arbitrary number of similar objects. This
is especially useful for building groups.

@item @b{Requesting Objects:}
@example
@var{obj} = @i{no}["@var{Atrax}"]       -- named object retrieval from repository
@var{obj} = @i{it}(@var{pos})
@var{obj} = @i{it}(@var{x},@var{y})
@var{obj} = @i{st}(@var{pos})
@var{obj} = @i{wo}:@b{it}(@var{pos})
@var{my_item} = @i{it}(@var{my_floor})  -- get the item that is on top of the given floor
@end example
The most common way is naming objects and the requesting the @samp{no}
repository for the object reference. If you know the position of the desired
object you can use one of the functions or world methods @samp{fl}, @samp{it},
@samp{st} that take a position, an object as position, or just the two
coordinates as arguments. Especially requesting one type of objects that is
positioned at the same grid as another object, the stone on top of a floor, etc.
can be very useful.

@item @b{Killing Objects:}
@example
@i{wo}[@var{pos}] = @{"@b{it_nil}"@}
@var{obj}:@b{kill}()
@end example
You remove an object by setting another replacement object at the same
position in the same layer. If you do not want to set a new object you can use
the placebo objects @samp{fl_nil}, @samp{it_nil}, @samp{st_nil}. Another way is
to call the @samp{kill()} method of an object or send it a @samp{kill} message.
You can only remove objects that are set on the grid. Neither actors nor owned
objects like items in a players inventory can be killed - they will simply
ignore the attempt.

@item @b{Comparing Objects}
@example
@var{obj1} == @var{obj2}
@var{obj1} ~= @var{obj2}
@end example
Objects can be directly compared on equality or inequality. It is an identity
comparison that acknowledges that you have two references of the same object.

@item @b{Existence of an object}
@example
@var{obj}:@b{exists}()
-@var{obj}                -- unary minus operator on object
if -@var{obj} then ...
@end example
Object references may get invalid due to objects being killed. In most cases
this creates no problem as requests to invalid objects will simply be ignored.
But if the level logic depends on the existence of an object you can call the
@samp{exists()} method or simply precede the reference by the unary minus
@samp{-} operator. Both ways return a simple bool value stating if the object
reference is still valid.

@item @b{Messages:}
@example
@var{my_boulder}:@b{message}("@b{orientate}", @var{WEST})
@var{my_boulder}:@b{orientate}(@var{EAST})
@var{my_door}:@b{open}()
@end example
@ref{Messages} are a main feature of Enigma. You can send them directly to any
object by the @samp{message()} method or by using any message directly as a
method call itself.

@item @b{Object Classification:}
@example
@var{obj}:@b{is}("@b{st_chess}")
@var{obj}:@b{is}("@b{st}")
@var{obj}:@b{is}("@b{st_chess_black}")
@end example
You create objects by giving an @ref{Object Kind}. Later on you can check a
given object for conformity to a given class or kind. Even though you can not
create abstract kind objects like @samp{st}, you can check this way if an object
is a stone. Checking for special subkinds may even evaluate the current state
or other attributes of an object to report its current classification.

@end table

@c ----------------- Group Tasks --------------------
@node Group Tasks
@subsection Group Tasks

For reference details @pxref{Group}.

@table @asis
@item @b{Creating Groups:}

@example
@var{group} = @i{no}["@b{Atrax}#*"]           -- a group of all matching objects
			        --   wildcards "*","?" allowed
@var{group} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3})
@var{group} = @i{grp}(@{@var{obj1}, @var{obj2}, @var{obj3}@})  -- a group of objects set up in a table
@end example

Requesting objects from the named object repository will result in a group of
objects if you make proper usage of wildcards. Appending an asterisk @samp{*}
to the autonaming hash will retrieve all objects that have been set with this
name suffix. But you can create a group by the @samp{grp} function, too. Simply
add the desired object reference as arguments, either single or as a table.

@item @b{Group Usage:}
@example
@var{floor_group}["@b{friction}"] = @var{3.2}      -- set attribute on all floors in the group
@var{door_group}:@b{message}("@b{open}")
@var{door_group}:@b{open}()
@var{stone_group}:@b{kill}()
@i{wo}[@var{floor_group}] = @{"@b{it_coin_m}"@}   -- add some money on all floor positions

@i{wo}[@var{pos}] = @{"@b{st_switch}", @b{target}=@var{door_group}, @b{action}="@b{open}"@}
@i{wo}[@var{pos}] = @{"@b{st_switch}", @b{target}="@var{door}#*", @b{action}="@b{close}"@}
@end example
Many object operations can be applied to groups in the same manner. The
operations will be applied to all members of the group. You set attributes,
send messages or call any method.

The world object takes a group as key, too. You can set objects of a given
definition to many positions at once.

Another usage of groups is the application as an attribute value. E.g. you can
define multiple targets by supplying a group.

@item @b{Group Operations:}
@example
@var{doors_lasers} = @var{doorgrp} + @var{lasergrp}       -- join of two groups
@var{lasergrp}     = @var{doors_lasers} - @var{doorgrp}   -- difference of two groups
@var{common_doors} = @var{doorgrp1} * @var{doorgrp2}      -- intersection of two groups
@end example
Groups offer some standard operations known from handling with sets.

@item @b{Group Members:}
@example
@var{count} = #@var{mygroup}        -- number of objects in the group
@var{obj}   = @var{mygroup}[@var{5}]     -- 5th object of the group
@var{obj}   = @var{mygroup}[@var{-1}]    -- last object of the group
for @var{i} = @var{1}, #@var{mygroup} do @var{obj} = @var{mygroup}[@var{i}] ... end
for @var{obj} in @var{mygroup} do ... end
@end example
You can access the members of a group by numbered indices. The size of a group
is reported by the standard Lua hash @samp{#} operator. If you need to iterate
over the objects of a group you can write easily Lua for loops. You can either
iterate with a counter or directly iterate the content objects.

@item @b{Shuffled Group:}
@example
@var{shuffled_group} = @var{sorted_group}:@b{shuffle}()
@var{shuffled_group} = @i{no}["@b{Atrax}#*"]:@b{shuffle}()
@end example
Every group returns a shuffled group with the same members when receiving the
message @code{"shuffle"}.

@item @b{Sorted Group:}
@example
@var{sorted_group} = @var{group}:@b{sort}("@b{linear}", po(@var{2}, @var{1}))
@var{sorted_group} = @var{group}:@b{sort}("@b{linear}")
@var{sorted_group} = @var{group}:@b{sort}("@b{circular}")
@var{sorted_group} = @var{group}:@b{sort}()
@end example
Sort group objects in linear order according to given direction vector, or
direction determined by the first two objects. Or order objects circular around
their center. If no argument is given order objects lexically.

@item @b{Subset Group:}
@example
@var{sub_group} = @var{group}:@b{sub}(@var{2})   -- first two objects
@var{sub_group} = @var{group}:@b{sub}(@var{-2})  -- last two objects
@var{sub_group} = @var{group}:@b{sub}(@var{2}, @var{4}) -- objects from 2 to 4
@var{sub_group} = @var{group}:@b{sub}(@var{2}, @var{-2}) -- two objects starting with 2
@end example
Build subgroup with given indices and numbers.

@item @b{Nearest Object:}
@example
@var{object} = @var{group}:@b{nearest}(@var{reference})
@end example
Search object in group that is nearest to the given reference object.
@end table

@c ----------------- Tiles and World Tasks --------------------
@node Tiles and World Tasks
@subsection Tiles and World Tasks

For reference details @pxref{Tile and Object Declaration}, @ref{Tiles Repository}
and @ref{World}.

@table @asis

@item @b{Tiles:}
@example
@i{ti}["@var{_}"] = @{"@b{fl_sahara}"@}
@i{ti}["@var{__}"] = @{"@b{fl_sahara}"@}
@i{ti}["@var{..}"] = @{"@b{fl_sand}"@}
@i{ti}["@var{##}"] = @{"@b{st_blocker}"@}
@i{ti}["@var{switch_template}"] = @{"@b{st_switch}"@}
@i{ti}["@var{..}"] = @{"@b{fl_abyss}"@}   -- redefinition causes error to avoid common mistakes
@i{ti}["@var{.w}"] = @i{ti}["@var{..}"] .. @{"@b{it_magicwand}"@}
@i{ti}["@var{ w}"] = @{"@b{fl_abyss}"@} .. @i{ti}(@{"@b{it_magicwand}"@})
@end example
The tiles repository @samp{ti} is like a table, but specialized on storage of
tile definitions. You can use any string as key. You can store the same
definition twice at different keys. But you are not allowed to redefine an
already set key. This is pure protection of common error situations. A
definition stored in the repository can be used in other definitions that
follow. Referencing a tile's repository entry at a given key like @samp{ti[".."]}
results in a tile value. Such tile values can be concatenated by the @samp{..}
operator with other tile values and anonymous tables containing object
definitions. The last example is a concatenation of two prior not declared
object definitions. You can not concatenate two anonymous tables. Lua forbids
that. By converting any of the two tables by the @samp{ti()} to a tile value the
concatenation gets valid.

@item @b{World Initialization}
@example
  @var{width}, @var{height} = @i{wo}(@i{ti}, "@var{__}", @{ -- second arg: default tile key that
  "@var{##__......}",                  --   defines the base, too - this example
  "@var{##..__.w__}",                  --   is 2 chars per tile/grid
  "@var{##.. w__..}"
  @})
@end example
The world is initialized by the @samp{wo()} call that is explained in details
at @ref{World Creation}. In the simple form you supply
the @samp{ti} handle as the first argument. The second argument is the key of
the default tile definition that defines the default floor to be set if a tile
does not contain another floor object. At the same time this key defines by its
length the standard key length as used in the following map, too. The third
argument is the map given as an anonymous table of strings. The world's size is
given by the maximum line length and the number of lines. These values are
returned by the call.

@end table

@c ----------------- Named Position Tasks --------------------
@node Named Positions Tasks
@subsection Named Positions Tasks

For reference details @pxref{PositionList}.

@table @asis
@item @b{Named Position Usage:}
@example
@var{obj}["@b{name}"] = "@var{anchor1}"
@var{obj}:@b{kill}()
@var{pos} = @i{po}["@var{anchor1}"]
@i{po}["@var{anchor2}"] = @var{pos}
@end example
The position of any named object can be directly retrieved. The position is
still accessible under the name, when the object gets killed. You can
additionally name own positions. Note that the position of an existing object
precedes a position stored under the same name.

@item @b{Creating Position Lists:}
@example
@var{polist} = @i{po}["@var{deepwater}#*"]
@var{polist} = @i{po}(@var{grp})
@end example
Requesting positions will result in a list of positions if you make proper usage
of wildcards. A given object group can be converted into a position list, too.

@item @b{Position List Usage:}
@example
@i{wo}[@var{polist}] = @i{ti}["@var{x}"]
@var{grp} = @i{fl}(@var{polist})
@end example
You can use a list of positions to set tiles or to retrieve a group of floors,
items, stones.

@item @b{Position List Operations:}
@example
@i{wo}[@var{polist} .. @i{po}["@var{beach}#*"]] = @{"@b{it_banana}"@}
@end example
Two position lists can be appended. Single positions can be appended to a given
position list, too.

@item @b{Position List Members:}
@example
for @var{i} = 1, #@var{polist} do
    @i{wo}[@var{polist}[@var{i}]] = @{"@b{it_cherry}"@}
end
@end example
Single positions within the list can be accessed by index. The whole list can
be traversed by a simple for loop. The hash length operator reports the number
of contained positions.

@end table

@c ----------------- Advanced Lua Examples --------------------

@node Advanced Lua Examples
@section Advanced Lua Examples

Now it is time to reveal the real power of the new API. Let us look again at
two real levels. Investigate the levels first by playing and then join
in the line by line commentary of the source code to understand how to
implement your own level ideas.

@menu
* Color Maze::    Enigma levelpack VIII, level #19
* Weirdly Wired:: Enigma levelpack VIII, level #22
@end menu


@c ----------------- Color Maze --------------------
@node Color Maze
@subsection Color Maze

Let us view the Lua source code part. We did add a line count in the first two
columns for reference purpose within this section. These line count numbers are
not part of the source code itself!

@example
01    @i{wo}["@b{ConserveLevel}"] = @var{false}
02    @i{wo}["@b{FollowGrid}"] = @var{false}
03    @i{wo}["@b{FollowMethod}"] = @var{FOLLOW_SCROLL}
04
05    @i{ti}["@var{ }"] = @{"@b{fl_fake_abyss}"@} .. @i{ti}(@{"@b{st_lightglass}"@})
06
07    @i{ti}["@var{!}"] = @{"@b{fl_blueslab}", "@var{blue#}", @var{_color}="@var{blue}"@}
08    @i{ti}["@var{@@}"] = @{"@b{fl_pinkbumps}", "@var{orange#}", @var{_color}="@var{orange}"@}
09    @i{ti}["@var{#}"] = @{"@b{fl_redslab}", "@var{red#}", @var{_color}="@var{red}"@}
10    @i{ti}["@var{$}"] = @{"@b{fl_lawn_b}", "@var{green#}", @var{_color}="@var{green}"@}
11
12    @i{ti}["@var{b}"] = @i{ti}["@var{!}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ns}", @b{state}=@var{OPEN}@}
13    @i{ti}["@var{B}"] = @i{ti}["@var{!}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ew}", @b{state}=@var{OPEN}@}
14    @i{ti}["@var{o}"] = @i{ti}["@var{@@}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ns}", @b{state}=@var{OPEN}@}
15    @i{ti}["@var{O}"] = @i{ti}["@var{@@}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ew}", @b{state}=@var{OPEN}@}
16    @i{ti}["@var{r}"] = @i{ti}["@var{#}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ns}", @b{state}=@var{OPEN}@}
17    @i{ti}["@var{R}"] = @i{ti}["@var{#}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ew}", @b{state}=@var{OPEN}@}
18    @i{ti}["@var{g}"] = @i{ti}["@var{$}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ns}", @b{state}=@var{OPEN}@}
19    @i{ti}["@var{G}"] = @i{ti}["@var{$}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ew}", @b{state}=@var{OPEN}@}
20
21    @i{ti}["@var{d}"] = @{"@b{it_document}", @b{text}="@var{text1}"@}
22    @i{ti}["@var{5}"] = @i{ti}["@var{b}"] .. @i{ti}["@var{d}"]
23    @i{ti}["@var{6}"] = @i{ti}["@var{O}"] .. @i{ti}["@var{d}"]
24    @i{ti}["@var{7}"] = @i{ti}["@var{r}"] .. @i{ti}["@var{d}"]
25    @i{ti}["@var{8}"] = @i{ti}["@var{G}"] .. @i{ti}["@var{d}"]
26
27    @i{ti}["@var{x}"] = @{"@b{it_sensor}", @b{invisible}=@var{true}, @b{target}="@var{gates}"@}
28    @i{ti}["@var{*}"] = @i{ti}["@var{x}"] .. @{"#@b{ac_marble_black}", "@var{me}"@}
29
30    @i{ti}["@var{?}"] = @{"@b{st_oxyd_a}"@}
31
32    @i{wo}(@i{ti}, "@var{ }", @{
33    --      |         1    1   |2    2
34    --      |1   5    0    5   |0    5
35           "@var{                           }",
36           "@var{ xO@@OxR#RxO@@OxB!BxR#RxB!Bx }", --01
37           "@var{ b   r   g   g   b   g   r }",
38           "@var{ !   #   $   $   !   $   # }",
39           "@var{ b   r   g   g   b   g   r }",
40           "@var{ xR#RxB!BxO@@OxG$GxO@@OxO@@Ox }", --05
41           "@var{ g   g   r   g   g   b   b }",
42           "@var{ $   $   #   $   $   !   ! }",
43           "@var{ g   g   r   g   g   b   b }",
44           "@var{ xR#RxO@@OxG$GxR#RxG$GxR#Rx }",
45           "@var{ g   b   b   o       b   r }", --10
46           "@var{ $   !   !   @@       !   # }",
47           "@var{ g   b   5   o   ?   b   r }", --
48           "@var{ xO@@OxO@@6*8$Gx   xG$GxR#Rx }",
49           "@var{ r   b   7   b   ?   o   o }",
50           "@var{ #   !   #   !       @@   @@ }", --15
51           "@var{ r   b   r   b       o   o }",
52           "@var{ xG$GxB!BxR#RxO@@OxR#RxG$Gx }",
53           "@var{ g   o   o   g   g   o   b }",
54           "@var{ $   @@   @@   $   $   @@   ! }",
55           "@var{ g   o   o   g   g   o   b }", --20
56           "@var{ xB!BxO@@OxR#RxR#RxO@@OxB!Bx }",
57           "@var{ o   r   g   g   b   b   g }",
58           "@var{ @@   #   $   $   !   !   $ }",
59           "@var{ o   r   g   g   b   b   g }", --
60           "@var{ xR#RxB!BxB!BxR#RxO@@OxR#Rx }", --25
61           "@var{                           }"@} --
62    --      |         1    1   |2    2
63    --      |1   5    0    5   |0    5
64    )
65
66    @var{last} = @b{it}(@i{no}["@var{me}"])   -- the last visited sensor
67    @var{move} = @var{0}              -- the count of link moves
68    @var{sequence} = @{@}         -- the sequence of the 4 colors that the user did choose
69
70    function @var{gates}(@var{value}, @var{sender})
71        if @var{last} ~= @var{sender} then
72            local @var{middle} = @var{last} + (@var{sender} - @var{last})/@var{2}
73            local @var{color} = @b{fl}(@var{middle})["@var{_color}"]
74            if @var{color} == @var{nil} then return end  -- someone cheated, avoid throwing an exception
75            @b{st}(@i{no}[@var{color}.."@var{#*}"]):@b{close}()
76            @var{sequence}[@var{move}%@var{4}] = @var{color}
77            if @var{move} >= @var{3} then
78                @b{st}(@i{no}[@var{sequence}[(@var{move}+@var{1})%@var{4}].."@var{#*}"]):@b{open}()
79            end
80            @var{move} = @var{move} + @var{1}
81            @var{last} = @var{sender}
82        end
83    end
@end example

Let us concentrate on new aspects not discussed in the previous
@ref{Basic Lua Examples}.

@example
01    @i{wo}["@b{ConserveLevel}"] = @var{false}
02    @i{wo}["@b{FollowGrid}"] = @var{false}
03    @i{wo}["@b{FollowMethod}"] = @var{FOLLOW_SCROLL}
@end example
This level must forbid the user to resurrect a marble at the start position.
At the same time the user should see the area around the marble as complete as
possible. Thus the scroll mode needs to be set, too. All this is done by
setting special @ref{Global Attributes}.

@example
05    @i{ti}["@var{ }"] = @{"@b{fl_fake_abyss}"@} .. @i{ti}(@{"@b{st_lightglass}"@})
32    @i{wo}(@i{ti}, "@var{ }", @{
@end example
The inaccessible areas are filled with a transparent glass on top of a black
floor as defined in line 5. The world initialization uses this tile definition
as the default tile. This is o.k. as it contains a floor definition. Additional
objects like the glass stone will never be set on default usage.

@example
07    @i{ti}["@var{!}"] = @{"@b{fl_blueslab}", "@var{blue#}", @var{_color}="@var{blue}"@}
08    @i{ti}["@var{@@}"] = @{"@b{fl_pinkbumps}", "@var{orange#}", @var{_color}="@var{orange}"@}
09    @i{ti}["@var{#}"] = @{"@b{fl_redslab}", "@var{red#}", @var{_color}="@var{red}"@}
10    @i{ti}["@var{$}"] = @{"@b{fl_lawn_b}", "@var{green#}", @var{_color}="@var{green}"@}
@end example
Every floor object is autonamed for later group access purposes. Additionally
every floor object sets a user attribute prefixed in its name by an underscore
@samp{_}. This attribute stores a string that we need later on in the callback
function.

@example
12    @i{ti}["@var{b}"] = @i{ti}["@var{!}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ns}", @b{state}=@var{OPEN}@}
13    @i{ti}["@var{B}"] = @i{ti}["@var{!}"] .. @{"@b{st_door}", @b{flavor}="@var{d}", @b{faces}="@var{ew}", @b{state}=@var{OPEN}@}
@end example
The doors are set without being named, as we will target them by their position.

@example
27    @i{ti}["@var{x}"] = @{"@b{it_sensor}", @b{invisible}=@var{true}, @b{target}="@var{gates}"@}
@end example
The actors moves are detected by invisible @ref{it_sensor}s that are positioned
on any intersection. The target is the @ref{Callback Function} @samp{gates}.
The action can be omitted as the function name is a unique target.

@example
66    @var{last} = @b{it}(@i{no}["@var{me}"])   -- the last visited sensor
@end example
A Lua variable that stores the last sensor visited by the marble. This is
initially the sensor beneath the start position of the marble. We do get the
marble by name, but do store the sensor item beneath it, that is an unnamed
object.

@example
67    @var{move} = @var{0}              -- the count of link moves
68    @var{sequence} = @{@}         -- the sequence of the 4 colors that the user did choose
@end example
These are the essential variables for our algorithm. The user is free in
selecting the sequence of the colored floors. We do initialize the sequence
by an anonymous table that will be filled with the color names. An additional
move counter will give us the current index into this table.

@example
70    function @var{gates}(@var{value}, @var{sender})
71        if @var{last} ~= @var{sender} then
@end example
The callback function provides the sender, the @ref{it_sensor}, that caused
the action. It is the current sensor. As the marble can return to the last
sensor, we have to check that it is a new sensor before taking any actions.
A simple object comparison suffices.

@example
72            local @var{middle} = @var{last} + (@var{sender} - @var{last})/@var{2}
73            local @var{color} = @b{fl}(@var{middle})["@var{_color}"]
@end example
We need to know the color of the floor strip that the marble did pass. We do
calculate the position of the middle of this floor strip by position calculation.
We simply take the middle position between the last and the current intersection.
Once we have the middle position we can get the floor object and retrieve the
private user attribute with the color description.

@example
74            if @var{color} == @var{nil} then return end  -- someone cheated, avoid throwing an exception
@end example
In regular play we are guaranteed to get a color value. But just in case a
gamer cheats he may have moved irregular without visiting neighboring sensors.
Just avoid errors. The gamer can not score anyway.

@example
75            @b{st}(@i{no}[@var{color}.."@var{#*}"]):@b{close}()
@end example
Knowing the color we want to close all doors on same colored floor strips. We
did autoname the floors by matching name prefixes. Thus we can retrieve all
floors of a given color by concatenating the color string with the suffix
@samp{#*} and requesting the named object repository. As we are interested in
the doors we do request the stone above every floor. We provide a group of
floors and get a group of stones. Not every floor has a door on top. That does
not matter as only existing objects are added to the resulting stone group.
Knowing the stones we just send them all a @samp{close} message.

@example
76            @var{sequence}[@var{move}%@var{4}] = @var{color}
@end example
We need to remember the sequence of colors. We just store the color name in
the table at the index given by the move count modulo 4. Yes we could limit
this statement to the first four moves. But who cares? The modulo operation
is simpler than a conditional expression.

@example
77            if @var{move} >= @var{3} then
78                @b{st}(@i{no}[@var{sequence}[(@var{move}+@var{1})%@var{4}].."@var{#*}"]):@b{open}()
79            end
@end example
On the first 3 moves we just do close doors and remember the color sequence.
But starting with the 4th move we need to open the next color in sequence.
We do retrieve the color string of the next color from the sequence table by
a simple modulo calculation. Having the color name we do the same trick as in
line 75. But this time we do send the @samp{open} messages to all affected doors.

@example
80            @var{move} = @var{move} + @var{1}
81            @var{last} = @var{sender}
@end example
Finally we just have to increase the move count and to remember the current
sender as the last visited sensor.

That is all to code a quite complex dynamic level idea like "Color Maze".

@c ----------------- Weirdly Wired --------------------
@node Weirdly Wired
@subsection Weirdly Wired
You should have restarted this level several times to notice the design changes
of the floor pattern and the border panel stones besides the dynamic wiring of
the stones.

Let us view the Lua source code part. We did add a line count in the first two
columns for reference purpose within this section. These line count number are
not part of the source code itself!

@example
01      <el:compatibility el:enigma="1.10">
02         <el:dependency el:path="lib/libmath" el:id="lib/libmath" el:release="1" el:preload="true"/>
03      </el:compatibility>
...
04    @i{ti}["@var{ }"] = @{"@b{fl_sahara}", @b{friction} = @var{3.5}, @b{adhesion} = @var{4.0}@}
05    @i{ti}["@var{a}"] = @{"@b{fl_ivory}", @b{friction} = @var{3.5}, @b{adhesion} = @var{4.0}@}
06    @i{ti}["@var{b}"] = @{"@b{fl_bright}", @b{friction} = @var{3.5}, @b{adhesion} = @var{4.0}@}
07    @i{ti}["@var{c}"] = @{"@b{fl_platinum}", @b{friction} = @var{3.5}, @b{adhesion} = @var{4.0}@}
08    @i{ti}["@var{_}"] = @{"@b{fl_water}"@}
09    @i{ti}["@var{@@}"] = @{"#@b{ac_marble_black}"@}
10    @i{ti}["@var{w}"] = @{"@b{st_flat_movable}", "@var{wood}#"@}
11    @i{ti}["@var{t}"] = @{"@b{it_trigger}", "@var{trigger}#"@}
12    @i{ti}["@var{d}"] = @{"@b{st_blocker}", "@var{door}#"@}
13    @i{ti}["@var{o}"] = @{"@b{st_oxyd}", @b{oxydcolor} = @var{OXYD_YELLOW}, @b{flavor} = "@var{a}"@}
14    @i{ti}["@var{O}"] = @{"@b{st_oxyd}", @b{oxydcolor} = @var{OXYD_WHITE}, @b{flavor} = "@var{a}"@}
15    @i{ti}["@var{1}"] = @{"@b{st_panel}", @b{cluster} = @var{1}@}
16    @i{ti}["@var{2}"] = @{"@b{st_panel}", @b{cluster} = @var{2}@}
17    @i{ti}["@var{S}"] = @{"@b{st_switch}", @b{target} = "@var{easy_mode_call}"@}
18
19    @var{floors}  = @{@i{ti}["@var{ }"], @i{ti}["@var{a}"], @i{ti}["@var{b}"], @i{ti}["@var{c}"]@}
20    @var{polynom} = @i{lib}.@i{math}.@i{random_vector}(@var{10}, @var{4})
21
22    function @var{myresolver}(@var{key}, @var{x}, @var{y})
23      if @var{key} == "@var{ }" then
24        return @var{floors}[@i{lib}.@i{math}.@i{cubic_polynomial}(@var{polynom}, @var{x}, @var{y}) % (#@var{floors}) + @var{1}]
25      elseif    (@var{key} == "@var{#}")
26            or ((@var{key} == "@var{_}") and (@i{random}(@var{4}) == @var{1}))
27            or ((@var{key} == "@var{S}") and @i{wo}["@b{IsDifficult}"]) then
28        return @i{ti}[""..@i{random}(@var{2})]
29      else
30        return @i{ti}[@var{key}]
31      end
32    end
33
34    @var{w}, @var{h} = @i{wo}(@var{myresolver}, "@var{ }", @{
35     -- 01234567890123456789
36       "@var{####################___________________}",
37       "@var{#                  #_____###o###_______}",
38       "@var{#   w   w t   t    #_____#d   d#_______}",
39       "@var{#     w   w t   t  #___### ### ###_____}",
40       "@var{#  w     t         #___#d d#_#d d#_____}",
41       "@var{#                  ##### ###_### ###___}",
42       "@var{S    w   w t @@ t        d#___#_#d d#___}",
43       "@var{#                  #######_####### #___}",
44       "@var{#  w     t         #_______O  d# # o___}",
45       "@var{#     w   w t   t  #_______### ### #___}",
46       "@var{#   w   w t   t    #_________#d   d#___}",
47       "@var{#                  #_________###O###___}",
48       "@var{####################___________________}"
49    @})
50
51    @var{door_p} = @i{lib}.@i{math}.@i{permutation}(@var{12})
52    @var{wire_p} = @i{lib}.@i{math}.@i{permutation}(@var{12})
53    @var{woods} = @i{no}["@var{wood}#*"]
54    @var{triggers} = @i{no}["@var{trigger}#*"]
55    @var{doors} = @i{no}["@var{door}#*"]
56
57    for @var{j} = @var{1}, @var{12} do
58      @var{triggers}[@var{j}].@b{target} = @var{doors}[@var{door_p}[@var{j}]]
59    end
60
61    for @var{j} = @var{1}, @var{9} do
62      @i{wo}:@b{add}(@{"@b{ot_wire}",
63              @b{anchor1} = @var{woods}[@var{wire_p}[@var{j} + @var{3}]],
64              @b{anchor2} = @var{woods}[@var{wire_p}[@var{j}%@var{3} + @var{1}]]@})
65      @i{wo}:@b{add}(@{"@b{ot_wire}", @b{name} = "@var{obsolete_wire}#",
66              @b{anchor1} = @var{woods}[@var{wire_p}[@var{j} + @var{3}]],
67              @b{anchor2} = @var{woods}[@var{wire_p}[@var{j}%@var{9} + @var{4}]]@})
68    end
69
70    function @var{easy_mode_call}(@var{is_on}, @var{sender})
71      if @var{is_on} then
72        @i{no}["@var{obsolete_wire}#*"]:@b{kill}()
73      else
74        for @var{j} = @var{1}, @var{9} do
75          @i{wo}:@b{add}(@{"@b{ot_wire}", @b{name} = "@var{obsolete_wire}#",
76             	  @b{anchor1} = @var{woods}[@var{wire_p}[@var{j} + @var{3}]],
77                @b{anchor2} = @var{woods}[@var{wire_p}[@var{j}%@var{9} + @var{4}]]@})
78        end
79      end
80    end
@end example
How is this versatility in design and action achieved as the last lines 69 to
79 obviously deal just with the easy mode diffs? Let us analyse the lines
that do the real work.

@example
01       <el:compatibility el:enigma="1.10">
02         <el:dependency el:path="lib/libmath" el:id="lib/libmath" el:release="1" el:preload="true"/>
03       </el:compatibility>
@end example
We make use of some functions of the @ref{libmath} library. Thus we need to
preload it, besides declaration of compatibility to Enigma 1.10.

@example
04    @i{ti}["@var{ }"] = @{"@b{fl_sahara}", @b{friction} = @var{3.5}, @b{adhesion} = @var{4.0}@}
05    @i{ti}["@var{a}"] = @{"@b{fl_ivory}", @b{friction} = @var{3.5}, @b{adhesion} = @var{4.0}@}
06    @i{ti}["@var{b}"] = @{"@b{fl_bright}", @b{friction} = @var{3.5}, @b{adhesion} = @var{4.0}@}
07    @i{ti}["@var{c}"] = @{"@b{fl_platinum}", @b{friction} = @var{3.5}, @b{adhesion} = @var{4.0}@}
@end example
Four floor types that the dynamic floor is composed of. They all are unified
in the @samp{friction} and @samp{adhesion} to provide smooth movement on the
stylish floor.

@example
10    @i{ti}["@var{w}"] = @{"@b{st_flat_movable}", "@var{wood}#"@}
11    @i{ti}["@var{t}"] = @{"@b{it_trigger}", "@var{trigger}#"@}
12    @i{ti}["@var{d}"] = @{"@b{st_blocker}", "@var{door}#"@}
@end example
The movable stone that will be wired, the target triggers and the doors to be
opened. All are autonamed for group retrieval from the named object repository.

@example
13    @i{ti}["@var{o}"] = @{"@b{st_oxyd}", @b{oxydcolor} = @var{OXYD_YELLOW}, @b{flavor} = "@var{a}"@}
14    @i{ti}["@var{O}"] = @{"@b{st_oxyd}", @b{oxydcolor} = @var{OXYD_WHITE}, @b{flavor} = "@var{a}"@}
@end example
A minor design aspect: selecting two unique colors for the @ref{st_oxyd}s.

@example
15    @i{ti}["@var{1}"] = @{"@b{st_panel}", @b{cluster} = @var{1}@}
16    @i{ti}["@var{2}"] = @{"@b{st_panel}", @b{cluster} = @var{2}@}
@end example
The base of the prominent all time different looking @ref{st_panel} border
design. Two tiles with panel stones assigned to two different clusters. The
engine will automatically join all neighboring stones of the same cluster to
big unified blocks. Now we just need to assign these tiles to the different
grid positions.

@example
17    @i{ti}["@var{S}"] = @{"@b{st_switch}", @b{target} = "@var{easy_mode_call}"@}
@end example
The left border switch that will just be used in easy mode. It is blocked in
line 27 to not appear in the regular mode. The target is the callback function
of lines 71 to 81.

@example
19    @var{floors}  = @{@i{ti}["@var{ }"], @i{ti}["@var{a}"], @i{ti}["@var{b}"], @i{ti}["@var{c}"]@}
20    @var{polynom} = @i{lib}.@i{math}.@i{random_vector}(@var{10}, @var{4})
@end example
Preparations for the floor design. The four floor tiles are stored in a table
for number based index access. Ten random numbers in the range 1 to 4 are
stored in a table, which we will use as polynom coefficients later on.

@example
22    function @var{myresolver}(@var{key}, @var{x}, @var{y})
34    @var{w}, @var{h} = @i{wo}(@var{myresolver}, "@var{ }", @{
@end example
Up to now we did look up the keys used in the map from our tiles repository
@samp{ti} that was the first argument of the world initialization call. But
now we use a @ref{Custom Resolver}.
The function starting in line 22 is called on every tile to be resolved. It has
the task of delivering the appropriate tile.

@example
23      if @var{key} == "@var{ }" then
24        return @var{floors}[@i{lib}.@i{math}.@i{cubic_polynomial}(@var{polynom}, @var{x}, @var{y}) % (#@var{floors}) + @var{1}]
@end example
These two lines generate the always changing floor design. For every map key
@samp{ } we calculate the cubic polynomial that is randomized due to the
coefficients. The resulting number is limited to the number of our four floors.
This number is taken as the index into our @samp{floors} table and the resulting
tile definition is returned.

@example
25      elseif    (@var{key} == "@var{#}")
26            or ((@var{key} == "@var{_}") and (@i{random}(@var{4}) == @var{1}))
27            or ((@var{key} == "@var{S}") and @i{wo}["@b{IsDifficult}"]) then
28        return @i{ti}[""..@i{random}(@var{2})]
@end example
And now we cluster the border panels. First we need to decide where to put
panels at all. The positions marked @samp{#} in the map are for sure.
Additionally we choose randomly every 4th @samp{_} position to be a panel
instead of being a water floor. Finally we replace just in difficult mode
the switch marked as @samp{S} by a panel stone. Now we need to assign to this
grid position one of the two panel cluster tiles. We simply generate a random
number out of 1 and 2. But we do need a string as the tiles key. We force Lua
to convert the number to string by concatenating an empty string @samp{""} with
the random number. Choosing the right panel variants to build up closed clusters
is done by the engine.

@example
29      else
30        return @i{ti}[@var{key}]
@end example
Finally for all other keys that need no special treatment we just take the
tile definition as stored in the tiles repository.

@example
34    @var{w}, @var{h} = @i{wo}(@var{myresolver}, "@var{ }", @{
35     -- 01234567890123456789
36       "@var{####################___________________}",
37       "@var{#                  #_____###o###_______}",
38       "@var{#   w   w t   t    #_____#d   d#_______}",
39       "@var{#     w   w t   t  #___### ### ###_____}",
...
@end example
The map uses the keys as interpreted by the custom resolver. Thus all mandatory
panel stones are marked by @samp{#} and all may be water by @samp{_}. All spaces
@samp{ } do not stand for the sahara floor definition in the tiles repository,
but are floor positions for our design floor set up in the custom resolver.
Note that even the @samp{w} marked tiles will set a design floor, as the
default floor is @samp{ }, too.

@example
51    @var{door_p} = @i{lib}.@i{math}.@i{permutation}(@var{12})
52    @var{wire_p} = @i{lib}.@i{math}.@i{permutation}(@var{12})
@end example
Now let us shuffle the trigger/door assignment and the wire distribution. We
do this by permuting 12 index numbers to be used for door and wire access.

@example
53    @var{woods} = @i{no}["@var{wood}#*"]
54    @var{triggers} = @i{no}["@var{trigger}#*"]
55    @var{doors} = @i{no}["@var{door}#*"]
@end example
Get the groups of movable stones, triggers and doors. It is essential to do this
once and to store the resulting groups as we want to index the group members.
Repeated access to the named object repository does not guarantee a stable
sorting of the result groups. Thus we operate on the stable once retrieved
and stored groups.

@example
57    for @var{j} = @var{1}, @var{12} do
58      @var{triggers}[@var{j}].@b{target} = @var{doors}[@var{door_p}[@var{j}]]
59    end
@end example
A random assignment of the triggers to the doors. Every trigger gets a random
indexed member of the door group as target. Note the alternative attribute
member access on the trigger. Instead of embracing the attribute's name in
square brackets and quoting the string constant as @samp{["target"]} the
author did prefer to write @samp{.target}. That is a legal Lua alternative
statement as long as the attribute's name is a legal Lua name (@pxref{Caveats}).

@example
61    for @var{j} = @var{1}, @var{9} do
62      @i{wo}:@b{add}(@{"@b{ot_wire}",
63              @b{anchor1} = @var{woods}[@var{wire_p}[@var{j} + @var{3}]],
64              @b{anchor2} = @var{woods}[@var{wire_p}[@var{j}%@var{3} + @var{1}]]@})
@end example
Finally we need to add the @ref{ot_wire} between our movable stones. This can
not be done within the map. We need to use the @ref{World} method
@samp{wo:add()}, which takes the two connected stones as two anchor attributes.
We select the first 3 stones of our wood group as stones to be connected with
3 other stones of the indices 4 to 12. Thus we take in every loop as the first
anchor one of the stones 4 to 12 and connect it to one of the first 3 stones by
a simple modulo operation. The first three stones now have three wires and are
finished. The last 9 stones have just one wire.

@example
65      @i{wo}:@b{add}(@{"@b{ot_wire}", @b{name} = "@var{obsolete_wire}#",
66              @b{anchor1} = @var{woods}[@var{wire_p}[@var{j} + @var{3}]],
67              @b{anchor2} = @var{woods}[@var{wire_p}[@var{j}%@var{9} + @var{4}]]@})
68    end
@end example
Now we wire these remaining 9 stones in sequence, in a closed circle. That gives
each stone 2 additional wires. We do this by connecting each of the stones 4 to
11 with its successor and finally connecting stone 12 to stone 4, what is done
by the modulo operation. This completes the level for the regular mode.
As preparation for the easy mode we do autoname these additional wires.

@example
71    function @var{easy_mode_call}(@var{is_on}, @var{sender})
72      if @var{is_on} then
73        @i{no}["@var{obsolete_wire}#*"]:@b{kill}()
@end example
Just for the easy mode we added a switch to remove and recreate the additional
wires. As we named these obsolete wires we can simply kill all of them in a
single call by applying the @samp{kill()} method to the group of these wires.

@example
73      else
74        for @var{j} = @var{1}, @var{9} do
75          @i{wo}:@b{add}(@{"@b{ot_wire}", @b{name} = "@var{obsolete_wire}#",
76             	  @b{anchor1} = @var{woods}[@var{wire_p}[@var{j} + @var{3}]],
77                @b{anchor2} = @var{woods}[@var{wire_p}[@var{j}%@var{9} + @var{4}]]@})
78        end
79      end
@end example
When the user switches off again, the wires should be recreated. That is done
by the same code as lines 65 to 68. Note that is essential that we stored and
kept the used wire permutation in the variable @samp{wire_p}.

@c ----------------- Introduction to Datatypes --------------------

@node Introduction to Datatypes
@section Introduction to Datatypes

Before describing the datatypes in detail let us look at the used common
concepts and conventions.

@menu
* Syntax and Conventions::         Abbreviations in syntax descriptions
* Value and Reference::            Basic differences of datatypes
* Polymorphism and Overloading::   Methods of Object Orientation
* Pseudo Datatypes::               Reinterpretation of datatypes
@end menu

@c ----------------- Syntax and Conventions --------------------

@node Syntax and Conventions
@subsection Syntax and Conventions

In the following subchapters we will describe the datatypes, their operators
and methods, and global functions in detail. We need some syntax and
conventions for an efficient description.

The following short names, and those derived by appending a number, do always
represent a value of the corresponding type:
@itemize @bullet
@item pos - @ref{Position}
@item obj - @ref{Object}
@item polist - @ref{PositionList}
@item group - @ref{Group}
@item cpos - constant position, a table with two numbers like @{2, 3@}
@end itemize

On syntax descriptions of datatype operators or methods we need to list allowed
argument types. Often several types are possible and you are allowed to choose
any of a list. In these cases we enlist the types enclosed by @samp{<} and
@samp{>} and separated by @samp{|}. These characters are not part of the
operator or method itself and should thus not be typed into the level code. Note
that we keep square braces @samp{[}, @samp{]} and curly braces @samp{@{},
@samp{@}} as literal Lua symbols. When these braces appear in the syntax you
need to type them in the code. E.g. the following syntax rule:

@example
result = @var{pos} + <@var{pos} | @var{obj} | @var{cpos} | @var{polist}>
@end example

allows you to write any of the following lines in your level

@example
@var{result} = @var{pos} + @var{pos}
@var{result} = @var{pos} + @var{obj}
@var{result} = @var{pos} + @var{cpos}
@var{result} = @var{pos} + @var{polist}
@end example

But a syntax rule like

@example
x = pos["x"]
@end example

requires the Lua square brackets to be coded literally. Of course you are
still free to name your position variable and the resulting value variable
whatever you like.

@c ----------------- Value and Reference --------------------

@node Value and Reference
@subsection Value and Reference

Another most important aspect of Lua data types is the difference between
values and references. Values are numbers, booleans like @samp{true} and
@samp{false}, strings and @samp{nil}. The only reference data type is the Lua
table.

Values are always constant. They can never be modified. You assign a value to
a variable. On calculations you may assign another value to the same variable.
But the original value does never get modified. That should be obvious if you
think of values like @samp{true} or numbers like @samp{7}. But it is even true
for strings like @code{"hello"}. When you append two strings you get a new
string. But the components themselves do not change. All "string modifying"
methods do return a new string with the resulting value. Thus a variable
containing the value of the original string still contains the unmodified value.

Tables are of a totally opposite nature. They represent data containers. In Lua
you are just handling references to these containers. When you add or change
a value within the container the table reference remains unmodified but the table
contents changes. Thus two variables containing both references to the same
table will afterwards both reference the same modified table.

We will denote for every new data type the character of being a value or a
reference. If you are unfamiliar to the resulting effects you may want to read
the appendix about @ref{Caveats}.

@c ----------------- Polymorphism and Overloading --------------------

@node Polymorphism and Overloading
@subsection Polymorphism and Overloading

@cindex polymorphism
You may have noticed that in many operations you can use an @ref{Object} as
a @ref{Position}. This is due to the fact that objects support most of the
position features as well. Objects are no positions, but they do speak the
same language. This feature is called @samp{polymorphism} and helps you to
simplify your code significantly. In the following subchapters you should
carefully look at the syntax to understand which types of arguments do fit in
seamlessly.

@cindex overloading
The number of usable operators is limited by Lua. Thus an addition of two data
by the @samp{+} operator causes different actions depending on the involved data
themselves. An addition of two positions results in a vectorial addition. But
the addition of two groups results in a join of the groups. This reuse of a
single operator is called @samp{overloading}.

Overloading combined with polymorphism can cause situations that are ambiguous
by design. E.g. we decided to allow the addition of a position with an object
resulting in the vectorial addition of the object's position to the first one.
At the same time we want to be able to join an object with an existing group
by usage of the @samp{+} operator. But what should be the result of an addition
of two objects? The vectorial addition of their positions, or the join of both
objects in a new group? Either makes sense and would be useful. In this case
we decided for the first possibility as the minus operation as the vectorial
difference between two objects is a very important feature. Anyway you can
always force the operation of your choice to be applied by transforming one
object either into a position or a group. Please read carefully the given
syntax rules for a clear understanding of the results.

@c ----------------- Pseudo Datatypes --------------------

@node Pseudo Datatypes
@subsection Pseudo Datatypes

Even though we introduce just the ten additional fundamental datatypes as
described in the following subchapters, the API does additionally differ
the same datatype according to its usage. E.g. a standard Lua number is used to
describe the @ref{state} of an object. Just in rare occurrences the state will
reflect a real number like the state of @ref{ot_counter}. For most objects
the state will just be one of a given set of allowed values, which happen to
be described by numbers by the API. Thus we speak of a pseudo datatype
in the case of @ref{state} values.

The API provides @ref{Common Constants} for all pseudo datatypes, all written in
upper case letters only. You should use exclusively these constants and never
their equivalent basic number or other type values. The usage of the constants
makes the level code readable and upward compatible if we ever should have the
need of changing the assigned values or transforming the pseudo datatype to
another datatype.

There is one abstract datatype that needs to be mentioned, as it uses two
different pseudo datatypes at the same time. This special case is the datatype
used to describe the @samp{direction} or @samp{orientation}. Both are
essentially the same. But we speak of @samp{orientation} if we are just
interested in enlisting the main directions by number values for the purpose of
identification. The constant values are given as @ref{orientations}.

Sometimes you need values for calculation of position offsets. In this case we
speak of a @samp{direction} and use @ref{Position} values as offset vectors.
The most common values are given as constants as listed in subchapter
@ref{direction offsets}. Note that our @samp{direction} values have no need of
being normalized to the length of 1.

A given @samp{orientation} can be transformed into a @samp{direction} value by
the conversion table @ref{ORI2DIR}.

@c ----------------- Position --------------------

@node Position
@section Position

A position is a Lua userdata type introduced by Enigma to handle world positions
as introduced in @ref{World's Shape and Coordinates}. A position is a value
and thus constant. Once a position is created it can not be modified anymore.
But you can calculate with positions by usage of operators. When you add two
position values you receive the resulting position as a new value.

In contrast to @ref{Object}s positions have an unlimited lifetime and will never
cease to exist. Thus you can store position values in global variables and
keep them as long as you need. The values are constant and will not change even
if the objects from which they have been derived have meanwhile moved to another
grid or even been killed.

Position values are not limited to valid world coordinates. Both coordinates
can take every positive or negative number and zero, too. Thus you can calculate
with positions and use them to express offsets between two other positions.

Positions are created by the @ref{Positions Repository} singleton handle,
that allows you to convert coordinates, objects, position constants into
positions. The handle allows you to retrieve existing named positions, too.
Furtheron positions are implicitly created as return values of many operations.

For task driven samples @pxref{Position Tasks}.

Let us look at the supported operators:

@menu
* Position Addition and Subtraction::     Operators @samp{+} and @samp{-}
* Position Multiplication and Division::  Operators @samp{*} and @samp{/}
* Position Sign::                         Unary Operator @samp{-}
* Position Center::                       Operator @samp{#}
* Position Comparison::                   Equality @samp{==} and Inequality @samp{~=}
* Position Concatenation::                Operator @samp{..}
* Position Coordinate Access::            Index Operators
* Position Grid Rounding::                Method @samp{grid()}
* Position Existence::                    Method @samp{exists()}
@end menu

@c ----------------- Position Addition and Subtraction --------------------

@node Position Addition and Subtraction
@subsection Position Addition and Subtraction

@table @asis
@item @b{Syntax:}
result = @i{pos} <@b{+}|@b{-}> <@i{pos} | @i{obj} | @i{cpos} | @i{polist}>

result = <@i{pos} | @i{obj} | @i{cpos} | @i{polist}> <@b{+}|@b{-}> @i{pos}

@item @b{Details:}
When a position is added to, or subtracted from another position or data
convertible to a position the result is the position value representing the
vectorial addition or difference of both arguments.

If a position is added to, or subtracted from a position list a new list is created
with the positions representing the sum or difference of the position with every
member of the supplied position list.

@item @b{Syntax Samples:}
@example
@var{newpos} = @i{po}(@var{3}, @var{4}) + @{@var{1}, @var{2}@}              -- = po(4, 6)
@var{newpos} = @var{myobject} - @i{po}(@var{1}, @var{5})
@var{newpolist} = @i{po}(@var{2}, @var{3}) + @var{NEIGHBORS_4}      -- po(1, 3) .. po(2, 4) .. po(3, 3) .. po(2, 2)
@var{newpolist} = @i{po}["@var{myfloor}#*"] - @i{po}(@var{3}, @var{0})
@end example
@end table

@c ----------------- Position Multiplication and Division --------------------

@node Position Multiplication and Division
@subsection Position Multiplication and Division

@table @asis
@item @b{Syntax:}
result = @i{pos} <@b{*}|@b{/}> @i{number}

result = @i{number} @b{*} @i{pos}

@item @b{Details:}
A scalar multiplication or division of a position vector. A position value
with both coordinate values multiplicated or divided by the given number
is returned.

@item @b{Syntax Samples:}
@example
@var{newpos} = @var{3} * @i{po}(@var{3}, @var{4})   -- = po(9, 12)
@var{newpos} = @i{po}(@var{2}, @var{3}) / @var{2}   -- = po(1, 1.5)
@end example
@end table

@c ----------------- Position Sign --------------------

@node Position Sign
@subsection Position Sign

@table @asis
@item @b{Syntax:}
result = -@i{pos}

@item @b{Details:}
An unary scalar multiplication of a position vector with @samp{-1}. A new
position value with both coordinate values multiplicated by @samp{-1} is returned.

@item @b{Syntax Samples:}
@example
@var{newpos} = -@i{po}(@var{3}, @var{4})   -- = po(-3, -4)
@end example
@end table

@c ----------------- Position Center --------------------

@node Position Center
@subsection Position Center

@table @asis
@item @b{Syntax:}
result = #@i{pos}

@item @b{Details:}
A rounding of a position vector to the center of the grid. A new position value
with coordinates of the center of the containing grid position is returned.

@item @b{Syntax Samples:}
@example
@var{newpos} = #@i{po}(@var{3}, @var{4})   -- = po(3.5, 4.5)
@end example
@end table

@c ----------------- Position Comparison --------------------

@node Position Comparison
@subsection Position Comparison

Equality and Inequality.

@table @asis
@item @b{Syntax:}
result = @i{pos1} <==|~=> @i{pos2}

@item @b{Details:}
A comparison of two position values. Two position values are equal if both
coordinates are equal. Otherwise they are unequal. If you want to know whether
two positions point to the same grid, you may want to round both position prior
comparison. You can round either to the center or to the grid by usage of
the position operator @samp{#} or the method @samp{grid()}.

@item @b{Syntax Samples:}
@example
@var{bool} = @i{po}(@var{3}, @var{4}) == @i{po}(@{@var{3}, @var{4}@})  -- = true
@var{bool} = @i{po}(@var{3}, @var{4}) == @i{po}(@var{4}, @var{3})    -- = false
@var{bool} = @i{po}(@var{3}, @var{4}) ~= @i{po}(@var{4}, @var{3})    -- = true
@end example
@end table

@c ----------------- Position Concatenation --------------------

@node Position Concatenation
@subsection Position Concatenation

@table @asis
@item @b{Syntax:}
result = @i{pos1} .. <@i{pos2} | @i{polist}>

result = <@i{pos1} | @i{polist}> .. @i{pos2}

@item @b{Details:}
Concatenates two positions or a position with an existing @ref{PositionList} to a
new PositionList containing all positions in the given order.  Note that this
operation is associative, that means it does not matter if you use braces in
multiple concatenations or not.

@item @b{Syntax Samples:}
@example
@var{newpolist} = @i{po}(@var{3}, @var{4}) .. @i{po}(@var{4}, @var{4})
@end example
@end table

@c ----------------- Position Coordinate Access --------------------

@node Position Coordinate Access
@subsection Position Coordinate Access

@table @asis
@item @b{Syntax:}
result = @i{pos}["x"]

result = @i{pos}["y"]

result1, result2 = @i{pos}:xy()

@item @b{Details:}
The single coordinates of a position can be read anytime. You can retrieve
single coordinates by Lua square bracket index access. Of course you can use
the Lua alternative dot index access syntax, too (see examples). If you want
to evaluate both coordinates, you can make use of the method @samp{xy()}, that
returns both numbers at once in a Lua multiple assignment.

@item @b{Syntax Samples:}
@example
@var{number} = @i{po}(@var{3}, @var{4})["@b{x}"]            -- = 3
@var{number} = @i{po}(@var{3}, @var{4}).@b{x}               -- = 3
@var{number} = @i{po}(@var{3}, @var{4})["@b{y}"]            -- = 4
@var{number} = @i{po}(@var{3}, @var{4}).@b{y}               -- = 4
@var{number1}, @var{number2} = @i{po}(@var{3}, @var{4}):@b{xy}()  -- = 3, 4
@end example
@end table

@c ----------------- Position Grid Rounding --------------------

@node Position Grid Rounding
@subsection Position Grid Rounding

@table @asis
@item @b{Syntax:}
result = @i{pos}:grid()

@item @b{Details:}
Returns a new position value that points to the upper left corner of the grid
that contains the position itself.

@item @b{Syntax Samples:}
@example
@var{newpos} = @i{po}(@var{3.2}, @var{4.7}):@b{grid}()    -- = 3, 4
@var{newpos} = @i{po}(@var{-2.4}, @var{-5.0}):@b{grid}()  -- = -3, -5
@end example
@end table

@c ----------------- Position Existence --------------------

@node Position Existence
@subsection Position Existence

@table @asis
@item @b{Syntax:}
result = @i{pos}:exists()

@item @b{Details:}
Checks if the position is part of the world and returns @samp{true} if it is
contained. Otherwise @samp{false} is returned.

Note that the @ref{Object}s @samp{exists} method reports the existence of the
object. Evaluation of @samp{po(obj):exists()} may result in @samp{false} for
existing objects. E.g. this result occurs for @ref{Item Objects} currently
being part of a player's inventory. The item exists, but is not part of the
world. But items contained in a bag placed in the world will report the same
position as the bag.

@item @b{Syntax Samples:}
@example
@var{boolean} = @i{po}(@var{3.2}, @var{4.7}):@b{exists}()
@end example
@end table


@c ----------------- Object --------------------

@node Object
@section Object

This datatype handles all world participating objects as described in
@ref{Object Layers}. When you request an object you get a reference to this
object and not the object itself. You can modify the object, but the object
can be modified by user actions, too. Deleting your reference by assigning
another value to your variable does not delete the object itself.

On the other hand an object can cease to exist due to user actions while you
still have a reference assigned to a Lua variable. Of course this reference
gets invalid when the referenced object is deleted. But such an invalid
reference, which we call a @samp{NULL} reference, is no longer fatal with the
new API. Any write accesses on such references are simply ignored. Thus you can
send messages to object references independently of their validity. Just on
read accesses you may want to prior check the existence of an object as you
would get @samp{nil} values on access of @samp{NULL} references.

Objects take attributes that you access by Lua index methods. Additional to
the object specific attributes you are free to store your own custom
attributes on any object. Custom attributes are any indices starting with an
underscore @samp{_} as prefix to their name.

The real world objects are created by assigning a tile declaration to
a @ref{World} position. You retrieve a corresponding object reference either
by the @ref{NamedObjects} repository, by @ref{Functions} or other methods that
return single object references.

Objects provide most methods of a @ref{Position} and can in most cases be
directly used as a position without explicit conversion. Just special methods
like existence differ on both datatypes. Of course all objects placed in the
world are limited to positions within the world. But be aware that portable
@ref{Item Objects} can well be part of a player's inventory and thus report a
position outside of the world. Actors will always report positions rounded to
the containing grid. This feature is legacy. As Lua code is anyway inappropriate
to handle actor movements we maintained this rounding feature.

Objects support standard set operators of @ref{Group}s, too, as long as one
operand is a group and the other an object.

For task driven samples @pxref{Object Tasks} and @ref{Attribute Tasks}.

@menu
* Object Attribute Access::           Index Operators @samp{[]}
* Object Messaging::                  Method Operator @samp{:}
* Object Comparison::                 Equality @samp{==} and Inequality @samp{~=}
* Object Existence::                  Method @samp{exists()}
* Object Kill::                       Method @samp{kill()}
* Object Kind Check::                 Method @samp{kind()} and @samp{is()}
* Object Coordinate Access::          Index Operators @samp{["x"]}, @samp{["y"]}
* Object Addition and Subtraction::   Operators @samp{+}, @samp{-}
* Object Center::                     Operator @samp{#}
* Object Join::                       Operator @samp{+}
* Object Intersection::               Operator @samp{*}
* Object Difference::                 Operator @samp{-}
* Object Sound::                      Method @samp{sound()}
@end menu

@c ----------------- Object Attribute Access --------------------
@node Object Attribute Access
@subsection Object Attribute Access

@table @asis
@item @b{Syntax:}
result = @i{obj}["attributename"]

@i{obj}["attributename"] = value

@i{obj}:set(@{attributename1=value1, attributename2=value2,...@})

@item @b{Details:}
Read or write object attributes as described in the following chapters or
custom attributes. The @samp{set} method allows you to set multiple attributes
at once. Attribute writes are ignored if the object reference is invalid.
Attribute reads require a valid object reference. Otherwise they return
@samp{nil}.

@item @b{Syntax Samples:}
@example
@var{value} = @var{obj}["@b{color}"]
@var{value} = @var{obj}.@b{color}
@var{obj}["@b{color}"] = @var{BLACK}
@var{obj}.@b{color} = @var{BLACK}
@var{obj}:@b{set}(@{@b{target}=@var{mydoor}, @b{action}="@b{open}"@})
@end example
@end table

@c ----------------- Object Messaging --------------------
@node Object Messaging
@subsection Object Messaging

@table @asis
@item @b{Syntax:}
result = @i{obj}:message("msg", value)

result = @i{obj}:msg(value)

@item @b{Details:}
Send a message with a given value or @samp{nil} to the object. Every message
can be sent directly as a method with the given message name. When the object
reference is invalid the message is simply ignored.

@item @b{Syntax Samples:}
@example
@var{value} = @var{obj}:@b{message}("@b{open}")
@var{value} = @var{obj}:@b{open}()
@var{value} = @var{obj}:@b{message}("@b{signal}", @var{1})
@var{value} = @var{obj}:@b{signal}(@var{1})
@end example
@end table

@c ----------------- Object Comparison --------------------
@node Object Comparison
@subsection Object Comparison

@table @asis
@item @b{Syntax:}
result = @i{obj1} <==|~=> @i{obj2}

@item @b{Details:}
A comparison of two object values. Two object values are equal if both
reference the same, still existing world object. Otherwise they are unequal.

@item @b{Syntax Samples:}
@example
@var{bool} = @var{obj1} == @var{obj1}  -- = true
@var{bool} = @var{obj1} == @var{obj2}  -- = false, if two different objects
@var{bool} = @var{obj1} ~= @var{obj2}  -- = true, if two different objects
@end example
@end table

@c ----------------- Object Existence --------------------
@node Object Existence
@subsection Object Existence

@table @asis
@item @b{Syntax:}
result = -@i{obj}

result = @i{obj}:exists()

@item @b{Details:}
Checks whether an object reference is still valid. Returns true if the object
still exists, otherwise false is returned for @samp{NULL} object references.

@item @b{Syntax Samples:}
@example
@var{bool} = -@var{obj}
@var{bool} = @var{obj}:@b{exists}()
@end example
@end table

@c ----------------- Object Kill --------------------
@node Object Kill
@subsection Object Kill

@table @asis
@item @b{Syntax:}
@i{obj}:kill()

@item @b{Details:}
Kills the object at once. Note that you should never kill a sender object
within a callback action. If you have need of killing the sender then add
the attribute @ref{safeaction} as explained in @ref{Target - Action}.

@item @b{Syntax Samples:}
@example
@var{obj}:@b{kill}()
@end example
@end table

@c ----------------- Object Kind Check --------------------
@node Object Kind Check
@subsection Object Kind Check

@table @asis
@item @b{Syntax:}
result = @i{obj}:is("kind")

result = @i{obj}:kind()

@item @b{Details:}
These methods allow you to check or retrieve the @ref{Object Kind}.

@item @b{Syntax Samples:}
@example
@var{bool} = @var{obj}:@b{is}("@b{st_chess}")
@var{string} = @var{obj}:@b{kind}()
@end example
@end table

@c ----------------- Object Coordinate Access --------------------
@node Object Coordinate Access
@subsection Object Coordinate Access

@table @asis
@item @b{Syntax:}
result = @i{obj}["x"]

result = @i{obj}["y"]

result1, result2 = @i{obj}:xy()

@item @b{Details:}
The single position coordinates of an object can be read anytime. You can
retrieve single coordinates by Lua square bracket index access. Of course you
can use the Lua alternative dot index access syntax, too (see examples). If you
want to evaluate both coordinates, you can make use of the method @samp{xy()},
that returns both numbers at once in a Lua multiple assignment. Anyway the
coordinates of an object are read only. You can not reposition an object by
changing its coordinates.

@item @b{Syntax Samples:}
@example
@var{number} = @var{obj}["@b{x}"]
@var{number} = @var{obj}.@b{x}
@var{number} = @var{obj}["@b{y}"]
@var{number} = @var{obj}.@b{y}
@var{number1}, @var{number2} = @var{obj}:@b{xy}()
@end example
@end table

@c ----------------- Object Addition and Subtraction --------------------
@node Object Addition and Subtraction
@subsection Object Addition and Subtraction

@table @asis
@item @b{Syntax:}
result = @i{obj} <@b{+}|@b{-}> <@i{pos} | @i{obj} | @i{cpos} | @i{polist}>

result = <@i{pos} | @i{obj} | @i{cpos} | @i{polist}> <@b{+}|@b{-}> @i{obj}

@item @b{Details:}
When an object is added to or subtracted from another position or data
convertible to a position the result is the position value representing the
vectorial addition or difference of both positions.

If an object is added to or subtracted from a position list a new list is created
with the positions representing the sum or difference of the position with every
member of the supplied position list.

@item @b{Syntax Samples:}
@example
@var{newpos} = @var{obj} + @{@var{1}, @var{2}@}
@var{newpos} = @var{myobject} - @var{obj}
@var{newpolist} = @var{obj} + @var{NEIGHBORS_4}
@var{newpolist} = @i{po}["@var{myfloor}#*"] - @var{obj}
@end example
@end table

@c ----------------- Object Center --------------------
@node Object Center
@subsection Object Center

@table @asis
@item @b{Syntax:}
result = #@i{obj}

@item @b{Details:}
A rounding of an objects' position vector to the center of the grid. A new
position value with coordinates of the center of the containing grid position
is returned.

@item @b{Syntax Samples:}
@example
@var{newpos} = #@var{obj}   -- e.g. po(3.5, 4.5)
@end example
@end table

@c ----------------- Object Join --------------------
@node Object Join
@subsection Object Join

@table @asis
@item @b{Syntax:}
result = @i{obj} + @i{group}

result = @i{group} + @i{obj}

@item @b{Details:}
A new set containing the objects of the group plus the single object is returned.
The object sequence is maintained. If the object is already member of the group
the new group will contain just one object reference, namely the first one in
sequence.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @var{obj1} + @i{grp}(@var{obj2}, @var{obj3}, @var{obj1})   -- = grp(obj1, obj2, obj3)
@var{newgroup} = @i{grp}(@var{obj2}, @var{obj3}) + @var{obj1}         -- = grp(obj2, obj3, obj1)
@end example
@end table

@c ----------------- Object Intersection --------------------
@node Object Intersection
@subsection Object Intersection

@table @asis
@item @b{Syntax:}
result = @i{obj} * @i{group}

result = @i{group} * @i{obj}

@item @b{Details:}
A new set containing just the object itself, in case it is part of the group,
too, or an empty group returned.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @var{obj1} * @i{grp}(@var{obj1}, @var{obj2})  -- = grp(obj1)
@var{newgroup} = @i{grp}(@var{obj2}) * @var{obj1}         -- = grp()
@end example
@end table

@c ----------------- Object Difference --------------------
@node Object Difference
@subsection Object Difference

@table @asis
@item @b{Syntax:}
result = @i{obj} - @i{group}

result = @i{group} - @i{obj}

@item @b{Details:}
In the first case a new set containing just the object itself, if it is not part
of the group, too, or an empty group returned. In the second case the new group
contains all members of the old group without the object. The sequence of
objects remains untouched.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @var{obj1} - @i{grp}(@var{obj2}, @var{obj1})  -- = grp()
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}) - @var{obj1}  -- = grp(obj2)
@end example
@end table

@c ----------------- Object Sound --------------------
@node Object Sound
@subsection Object Sound

@table @asis
@item @b{Syntax:}
result = @i{obj}:sound("name", volume)

@item @b{Details:}
Play a sound of given name at the position of the object. The volume defaults
to @samp{1}.

@item @b{Syntax Samples:}
@example
@var{obj}:@b{sound}("@b{quake}")
@var{obj}:@b{sound}("@b{quake}", @var{2})
@end example
@end table


@c ----------------- Group --------------------

@node Group
@section Group

A group is a sorted set of @ref{Object}s. Every object can be contained just
in one instance in the group. In contrast to a Lua table the group is a constant
value datatype. Once you retrieved a group it can not be modified. But you can
calculate and apply operators like join, intersection and difference on
groups and generate thereby other group values as results.

Even though groups as values are long living you should be careful in keeping
a group longer than a callback evaluation. Groups contain object references and
objects can be killed. Thus a prior retrieved group may contain invalid
object references on a subsequent callback evaluation. This may be uncritical
if you just send a message to a group, but in other cases you may need to
clean the group from invalid members (see below).

You create a group by listing the contained objects as arguments to the
@samp{grp()} @ref{Functions}, by retrieving objects from the @ref{NamedObjects}
repository or as result of other methods and calculations.

As groups are constant the sequence of contained objects is stable. All
operations that generate resulting new groups maintain this sequence as far
as possible. E.g. a join of two groups takes the objects of the first group
in the given sequence and appends the additional objects of the second group
in the sequence they appear in the second group.

All group operations that return new groups clean their results from any
meanwhile invalid @samp{NULL} object references. You can use this feature
to clean a group by the function @samp{grp()}.

Any message sent to a group will be forwarded to all its members in sequence.
An attribute write access to a group results in series of attribute writes
on every group member in sequence, too.

But of course you can iterate over a group and access every member by index
access. Several special methods for common group evaluations like shuffling,
subgroup, sort, etc. are supported, too.

For task driven samples @pxref{Group Tasks}.

@menu
* Group Messaging::                  Method Operator @samp{:}
* Group Attribute Write::            Index Operators @samp{[]}
* Group Comparison::                 Equality @samp{==} and Inequality @samp{~=}
* Group Length::                     Operator @samp{#}
* Group Member Access::              Index Operators @samp{[]}
* Group Loop::                       @samp{for obj in group do ... end}
* Group Join::                       Operator @samp{+}
* Group Intersection::               Operator @samp{*}
* Group Difference::                 Operator @samp{-}
* Group Shuffle::                    Method @samp{shuffle()}
* Group Sorting::                    Method @samp{sort()}
* Group Subset::                     Method @samp{sub()}
* Group Nearest Object::             Method @samp{nearest()}
@end menu

@c ----------------- Group Messaging --------------------
@node Group Messaging
@subsection Group Messaging

@table @asis
@item @b{Syntax:}
result = @i{group}:message("msg", value)

result = @i{group}:msg(value)

@item @b{Details:}
Send a message with a given value or @samp{nil} to all objects in the group.
Every message can be sent directly as a method with the given message name.
When an object reference is invalid the message is simply ignored. The result
is the return value of the message to the last object in the group, or @samp{nil}
for an empty group.

You are even allowed to send a @samp{kill()} message to all objects in a group.
The objects will be killed, but the group remains filled with invalid @samp{NULL}
object references.

@item @b{Syntax Samples:}
@example
@var{value} = @var{group}:@b{message}("@b{open}")
@var{value} = @var{group}:@b{open}()
@var{value} = @var{group}:@b{message}("@b{signal}", @var{1})
@var{value} = @var{group}:@b{signal}(@var{1})
@var{value} = @var{group}:@b{kill}()
@end example
@end table

@c ----------------- Group Attribute Write --------------------
@node Group Attribute Write
@subsection Group Attribute Write

@table @asis
@item @b{Syntax:}
@i{group}["attributename"] = value

@i{group}:set(@{attributename1=value1, attributename2=value2,...@})

@item @b{Details:}
Set attributes as described in the following chapters or custom attributes on
all objects of the group. The @samp{set} method allows you to set multiple
attributes at once. Attribute writes are ignored if an object reference is
invalid. Attribute read on groups in not allowed - the group index read is
overloaded as a group member access.

@item @b{Syntax Samples:}
@example
@var{group}["@b{color}"] = @var{BLACK}
@var{group}.@b{color} = @var{BLACK}
@var{group}:@b{set}(@{@b{target}=@var{mydoor}, @b{action}="@b{open}"@})
@end example
@end table

@c ----------------- Group Comparison --------------------
@node Group Comparison
@subsection Group Comparison

@table @asis
@item @b{Syntax:}
result = @i{group1} <==|~=> @i{group2}

@item @b{Details:}
A comparison of two groups. Two groups are equal if both contain the same set
of objects independent of their sequence within both groups. Otherwise they are
unequal.

@item @b{Syntax Samples:}
@example
@var{bool} = @i{grp}(@var{obj1}, @var{obj2}) == @i{grp}(@var{obj2}, @var{obj1})  -- = true
@var{bool} = @i{grp}(@var{obj1}, @var{obj2}) == @i{grp}(@var{obj1}, @var{obj3})  -- = false, if different object contents
@var{bool} = @i{grp}(@var{obj1}) ~= @i{grp}(@var{obj2}, @var{obj1})        -- = true, if different object contents
@end example
@end table

@c ----------------- Group Length --------------------
@node Group Length
@subsection Group Length

@table @asis
@item @b{Syntax:}
result = #@i{group}

@item @b{Details:}
Number of objects contained in the group. Invalid @samp{NULL} object references
are counted, too.

@item @b{Syntax Samples:}
@example
@var{number} = #@i{grp}(@var{obj1}, @var{obj2})         -- = 2
for @var{i} = @var{1}, #@var{group} do @var{obj} = @var{group}[@var{i}] ... end
@end example
@end table

@c ----------------- Group Member Access --------------------
@node Group Member Access
@subsection Group Member Access

@table @asis
@item @b{Syntax:}
result = @i{group}[@i{index}]

result = @i{group}[@i{obj}]

@item @b{Details:}
An index like read access with an index number between 1 and #@i{group} returns
the object in the related group sequence position. Negative indices between
-#@i{group} and -1 give the same objects. Thus you can always access the last
object at index -1. All other index positions return an invalid @samp{NULL}
object - not @samp{nil} as tables do! Thus you are always able to send messages
to returned object references.

An index like read access with an object as index returns the sequence position
number, the number index, of the object if it is contained in the group or
@samp{nil} if it is not contained.

@item @b{Syntax Samples:}
@example
@var{object} = @i{grp}(@var{obj1}, @var{obj2})[2]     -- = obj2
@var{object} = @i{grp}(@var{obj1}, @var{obj2})[-1]    -- = obj2
@var{object} = @i{grp}(@var{obj1}, @var{obj2})[0]     -- = NULL object
for @var{i} = @var{1}, #@var{group} do @var{obj} = @var{group}[@var{i}] ... end
@var{number} = @i{grp}(@var{obj1}, @var{obj2})[@var{obj2}]  -- = 2
@var{number} = @i{grp}(@var{obj1}, @var{obj2})[@var{obj3}]  -- = nil
@end example
@end table

@c ----------------- Group Loop --------------------
@node Group Loop
@subsection Group Loop

@table @asis
@item @b{Syntax:}
for @i{obj} in @i{group} do ... end

@item @b{Details:}
Looping over all objects contained in a group. The loop occurs in the sequence
of the contained objects and includes all objects, even invalid @samp{NULL}
object references.

@item @b{Syntax Samples:}
@example
for @var{obj} in @var{group} do @var{obj}:@b{toggle}() end
@end example
@end table


@c ----------------- Group Join --------------------
@node Group Join
@subsection Group Join

@table @asis
@item @b{Syntax:}
result = @i{group} + <@i{obj}|@i{group}>

result = <@i{obj}|@i{group}> + @i{group}


@item @b{Details:}
A new set containing any object of both arguments just once, is returned. The
object sequence is maintained. If an object is member of both arguments the new
group will contain just one object reference, namely the first one in sequence.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @var{obj1} + @i{grp}(@var{obj2}, @var{obj3}, @var{obj1})   -- = grp(obj1, obj2, obj3)
@var{newgroup} = @i{grp}(@var{obj2}, @var{obj3}) + @i{grp}(@var{obj1}, @var{obj3})   -- = grp(obj2, obj3, obj1)
@end example
@end table

@c ----------------- Group Intersection --------------------
@node Group Intersection
@subsection Group Intersection

@table @asis
@item @b{Syntax:}
result = <@i{obj}|@i{group}> * @i{group}

result = @i{group} * <@i{obj}|@i{group}>

@item @b{Details:}
A new set containing just those objects that are contained in both arguments. The
objects are returned in the same sequence as they appear in the first argument.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @var{obj1} * @i{grp}(@var{obj2}, @var{obj1})  -- = grp(obj1)
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}) * @i{grp}(@var{obj2}, @var{obj1}, @var{obj3})  -- = grp(obj1, obj2)
@end example
@end table

@c ----------------- Group Difference --------------------
@node Group Difference
@subsection Group Difference

@table @asis
@item @b{Syntax:}
result = <@i{obj}|@i{group}> - @i{group}

result = @i{group} - <@i{obj}|@i{group}>

@item @b{Details:}
A new set containing just those objects of the first argument, that are not
contained in the second argument is returned. The sequence of the objects
in the new group is the same as in the first argument.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @var{obj1} - @i{grp}(@var{obj2}, @var{obj1})  -- = grp()
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}) - @i{grp}(@var{obj2}, @var{obj4})  -- = grp(obj1, obj3)
@end example
@end table

@c ----------------- Group Shuffle --------------------
@node Group Shuffle
@subsection Group Shuffle

@table @asis
@item @b{Syntax:}
result = @i{group}:shuffle()

@item @b{Details:}
Returns a new group with the same objects in another random sequence. Note that
all invalid @samp{NULL} object references are removed in the resulting group by
this method call.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2})
@end example
@end table

@c ----------------- Group Sorting --------------------
@node Group Sorting
@subsection Group Sorting

@table @asis
@item @b{Syntax:}
result = @i{group}:sort("circular")

result = @i{group}:sort("linear" <, @i{direction}>)

result = @i{group}:sort()

@item @b{Details:}
Returns a new group with the same objects in another sorted sequence. Note that
all invalid @samp{NULL} object references are removed in the resulting group by
this method call.

With a string argument @code{"circular"} the objects are arranged around their
center by their angle. The distance from this center has no influence.

With a string argument @code{"linear"} the objects are arranged in a linear
fashion. You either supply a @ref{Position} as sorting direction vector, or
the first two objects of the group will define the sorting direction as default.

If no sorting argument is supplied the objects will be sorted by their name
in lexical order.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}):sort("linear", po(2,1))
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}):sort("circular")
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}):sort()
@end example
@end table

@c ----------------- Group Subset --------------------
@node Group Subset
@subsection Group Subset

@table @asis
@item @b{Syntax:}
result = @i{group}:sub(@i{number})

result = @i{group}:sub(@i{start}, @i{end})

result = @i{group}:sub(@i{start}, -@i{number})

@item @b{Details:}
Returns a new group with a subset of the contained objects. The sequence of
objects in the new group is identical to the sequence in the originating group.
Note that all invalid @samp{NULL} object references are removed in the resulting
group by this method call after determination of the subset candidate objects.

With a number as argument you determine the number of requested objects. A
positive number returns the amount of objects starting with the first object
of the group. Whereas a negative number returns objects from the tail of the
group. In this case the absolute value determines the number of selected objects
counted backwards from the last one in sequence.

With two positive numbers as arguments you define the first and the last sequence
index of the requested subset.

With two numbers, but the second one being negative, you define the first object
with the first number and with the absolute value of the second number you define
the amount of objects you want in your subset.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}, @var{obj4}):sub(2)     -- = grp(obj1, obj2)
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}, @var{obj4}):sub(-2)    -- = grp(obj3, obj4)
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}, @var{obj4}):sub(2, 4)  -- = grp(obj2, obj3, obj4)
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}, @var{obj4}):sub(2, -2) -- = grp(obj2, obj3)
@end example
@end table

@c ----------------- Group Nearest Object --------------------
@node Group Nearest Object
@subsection Group Nearest Object

@table @asis
@item @b{Syntax:}
result = @i{group}:nearest(@i{obj})

@item @b{Details:}
Returns the object contained in the group that is nearest to the given reference
object. The distances are calculated exactly without rounding actor positions.
In case two objects have the same distance from the reference object one is
chosen by chance as the result.

@item @b{Syntax Samples:}
@example
@var{newobject} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3}):nearest(@var{obj4})
@end example
@end table


@c ----------------- NamedObjects --------------------

@node NamedObjects
@section NamedObjects

The datatype NamedObjects is used by just one object, the singleton repository
of named objects. Whenever you name an object, @pxref{Object Naming}, this
repository registers its name and allows you to retrieve the object lateron
by providing its name.

Being a singleton you can not create new NamedObjects. The singleton is stored
at the global variable @samp{no} on level load.

@menu
* NamedObjects Repository Request::  Index Operator @samp{[]} read
* NamedObjects Object Naming::       Index Operator @samp{[]} write
@end menu

@c ----------------- NamedObjects Repository Request --------------------
@node NamedObjects Repository Request
@subsection NamedObjects Repository Request

@table @asis
@item @b{Syntax:}
result = no["@i{name}"]

@item @b{Details:}
Request of one or several objects from the repository. If no wildcard
characters are used in the name an @ref{Object} value is returned. It is either
the unique object with the given name, or an invalid @samp{NULL} object if no
object exists with the given name.

If the requested name contains a wildcard character, either an asterisk @samp{*}
or a question mark @samp{?}, a @ref{Group} containing all objects with matching
names is returned. An asterisk matches zero, one or several arbitrary characters.
A question mark matches a single arbitrary character. Both wildcard characters
can be used anywhere in the string and in arbitrary multiplicity. Anyway the
result is always returned as a @ref{Group}. The group may contain multiple
objects, just a single object, or even no objects at all when no existing object
matches your name pattern.

@item @b{Syntax Samples:}
@example
@var{obj} = @i{no}["@var{mydoor}"]       -- exact name match
@var{group} = @i{no}["@var{mydoors#*}"]  -- any suffix
@var{group} = @i{no}["@var{mydoor?}"]    -- just one char suffix
@var{group} = @i{no}["@var{mydoors?#*}"] -- matches e.g. "mydoorsA#123435", "mydoorsB#1213"
@end example
@end table

@c ----------------- NamedObjects Object Naming --------------------
@node NamedObjects Object Naming
@subsection NamedObjects Object Naming

@table @asis
@item @b{Syntax:}
no["@i{name}"] = @i{obj}

@item @b{Details:}
Index write accesses to the singleton allow you to name or rename objects. Note
that you can name or rename objects by @ref{Object} attribute writes, too.
The object's name is stored as attribute @code{"name"}. Both ways of naming
an object are totally equivalent.

@item @b{Syntax Samples:}
@example
@i{no}["@var{myobject}"] = @var{obj}
@end example
@end table


@c ----------------- PositionList --------------------

@node PositionList
@section PositionList

A PositionList is a sorted set, known as list, of @ref{Position}s. Like a
@ref{Group} this container is a constant datatype, that can not be modified. But
you can easily compose new position lists by concatenation of existing lists and
single positions.

An important difference to a group is the ability of a position list to store
a position multiple times at different locations in its sequence. Thus a
position list is suited to describe paths, even paths that are closed or
cross itself.

As @ref{Position}s are values that never become invalid, position lists once
created will never change or get invalid. They are true values themselves. Thus
they are the containers of choice for longterm storage.

You can easily create a position list by @ref{PositionList Conversion}, which
is featured by the @ref{Positions Repository} singleton and allows you to
transform a group into a position list by the simple expression
@samp{po(group)}. On the other hand you can retrieve all @ref{Object}s of a
basic kind located along a position list path by @ref{Functions} like
@samp{st(polist)}, @samp{it(polist)} and @samp{fl(polist)}.

As a unique floor object is guaranteed to be on every grid position, you can
convert a given list of unique grid positions to a group of floors without
loosing any information. Now you can apply all group methods on the floors, like
shuffling, sorting, subgrouping, etc.. Finally you can convert the resulting
group back to a persistent position list. Of course the conversions preserve
the sequence of members.

Some additional position specific operators are supplied to allow simple
translations and stretchings of position lists.

Note that in contrast to a @ref{Group} this datatype can not directly be stored
in an @ref{Object} attribute. But you can always store a @ref{Group} of floors
in an attribute. In case floors can be destroyed you may need to name these
floors as discussed in @ref{Named Positions}.

For task driven samples @pxref{Named Positions Tasks}.

@menu
* PositionList Comparison::          Equality @samp{==} and Inequality @samp{~=}
* PositionList Length::              Operator @samp{#}
* PositionList Member Access::       Index Operators @samp{[]}
* PositionList Concatenation::       Operator @samp{..}
* PositionList Translation::         Operators @samp{+} and @samp{-}
* PositionList Stretching::          Operators @samp{*} and @samp{/}
@end menu

@c ----------------- PositionList Comparison --------------------
@node PositionList Comparison
@subsection PositionList Comparison

@table @asis
@item @b{Syntax:}
result = @i{polist1} <==|~=> @i{polist2}

@item @b{Details:}
A comparison of two position lists. Two position lists are equal if both contain
the same positions in the identical sequence. Otherwise they are unequal.

@item @b{Syntax Samples:}
@example
@var{bool} = (@i{po}(@var{2},@var{3}).. @i{po}(@var{5},@var{7})) == (@i{po}(@var{2},@var{3}) .. @i{po}(@var{5},@var{7}))  -- = true
@var{bool} = (@i{po}(@var{2},@var{3}).. @i{po}(@var{5},@var{7})) == (@i{po}(@var{4},@var{0}) .. @i{po}(@var{5},@var{7}))  -- = false, different positions
@var{bool} = (@i{po}(@var{2},@var{3}).. @i{po}(@var{5},@var{7})) == (@i{po}(@var{5},@var{7}) .. @i{po}(@var{2},@var{3}))  -- = false, different sequence
@end example
@end table

@c ----------------- PositionList Length --------------------
@node PositionList Length
@subsection PositionList Length

@table @asis
@item @b{Syntax:}
result = #@i{polist}

@item @b{Details:}
Number of positions contained in the list.

@item @b{Syntax Samples:}
@example
@var{number} = #(@i{po}(@var{2},@var{3}) .. @i{po}(@var{5},@var{7})) -- = 2
for @var{i} = @var{1}, #@var{polist} do @var{pos} = @var{polist}[@var{i}] ... end
@end example
@end table

@c ----------------- PositionList Member Access --------------------
@node PositionList Member Access
@subsection PositionList Member Access

@table @asis
@item @b{Syntax:}
result = @i{group}[@i{index}]

@item @b{Details:}
An index like read access with an index number between 1 and #@i{polist} returns
the position in the related position list position. Negative indices between
-#@i{polist} and -1 give the same positions. Thus you can always access the last
position at index -1. All other indices return a Lua @samp{nil} value like
tables.

@item @b{Syntax Samples:}
@example
@var{pos} = (@i{po}(@var{2},@var{3}) .. @i{po}(@var{5},@var{7}))[2]     -- = po(5,7)
@var{pos} = (@i{po}(@var{2},@var{3}) .. @i{po}(@var{5},@var{7}))[-1]    -- = po(5,7)
@var{pos} = (@i{po}(@var{2},@var{3}) .. @i{po}(@var{5},@var{7}))[0]     -- = nil
for @var{i} = @var{1}, #@var{polist} do @var{pos} = @var{polist}[@var{i}] ... end
@end example
@end table

@c ----------------- PositionList Concatenation --------------------
@node PositionList Concatenation
@subsection PositionList Concatenation

@table @asis
@item @b{Syntax:}
result = @i{polist1} .. <@i{pos} | @i{polist2}>

result = <@i{pos} | @i{polist1}> .. @i{polist2}

@item @b{Details:}
Concatenates two position lists or a position with a position list to a
new PositionList containing all positions in the given order. Note that this
operation is associative, that means it does not matter if you use braces in
multiple concatenations or not.

@item @b{Syntax Samples:}
@example
@var{newpolist} = @i{po}(@i{po}(@var{2},@var{3}), @i{po}(@var{5},@var{7})) .. @i{po}(@var{4}, @var{4}) -- = (2,3),(5,7),(4,4)
@end example

@item @b{Caveats:}
Note that due to the value nature of position lists the concatenation creates
a new value. This is an expensive operation. When you are collecting potentially
large number of positions in a loop, you should not concat each new candidate
to an existing position list. Avoid the creation of numerous position list
values and collect the positions in a standard Lua table. Convert this table
at the end to a position list (@xref{PositionList Conversion}).

@example
@var{result} = @{@}
for @var{x} = 1, 200 do
    table.insert(@var{result}, @i{po}(@var{x}, 17))
end
return @i{po}(@var{result})
@end example

@end table

@c ----------------- PositionList Translation --------------------
@node PositionList Translation
@subsection PositionList Translation

@table @asis
@item @b{Syntax:}
result = @i{polist} <@b{+}|@b{-}> <@i{pos} | @i{obj} | @i{cpos}>

result = <@i{pos} | @i{obj} | @i{cpos}> <@b{+}|@b{-}> @i{polist}

@item @b{Details:}
If a position or data convertible to a position is added to or subtracted from
a position list a new list is created with the positions representing the sum or
difference of the position with every member of the position list. In total the
position list is shifted by the position as a vector.

@item @b{Syntax Samples:}
@example
@var{newpolist} = @i{po}(@var{2}, @var{3}) + @var{NEIGHBORS_4}      -- po(1, 3) .. po(2, 4) .. po(3, 3) .. po(2, 2)
@var{newpolist} = @i{po}["@var{myfloor}#*"] - @i{po}(@var{3}, @var{0})
@end example
@end table

@c ----------------- PositionList Stretching --------------------
@node PositionList Stretching
@subsection PositionList Stretching

@table @asis
@item @b{Syntax:}
result = @i{polist} @b{*} @i{number}

result = @i{number} @b{*} @i{polist}

@item @b{Details:}
A scalar multiplication or division of all positions in a position list. All
position values are multiplicated or divided by the given number in both
coordinate values. In total the position list is stretched by a scalar factor.

@item @b{Syntax Samples:}
@example
@var{newpolist} = @var{2} * @var{NEIGHBORS_4}              -- = po(9, 12)
@var{newpolist} = (@i{po}(@var{2},@var{4}) .. @i{po}(@var{6},@var{7})) * @var{1/2}   -- = (1, 2), (3, 3.5)
@end example
@end table


@c ----------------- Positions Repository --------------------

@node Positions Repository
@section Positions Repository

The Positions datatype is just used by a single instance, the singleton
repository of named positions. Besides the management of named positions it
provides useful conversions of other datatypes to position based types.

Being a singleton you can not create a new Positions Repository. The singleton
that is available on level load is stored at the global variable @samp{po}.

The position repository is an extension of the @ref{NamedObjects} repository.
Whenever you name an object, @xref{Object Naming}, this repository registers
its name and allows you to retrieve lateron the current object's position by
providing its name. But even when a floor object gets killed, its position
entry remains stored as @ref{Named Positions}. Of course you can name positions
yourself, but positions of existing named objects will always override plane
named positions on name clashes.

For task driven samples @pxref{Named Positions Tasks}.

@menu
* Positions Repository Request::  Index Operator @samp{[]} read
* Positions Repository Storage::  Index Operator @samp{[]} write
* Position Conversion::           Function @samp{po()}
* PositionList Conversion::       Function @samp{po()}
@end menu

@c ----------------- Positions Repository Request --------------------
@node Positions Repository Request
@subsection Positions Repository Request

@table @asis
@item @b{Syntax:}
result = po["@i{name}"]

@item @b{Details:}
Request of one or several positions from the repository. If no wildcard
characters are used in the name the @ref{Position} value of the unique object
with the given name, if existent, is returned. It no object exists with the
name, the last position stored with the same name is returned. If no position
exists the value @samp{nil} is returned.

If the requested name contains a wildcard character, either an asterisk @samp{*}
or a question mark @samp{?}, a @ref{PositionList} containing all positions with
matching names is returned. An asterisk matches zero, one or several arbitrary
characters. A question mark matches a single arbitrary character. Both wildcard
characters can be used anywhere in the string and in arbitrary multiplicity.
Anyway the result is always returned as a @ref{PositionList}. The list may
contain multiple positions, just a single position, or even no position at all
when no existing position matches your name pattern.

@item @b{Syntax Samples:}
@example
@var{pos} = @i{po}["@var{mydoor}"]        -- exact name match
@var{polist} = @i{po}["@var{mydoors#*}"]  -- any suffix
@var{polist} = @i{po}["@var{mydoor?}"]    -- just one char suffix
@var{polist} = @i{po}["@var{mydoors?#*}"] -- matches e.g. "mydoorsA#123435", "mydoorsB#1213"
@end example
@end table

@c ----------------- Positions Repository Storage --------------------
@node Positions Repository Storage
@subsection Positions Repository Storage

@table @asis
@item @b{Syntax:}
po["@i{name}"] = @i{obj}

@item @b{Details:}
Index write accesses to the singleton allows you to name or rename positions.
Note that can not assign a new position to a name that currently references
an existing @ref{Object}. Such write access are silently ignored.

@item @b{Syntax Samples:}
@example
@i{po}["@var{mypos}"] = @var{pos}
@end example
@end table

@c ----------------- Position Conversion --------------------
@node Position Conversion
@subsection Position Conversion

@table @asis
@item @b{Syntax:}
result = po(<@i{obj} | @i{pos} | @{@var{x}, @var{y}@} | @var{x}, @var{y} >)

@item @b{Details:}
Converts its argument to a new position value.

@item @b{Syntax Samples:}
@example
@var{pos} = @i{po}(@var{pos2})
@var{pos} = @i{po}(@var{obj})
@var{pos} = @i{po}(@{@var{2}, @var{4}@})
@var{pos} = @i{po}(@var{3}, @var{7})
@end example
@end table

@c ----------------- PositionList Conversion --------------------
@node PositionList Conversion
@subsection PositionList Conversion

@table @asis
@item @b{Syntax:}
result = po(@i{group} | @{@i{pos1}, @i{pos2}, @i{pos3}@})

@item @b{Details:}
Converts the given group or table of positions to a new @ref{PositionList}
value, that contains the positions of all valid group @ref{Object}s or table
members in the same sequence.

@item @b{Syntax Samples:}
@example
@var{polist} = @i{po}(@var{group})
@var{polist} = @i{po}(@{@i{po}(@var{3}, @var{7}), @i{po}(@var{2}, @var{6})@})
@var{polist} = @i{po}(@{@})  -- an empty position list
@end example
@end table

@c ----------------- Tile and Object Declaration --------------------

@node Tile and Object Declaration
@section Tile and Object Declaration

A tile is the description of one or several objects that should be positioned
on the same grid position. A single object can be set up by a straight
object declaration, an anonymous Lua table with entries for the object kind
and all attributes. The object declaration comes in three minor variations:

@example
@{"@b{st_chess}", @b{name}="@var{jumper}", @b{color}=@var{WHITE}@}
@{"@b{st_chess_white}", "@var{jumper}", @var{_myattr}=@var{5}@}
@{"@b{ac_marble}", 0.2, 0.6, @b{name}="@var{blacky}"@}
@end example

The first entry, the one stored at table position @samp{1}, has always to be
the kind name of a supported Enigma object. In the first example all other
table entries are key value pairs with the key being the attribute name. The
second example uses the shortcut of specifying the name attribute value as
second table entry, that will be stored at table position @samp{2}. It has to
be a string value. The third variation, that is useful for actor declarations,
stores the grid offsets in x and y directions in the table positions @samp{2} and
@samp{3}. Of course you can not use the name attribute shortcut in the same
declaration.

These table driven object declarations are always sufficient if you just want to
set a single object at once. But tiles do often take an item or a stone besides
a floor. So we need an Enigma data type being able to handle these multiple
declarations. This is the @samp{tile} data type. It can take just one object
declaration or an arbitrary list of declarations. You convert a table object
declaration into a tile by the @ref{Tiles Repository} handle. Once you have a
tile you can concat other tiles or table object declarations to set up new
tiles.

Enigma guarantees that the objects will be set to the world in the sequence
of declarations in the tile.

@obindex fl_nil
@obindex it_nil
@obindex st_nil
@obindex nil
Even though in most cases you use object declarations and tiles to set objects
you may need in some advanced usage cases to supply such a datatype in
situations where you want to add nothing at all or even want to kill a
possibly existing object. In these cases you can supply one of the pseudo object
kind names @code{"fl_nil"}, @code{"it_nil"}, @code{"st_nil"} or @code{"nil"}.
While the first three pseudo kinds will kill existing objects on the given
layer, the last pseudo kind will just do nothing. It is equivalent, but more
expressive than an empty Lua table being used as an object declaration:

@example
@i{ti}["@var{D}"] = @i{cond}(@i{wo}["@b{IsDifficult"}], @{"@b{st_death}"@}, @{"@b{nil}"@})
@i{ti}["@var{S}"] = @{"@b{st_surprise}", @b{selection}=@{"@b{st_box}", "@b{st_nil}"@}@}
function @var{customresolver}(@var{key}, @var{x}, @var{y})
    if @var{key} == "@var{a}" then
        return @{"@b{nil}"@}
    elseif @var{key} == "@var{b}" then
        return @{@}
    else
        return @i{ti}[@var{key}]
    end
end
@end example

The first sample uses the pseudo to supply a valid third arguement to the
@ref{cond} function that causes no syntax error when being passed to the
world in easy mode.

The second sample uses the pseudo to kill the @ref{st_surprise} even when
no substitution stone is being set.

The last example of a @ref{Custom Resolver} provides a solution for avoiding
the change of the world on a given key in the world map. Usually you will always
set at least a floor object. But if you draw a map during runtime there is no
longer the need of setting inital floors. In cases where this can not be handled
by proper usage of default keys the pseudo kind @code{"nil"} is your friend.

For task driven samples @pxref{Tiles and World Tasks}.

@menu
* Tile concat::     Compose a new tile as concatenation of two other
@end menu

@c ----------------- Tile concat --------------------

@node Tile concat
@subsection Tile concat

@table @asis
@item @b{Syntax:}
result = @i{tile} .. <@i{tile} | @i{odecl}>

result = <@i{tile} | @i{odecl}> .. @i{tile}

@item @b{Details:}
Compose a new tile by concatenation of a tile with another tile or a table
object declaration. In a concatenated chain of tiles and object declarations
one of the first two evaluated arguments needs to be a tile as two Lua tables
do not know how to concat.

Note that Lua does evaluate the @samp{..} operator from right to left! Thus you
need either use proper braces or you need to guarantee that at least one of the
two rightmost tokens is a tile.

@item @b{Syntax Samples:}
@example
@var{newtile} = @i{ti}@{"@b{st_chess}"@} .. @{"@b{fl_sahara}"@}
@var{newtile} = @i{ti}@{"@b{st_chess}"@} .. @{"@b{fl_sahara}"@} .. @{"@b{it_cherry}"@}   -- Lua error due to right to left evaluation
@var{newtile} = (@i{ti}@{"@b{st_chess}"@} .. @{"@b{fl_sahara}"@}) .. @{"@b{it_cherry}"@} -- evaluation order fixed
@var{newtile} = @i{ti}@{"@b{st_chess}"@} .. @{"@b{fl_sahara}"@} .. @i{ti}@{"@b{it_cherry}"@} -- converted one of the two critical declarations
@end example

@end table


@c ----------------- Tiles Repository --------------------

@node Tiles Repository
@section Tiles Repository

The Tiles datatype is just used by a single instance, the singleton repository of
@ref{Tile and Object Declaration}s. Besides the management of tiles it provides
useful conversions of table based object declarations to tiles.

Being a singleton you can not create a new Tiles repository. The singleton is
stored at the global variable @samp{ti} on level load.

The repository stores tiles for given string keys. The key strings can be
of any length. Due to Lua limitations they need to be composed of printable
7-bit ASCII characters.

You can assign a tile to every key just once. A reassign causes an error. On
one hand this allows internal implementation optimization, but on the other hand
an unforeseen key reassignment is the most common level coding error that
needs to be reported.

For task driven samples @pxref{Tiles and World Tasks}.

@menu
* Tiles Storage::     Store a tile for a key
* Tiles Request::     Retrieve a tile for a key
* Tile Conversion::   Convert an object declaration into a tile
@end menu

@c ----------------- Tiles Storage --------------------

@node Tiles Storage
@subsection Tiles Storage

@table @asis
@item @b{Syntax:}
ti["@i{key}"] = <@i{tile}|@i{odecl}>

@item @b{Details:}
Index write accesses to the singleton allows you to assign a tile or an table
based object declaration, that is autoconverted to a tile, to a given key. The
key must be a unique string. Unique in the sense that you can not reassign a
new tile to key to which previously another tile has been assigned.

@item @b{Syntax Samples:}
@example
@i{ti}["@var{#}"] = @var{tile}
@i{ti}["@var{$}"] = @{"@b{st_chess}"@}
@i{ti}["@var{$}"] = @{"@b{st_switch}"@}   -- error of key reassignment
@i{ti}["@var{anykey}"] = @{"@b{st_chess}"@}
@end example
@end table


@c ----------------- Tiles Request --------------------

@node Tiles Request
@subsection Tiles Request

@table @asis
@item @b{Syntax:}
result = ti["@i{key}"]

@item @b{Details:}
Request of the tile that has been assigned to the given key. If no tile has yet
been stored for the key a Lua @samp{nil} value is returned. Note that this
tiles repository does not use wildcard characters as the named objects and
positions repositories do. The asterisk @samp{*} and question mark @samp{?} are
just keys as any other characters.

@item @b{Syntax Samples:}
@example
@var{tile} = @i{ti}["@var{#}"]
@end example
@end table

@c ----------------- Tile Conversion --------------------

@node Tile Conversion
@subsection Tile Conversion

@table @asis
@item @b{Syntax:}
result = ti(@i{odecl})

@item @b{Details:}
Converts a table based object declaration to a new tile value.

@item @b{Syntax Samples:}
@example
@var{tile} = @i{ti}(@{"@b{st_chess}"@})
@var{tile} = @i{ti}@{"@b{st_chess}"@}   -- Lua syntax equivalence
@end example
@end table


@c ----------------- World --------------------

@node World
@section World

The World datatype is just used by a single instance, another singleton object.
A reference to this singleton is stored at the Lua global variable @samp{wo} on
level load. Being a singleton you can not instantiate another World object.

But even though the singleton @samp{wo} already exists on load of a level the
world is still undefined in all aspects. From the first line of Lua code you
can access the @ref{Global Attributes}. But the world gets really set up with
the @ref{World Creation}. After this call the world has a well defined size
and is filled with an initial set of objects that you can access and modify
from this moment on.

@menu
* World Creation::        Set up world with objects
* World Tile Set::        Index Operator @samp{[]} write
* Global Attribute Set::  Index Operator @samp{[]} write
* Global Attribute Get::  Index Operator @samp{[]} read
* add::                   Add single objects to the world or an inventory
* drawBorder::            Draw a rectangular border with a tile
* drawMap::               Draw objects given by a map of tile keys
* drawRect::              Fill a complete rectangle with a tile
* world floor::           Retrieval of floor objects
* world item::            Retrieval of item objects
* shuffleOxyd::           Oxyd Shuffling Rules
* world stone::           Retrieval of stone objects
@end menu

@c ----------------- World Creation --------------------

@node World Creation
@subsection World Creation

Once all parameters have been set and all tiles have been declared it is time
to create the level world with all its objects. This is done by the following
constructor that appears in three variations.

@table @asis
@item @b{Syntax:}
width, height = @b{wo}(@i{topresolver}, @i{defaultkey}, @i{map})

width, height = @b{wo}(@i{topresolver}, @i{libmap})

width, height = @b{wo}(@i{topresolver}, @i{defaultkey}, @i{width}, @i{height})

@table @asis
@item @i{topresolver} = @code{ti} | @i{resolver} | @i{localresolver}
Every tile in the world is given by a key that needs to be resolved to its
declaration. This can be done either by the @ref{Tiles Repository} @samp{ti}, or
by given library @ref{Resolvers} or by a local @ref{Custom Resolver} function.
This argument takes the top resolver that is requested first.
@item @i{defaultkey}
A string that defines the key that should be taken as default. It is taken
if no other key is given and it is added to a tile if a floor object is
missing. The character length of this key defines the key size within the map
@item @i{map}
A table of strings. Each string describes a row of tiles by its tile keys.
If a map is given, the world size is determined from the longest string and
the number of rows.
@item @i{libmap}
A map of the library @ref{libmap}
@item @i{width}
As an argument that is given instead of a map it describes the width of the
desired world.
@item @i{height}
As an argument that is given instead of a map it describes the height of the
desired world.
@end table

@item @b{Syntax Samples:}
@example
w, h = wo(ti, "  ", 20, 13)
w, h = wo(resolver, " ", @{
       "                    ",
       ...
       "                    "@})
w, h = wo(ti, mylibmap)
@end example

@item @b{Details:}
This world constructor may just be called once. Every subsequent call causes
an error. This call sets the size of the world to fixed values that are reported
by its two return values. The world size can later on be retrieved by the world
attributes @ref{Width} and @ref{Height}, too.

A mapless world is filled with default tiles. Rows in a given map that are
shorter than others are filled with default tiles, too. Any tile that does
not define a floor object will add the floor object of the default tile.

Every key is resolved to its tile declaration via the given resolver chain.
The top resolver is given to this call as a parameter. If it is @samp{ti} the
chain consists just of one element and the tile declaration stored in the tiles
repository at the given key is taken. Otherwise the resolvers will be evaluated
as explained in @ref{Resolver Chaining}.

@end table

@c ----------------- World Tile Set --------------------
@node World Tile Set
@subsection World Tile Set

@table @asis
@item @b{Syntax:}
@b{wo}[<@i{object} | @i{position} | @i{table} | @i{group} | @i{polist}>] = @i{tile_declarations}

@item @b{Details:}
Index write accesses to an index that can be interpreted as a grid position or
a list of grid positions allows you to set one or several new objects to the
given positions according to the supplied tile declaration.

@item @b{Syntax Samples:}
@example
@i{wo}[@i{no}["@var{myobjectname}"]] = @{"@b{st_chess}"@}
@i{wo}[@i{po}(@var{3}, @var{4})] = @i{ti}["@var{x}"]
@i{wo}[@{@var{2}, @var{5}@}] = @i{ti}["@var{x}"] .. @i{ti}["@var{y}"]
@i{wo}[@i{no}["@var{floorgroup#*}"]] = @{"@b{it_burnable_oil}"@}
@i{wo}[@i{no}["@var{myobjectname}"] + @b{NEIGHBORS_4}] = @i{ti}["@var{x}"]
@end example
@end table


@c ----------------- Global Attribute Set --------------------
@node Global Attribute Set
@subsection Global Attribute Set

@table @asis
@item @b{Syntax:}
@b{wo}["attritbutename"] = value

@item @b{Details:}
Write accesses to string type indices allows you to change @ref{Global Attributes}.
Just existing attributes with write accessibility may be changed. Note that
some attributes must be set prior @ref{World Creation} to take proper affect.

@item @b{Syntax Samples:}
@example
@i{wo}["@b{ConserveLevel}"] = true
@end example
@end table


@c ----------------- Global Attribute Get --------------------
@node Global Attribute Get
@subsection Global Attribute Get

@table @asis
@item @b{Syntax:}
@var{var} = @b{wo}["attritbutename"]

@item @b{Details:}
Read accesses to string type indices allows you to retrieve @ref{Global Attributes}.
Just existing attributes with read accessibility can be read. Note that
some attributes report proper values just after @ref{World Creation}.

@item @b{Syntax Samples:}
@example
@var{var} = @i{wo}["@b{IsDifficult}"]
@end example
@end table


@c ----------------- add --------------------
@node add
@subsection add

Add @ref{Other Objects} to the world or a portable item to an inventory or
other container object.

@table @asis
@item @b{Syntax:}
@b{wo:add}(@i{tile_declarations})

@b{wo:add}(@i{target}, @i{tile_declarations})

@table @asis
@item @i{tile_declarations}
One or many other object declarations given as tiles or anonymous tables.
@item @i{target}
@samp{YIN}, @samp{YANG} or valid @ref{Object Reference}
@end table

@item @b{Syntax Samples:}
@example
wo:add(@{"ot_rubberband", anchor1="a1", anchor2="w", length=2, strength=80, threshold=0@})
wo:add(ti["r"] .. @{"ot_wire", anchor1="w1", anchor2="w2"@})
wo:add(YIN, @{"it_magicwand"@})
wo:add(no["mybag"], @{"it_magicwand"@} .. ti["h"] .. ti["c"])
@end example

@item @b{Details:}
Just @ref{Other Objects} can be directly added to the world. Just portable
@ref{Item Objects} can be added to the player's inventories @samp{YIN} and
@samp{YANG} and to @ref{it_bag}s. No other targets do currently add objects by
this method.

@end table

@c ----------------- drawBorder --------------------
@node drawBorder
@subsection drawBorder

Draw a border around a rectangle out of given tiles.

@table @asis
@item @b{Syntax:}
@b{wo:drawBorder}(@i{upperleft_edge}, @i{lowerright_edge}, <@i{tile} | @i{key}, @i{resolver}>)

@b{wo:drawBorder}(@i{upperleft_edge}, @i{width}, @i{height}, <@i{tile} | @i{key}, @i{resolver}>)

@table @asis
@item @i{upperleft_edge}
Upper left anchor position of the rectangle.
@item @i{lowerright_edge}
Lower right end position of the rectangle.
@item @i{width}
Width of the rectangle.
@item @i{height}
Height of the rectangle.
@item @i{tile}
A tile or an object declaration.
@item @i{key}
A key string to be resolved via the given resolver.
@item @i{resolver}
A resolver to be used for resolving the key to a valid tile.
@end table

@item @b{Syntax Samples:}
@example
wo:drawBorder(po(0, 0), wo["Width"], wo["Height"], ti["#"])
wo:drawBorder(no["myRectUL"], no["myRectLR"], @{"st_grate1"@})
wo:drawBorder(no["myRectUL"], no["myRectLR"], @{"fl_water"@} .. ti["X"])
wo:drawBorder(no["myRectUL"], no["myRectLR"], "x", myresolver)
@end example

@item @b{Details:}
The rectangle as four one grid thick lines is drawn with the given tile. That
means on every position of the rectangle itself an instance of every object of
the tile declaration is set. The rectangle may degenerate to a single line.

@end table

@c ----------------- drawMap --------------------
@node drawMap
@subsection drawMap

Even if the world is initialized by a map on creation of the world
(@pxref{World Creation}), it is sometime useful to
be able to draw smaller submaps either as part of the initialization or as
dynamic level changes within @ref{Callback Function}. Of course the main purpose
of @samp{drawMap} is the drawing of repeating patterns.

@table @asis
@item @b{Syntax:}

@b{wo:drawMap}(@i{resolver}, @i{anchor}, @i{ignore}, @i{map}, [@i{readdir}])

@b{wo:drawMap}(@i{resolver}, @i{anchor}, @i{libmap-map}, [@i{readdir}])

@table @asis
@item @i{subresolver}
Resolver to which unresolved requests should be forwarded. May be @samp{ti}
as the final resolver of the resolver chain.
@item @i{anchor}
The anchor position where the upper left tile of the map should be drawn.
@item @i{ignore}
A tile key string that should be ignored. This key string is mandatory, even
if it not used within the map.
@item @i{map}
A table of strings. Each string describes a row of tiles by its tile keys.
@item @i{libmap-map}
If the map used is created via @ref{libmap}, the @samp{ignore}-string can
be omitted. The map's default key will then be ignored instead.
@item @i{readdir}
An optional argument to modify the direction of the map relative to the world.
This argument can be any of the constants described in @ref{Rotating and
Mirroring Maps}.
@end table

@item @b{Syntax Samples:}
@example
wo:drawMap(ti, po(5, 7), "-", @{"abcabc"@})
wo:drawMap(ti, anchor_object, "--", @{"--##--##","##--##"@})
wo:drawMap(ti, @{12, 5@}, " ", @{"122  221"@}, MAP_ROT_CW)
@end example

@item @b{Details:}
The syntax is similar to the world creation call. But there are two essential
differences you need to be aware of. First the map is drawn in the already
existing world. Thus we need to define the position. This is done via the
anchor position, which can be an already existing object, too.

The second difference is in the definition of a tile key string for tiles in
the map that should be ignored. Remember that the world initialization requested
a default tile key string. This default is still valid. But with the given
ignore key string we can draw arbitrary shaped patterns by filling unused
grids in the map with this key.

The length of the ignore key defines the map key length. It is strongly
recommended to use the same key length as in the world map.

The rows of the supplied map are drawn from the anchor position. The rows may
be of different length and may start with ignore tile keys. The anchor must be
the position composed of the smallest x and smallest y coordinate within the
pattern.

You can use drawMap anywhere after the world creation. You are even allowed to
use it within the world creation in a resolver.

@item @b{Full Example:}
@example
01    @i{ti}["@var{ }"] = @{"@b{fl_plank}"@}
02    @i{ti}["@var{X}"] = @{"@b{st_oxyd}"@}
03    @i{ti}["@var{B}"] = @{"@b{st_passage_black}", @b{flavor}="@var{frame}"@}
04    @i{ti}["@var{W}"] = @{"@b{st_passage_white}", @b{flavor}="@var{frame}"@}
05    @i{ti}["@var{y}"] = @{"@b{it_yinyang}"@}
06    @i{ti}["@var{1}"] = @{"@b{#ac_marble_black}"@}
07    @i{ti}["@var{2}"] = @{"@b{#ac_marble_white}"@}
08
09    function @var{myresolver}(@var{key}, @var{x}, @var{y})
10        if @var{key} == "@b{w}" then
11            @i{wo}:@b{drawMap}(ti, po(x-1, y-1), "-", @{"-W-",
12                                               "WXW",
13                                               "-W-"@})
14            return @i{ti}(@{@})
15        elseif @var{key} == "@b{b}" then
16            @i{wo}:@b{drawMap}(ti, po(x-1, y-1), "-", @{"-B",
17                                               "BXB",
18                                               "-B"@})
19            return @i{ti}(@{@})
20        else
21            return @i{ti}[@var{key}]
22        end
23    end
24
25    w, h = @i{wo}(@i{myresolver}, "@var{ }", @{
26      "                    ",
27      "  b         b       ",
28      "       w       w    ",
29      "                    ",
30      "                    ",
31      "   w                ",
32      "         12      b  ",
33      "              w     ",
34      "         w          ",
35      "      b             ",
36      "   w           b    ",
37      "         b          ",
38      "                    "
39    @})
40    @i{wo}:@b{shuffleOxyd}()
@end example
@end table

@c ----------------- drawRect --------------------
@node drawRect
@subsection drawRect

Fill a rectangle with a given tile.

@table @asis
@item @b{Syntax:}
@b{wo:drawRect}(@i{upperleft_edge}, @i{lowerright_edge}, <@i{tile} | @i{key}, @i{resolver}>)

@b{wo:drawRect}(@i{upperleft_edge}, @i{width}, @i{height}, <@i{tile} | @i{key}, @i{resolver}>)

@table @asis
@item @i{upperleft_edge}
Upper left anchor position of the rectangle.
@item @i{lowerright_edge}
Lower right end position of the rectangle.
@item @i{width}
Width of the rectangle.
@item @i{height}
Height of the rectangle.
@item @i{tile}
A tile or an object declaration.
@item @i{key}
A key string to be resolved via the given resolver.
@item @i{resolver}
A resolver to be used for resolving the key to a valid tile.
@end table

@item @b{Syntax Samples:}
@example
wo:drawRect(po(0, 0), wo["Width"], wo["Height"], ti[" "])
wo:drawRect(no["myRectUL"], no["myRectLR"], @{"fl_water"@})
wo:drawRect(no["myRectUL"], no["myRectLR"], @{"fl_water"@} .. ti["#"])
wo:drawRect(no["myRectUL"], no["myRectLR"], "x", myresolver)
@end example

@item @b{Details:}
The complete rectangle is filled with the given tile. That means on every
position of the rectangle and its interior an instance of every object of
the tile declaration is set. The rectangle may degenerate to a single line.

@end table

@c ----------------- world floor --------------------
@node world floor
@subsection world floor

Retrieves the floor objects for the given position or positions.

@table @asis
@item @b{Syntax:}
result = @b{wo}:@b{fl}(<@i{pos}| @{@i{x}, @i{y}@}|@i{x}, @i{y}| @i{obj} | @i{group}| @i{polist}>)

@item @b{Details:}
This world method is identical to the global function @ref{fl}.

@end table

@c ----------------- world item --------------------
@node world item
@subsection world item

Retrieves the item objects for the given position or positions.

@table @asis
@item @b{Syntax:}
result = @b{wo}:@b{it}(<@i{pos}| @{@i{x}, @i{y}@}|@i{x}, @i{y}| @i{obj} | @i{group}| @i{polist}>)

@item @b{Details:}
This world method is identical to the global function @ref{it}.

@end table

@c ----------------- shuffleOxyd --------------------
@node shuffleOxyd
@subsection shuffleOxyd

Shuffling the color distribution of the @ref{st_oxyd} makes every level, that
is no meditation, a bit generic. On every level start the level looks a little
bit different and the user has to solve a modified level. This provides long
term amusement. Thus the call of this method is part of most levels.

Many levels just call this method without any arguments. This results in a
shuffling of all @ref{st_oxyd} that are not excluded by a @samp{noshuffle}
attribute.

But sometimes levels need to influence the shuffling, either for ensuring that
the level remains solvable, or simply to ensure fairness. Imagine a level that
has two @ref{st_oxyd}s in every corner. If by chance a user gets a distribution
where he has in each corner a pair of same colored oxyds, the level might be
trivial. Another level may have a passage that the marble can pass just a few
times. With 5 or more oxyds on each side of the passage you need to ensure that
the marble never needs to pass the passage more often than possible. Both
situations can be handled by providing proper rules as arguments to this method.

@table @asis
@item @b{Syntax:}

@b{wo:shuffleOxyd}(@i{rules})

@table @asis
@item @i{rules} = @i{rule}, @i{rule},...
No rule or as many as you like, all separated by a comma.
@item @i{rule} = @{@i{group1}, @i{group2}, @i{maxrule}, @i{minrule}, @i{circularrule}, @i{linearrule}, @i{log}@}
Each rule is a table with a subset of the listed entries. The @i{group1} entry
is mandatory. All other entries are optional and can be added in any combination.
@item @i{group1} = @i{group} | @i{objectreference} | @i{objectspecifier}
A description of oxyd objects that are part of the first rule group. Either
a group or a single object reference or a string specifier that resolves to a
single or via wildcard to several oxyd objects are legal descriptors.
@item @i{group2} = @i{group} | @i{objectreference} | @i{objectspecifier}
A description of oxyd objects that are part of the second rule group. Either
a group or a single object reference or a string specifier that resolves to a
single or via wildcard to several oxyd objects are legal descriptors.
@item @i{maxrule} = @code{max = }@i{number}
The maximum number of oxyd pairs.
@item @i{minrule} = @code{min = }@i{number}
The minimum number of oxyd pairs.
@item @i{circularrule} = @code{circular = true}
Avoid any pair of neighboring oxyds in group1. Avoid an oxyd pair of first and
last oxyd in group1, too.
@item @i{linearrule} = @code{linear = true}
Avoid any pair of neighboring oxyds in group1.
@item @i{log} = @code{log = } @ @  @code{"solution"} |@code{"count"} |@code{"all"}
Log additional information to the log stream for debugging purposes and
security checks by the level author.
@end table

@item @b{Syntax Samples:}
@example
wo:shuffleOxyd()
wo:shuffleOxyd(@{no["borderoxyds#*"]:sort("circular"), circular=true@})
wo:shuffleOxyd(@{"leftoxyds#*","rightoxyds#*", min=3@}, @{"islandoxyds#*", max=0@})
@end example

@item @b{Details:}

Any call of @samp{wo:shuffleOxyd()} must occur after all @ref{st_oxyd} have been
set. That means that it must follow the standard world initialization
(@pxref{World Creation}). As a side effect shuffleOxyd
will assign colors to all @samp{OXYD_AUTO} colored @ref{st_oxyd}.

Once called the given shuffling rules remain valid. Any further reshuffling
must be done by messages @samp{closeall} and @samp{shuffle} to one arbitrary
@ref{st_oxyd} instance. No addition of an @ref{st_oxyd} or subsequent
@samp{wo:shuffleOxyd()} calls are possible without disturbing and deleting the
given rules.

Rule based shuffling is limited to a maximum of one pair of each standard oxyd
color plus any combination of additional special fake, quake or bold oxyds
summing up to a maximum of 32 oxyds. If more than 32 oxyds or 2 or more pairs
of a single standard color are set, all oxyds will be shuffled by random
ignoring any provided rules.

There are basically two different types of rules. Those with one group and those
with two groups of oxyds (Note that group is the general API expression for
a set of oxyds and not a mathematical group). For a single group the rules apply
to the oxyd instances within this group. For two groups the rules apply to oxyd
pairs with one oxyd in the first group and the other in the second group.

E.g. @samp{@{"islandoxyds#*", max=0@}} requests that there is no pair within
this group of oxyds. Whereas @samp{@{"leftoxyds#*","rightoxyds#*", min=3@}}
requests that there are 3 different oxyd pairs, each with one oxyd out of the
leftoxyd group and the second out of the rightoxyd group.

Linear and circular rules can only be applied to a single group. They are
shortcuts for the most common rules that are applied to oxyds arranged on a
line or a circle. In both cases they avoid pairs of neighboring oxyds. They
are equivalent to @samp{n-1} res. @samp{n} rules with all possible neighboring
oxyd pairs as two groups and a rule of @samp{max=0}.

Note that you can apply several rules at once to given groups. E.g. you can
apply a minrule and a maxrule within one rule!

The shuffling process consists always of two stages. The most important first
stage generates a valid oxyd pair distribution. That means that we settle which
pairs will have the same color. But the color itself is assigned in an
independent second stage. As for the examination of given rules just the pair
distribution is relevant, we do just count and log these different distributions
ignoring the colors.

With 16 oxyds of 8 different colors and no restricting rules you have 2027025
(15 * 13 * 11 * 9 * 7 * 5 * 3) different valid distributions. Keep in mind
that useful rules should always keep hundreds or thousands of different valid
distributions for a level.

For debugging purposes you can add a log parameter to one of the rules (it does
not matter to which one). If you request the log of @samp{solution} the
pair distribution will be printed to the log stream.

In case of @samp{count} the number of different oxyd distributions will be
counted and logged. It is recommended to check the count on complex rules to
ensure that enough distributions remain for a varying game. But be careful
applying count on trivial rules. With 16 oxyds there may be as many as
2027025 distributions and it may take a standard PC up to 30 seconds to count
them - add a factor of 17*19 for 20 oxyds!

Be very, very cautious in usage of logging @samp{all}. This call tries to print
all solutions. It takes ages if there are too many solutions. First check the
count before trying to log the solutions.

@item @b{Full Example:}
@example
01    @i{wo}["@b{ConserveLevel}"] = @var{false}
02
03    @i{ti}["@var{~}"] = @{"@b{fl_water}"@}
04    @i{ti}["@var{ }"] = @{"@b{fl_plank}"@}
05    @i{ti}["@var{c}"] = @{"@b{it_crack_l}", @b{brittleness}=@var{0}@}
06    @i{ti}["@var{^}"] = @{"@b{st_oneway_n}"@}
07    @i{ti}["@var{1}"] = @{"@b{ac_marble_black}", 0, 0.5@}
08
09    @i{ti}["@var{x}"] = @{"@b{st_oxyd}", "island#"@}
10    @i{ti}["@var{y}"] = @{"@b{st_oxyd}", "left#"@}
11    @i{ti}["@var{z}"] = @{"@b{st_oxyd}", "right#"@}
12
13    w, h = @i{wo}(@i{ti}, "@var{ }", @{
14      "@var{~~x  x  x  x  x  x~~}",
15      "@var{~~                ~~}",
16      "@var{~~~~^~~~~~~~~~~^~~~~}",
17      "@var{y       ~~~~       z}",
18      "@var{~       cccc       ~}",
19      "@var{y       ~~~~       z}",
20      "@var{~       cccc       ~}",
21      "@var{y       ~~~~       z}",
22      "@var{~       cccc       ~}",
23      "@var{y       ~~~~       z}",
24      "@var{~~~~c~~~~~~~~~~c~~~~}",
25      "@var{~~                ~~}",
26      "@var{~~        1       ~~}"
27    @})
28
29    @i{wo}:@b{shuffleOxyd}(@{"@b{island#*}", @b{min}=@var{3}, @b{linear}=@var{true}@}, @{"@b{left#*}","@b{right#*}", @b{max}=@var{2}, @b{min}=@var{2}@})
@end example

This level uses 14 oxyds. The 6 oxyds in the upper row are on an island that
can not be left once the marble entered it through one of the oneways. Thus
we need 3 pairs of oxyds on this island, which are enforced by the min rule.
To avoid trivial neighboring pairs on the island, we do add a linear rule, too.
The marble can pass just three times between the left and right islands. This
allows a first look on the color oxyds with one pass and opening one pair on
each of the two following passes. Thus we limit the number of pairs by a max
rule to 2. To avoid trivial oxyd pair distributions, like two pairs on the left
and two pairs on the right side, we do add a min rule that enforces that two
shared pairs of oxyds do exist.
@end table

@c ----------------- world stone --------------------
@node world stone
@subsection world stone

Retrieves the stone objects for the given position or positions.

@table @asis
@item @b{Syntax:}
result = @b{wo}:@b{st}(<@i{pos}| @{@i{x}, @i{y}@}|@i{x}, @i{y}| @i{obj} | @i{group}| @i{polist}>)

@item @b{Details:}
This world method is identical to the global function @ref{st}.

@end table


@c ----------------- Functions --------------------

@node Functions
@section Functions

Besides all the features strongly related to a value as context and thus
implemented as operators or methods of these datatypes, a few other tasks
remain. These are either context free or take at least in one variation just a
standard Lua datatype, that does not supply a context. Thus these tasks are
implemented as simple functions.

@menu
* assert_bool::     Throws an error if a condition doesn't hold.
* assert_type::     Throws an error if a variable is not of a given type.
* cond::            A ternary operator, wrapper for if-then-else.
* etype::           An advanced function to return normal and user data types.
* fl::              Floor retrieval
* grp::             Create a group out of the argument objects
* it::              Item retrieval
* ORI2DIR::         Orientation to direction conversion
* random::          Random number generator
* st::              Stone retrieval
* usertype::        Type info for Enigma userdata types
@end menu

@c ----------------- assert_bool --------------------

@node assert_bool
@subsection assert_bool
@findex assert_bool

The function @samp{assert_bool} throws an error if a given condition doesn't hold.

@table @asis
@item @b{Syntax:}
@b{assert_bool}(@i{condition}, @i{message}, @i{level})

@table @asis
@item @i{condition}
A boolean expression or anything else. If it is @code{false} or @code{nil}, an
error will be thrown.

@item @i{message}
A string, holding the error message. If @code{message} is nil or empty, an
"anonymous assertion" will be thrown, but it's always better to provide a
meaningful error message.

@item @i{level}
@code{level} specifies the error position in the same way as does Lua's
@samp{error}-function. Default is 1.
@end table

@item @b{Syntax Samples:}
@example
@i{assert_bool}(@i{no}["@var{mystone}"]:@b{exists}(), "@var{Stone 'mystone' has disappeared.}")
@end example

@item @b{Details:}
Assertions help you to detect coding errors. They are heavily used on argument
checks of library functions and resolver implementations. As the assertions
should not lead to performance penalties during runtime they are usually just
evaluated when the level's @samp{status} is declared in the XML header element
@ref{<version>} with a value of either @code{"test"} or @code{"experimental"}.

For @code{"stable"} and @code{"released"} levels standard assert statements are
simply skipped on compilation like Lua comments. But you can enforce assert
statements to be executed even in these modes by the following pattern of
assignment and additional braces:
@example
@var{dummy} = (@i{assert_bool})(@i{no}["@var{mystone}"]:@b{exists}(), "@var{Stone 'mystone' has disappeared.}")
@end example

Similar to @ref{cond}, all side effects within the evaluation of @samp{message}
and @samp{level} will appear.

See Lua's manual for more detailed information about the @samp{error}-function.

@end table

@c ----------------- assert_type --------------------

@node assert_type
@subsection assert_type
@findex assert_type

The function @samp{assert_type} throws an error if the first argument is not of one of the
specified types.

@table @asis
@item @b{Syntax:}
@b{assert_type}(@i{var}, @i{vardescription}, @i{level}, @i{type1}, @i{type2}, ...)

@table @asis
@item @i{var}
Any kind of variable.

@item @i{vardescription}
If @samp{var} is not of one of the types @samp{type1}, @samp{type2} ...,
then an error message will be thrown which includes the actual type of
@samp{var} and the desired types. @samp{vardescription} is a string which
holds additional information for the error message. It should be a lower-case
not-too-short description of @samp{var} (a name, as it is), additional
details should be added in brackets.

@item @i{level}
@code{level} specifies the error position in the same way as does Lua's
@samp{error}-function. Can't be omitted, use @samp{1} if in doubt.

@item @i{type1}, @i{type2}, ...
A sequence of strings. If @samp{var} is none of these types, the error will
be thrown. See details below for type descriptors.
@end table

@item @b{Syntax Samples:}
@example
@i{assert_type}(@var{arg1}, "@var{mygreatfunction first argument (level width)}", @var{1}, "@b{nil}", "@b{positive integer}", "@b{position}")
@end example

@item @b{Details:}
Assertions help you to detect coding errors. They are heavily used on argument
checks of library functions and resolver implementations. As the assertions
should not lead to performance penalties during runtime they are usually just
evaluated when the level's @samp{status} is declared in the XML header element
@ref{<version>} with a value of either @code{"test"} or @code{"experimental"}.

For @code{"stable"} and @code{"released"} levels standard assert statements are
simply skipped on compilation like Lua comments. But you can enforce assert
statements to be executed even in these modes by the following pattern of
assignment and additional braces:
@example
@var{dummy} = (@i{assert_type})(@var{arg1}, "@var{myfunction first argument}", @var{1}, "@b{integer}")
@end example

Possible types are all Lua types (like @code{"nil"}, @code{"number"},
@code{"boolean"}, @code{"string"}, @code{"table"}, @code{"function"}) except
@code{"userdata"}, all Enigma-own user types (@code{"object"},
@code{"position"}, @code{"tile"}, @code{"tiles"}, @code{"group"},
@code{"world"}, @code{"polist"}, @code{"unknown"}), and
types defined inside metatables (@code{"map"} from @ref{libmap}), see
@ref{etype}. In addition, the following type descriptors are recognized:
@table @asis
@item @code{"integer"}
Any integer number (..., -2, -1, 0, 1, 2, ...)
@item @code{"positive"}
Any number which is positive and not zero.
@item @code{"non-negative"}
Any number which is not negative, i.e. which is positive or zero.
@item @code{"natural"}
Any non-negative integer number (0, 1, 2, ...).
@item @code{"positive integer"}
Any positive integer number (1, 2, 3, ...).
@item @code{"non-empty string"}
Any string other than the empty string @code{""}.
@item @code{"any table"}
If @samp{var} is a table, the @samp{_type}-attribute of its metatable will
be used as its @ref{etype}. In particular, it won't be accepted as a
@code{"table"} anymore, if this @samp{_type}-attribute exists. For example,
@example
assert_type(mytable, "large table", 1, "table")
@end example
will throw an assertion when @samp{mytable} is a @code{"map"}, although,
technically, a @code{"map"} always is a @code{"table"}. You can use
@code{"any table"} as type to allow for any table, regardless of its metatable.
@item @code{"valid object"}
Any valid object.
@end table

Similar to @ref{cond}, all side effects within the evaluation of
@samp{vardescription}, @samp{level} and any type descriptor will apply.

See Lua's manual for more detailed information about the @samp{error}-function.

@item @b{Full Example:}
@example
function paint_lawn(pos)
    assert_type(pos, "paint_lawn first argument", 2, "position", "object", "polist", "group", "table")
    if etype(pos) == "object" then
        assert_bool(-pos, "paint_lawn: Object not existing.", 2)
    end
    wo[pos] = ti["lawn"]
end
paint_lawn(no["mystone"])
paint_lawn("myotherstone")
@end example
If @samp{mystone} doesn't exist, @code{no["mystone"]} will still be of etype
@code{"object"}, an invalid object. Hence @code{assert_type} will not trigger,
but @code{assert_bool} will.

If @samp{mystone} exists, the second @samp{paint_lawn} will throw an error via
@samp{assert_type}, as @code{pos} now is a @code{"string"}. The error message
will be:
@example
Wrong type for paint_lawn first argument, is string, must be one of position,
object, polist, group, table.
@end example
@end table

@c ----------------- cond --------------------

@node cond
@subsection cond

@samp{cond} is a conditional assignment, a substitution for the ternary
@samp{?:} operator of C-like languages. Note however, that it is not an
equivalent substitution but just a workaround with some subtle side effects.

@table @asis
@item @b{Syntax:}
@b{cond}(@i{condition}, @i{iftrue}, @i{iffalse})

@table @asis
@item @i{condition}
A boolean expression.

@item @i{iftrue}
The expression to be returned if @samp{condition} is true.

@item @i{iffalse}
The expression to be returned if @samp{condition} is false.
@end table

@item @b{Syntax Samples:}
@example
@i{ti}["@var{x}"] = @i{cond}(@i{wo}["@b{IsDifficult}"], @{"@b{st_death}"@}, @i{ti}["@var{#}"])
@i{ti}["@var{D}"] = @i{cond}(@i{wo}["@b{IsDifficult"}], @{"@b{st_death}"@}, @{"@b{nil}"@})
@end example

@item @b{Details:}
@samp{cond} always evaluates both expressions @samp{iftrue} and
@samp{iffalse}, regardless of @samp{condition}. Hence,
@example
@var{mytable} = @{@var{1},@var{2},@var{3},@var{4},@var{5},@var{6},@var{7},@var{8},@var{9},@var{0}@}
@var{removed_element} = @i{cond}(@var{i} < @var{5}, @i{table}.@i{remove}(@var{mytable}, @var{i}), @i{table}.@i{remove}(@var{mytable}, @var{5}))
@end example
will always remove two elements. With @samp{i=2} the @samp{2} will be returned
but @samp{mytable} will result in @samp{@{1,3,4,5,7,8,9,0@}}, and with @samp{i=6}
you get the @samp{5} but mytable will be @samp{@{1,2,3,4,7,8,9,0@}}.

Another Enigma example that will cause errors is:
@example
@var{w},@var{h} = @i{cond}(@i{wo}["@b{IsDifficult}"], @i{wo}(@i{ti}, " ", @var{map1}), @i{wo}(@i{ti}, " ", @var{map2}))
@end example
Both, the second and the third argument will be evaluated. Thus two contradicting
attempts to create a new world will be made causing the second one to fail. Use
the following statement instead:
@example
@var{w},@var{h} = @i{wo}(@i{ti}, " ", @i{cond}(@i{wo}["@b{IsDifficult}"], @var{map1}, @var{map2}))
@end example
However, in most cases @samp{cond} is used anyway with static expressions for
@samp{iftrue} and @samp{iffalse} (e.g. strings or variables) and no side effects
will occur.

@end table

@c ----------------- etype --------------------
@node etype
@subsection etype
@findex etype

The function @samp{etype()} returns the advanced type of its argument.

@table @asis
@item @b{Syntax:}
@b{etype}(@i{var})

@table @asis
@item @i{var}
Any kind of variable.
@end table

@item @b{Syntax Samples:}
@example
@var{argtype} = @i{etype}(@var{value})
@end example

@item @b{Details:}
Lua types are @code{"nil"}, @code{"number"}, @code{"boolean"}, @code{"string"},
@code{"table"}, @code{"function"}, @code{"userdata"}, and @code{"thread"}. You
can use Lua's @samp{type}-function to query the type of any variable. However,
Enigma defines more types through various means, and these types can be queried
via @samp{etype}. @samp{etype} will return its argument's Lua type as usual,
with the following two exceptions:
@table @asis
@item @i{"userdata"}
Instead of @code{"userdata"}, Enigma's special types will be returned. These
special types are @code{"object"}, @code{"position"}, @code{"tile"},
@code{"tiles"}, @code{"group"}, @code{"world"}, @code{"polist"} and
@code{"default"}. If an unknown userdata is encountered, @code{"unknown"} will
be returned.

@item @i{"table"}
If @code{var} is a table, its metatable will be queried. If there is an entry
@samp{_type}, this entry will be used as @code{etype}. Most important examples
of this kind are @ref{libmap}-maps, @ref{Resolvers} and @ref{res.maze} with its
mazes and cells. So @samp{etype} will return @code{"map"}, @code{"resolver"},
@code{"maze"} and @code{"cell"}, too. You may access the @code{etype}-system
through @samp{_type} whenever you use metatables on your own.
@end table

@end table

@c ----------------- fl --------------------
@node fl
@subsection fl
@findex fl

The function @samp{fl()} retrieves the floor objects for the given position or
positions.

@table @asis
@item @b{Syntax:}
result = @b{fl}(<@i{pos}| @{@i{x}, @i{y}@}|@i{x}, @i{y}| @i{obj} | @i{group}| @i{polist}>)

@item @b{Details:}
If the argument describes a single position, the floor object at this position
is returned. When this single position is outside of the world an invalid
@samp{NULL} @ref{Object} reference is returned.

If the argument is either a @ref{Group} or @ref{PositionList} all floor objects
of the related positions are retrieved and added in the same sequence to a new
result group. Invalid positions will be skipped without adding an object to the
group.

In any case you can send messages to the result value.

@item @b{Syntax Samples:}
@example
@var{floor} = @i{fl}(@i{po}(@var{3}, @var{5}))
@var{floor} = @i{fl}(@{@var{3}, @var{5}@})
@var{floor} = @i{fl}(@var{3}, @var{5})
@var{floor} = @i{fl}@{@var{3}, @var{5}@}     -- by Lua syntax equivalence
@var{floor} = @i{fl}(@var{mystone})
@var{group} = @i{fl}(@i{no}["door#*"])
@var{group} = @i{fl}(@i{po}(@var{3}, @var{5})..@i{po}(@var{4}, @var{2}))
@end example

@end table

@c ----------------- grp --------------------
@node grp
@subsection grp
@findex grp

The function @samp{grp()} builds a @ref{Group} out of its argument @ref{Object}s.

@table @asis
@item @b{Syntax:}
@b{grp}(<@{@i{obj1},@i{obj2},...@}| @i{obj1},@i{obj2},... |@i{group}>)

@item @b{Details:}
Returns a new @ref{Group} that is build up by the objects listed by the
arguments. The contents objects must be either listed in a Lua table, given
as multiple single object arguments or an existing group. In all cases the
sequence of objects is maintained in the returned new group, but all invalid
@samp{NULL} objects are omitted. In case one object is listed multiple times
just the first instance will occur in the group and subsequent instances will
be omitted.

@item @b{Syntax Samples:}
@example
@var{newgroup} = @i{grp}(@var{obj1}, @var{obj2}, @var{obj3})
@var{newgroup} = @i{grp}(@{@var{obj1},@var{obj2}@})
@var{newgroup} = @i{grp}@{@var{obj1},@var{obj2}@}   -- Lua syntax equivalence
@var{newgroup} = @i{grp}@{@}            -- empty group
@var{newgroup} = @i{grp}(@var{group})       -- a copy of group cleaned of invalid @samp{NULL} objects
@end example

@end table

@c ----------------- it --------------------
@node it
@subsection it
@findex it

The function @samp{it()} retrieves the item objects for the given position or
positions.

@table @asis
@item @b{Syntax:}
result = @b{it}(<@i{pos}| @{@i{x}, @i{y}@}|@i{x}, @i{y}| @i{obj} | @i{group}| @i{polist}>)

@item @b{Details:}
If the argument describes a single position, the item object at this position
is returned. When no item is located at the given single position or this
position is outside of the world an invalid @samp{NULL} @ref{Object} reference
is returned.

If the argument is either a @ref{Group} or @ref{PositionList} all item objects
of the related positions are retrieved and added in the same sequence to a new
result group. Invalid positions or positions without items will be skipped
without adding an object to the group.

In any case you can send messages to the result value.

@item @b{Syntax Samples:}
@example
@var{item} = @i{it}(@i{po}(@var{3}, @var{5}))
@var{item} = @i{it}(@{@var{3}, @var{5}@})
@var{item} = @i{it}(@var{3}, @var{5})
@var{item} = @i{it}@{@var{3}, @var{5}@}     -- by Lua syntax equivalence
@var{item} = @i{it}(@var{mystone})
@var{group} = @i{it}(@i{no}["door#*"])
@var{group} = @i{it}(@i{po}(@var{3}, @var{5})..@i{po}(@var{4}, @var{2}))
@end example

@end table

@c ----------------- ORI2DIR --------------------
@node ORI2DIR
@subsection ORI2DIR

The table @samp{ORI2DIR[]} converts orientation values to direction values.

@table @asis
@item @b{Syntax:}
result = @b{ORI2DIR}[@var{orientation}]

@item @b{Details:}
The table has stored the proper directions values at the index positions of
the related orientations.

@item @b{Syntax Samples:}
@example
@var{direction} = @i{ORI2DIR}[NORTH]      -- N  = po(0, -1)
@var{direction} = @i{ORI2DIR}[SOUTHEAST]  -- SE = po(1,  1)
@var{direction} = @i{ORI2DIR}[NODIR]      --      po(0,  0)
@end example

@end table
@c ----------------- random --------------------
@node random
@subsection random
@findex random

The function @samp{random()} is a syntax compatible replacement for the standard
Lua function @samp{math.random()}. Both names refer to the same Enigma random
implementation.

@table @asis
@item @b{Syntax:}
result = @b{random}(<|@var{n}|@var{l},@var{u}>)

@item @b{Details:}
When called without arguments, math.random returns a pseudo-random real number
in the range [0,1). When called with a number n, math.random returns a
pseudo-random integer in the range [1,n]. When called with two arguments, l and
u, math.random returns a pseudo-random integer in the range [l,u].

The only difference from the Lua implementation is the random generator itself.
Enigma uses an own implementation that guarantees the same pseudo-random
number sequence on any operating system and any processor for a given seed.
This feature will be important for future Enigma versions and thus the
randomseed can not be modified by the level itself.

@item @b{Syntax Samples:}
@example
@var{float} = @i{random}()          -- e.g. 0.402834
@var{integer} = @i{random}(20)      -- e.g. 13
@var{integer} = @i{random}(5, 10)   -- e.g. 5
@end example

@end table
@c ----------------- st --------------------
@node st
@subsection st
@findex st

The function @samp{st()} retrieves the stone objects for the given position or
positions.

@table @asis
@item @b{Syntax:}
result = @b{st}(<@i{pos}| @{@i{x}, @i{y}@}|@i{x}, @i{y}| @i{obj} | @i{group}| @i{polist}>)

@item @b{Details:}
If the argument describes a single position, the stone object at this position
is returned. When no stone is located at the given single position or this
position is outside of the world an invalid @samp{NULL} @ref{Object} reference
is returned.

If the argument is either a @ref{Group} or @ref{PositionList} all stone objects
of the related positions are retrieved and added in the same sequence to a new
result group. Invalid positions or positions without stone will be skipped
without adding an object to the group.

In any case you can send messages to the result value.

@item @b{Syntax Samples:}
@example
@var{stone} = @i{st}(@i{po}(@var{3}, @var{5}))
@var{stone} = @i{st}(@{@var{3}, @var{5}@})
@var{stone} = @i{st}(@var{3}, @var{5})
@var{stone} = @i{st}@{@var{3}, @var{5}@}     -- by Lua syntax equivalence
@var{stone} = @i{st}(@var{myfloor})
@var{group} = @i{st}(@i{no}["cherry#*"])
@var{group} = @i{st}(@i{po}(@var{3}, @var{5})..@i{po}(@var{4}, @var{2}))
@end example

@end table

@c ----------------- usertype --------------------
@node usertype
@subsection usertype
@findex usertype

The function @samp{usertype()} returns type info for Enigma data types.

@table @asis
@item @b{Syntax:}
@b{usertype}(@i{var})

@table @asis
@item @i{var}
Any kind of variable.
@end table

@item @b{Syntax Samples:}
@example
@var{argtype} = @i{usertype}(@var{value})
@end example

@item @b{Details:}
Just for Lua type @code{"userdata"} Enigma's special type info will be returned.
These special types are @code{"object"}, @code{"position"}, @code{"tile"},
@code{"tiles"}, @code{"group"}, @code{"world"}, @code{"polist"} and
@code{"default"}. If another data type is encountered, @code{"unknown"} will
be returned.

The function @ref{etype} provides a more general type evaluation for arbitrary
data types and is partially based on this function.

@end table


@c ===================  Commons  =======================
@node Common Attributes and Messages
@chapter Common Attributes and Messages

Some attributes, messages and constants are common to many objects or even
supported by all objects. We describe them here in detail. The following
chapters will just reference them or even skip them when they are generally
supported and used in the default manner.

@menu
* Common Attributes::
* Common Messages::
* Common Constants::
* Global Attributes::
@end menu

@c ----------------- Common Attributes --------------------
@node Common Attributes
@section Common Attributes

@menu
* name::
* state::
* target::
* action::
* nopaction::
* safeaction::
* inverse::
* destination::
* friction::
* adhesion::
* checkerboard::
* rubbers::
* wires::
* fellows::
@end menu

@node name
@subsection name

The attribute of @ref{Object Naming} that allows you to name any object for
reference purposes. It is up to you to ensure the uniqueness of the names. But
the engine supports you by autonumbering names ending on a @samp{#} sign
(@pxref{Object Naming}). If you reuse an already used name the first object will
be unnamed and all name references will point to the new named object. If you
have need of naming an object you should do it with the object creation as
a few objects have need of names and will otherwise be named by the engine with
unique names.

Note that this attribute is not listed in the individual object descriptions.

@table @asis
@item @b{Type:} @ @ string
@item @b{Values:} @ @ @{a-zA-Z0-9_@}+
A sequence of characters of the given characters plus special characters as
mentioned in the text above.
@item @b{Default:} @ @ @code{nil}
Some objects will be autonamed if no name is defined.
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by all objects
@end table

@node state
@subsection state

The central attribute of any object that describes the current state of an
object in its standard life cycle. This @ref{Object State} is described by
a simple number. Most dynamic objects have just 2 states. Others may have more.
The available states are listed with each object. This universal attribute
allows common messages like @ref{toggle}, @ref{signal}, @ref{on}, @ref{off},
@ref{open}, @ref{close}.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ dependent on the individual object
Please use the given upper case constants.
@item @b{Default:} @ @ @code{0}
@item @b{Access:} @ @ read/sometimes write
While it is common to set the state attribute on object creation, it is
preferable to change the object state later on by messages.
@item @b{Support:} @ @ by all objects
@end table

@node target
@subsection target

All active objects react on being triggered by performing an action on their
targets. This attribute is part of the @ref{Target - Action} paradigm that
guarantees plugability of objects. You can either set a general @samp{target}
attribute for an object, or you can set @ref{state} dependent attributes
@samp{target_0}, @samp{target_1},... (@pxref{Object State}). They all have the
same syntax:

@table @asis
@item @b{Type:} @ @ string, object, group, tokens @ @ @xref{Object Description}
Single targets may be declared by their object name or their reference. Multiple
targets can be declared by usage of groups and tokens.
@item @b{Values:} @ @ @xref{Object Attributes}
@example
target = "myDoor"
target = myObject
target = @{"myDoor", myObject@}
target = @{grp(obj1, obj2), "myDoor", myObject@}
@end example

@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by all objects
@end table

@node action
@subsection action

All active objects react on being triggered by performing an action on their
targets. This attribute is part of the @ref{Target - Action} paradigm that
guarantees plugability of objects. You can either set a general @samp{action}
attribute for an object, or you can set @ref{state} dependent attributes
@samp{action_0}, @samp{action_1},... (@pxref{Object State}). They all have the
same syntax:

@table @asis
@item @b{Type:} @ @ string, tokens of strings @ @ @xref{Target - Action}
A single action may be declared by its message string. Multiple actions that
match multiple targets can be declared by tokens of strings.
@item @b{Values:} @ @ @xref{Object Attributes}
@example
action = "open"
action = @{"open", "turn", "toggle"@}
@end example

@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by all objects
@end table

@node nopaction
@subsection nopaction

A very special addition to the @ref{Target - Action} paradigm that allows
in case of state specific actions to deny the sending of default messages
(@pxref{Object State}).

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by all objects
@end table

@node safeaction
@subsection safeaction

A very special addition to the @ref{Target - Action} paradigm that allows
to kill the sender within the execution of the action code.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by all objects
@end table

@node inverse
@subsection inverse

An attribute that requests an inversion of the action value. It is supported by
all objects with boolean action values.

Note that this attribute is not listed in the individual object description
if the object has boolean action values.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by most objects
All objects with boolean action values will support this attribute. Additionally
some objects with other invertible action value types like orientations will
support the inversion of their attributes as stated in the individual object
descriptions.
@end table

@node destination
@subsection destination

An attribute that describes one or several destinations. It is used by objects
like @ref{it_vortex} and @ref{it_wormhole} to describe their teleporting
destination and by @ref{ac_horse} to describe its traveling path.

Note that this attribute is only supported if it is listed in the individual
description.

@table @asis
@item @b{Type:} @ @ tokens or a single position
Just a single position for a first destination is allowed. Use tokens to
define multiple destination.
@item @b{Values:} @ @ @xref{Object Attributes}
@example
destination = po(3.0, 4.7)
destination = "myFloor"
destination = myObject
destination = @{"vortex2","vortex3","vortex4"@}
po["dest1"] = po(3,4)
po["dest2"] = po(7,8)
destination = @{"dest1","dest2","myFloor"@}
@end example
Note that objects like @samp{it_wormhole} that have just a single destination
do take the first token object. Note that in contrast to @ref{target} tokens a
destination tokens argument can take named positions, too. Referencing floors
that may be destructed by bombs, cracks, floor building stones, etc. are safe
destinations, too.
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by teleporting objects
@end table

@node friction
@subsection friction

An attribute that describes the decelerating friction force on actors that are
on the floor. The friction force increases with the speed of the actor and
is decelerating for positive friction values. But friction can be set to
negative values as well what generates an accelerating force that is very
difficult to control for the player.

Besides all floors some floor covering items like @ref{it_strip},
@ref{it_meditation} may provide friction values as well to deviate from the
floor friction.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ any floating point number
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by all floor, and floor covering item objects
@end table

@node adhesion
@subsection adhesion

An attribute that describes the adhesion that allows an actor to accelerate on
a floor. Greater adhesion leads to more accelerating force at the same given
mouse speed. Adhesion can be set to negative values as well what generates an
accelerating force in the inverse direction of the mouse movement which is a
little bit difficult to control for the player.

Besides all floors some floor covering items like @ref{it_strip},
@ref{it_meditation} may provide adhesion values as well to deviate from
the floor adhesion.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ any floating point number
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by all floors, and floor covering item objects
@end table

@node checkerboard
@subsection checkerboard

An attribute that defines if a given object declaration should only be applied
on 'even' or 'uneven' grid positions. Setting this attribute to @samp{0} assures
that this object will only be set on grid positions with an even sum of
@code{x + y} grid coordinates, where as a value of @samp{1} assures that the
sum must be uneven. This way you can easily provide two different object
declarations for a tile to generate an arbitrarily shaped map of checkerboard
floors, items or stones.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ @code{0}, @code{1}
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by all floor, stone and item objects
@example
ti["c"] = ti(@{"fl_sahara", checkerboard=0@}) .. @{"fl_tigris", checkerboard=1@}
@end example
@end table

@node rubbers
@subsection rubbers

An attribute that gives you access to the @ref{ot_rubberband}s that are
currently connected to this object.

Note that this attribute is read only. You can use the rubberband references
to kill or reconnect single rubberbands. But to add new rubberbands you need
to use the world's @samp{add} method.

@table @asis
@item @b{Type:} @ @ group of @ref{ot_rubberband} objects
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read only
@item @b{Support:} @ @ by actor and stone objects
@end table

@node wires
@subsection wires

An attribute that gives you access to the @ref{ot_wire}s that are
currently connected to this stone object.

Note that this attribute is read only. You can use the wire references
to kill or reconnect single wires. But to add new wires you need
to use the world's @samp{add} method.

@table @asis
@item @b{Type:} @ @ group of @ref{ot_wire} objects
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read only
@item @b{Support:} @ @ by all stone objects
@end table

@node fellows
@subsection fellows

An attribute that gives you access to the group of all objects that are currently
connected either by an @ref{ot_rubberband} or an @ref{ot_wire}.

Note that this attribute is read only. It is just for evaluation of the current
level state. But to add new rubberbands or wires you need to use the
world's @samp{add} method.

@table @asis
@item @b{Type:} @ @ group of objects
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read only
@item @b{Support:} @ @ by actor and stone objects
@end table

@c ----------------- Common Messages --------------------
@node Common Messages
@section Common Messages

@menu
* toggle::
* nop::
* signal::
* on::
* off::
* open::
* close::
* ignite::
* heat::
* setfire::
* kill::
* sound::
* disconnect::
@end menu

@node toggle
@subsection toggle

This is the default message that is always taken if no other message is provided.
It toggles the @ref{Object State} quite independent of the very nature of the
state. Two-stated objects like switches will toggle their state form @samp{ON}
to @samp{OFF} or from @samp{OFF} to @samp{ON}. Door like objects will toggle
their state from @samp{OPEN} to @samp{CLOSED} or from @samp{CLOSED} to
@samp{OPEN}. Other objects like @ref{st_fourswitch} will turn into the next
orientation. Generally the object will toggle to its next state.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by nearly all objects which use the @samp{state} attribute
@end table

@node nop
@subsection nop

A dummy message that just does nothing: no operation. You may need it in cases
of state dependent actions to block an otherwise sent default @samp{toggle}
message (@pxref{Object State}).

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by all objects
@end table

@node signal
@subsection signal

A signal message tries to set the object to the state 0 (@samp{OFF},
@samp{CLOSED}) or state 1 (@samp{ON}, @samp{OPEN}) according to its value. This
message allows you to keep the states of an action source and a receiving object
in sync. Note that values like @samp{true}, @samp{false} and orientation values
like @samp{WEST} to @samp{NORTH} are converted to 0 and 1. This allows you to
use @samp{signal} as action message on most objects.

@table @asis
@item @b{Value:} @ @ @code{0}, @code{1}
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by nearly all objects which use the @samp{state} attribute
@end table

@node on
@subsection on

This message is just supported by objects that can be switched on and off. Just
objects in state @samp{OFF} will be switched on. An object in state @samp{ON}
remains unchanged in its state.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by objects that can be switched on and off
@end table

@node off
@subsection off

This message is just supported by objects that can be switched on and off. Just
objects in state @samp{ON} will be switched off. An object in state @samp{OFF}
remains unchanged in its state.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by objects that can be switched on and off
@end table

@node open
@subsection open

This message is just supported by door like objects that can be opened and closed.
Just objects in state @samp{CLOSED} will be opened. An object in state
@samp{OPEN} remains unchanged in its state.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by door like objects that can be opened and closed
@end table

@node close
@subsection close

This message is just supported by door like objects that can be opened and closed.
Just objects in state @samp{OPEN} will be closed. An object in state
@samp{CLOSED} remains unchanged in its state.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by door like objects that can be opened and closed
@end table

@node ignite
@subsection ignite

Sets fire to a floor if it is burnable (@pxref{Fire Spreading}) or start an
explosion or shattering of items like @ref{it_dynamite}, @ref{it_bomb} or
stones like @ref{st_ice}, @ref{st_dispenser} and many more.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by all @ref{Floor Objects} and explosive or shattering items and stones
@end table

@node heat
@subsection heat

Sets fire to a floor if it is burnable (@pxref{Fire Spreading}) or causes a
@ref{Heat-Transformation} on a floor or other objects like @ref{st_ice} that
starts melting. Some objects do react on a heat message like on an @ref{ignite}
message by explosions or shattering.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by all @ref{Floor Objects} and some other objects.
@end table

@node setfire
@subsection setfire

Sets fire to a floor if it is burnable (@pxref{Fire Spreading}).

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by all @ref{Floor Objects}
@end table

@node kill
@subsection kill

This message causes the recipient to cease to exist. You are just allowed to
kill objects that are directly part of the world. Objects owned by players,
being content part of a bag or otherwise owned by another object will refuse
this message on behalf of their owner.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by all world owned objects
@end table

@node sound
@subsection sound

This message causes the recipient to play the sound given by the first
string argument value. It is played at the position of the object. The
volume can be defined by a second number argument and defaults to @code{1.0}.

@table @asis
@item @b{Value:} @ @ string [, number]
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by all objects
@end table

@node disconnect
@subsection disconnect

This message causes the recipient to disconnect from all @ref{fellows} by
cutting all @ref{wires} and @ref{rubbers} that are connected to it.

@table @asis
@item @b{Value:} @ @ -
@item @b{Returns:} @ @ -
@item @b{Support:} @ @ by all objects
@end table


@c ----------------- Common Constants --------------------
@node Common Constants
@section Common Constants

Constants for @ref{Pseudo Datatypes}.

@menu
* state values::
* color values::
* actor controllers::
* oxyd colors::
* orientations::
* direction offsets::
* position lists::
* essentialness::
* meditation types::
* glasses abilities::
* coinslot acceptance::
* rubberband length::
* subsoil kind::
* screen scrolling::
* map read directions::
@end menu

@node state values
@subsection state values

Number constants for object attribute @ref{state}. Please choose the constant
that is appropriate for an object and do avoid using numbers.

@itemize @bullet
@item @samp{OFF} = @code{0}, all switch like objects
@item @samp{ON} = @code{1}, all switch like objects
@item @samp{CLOSED} = @code{0}, all door like objects
@item @samp{OPEN} = @code{1}, all door like objects
@item @samp{IDLE} = @code{0}, other objects in the default passive state
@item @samp{ACTIVE} = @code{1}, other objects in the active state
@item @samp{INACTIVE} = @code{2}, other objects in the inactive state
@item @samp{OXYDPAIR} = @code{2}, just by @ref{st_oxyd}
@item @samp{LIGHT} = @code{0}, by @ref{st_disco}
@item @samp{MEDIUM} = @code{1}, by @ref{st_disco}, @ref{it_crack}, @ref{it_extinguisher}
@item @samp{DARK} = @code{2}, by @ref{st_disco}
@item @samp{FLOODING} = @code{1}, by @ref{fl_water}, @ref{fl_wood}, @ref{fl_hay}, @ref{fl_rock}
@item @samp{INVISIBLE} = @code{-1}, by @ref{it_crack}
@item @samp{SMALL} = @code{0}, by @ref{it_crack}
@item @samp{LARGE} = @code{2}, by @ref{it_crack}
@item @samp{YIN} = @code{0}, by @ref{fl_yinyang} and all actors as @ref{owner} value
@item @samp{YANG} = @code{1}, by @ref{fl_yinyang} and all actors as @ref{owner} value
@item @samp{EMPTY} = @code{0}, by @ref{it_extinguisher}
@item @samp{FULL} = @code{2}, by @ref{it_extinguisher}
@item @samp{BROKEN} = @code{1}, by @ref{it_bottle}
@item @samp{BREAKING} = @code{2}, by @ref{st_quake}
@item @samp{CW} = @code{0}, clockwise, by @ref{st_rotator}
@item @samp{CCW} = @code{1}, counterclockwise, by @ref{st_rotator}
@end itemize


@node color values
@subsection color values

Number constants for attribute @ref{color}. Please choose the constant
that is appropriate for an object and do avoid using numbers. Note that objects
do support a color attribute only, if it is related to a functionality. The
color of @ref{st_oxyd} uses another enumeration scheme due to legacy reasons,
@pxref{oxyd colors}.

@itemize @bullet
@item @samp{BLACK} = @code{0}, all black/white colored objects
@item @samp{WHITE} = @code{1}, all black/white colored objects
@item @samp{BLUE} = @code{2}, by @ref{st_puzzle}
@item @samp{YELLOW} = @code{3}, by @ref{st_puzzle}
@item @samp{NOCOLOR} = @code{nil}, some objects, that exist in black, white variants,
too, like @ref{st_switch}
@end itemize

@node actor controllers
@subsection actor controllers

Number constants for actor attribute @ref{controllers}. Please choose the
constant that is appropriate for an object and do avoid using numbers.

@itemize @bullet
@item @samp{CTRL_NONE} = @code{0}, by all actors
@item @samp{CTRL_YIN} = @code{1}, by all actors
@item @samp{CTRL_YANG} = @code{2}, by all actors
@item @samp{CTRL_YINYANG} = @code{3}, by all actors
@end itemize

@node oxyd colors
@subsection oxyd colors

Number constants for @ref{st_oxyd} attribute @samp{oxydcolor}. Please choose the
constant that is appropriate for an object and do avoid using numbers.

@itemize @bullet
@item @samp{OXYD_BLUE} = @code{0}, by @ref{st_oxyd}
@item @samp{OXYD_RED} = @code{1}, by @ref{st_oxyd}
@item @samp{OXYD_GREEN} = @code{2}, by @ref{st_oxyd}
@item @samp{OXYD_YELLOW} = @code{3}, by @ref{st_oxyd}
@item @samp{OXYD_CYAN} = @code{4}, by @ref{st_oxyd}
@item @samp{OXYD_PURPLE} = @code{5}, by @ref{st_oxyd}
@item @samp{OXYD_WHITE} = @code{6}, by @ref{st_oxyd}
@item @samp{OXYD_BLACK} = @code{7}, by @ref{st_oxyd}
@item @samp{OXYD_GRAY} = @code{8}, by @ref{st_oxyd}
@item @samp{OXYD_ORANGE} = @code{9}, by @ref{st_oxyd}
@item @samp{OXYD_PINE} = @code{10}, by @ref{st_oxyd}
@item @samp{OXYD_BROWN} = @code{11}, by @ref{st_oxyd}
@item @samp{OXYD_AUTO} = @code{-1}, by @ref{st_oxyd}
@item @samp{OXYD_FAKE} = @code{-2}, by @ref{st_oxyd}
@item @samp{OXYD_QUAKE} = @code{-3}, by @ref{st_oxyd}
@item @samp{OXYD_BOLD} = @code{-4}, by @ref{st_oxyd}
@end itemize


@node orientations
@subsection orientations

Number constants for attributes @samp{orientation} or @samp{slope}. Please
choose the constant that is appropriate for an object and do avoid using numbers.

@itemize @bullet
@item @samp{RANDOMDIR} = @code{-2}, by @ref{st_mirror}
@item @samp{NODIR} = @code{-1}, by @ref{fl_slope}
@item @samp{WEST} = @code{0}, by all objects with 4 orientations
@item @samp{SOUTH} = @code{1}, by all objects with 4 orientations
@item @samp{EAST} = @code{2}, by all objects with 4 orientations
@item @samp{NORTH} = @code{3}, by all objects with 4 orientations
@item @samp{NORTHWEST} = @code{4}, by all objects with 8 orientations
@item @samp{SOUTHWEST} = @code{5}, by all objects with 8 orientations
@item @samp{SOUTHEAST} = @code{6}, by all objects with 8 orientations
@item @samp{NORTHEAST} = @code{7}, by all objects with 8 orientations
@end itemize

Just for @ref{st_mirror} another alternative orientation notation exists:

@itemize @bullet
@item @samp{BACKSLASH} = @code{0}, by @ref{st_mirror}
@item @samp{HORIZONTAL} = @code{1}, by @ref{st_mirror}
@item @samp{SLASH} = @code{2}, by @ref{st_mirror}
@item @samp{VERTICAL} = @code{3}, by @ref{st_mirror}
@end itemize

@node direction offsets
@subsection direction offsets

Position constants as vectorial direction offsets. Please choose the constant
that is appropriate for a calculation and do avoid using the trivial positions
instead.

@itemize @bullet
@item @samp{N} = @code{po(0, -1)}
@item @samp{E} = @code{po(1, 0)}
@item @samp{S} = @code{po(0, 1)}
@item @samp{W} = @code{po(-1, 0)}
@item @samp{NE} = @code{N + E}
@item @samp{NW} = @code{N + W}
@item @samp{SE} = @code{S + E}
@item @samp{SW} = @code{S + W}
@item @samp{NNE} = @code{N + NE}, by @ref{st_chess}
@item @samp{ENE} = @code{E + NE}, by @ref{st_chess}
@item @samp{ESE} = @code{E + SE}, by @ref{st_chess}
@item @samp{SSE} = @code{S + SE}, by @ref{st_chess}
@item @samp{SSW} = @code{S + SW}, by @ref{st_chess}
@item @samp{WSW} = @code{W + SW}, by @ref{st_chess}
@item @samp{WNW} = @code{W + NW}, by @ref{st_chess}
@item @samp{NNW} = @code{N + NW}, by @ref{st_chess}
@end itemize

@node position lists
@subsection position lists

Position list constants. Please choose the constant that is appropriate for a
calculation and do avoid using the trivial position lists instead.

@itemize @bullet
@item @samp{NEIGHBORS_4} = @code{W .. S .. E .. N}
@item @samp{NEIGHBORS_8} = @code{NEIGHBORS_4 .. NW .. SW ..SE .. NE}
@item @samp{NEIGHBORS_CHESS} = @code{NNE .. ENE .. ESE .. SSE .. SSW .. WSW .. WNW .. NNW}
@end itemize

@node essentialness
@subsection essentialness

Number constants for attribute @ref{essential}. Please choose the constant that
is appropriate for an object and do avoid using numbers.

@itemize @bullet
@item @samp{DISPENSABLE} = @code{0}, by all actors and @ref{it_meditation}
@item @samp{INDISPENSABLE} = @code{1}, by all actors and @ref{it_meditation}
@item @samp{PERKIND} = @code{2}, by all actors
@end itemize

@node meditation types
@subsection meditation types

Number constants for @ref{it_meditation} attribute @ref{state}. Please choose
the constant that is appropriate for an object and do avoid using numbers.

@itemize @bullet
@item @samp{MEDITATION_CALDERA} = @code{-3}, by @ref{it_meditation}
@item @samp{MEDITATION_HOLLOW} = @code{-2}, by @ref{it_meditation}
@item @samp{MEDITATION_DENT} = @code{-1}, by @ref{it_meditation}
@item @samp{MEDITATION_BUMP} = @code{1}, by @ref{it_meditation}
@item @samp{MEDITATION_HILL} = @code{2}, by @ref{it_meditation}
@item @samp{MEDITATION_VOLCANO} = @code{3}, by @ref{it_meditation}
@end itemize

@node glasses abilities
@subsection glasses abilities

Number constants for @ref{it_glasses} attribute @ref{state} and global variable
@ref{ExtralifeGlasses}. Please use sums of the constants that are appropriate
for your glasses and do avoid using numbers.

@itemize @bullet
@item @samp{SPOT_NOTHING} = @code{0}, by @ref{it_glasses}
@item @samp{SPOT_DEATH} = @code{1}, by @ref{it_glasses}
@item @samp{SPOT_HOLLOW} = @code{2}, by @ref{it_glasses}
@item @samp{SPOT_ACTORIMPULSE} = @code{4}, by @ref{it_glasses}
@item @samp{SPOT_SENSOR} = @code{8}, by @ref{it_glasses}
@item @samp{SPOT_LIGHTPASSENGER} = @code{16}, by @ref{it_glasses}
@item @samp{SPOT_TRAP} = @code{32}, by @ref{it_glasses}
@end itemize

@node coinslot acceptance
@subsection coinslot acceptance

Number constants for @ref{st_coinslot} attributes @samp{interval_*}. Please
choose the constant that is appropriate for the coinslot and do avoid using
numbers.

@itemize @bullet
@item @samp{COIN_IGNORE} = @code{-1}, by @ref{st_coinslot}
@item @samp{COIN_REJECT} = @code{-2}, by @ref{st_coinslot}
@end itemize

@node rubberband length
@subsection rubberband length

Number constant for @ref{it_rubberband}, @ref{st_rubberband} and @ref{ot_rubberband}
attribute @samp{length}. Please choose the constant that is appropriate for the
rubberband length and do avoid using numbers.

@itemize @bullet
@item @samp{AUTOLENGTH} = @code{-1}, by @ref{it_rubberband}, @ref{st_rubberband} and @ref{ot_rubberband}
@end itemize

@node subsoil kind
@subsection subsoil kind

Number constants for the global attribute @ref{SubSoil}. Please
choose the constant that is appropriate for the SubSoil and do avoid using
numbers.

@itemize @bullet
@item @samp{SUBSOIL_ABYSS} = @code{0}, by @ref{it_explosion}
@item @samp{SUBSOIL_WATER} = @code{1}, by @ref{it_explosion}
@item @samp{SUBSOIL_AUTO} = @code{2}, by @ref{it_explosion}
@end itemize

@node screen scrolling
@subsection screen scrolling

Constants for screen scrolling global attributes @ref{FollowMethod} and
@ref{FollowAction}. Please choose the constants that are appropriate for
screen scrolling and do avoid using numbers or position values.

@itemize @bullet
@item @samp{FOLLOW_NO} = @code{0}, by global @ref{FollowMethod}
@item @samp{FOLLOW_SCROLL} = @code{1}, by global @ref{FollowMethod}
@item @samp{FOLLOW_FLIP} = @code{2}, by global @ref{FollowMethod}
@end itemize

@itemize @bullet
@item @samp{FOLLOW_FULLSCREEN} = @code{po(19, 12)}, by global @ref{FollowAction}
@item @samp{FOLLOW_HALFSCREEN} = @code{po(9.5, 6)}, by global @ref{FollowAction}
@end itemize

@node map read directions
@subsection map read directions

Constants for map read directions (see @ref{drawMap}) and map transformations (see
@ref{Rotating and Mirroring Maps} and @ref{Map Transformation}). They
are not numbers, to allow advanced operations on them when libmap is loaded, see
@ref{Map Transformation Composition and Powers}.

@itemize @bullet
@item @samp{MAP_IDENT} = no transformation
@item @samp{MAP_ROT_CW} = rotate map 90 degrees clockwise
@item @samp{MAP_ROT_180} = rotate map 180 degrees
@item @samp{MAP_ROT_CCW} = rotate map 90 degrees counter-clockwise
@item @samp{MAP_FLIP_BACKSLASH} = flip upper-left and lower-right corners
@item @samp{MAP_FLIP_HORIZONTAL} = flip right and left
@item @samp{MAP_FLIP_SLASH} = flip upper-right and lower-left corners
@item @samp{MAP_FLIP_VERTICAL} = flip up and down
@end itemize

Because map transformations are not numbers, you may not save them as
attributes of objects. Instead, you have to use @samp{index} and
@samp{MAP_ALL}, see @ref{Map Transformation Index and MAP_ALL}.

@c ----------------- Global Attributes --------------------
@node Global Attributes
@section Global Attributes

@menu
* ActorimpulseStrength::
* AllowSingleOxyds::
* AllowSuicide::
* AutoRespawn::
* ConserveLevel::
* CrackSpreading::
* CreatingPreview::
* ElectricStrength::
* ExtralifeGlasses::
* FallenPuzzle::
* FollowAction::
* FollowGrid::
* FollowMethod::
* FollowThreshold::
* Fragility::
* FrictionStrength::
* GlobalForce::
* Height::
* InfiniteReincarnation::
* IsDifficult::
* MagnetRange::
* MagnetStrength::
* MaxOxydColor::
* MeditationStrength::
* ProvideExtralifes::
* RubberViolationStrength::
* ShowMoves::
* SlopeStrength::
* SublevelNumber::
* SublevelTitle::
* SubSoil::
* SurviveFinish::
* SwampSinkTime::
* WaterSinkTime::
* Width::
* WormholeRange::
* WormholeStrength::
@end menu

@node ActorimpulseStrength
@subsection ActorimpulseStrength

A global scalar default factor for the actorimpulse stone bumping force. This
global value is only used if no object specific value is set.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{+200.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{st_actorimpulse}
@end table

@node AllowSingleOxyds
@subsection AllowSingleOxyds

A global variable that enables the existence of single unmatched @ref{st_oxyd}
stones. Setting this variable to @code{true} allows you to set uneven numbers
of oxyd stones for fixed colors. If a level deletes or adds oxyd stones during
runtime a @code{true} value avoids possible problems due to temporary uneven
oxyd stone numbers. The default @code{false} value causes an error message on
detection of uneven oxyd numbers.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{st_oxyd}
@end table

@node AllowSuicide
@subsection AllowSuicide

A global variable that enables the user to commit suicide with all owned
actors by pressing @samp{F3}. As this legacy feature can cause unexpected
shortcuts, you can deny this freedom. A single actor suicide as committed by
activation of an @ref{it_spoon} is not affected by this global variable.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{true}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ no object
@end table

@node AutoRespawn
@subsection AutoRespawn

A global variable that determines, if in absence of an @ref{it_flag} drop given
respawn position, the last recorded secure actor position should be taken
instead of the starting position, in case the actor dies and is resurrected.

The recorded auto respawn position will be appropriate for common actor deaths
like sinking in @ref{fl_water}, falling into @ref{fl_abyss}, hitting of
@ref{st_death}, slipping from an @ref{it_strip}, being hit by an
@ref{it_laserbeam}. Even a jump into one these lethal destinations resurrects
the actor onto the position from where the actor started its jump. There is no
danger of being resurrected on floors without @ref{adhesion (floor)}.

The usage of @ref{it_flag} in combination with AutoRespawn is fully supported.
On drop of a flag, the flag position remains the valid respawn position until
a flag is picked up. After a pickup of the flag, the position defined by the
flag gets deleted and the AutoRespawn position gets active until a flag is
dropped again.

Deaths caused by actor collisions, @ref{it_crack} and floor shattering
explosions can lead to lethal AutoRespawn positions. Either avoid setting
AutoRespawn to @code{true} in such cases or provide an @ref{it_flag} in such
cases.

Shortcuts introduced by AutoRespawn are unlikely, but not generally impossible.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{ac_marble}, @ref{ac_pearl}
@end table

@node ConserveLevel
@subsection ConserveLevel

A global variable that determines if a dead actor will be resurrected in case of
@ref{it_extralife}s in the gamer's inventory.

If @code{true}, dead actors attached to a player will be resurrected as long as
extralifes are available. If a player has no living actor to control or is
missing the actor's @ref{essential} constraints, the player is
dead. The level may still continue if a second player is alive. If the gamer has
an @ref{it_yinyang} in his inventory in single user mode, the control switches
to the second player. If all players are dead, a new level game is started.

If the conserve mode is @code{false}, no actors will be resurrected. As soon as
the player is dead and the control cannot switch to another player, all dead
actors are resurrected by using extralifes, and the level is restarted without
finishing the level game.

Use @code{false} if the level can either be not solved in case of resurrected
actors or would provide a major shortcut. In all other cases, mode @code{true}
with proper usage of actors @ref{essential} constraints will be preferable.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{true}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ no objects
@end table

@node CrackSpreading
@subsection CrackSpreading

A global default value denoting the probability that a brittle floor plate, that
is a floor with an @ref{it_crack} on top, causes direct neighboring floors to
either be marked with an invisible crack or to toggle such invisible cracks to
a small visible cracks. A value of @code{1.0} ensures that the crack spreads to
the direct neighbors, a value of @code{0.0} prohibits the spreading to neighbor
grids. Note that even if crack spreading is prohibited, existing cracks on
neighbor grids may continue disintegrating due to their @ref{Fragility}. For
more details see @ref{it_crack}.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number between @code{0.0} and @code{1.0}
@item @b{Default:} @ @ @code{0.5}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_crack}
@end table

@node CreatingPreview
@subsection CreatingPreview

A global read only variable that indicates if the current level load is just for
creating a preview thumbnail of the level or a real game play. If @samp{true},
you can, e.g., change the start-position of the main actor to display another
part of the level in the preview, or hide objects from it. When changing the
initial position, it might be advantageous to also set the
@ref{Display Follow Strategy} to permanent smooth scrolling:

@example
if wo["CreatingPreview"] then
    wo["FollowGrid"] = false
    wo["FollowMethod"] = FOLLOW_SCROLL
end
@end example

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read only
@item @b{Support:} @ @ object independent
@end table

@node ElectricStrength
@subsection ElectricStrength

A global scalar default factor for electrical forces. Positive numbers result in
attracting forces for opposite charges and repelling forces for equal signed
charges. Where as negative numbers result in repelling forces for opposite
charges and attracting forces for equal signed charges. This global value is
always multiplied by the charge load of the affected actors. The actor's charge
load usually results from hits of @ref{st_charge}.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{15.0}
Positive numbers are attracting, negative numbers are repelling.
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{Actor Objects}
@end table

@node ExtralifeGlasses
@subsection ExtralifeGlasses

A global variable that defines the @ref{it_glasses} type that is generated on
the laser light conversion of an @ref{it_extralife}

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ positive integer number
A sum out of the constants @samp{SPOT_DEATH}, @samp{SPOT_HOLLOW},
@samp{SPOT_ACTORIMPULSE}, @samp{SPOT_SENSOR}, @samp{SPOT_LIGHTPASSENGER},
@samp{SPOT_TRAP}
@item @b{Default:} @ @ @code{SPOT_DEATH + SPOT_HOLLOW + SPOT_LIGHTPASSENGER}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_extralife}
@end table

@node FallenPuzzle
@subsection FallenPuzzle

A global object replacement kind for @ref{st_puzzle}s fallen into @ref{fl_water}
or @ref{fl_abyss}. Besides any floor kind you can use any key of a tile
declaration preceeded by an equal sign @code{'='}. By this second method you
can use attributed floor kinds with special values for friction and adhesion.

Additionally you can set this global @samp{FallenPuzzle} attribute to
@code{"it_pipe"} or @code{"it_stip"}. In both cases fallen puzzle objects will
be replaced by items of the given class with the identical connections as the
fallen puzzle stones. Just in case that an item of the given class is already
present at one of the affected grid positions the connections of these will be
adjusted in a special way. An existing @code{"it_pipe"} remains unchanged, but
an @code{"it_stip"} will add the connections of the fallen puzzle to its own
connections.

@table @asis
@item @b{Type:} @ @ string
@item @b{Values:} @ @ any floor object kind, @code{"it_strip"}, @code{"it_pipe"} or @code{"=key"}, with key being a valid tile key
@item @b{Default:} @ @ @code{"fl_gray"}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{st_puzzle}
@end table

@node FollowAction
@subsection FollowAction

A global variable that describes the action of the display on relocation. This
attribute is introduced for future extensions, but is currently just partially
supported. Just the values listed below are used. Please use this attribute
just as explained in @ref{Display Follow Strategy}.

@table @asis
@item @b{Type:} @ @ number or position
@item @b{Values:} @ @ @code{0}, @code{FOLLOW_FULLSCREEN}, @code{HALFSCREEN}
The distance of display readjustment. Positions are used to supply different
values for x and y. The value @samp{@{19, 12@}} is a standard full screen move.
The value @samp{@{9.5, 6@}} is a standard half screen move. A value @samp{0}
is a minimal smooth move or the default value for grid based moves.
@item @b{Default:} @ @ @code{@{19, 12@}}
Actually the default is mode based (@pxref{Display Follow Strategy}).
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ no objects
@end table


@node FollowGrid
@subsection FollowGrid

A global variable that determines if the display is fixed in its static
positions to grids or if it can be scrolled to any pixel position
(@pxref{Display Follow Strategy}).

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{true}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ no objects
@end table

@node FollowMethod
@subsection FollowMethod

A global variable that describes the method how the display moves, either not
at all, by pixelwise scrolling, or by flipping to another screen or region
(@pxref{Display Follow Strategy}).

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ @code{FOLLOW_NO}, @code{FOLLOW_SCROLL}, @code{FOLLOW_FLIP}
@item @b{Default:} @ @ @code{FOLLOW_FLIP}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ no objects
@end table

@node FollowThreshold
@subsection FollowThreshold

A global variable that describes the threshold at which a crossing active marble
triggers the display to relocate. It is given as the distance to the screen
boundary (@pxref{Display Follow Strategy}).

@table @asis
@item @b{Type:} @ @ number or position
@item @b{Values:} @ @ 0 or positive number, or a pair of two positive numbers
The distance from the screen boundary at which the displays readjusts. Positions
are used to supply different values for x and y. All values need to be less
than half of the screen size.
@item @b{Default:} @ @ @code{0.5}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ no objects
@end table

@node Fragility
@subsection Fragility

A global default value denoting the probability that a brittle floor plate, that
is a floor with an @ref{it_crack} on top, continues to disintegrate on events
like an actor entering, passing a neighboring @ref{it_crack}, nearby explosions
or fire heating. A value of @code{1.0} ensures that the crack continues to
disintegrates on these events, a value of @code{0.0} prohibits visible cracks
to get larger. This default is superseded by @ref{fragility (floor)} and
@ref{it_crack} specific values.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number between @code{0.0} and @code{1.0}
@item @b{Default:} @ @ @code{1.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_crack} and @ref{Floor Objects}
@end table

@node FrictionStrength
@subsection FrictionStrength

A global scalar default factor for floor friction values. This global value is
always multiplied by the floor specific friction on calculation of the friction
force applied to actors.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{1.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ all floors
@end table

@node GlobalForce
@subsection GlobalForce

A global constant force that is added to every actor on every grid. The force
is given as a vector constant by a value of type @ref{Position}.

@table @asis
@item @b{Type:} @ @ @ref{Position}
@item @b{Values:} @ @ pair of float numbers
@item @b{Default:} @ @ @code{po(0.0, 0.0)}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ all floors
@end table

@node Height
@subsection Height

A global read only variable reports the height of the world in grid units.
This is set by the initial world constructor call
(@pxref{World Creation}).

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ positive integer number
@item @b{Default:} @ @ @code{?}
@item @b{Access:} @ @ read only
@item @b{Support:} @ @ object independent
@end table

@node InfiniteReincarnation
@subsection InfiniteReincarnation

A global variable that switches off the @ref{it_extralife} consumption on
resurrection of a dead actor. Usually the number of extralifes is counted,
the items are explicitly set or an @ref{st_dispenser} for extralifes is located
at strategic positions. The main purpose of this flag is the support of easy
modes for very lethal levels, that should give the user the opportunity to
exercise difficult patterns. Usage of this flag for the regular difficult mode
is deprecated.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ object independent
@end table

@node IsDifficult
@subsection IsDifficult

A global read only variable that defines the current difficulty mode selected
by the user. All differences of easy and difficult mode within the level should
be coded solely in dependence of this flag. If a level that supports an easy
mode the author needs to declare it in the XML header in the element
@ref{<modes>}.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{true}
@item @b{Access:} @ @ read only
@item @b{Support:} @ @ object independent
@end table

@node MagnetRange
@subsection MagnetRange

A global default distance up to which magnets apply forces to actors. This
global value is only used if no object specific value is set.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ positive float number or zero
@item @b{Default:} @ @ @code{10.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_magnet}
@end table

@node MagnetStrength
@subsection MagnetStrength

A global scalar default factor for magnet forces. Positive numbers are
attracting forces where as negative numbers are repelling forces. This global
value is only used if no object specific value is set.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{30.0}
Positive numbers are attracting, negative numbers are repelling.
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_magnet}
@end table

@node MaxOxydColor
@subsection MaxOxydColor

A global variable that limits the number of colors assigned to autocolored
@ref{st_oxyd}. Be careful with increasing this value beyond its default.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ @code{OXYD_BLUE}, ... @code{OXYD_BROWN}
@item @b{Default:} @ @ @code{OXYD_BLACK}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{st_oxyd}
@end table

@node MeditationStrength
@subsection MeditationStrength

A global scalar default factor for @ref{it_meditation} slope forces. Positive
numbers are downhill forces that let actors roll into dents and hollows and roll
down from hills and bumps.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{1.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_meditation}
@end table

@node ProvideExtralifes
@subsection ProvideExtralifes

A global variable that causes two @ref{it_extralife}s to be added to both player
inventories on start of a new level. Set it to @samp{false} if a gamer could
misuse these items. It is important to set this attribute before the world is
created (@pxref{World Creation}).

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{true}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ object independent
@end table

@node RubberViolationStrength
@subsection RubberViolationStrength

A global scalar default factor for the @ref{ot_rubberband} force that is applied
to actors if the length of the rubberband exceeds the given min or max limits.
This can happen due to extraordinary events like actor warping, actor
resurrection, moving anchor stones or simply new rubberbands that are created
with off limit length.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ positive float number
@item @b{Default:} @ @ @code{50.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{ot_rubberband}
@end table

@node ShowMoves
@subsection ShowMoves

A global variable that enables or disables the display of the stone push
counter besides the level time. It is mainly used in Sokoban like levels.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ object independent
@end table

@node SlopeStrength
@subsection SlopeStrength

A global scalar default factor for @ref{fl_slope} floor gradient forces. This
global value is used if no slope object specific strength factor is supplied.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{25.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{fl_slope}
@end table

@node SublevelNumber
@subsection SublevelNumber

A global variable that is only used by @ref{Multilevel Files}. It contains the
number of the sublevel that should be loaded and played. The number is preset
to a value between @code{1} and the @samp{quantity} given in the
@ref{Info metadata}.

@table @asis
@item @b{Type:} @ @ int
@item @b{Values:} @ @ positive integer numbers
@item @b{Default:} @ @ @code{1}
@item @b{Access:} @ @ read only
@item @b{Support:} @ @ no objects
@end table

@node SublevelTitle
@subsection SublevelTitle

A global variable that is only used by @ref{Multilevel Files}. If the sublevel
provides an individual title this variable must be set on level load to the
title string. An empty string value causes an auto generated title based on
the title given in the @ref{<identity>} element and the @ref{SublevelNumber}.

@table @asis
@item @b{Type:} @ @ string
@item @b{Values:} @ @ any string
@item @b{Default:} @ @ @code{""}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ no objects
@end table

@node SubSoil
@subsection SubSoil

A global variable that defines the subsoil which replaces a floor on its
physical destruction. @ref{it_bomb}s and @ref{ot_cannonball}s can cause
@ref{it_explosion}_debris which in turn dissolves the floor to the base
subsoil. The special value @code{SUBSOIL_AUTO} determines the subsoil based
on the surrounding floors. Any @ref{fl_water} on a direct neighboring floor
causes the floor to be replaced by water, too. Otherwise the default
@ref{fl_abyss} will be used as replacement.

@table @asis
@item @b{Type:} @ @ int
@item @b{Values:} @ @ @code{SUBSOIL_ABYSS}, @code{SUBSOIL_WATER}, @code{SUBSOIL_AUTO}
@item @b{Default:} @ @ @code{SUBSOIL_ABYSS}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_explosion}
@end table

@node SurviveFinish
@subsection SurviveFinish

A global variable that defines if the essential actors have to survive the
finish of the game (@pxref{Ending Conditions}). With this attribute set to
@samp{false} a gamer can sacrifice an essential actor to finish the level in the
same step in some subtle cases.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ @code{true}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ object independent
@end table

@node SwampSinkTime
@subsection SwampSinkTime

A global default for the time it takes a static actor to sink in @ref{fl_swamp}.
Fast moving actors will need slightly more time than static actors.

@table @asis
@item @b{Type:} @ @ number or @code{nil}
@item @b{Values:} @ @ positive float number or zero or @code{nil}
Sink time in seconds or @samp{nil} for an infinite time aka not sinking. Time
values smaller than approximately 0.7 ms will be rounded down to 0 ms.
@item @b{Default:} @ @ @code{1.75}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{fl_swamp}
@end table

@node WaterSinkTime
@subsection WaterSinkTime

A global default for the time it takes an actor to sink in @ref{fl_water}.

@table @asis
@item @b{Type:} @ @ number or @code{nil}
@item @b{Values:} @ @ positive float number or zero or @code{nil}
Sink time in seconds or @samp{nil} for an infinite time aka not sinking. Time
values smaller than approximately 0.7 ms will be rounded down to 0 ms.
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{fl_water}
@end table

@node Width
@subsection Width

A global read only variable reports the width of the world in grid units.
This is set by the initial world constructor call
(@pxref{World Creation}).

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ positive integer number
@item @b{Default:} @ @ @code{?}
@item @b{Access:} @ @ read only
@item @b{Support:} @ @ object independent
@end table


@node WormholeRange
@subsection WormholeRange

A global default distance up to which wormholes apply forces to actors. This
global value is only used if no object specific value is set.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ positive float number or zero
@item @b{Default:} @ @ @code{10.0}
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_wormhole}
@end table

@node WormholeStrength
@subsection WormholeStrength

A global scalar default factor for wormhole forces. Positive numbers are
attracting forces where as negative numbers are repelling forces. This global
value is only used if no object specific value is set.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{30.0}
Positive numbers are attracting, negative numbers are repelling.
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ @ref{it_wormhole}
@end table

@c ===================  Floors  =======================

@node Floor Objects
@chapter Floor Objects

@menu
* Floor Overview::
* Floor Attributes::
* Standard Floors::
* Special Floors::
@end menu

@c ----------------- Overview Floor --------------------
@node Floor Overview
@section Floor Overview

@multitable @columnfractions .08 .25 .08 .25 .09 .25
@item @image{images/fl_abyss, 12mm} @tab @yref{fl_abyss}
@tab @image{images/fl_adhesionless, 12mm} @tab @yref{fl_adhesionless}
@tab @image{images/fl_aquamarine, 12mm} @tab @yref{fl_aquamarine}
@item @image{images/fl_bast, 12mm} @tab @yref{fl_bast}
@tab @image{images/fl_bluegray, 12mm} @tab @yref{fl_bluegray}
@tab @image{images/fl_bluegreen, 12mm} @tab @yref{fl_bluegreen}
@item @image{images/fl_blueslab, 12mm} @tab @yref{fl_blueslab}
@tab @image{images/fl_brick, 12mm} @tab @yref{fl_brick}
@tab @image{images/fl_bridge_bw_closed, 12mm} @tab @yref{fl_bridge}_bw
@item @image{images/fl_bridge_gc_closed, 12mm} @tab @yref{fl_bridge}_gc
@tab @image{images/fl_bright, 12mm} @tab @yref{fl_bright}
@tab @image{images/fl_concrete, 12mm} @tab @yref{fl_concrete}
@item @image{images/fl_darkgray, 12mm} @tab @yref{fl_darkgray}
@tab @image{images/fl_dark, 12mm} @tab @yref{fl_dark}
@tab @image{images/fl_dunes, 12mm} @tab @yref{fl_dunes}
@item @image{images/fl_fake_trigger, 12mm} @tab @yref{fl_fake}_trigger
@tab @image{images/fl_forward_a_bridge_bw_closed, 12mm} @tab @yref{fl_forward}_bridgewood
@tab @image{images/fl_forward_a_bright, 12mm} @tab @yref{fl_forward}_bright
@item @image{images/fl_forward_a_darkgray, 12mm} @tab @yref{fl_forward}_darkgray
@tab @image{images/fl_forward_a_platinum, 12mm} @tab @yref{fl_forward}_platinum
@tab @image{images/fl_forward_a_rough, 12mm} @tab @yref{fl_forward}_rough
@item @image{images/fl_gravel, 12mm} @tab @yref{fl_gravel}
@tab @image{images/fl_gray, 12mm} @tab @yref{fl_gray}
@tab @image{images/fl_hay, 12mm} @tab @yref{fl_hay}
@item @image{images/fl_himalaya, 12mm} @tab @yref{fl_himalaya}
@tab @image{images/fl_ice, 12mm} @tab @yref{fl_ice}
@tab @image{images/fl_inverse_gray, 12mm} @tab @yref{fl_inverse}_gray
@item @image{images/fl_inverse_white, 12mm} @tab @yref{fl_inverse}_white
@tab @image{images/fl_ivory, 12mm} @tab @yref{fl_ivory}
@tab @image{images/fl_lawn, 12mm} @tab @yref{fl_lawn}
@item @image{images/fl_marble, 12mm} @tab @yref{fl_marble}
@tab @image{images/fl_metal, 12mm} @tab @yref{fl_metal}
@tab @image{images/fl_mortar, 12mm} @tab @yref{fl_mortar}
@item @image{images/fl_pinkbumps, 12mm} @tab @yref{fl_pinkbumps}
@tab @image{images/fl_plank, 12mm} @tab @yref{fl_plank}
@tab @image{images/fl_platinum, 12mm} @tab @yref{fl_platinum}
@item @image{images/fl_red, 12mm} @tab @yref{fl_red}
@tab @image{images/fl_redslab, 12mm} @tab @yref{fl_redslab}
@tab @image{images/fl_rock, 12mm} @tab @yref{fl_rock}
@item @image{images/fl_rough, 12mm} @tab @yref{fl_rough}
@tab @image{images/fl_sahara, 12mm} @tab @yref{fl_sahara}
@tab @image{images/fl_samba, 12mm} @tab @yref{fl_samba}
@item @image{images/fl_sand, 12mm} @tab @yref{fl_sand}
@tab @image{images/fl_scales_brick, 12mm} @tab @yref{fl_scales}_brick
@tab @image{images/fl_scales_bridge_bw_closed, 12mm} @tab @yref{fl_scales}_bridgewood
@item @image{images/fl_scales_concrete, 12mm} @tab @yref{fl_scales}_concrete
@tab @image{images/fl_scales_darkgray, 12mm} @tab @yref{fl_scales}_darkgray
@tab @image{images/fl_scales_gray, 12mm} @tab @yref{fl_scales}_gray
@item @image{images/fl_scales_platinum, 12mm} @tab @yref{fl_scales}_platinum
@tab @image{images/fl_slope_f, 12mm} @tab @yref{fl_slope}
@tab @image{images/fl_slope, 12mm} @tab @yref{fl_slope}_ps
@item @image{images/fl_slope_c, 12mm} @tab @yref{fl_slope}_ise
@tab @image{images/fl_slope_b, 12mm} @tab @yref{fl_slope}_ose
@tab @image{images/fl_space, 12mm} @tab @yref{fl_space}
@item @image{images/fl_stone, 12mm} @tab @yref{fl_stone}
@tab @image{images/fl_swamp, 12mm} @tab @yref{fl_swamp}
@tab @image{images/fl_thief, 12mm} @tab @yref{fl_thief}
@item @image{images/fl_thief_capture, 12mm} @tab @yref{fl_thief}
@tab @image{images/fl_thief_drunken, 12mm} @tab @yref{fl_thief}
@tab @image{images/fl_tigris, 12mm} @tab @yref{fl_tigris}
@item @image{images/fl_water, 12mm} @tab @yref{fl_water}
@tab @image{images/fl_white, 12mm} @tab @yref{fl_white}
@tab @image{images/fl_wood, 12mm} @tab @yref{fl_wood}
@item @image{images/fl_woven, 12mm} @tab @yref{fl_woven}
@tab @image{images/fl_yinyang_yang, 12mm} @tab @yref{fl_yinyang}_yang
@tab @image{images/fl_yinyang_yin, 12mm} @tab @yref{fl_yinyang}_yin
@end multitable

@c ----------------- Floor Attributes --------------------
@node Floor Attributes
@section Floor Attributes

@menu
* adhesion (floor)::        Effectiveness of mousemotion
* burnable::                -
* eternal::                 -
* faces (floor)::           Framing Configuration
* fastfire::                -
* floodable::               Flood Affinity
* force_x::                 Constant Force
* force_y::                 Constant Force
* fragility (floor)::       Crack
* freeze_check (floor)::    Freeze Checking
* friction (floor)::        Decelerating friction force factor
* ignitable::               -
* indestructible::          System Flag for destruction resistance
* initfire::                -
* noash::                   -
* push_directions::         Puzzle Shuffle Hint
* secure::                  -
* texture::                 Graphical Image Texture
@end menu


@c ----------------- adhesion (floor) --------------------
@node adhesion (floor)
@subsection adhesion (floor)

The responsiveness of an actor on mouse movements. It is a scalar factor to
the accelerating force applied to an actor. Note that the actor itself
has another scalar @ref{adhesion (actor)} factor. The adhesion may take negative
values, too. Such values correspond to inverse forces.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- burnable --------------------
@node burnable
@subsection burnable

Determines whether the floor starts to burn when a fire is nearby and the item
on the floor allows it to burn. @xref{Fire Spreading} for details.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- eternal --------------------
@node eternal
@subsection eternal

Determines whether a fire keeps on burning unlimited, until an external cause
stops it. @xref{Fire Spreading} for details.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- faces (floor) --------------------
@node faces (floor)
@subsection faces (floor)

Describes if a floor is framed.

Currently a floor is either not framed at all or framed on all sides. The frame
attribute can not be directly accessed and modified on most floors. Append the
string @code{"_framed"} to a given floor name to yield the all side framed
variant.

@table @asis
@item @b{Type:} @ @ string or nil
@item @b{Values:} @ @ @code{nil}, @code{"nesw"}
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ none - with a few exceptions
@end table

@c ----------------- fastfire --------------------
@node fastfire
@subsection fastfire

When set to @code{true}, fire will spread faster than usual, with the same
speed as if @ref{it_burnable}[_oil] would be on it. @xref{Fire Spreading} for
details.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- floodable --------------------
@node floodable
@subsection floodable

Determines whether a floor can be flooded by @ref{fl_water} from a neighboring
floor. @xref{Flood Spreading} for details.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- force_x --------------------
@node force_x
@subsection force_x

A constant floor specific force into east direction applied additionally to all
other forces to all actors on the floor.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- force_y --------------------
@node force_y
@subsection force_y

A constant floor specific force into south direction applied additionally to all
other forces to all actors on the floor.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- fragility (floor) --------------------
@node fragility (floor)
@subsection fragility (floor)

A value denoting the probability that a brittle floor plate, that is a floor
with an @ref{it_crack} on top, continues to disintegrate on events like an actor
entering, passing a neighboring @ref{it_crack}, nearby explosions or fire
heating. A value of @code{1.0} ensures that the crack continues to disintegrate
on these events, a value of @code{0.0} prohibits visible cracks to get larger.
This value is defaulted by @ref{Fragility} and superseded by @ref{it_crack}
specific values.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float numbers between @code{0.0} and @code{1.0}
@item @b{Default:} @ @ @code{1.0}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- freeze_check --------------------
@node freeze_check (floor)
@subsection freeze_check (floor)

If @code{true}, allows for @ref{Freeze Checking} on this floor tile. Note that
Freeze Checking only works with those (movable) stones that have additionally set
@code{freeze_check = true} on their own, see @ref{freeze_check (stone)}.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- friction (floor) --------------------
@node friction (floor)
@subsection friction (floor)

@pxref{friction}.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- ignitable --------------------
@node ignitable
@subsection ignitable

When @code{true}, and the item on the floor allows it to burn, it will start
burning on nearby explosions. @xref{Fire Spreading} for details.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- indestructible --------------------
@node indestructible
@subsection indestructible

Most floors can dissolve to @ref{fl_abyss} or @ref{fl_water} on destruction
by explosions, fire, @ref{ot_cannonball} hits, @ref{it_crack}, @ref{it_trap},
etc. But a few like @ref{fl_abyss}, @ref{fl_water} and @ref{fl_swamp} are
indestructible by all these events.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ none
@end table

@c ----------------- initfire --------------------
@node initfire
@subsection initfire

When set to @code{true}, the floor will start to burn after level
initialization. @xref{Fire Spreading} for details.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- noash --------------------
@node noash
@subsection noash

Determines whether @ref{it_burnable}_ash is put onto the floor after a fire
stops. Ash stops a floor from re-igniting, so @code{noash = true} will allow a
floor to start burning a second time, unless the item on it or its
@code{burnable}-attribute deny fire. @xref{Fire Spreading} for details.

@ref{fl_abyss} is the only floor with @code{noash = true} by default, because
ash falls into the abyss. Note however, that @ref{fl_abyss} isn't burnable by
default.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- push_directions --------------------
@node push_directions
@subsection push_directions

A hint for the resolver @ref{res.puzzle} for shuffling of a puzzle. A floor
marked with this attribute guarantees that an adjacent puzzle row or column
can be push rotated into the listed directions by the user.

@table @asis
@item @b{Type:} @ @ string or nil
@item @b{Values:} @ @ @code{nil}, @code{"nesw"}
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- secure --------------------
@node secure
@subsection secure

Ensures that a nearby fire eventually ignites this floor. @xref{Fire Spreading}
for details.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- texture --------------------
@node texture
@subsection texture

Many floors do provide several textures - graphical image variations that are
without any influence on the physical engine. Most floors do select a random
texture in their default variant. This generates areas without unintended
optical effects. But on some floors you can select the textures by means
of variant kind names to create your own graphical floor layout.

@table @asis
@item @b{Type:} @ @ integer number or string
@item @b{Values:} @ @ integer number or string
@item @b{Default:} @ @ @code{1}
@item @b{Access:} @ @ currently none - just by varying kind strings on some floors
@end table

@c ----------------- Standard Floor --------------------
@node Standard Floors
@section Standard Floors

@menu
* fl_adhesionless::   Floor without adhesion but friction
* fl_aquamarine::     Aquamarine floor with low friction
* fl_bast::           Brown woven bast with black background
* fl_bluegray::       Light blue gray floor
* fl_bluegreen::      Dark blue green floor
* fl_blueslab::       Dark blue marbled slab
* fl_brick::          Floor composed of small red bricks
* fl_bright::         Nearly white floor
* fl_concrete::       Granular gray concrete
* fl_dark::           Nearly black floor
* fl_darkgray::       Cold gray floor
* fl_dunes::          Brown granular dunes
* fl_gravel::         Dark gray, granular floor
* fl_gray::           Gray with some brown spots
* fl_himalaya::       Blue purple marbled floor
* fl_ivory::          Warm pearl white floor
* fl_lawn::           Grass in several textures
* fl_marble::         Light red brown marbled floor
* fl_metal::          Metal floor in several textures
* fl_mortar::         Rough white floor with gray wrinkles
* fl_pinkbumps::      Pink floor with white bumps
* fl_plank::          Small diagonal planks
* fl_platinum::       Warm light gray floor
* fl_red::            Warm red floor with low friction
* fl_redslab::        Dark red marbled slab
* fl_rough::          Rough warm white floor
* fl_sahara::         Bright yellow sandstone floor
* fl_samba::          Grey bleached wooden floor
* fl_sand::           Granular orange gray sand floor
* fl_space::          Black space with a few sparkling stars
* fl_stone::          Granular brown gray floor
* fl_tigris::         Red sandstone floor
* fl_white::          Pure white floor
* fl_woven::          White black woven floor
@end menu
@c ----------------- Adhesionless Floor --------------------
@node fl_adhesionless
@subsection fl_adhesionless
@obindex fl_adhesionless

Orange velvet that offers no adhesion but causes friction.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 0.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 2.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_adhesionless, 12mm} @b{fl_adhesionless}
@end table
@end table

@c ----------------- Aquamarine Floor --------------------
@node fl_aquamarine
@subsection fl_aquamarine
@obindex fl_aquamarine

Aquamarine floor with low friction.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 0.4 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_aquamarine, 12mm} @b{fl_aquamarine}
@item @image{images/fl_aquamarine_framed, 12mm} @b{fl_aquamarine_framed}
@end table
@end table

@c ----------------- Bast Floor --------------------
@node fl_bast
@subsection fl_bast
@obindex fl_bast

Brown woven bast with black background.

When burnt, @code{fl_bast} will become @ref{fl_abyss}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.5 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 1.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_bast, 12mm} @b{fl_bast}
@item @image{images/fl_bast_framed, 12mm} @b{fl_bast_framed}
@end table
@end table

@c ----------------- Bluegray Floor --------------------
@node fl_bluegray
@subsection fl_bluegray
@obindex fl_bluegray

Light blue gray floor, visually indistinguishable from @ref{fl_thief}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.5 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 4.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_bluegray, 12mm} @b{fl_bluegray}
@item @image{images/fl_bluegray_framed, 12mm} @b{fl_bluegray_framed}
@end table
@end table

@c ----------------- Bluegreen Floor --------------------
@node fl_bluegreen
@subsection fl_bluegreen
@obindex fl_bluegreen

Dark blue green floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_bluegreen, 12mm} @b{fl_bluegreen}
@item @image{images/fl_bluegreen_framed, 12mm} @b{fl_bluegreen_framed}
@end table
@end table

@c ----------------- Blueslab Floor --------------------
@node fl_blueslab
@subsection fl_blueslab
@obindex fl_blueslab

Dark blue slab like floor, that is marbled with black. A matching floor is
@ref{fl_redslab}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 7.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_blueslab, 12mm} @b{fl_blueslab}
@item @image{images/fl_blueslab_framed, 12mm} @b{fl_blueslab_framed}
@end table
@end table

@c ----------------- Brick Floor --------------------
@node fl_brick
@subsection fl_brick
@obindex fl_brick

Floor composed of small red bricks.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_brick, 12mm} @b{fl_brick}
@item @image{images/fl_brick_framed, 12mm}  @b{fl_brick_framed}
@end table
@end table

@c ----------------- Bright Floor --------------------
@node fl_bright
@subsection fl_bright
@obindex fl_bright

Nearly white floor without any yinyang related features. A matching floor is
@ref{fl_dark}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.5 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_bright, 12mm} @b{fl_bright}
@item @image{images/fl_bright_framed, 12mm} @b{fl_bright_framed}
@end table
@end table

@c ----------------- Concrete Floor --------------------
@node fl_concrete
@subsection fl_concrete
@obindex fl_concrete

Granular gray concrete.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.3 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 4.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_concrete, 12mm} @b{fl_concrete}
@item @image{images/fl_concrete_framed, 12mm} @b{fl_concrete_framed}
@end table
@end table

@c ----------------- Dark Floor --------------------
@node fl_dark
@subsection fl_dark
@obindex fl_dark

Nearly black floor without any yinyang related features. A matching floor is
@ref{fl_bright}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.5 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_dark, 12mm} @b{fl_dark}
@item @image{images/fl_dark_framed, 12mm} @b{fl_dark_framed}
@end table
@end table

@c ----------------- Darkgray Floor --------------------
@node fl_darkgray
@subsection fl_darkgray
@obindex fl_darkgray

A medium to dark gray floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.6 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_darkgray, 12mm} @b{fl_darkgray}
@item @image{images/fl_darkgray_framed, 12mm} @b{fl_darkgray_framed}
@end table
@end table

@c ----------------- Dunes Floor --------------------
@node fl_dunes
@subsection fl_dunes
@obindex fl_dunes

Brown granular dunes.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 1.3 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_dunes, 12mm} @b{fl_dunes}
@item @image{images/fl_dunes_framed, 12mm} @b{fl_dunes_framed}
@end table
@end table

@c ----------------- Gravel Floor --------------------
@node fl_gravel
@subsection fl_gravel
@obindex fl_gravel

Dark gray, granular floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.5 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.2 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_gravel, 12mm} @b{fl_gravel}
@item @image{images/fl_gravel_framed, 12mm} @b{fl_gravel_framed}
@end table
@end table

@c ----------------- Gray Floor --------------------
@node fl_gray
@subsection fl_gray
@obindex fl_gray

Gray with some brown spots.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 5.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_gray, 12mm} @b{fl_gray}
@item @image{images/fl_gray_framed, 12mm} @b{fl_gray_framed}
@end table
@end table

@c ----------------- Himalaya Floor --------------------
@node fl_himalaya
@subsection fl_himalaya
@obindex fl_himalaya

Blue purple marbled floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 5.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_himalaya, 12mm} @b{fl_himalaya}
@item @image{images/fl_himalaya_framed, 12mm} @b{fl_himalaya_framed}
@end table
@end table

@c ----------------- Ivory Floor --------------------
@node fl_ivory
@subsection fl_ivory
@obindex fl_ivory

Warm ivory or pearl white floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.6 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 2.2 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_ivory, 12mm} @b{fl_ivory}
@item @image{images/fl_ivory_framed, 12mm} @b{fl_ivory_framed}
@end table
@end table

@c ----------------- Lawn Floor --------------------
@node fl_lawn
@subsection fl_lawn
@obindex fl_lawn

Grass floor. Light and dark grass and different textures of both exist.

When burnt, @code{fl_lawn} becomes @ref{fl_dunes}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.5 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 4.0 @ @ @xref{friction}
@item @b{texture}, @ @ @i{values}: "a","b","c1","c2","c3","c4","d1","d2","d3","d4","e1","e2","e3","e4" ; @ @ @i{default}: "a"; @ @ @i{access}: @code{none}  @ @ @xref{texture}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/fl_lawn, 12mm} @tab @b{fl_lawn_a}: texture = @samp{"a"}
@tab @image{images/fl_lawn_c, 12mm} @tab @b{fl_lawn_b}: texture = @samp{"b"}
@item @image{images/fl_lawn_e, 12mm} @tab @b{fl_lawn_c1}: texture = @samp{"c1"}
@tab @image{images/fl_lawn_f, 12mm} @tab @b{fl_lawn_c3}: texture = @samp{"c3"}
@item @image{images/fl_lawn_e2, 12mm} @tab @b{fl_lawn_c2}: texture = @samp{"c2"}
@tab @image{images/fl_lawn_f2, 12mm} @tab @b{fl_lawn_c4}: texture = @samp{"c4"}
@item @image{images/fl_lawn_g, 12mm} @tab @b{fl_lawn_d1}: texture = @samp{"d1"}
@tab @image{images/fl_lawn_h, 12mm} @tab @b{fl_lawn_d3}: texture = @samp{"d3"}
@item @image{images/fl_lawn_g2, 12mm} @tab @b{fl_lawn_d2}: texture = @samp{"d2"}
@tab @image{images/fl_lawn_h2, 12mm} @tab @b{fl_lawn_d4}: texture = @samp{"d4"}
@item @image{images/fl_lawn_i, 12mm} @tab @b{fl_lawn_e1}: texture = @samp{"e1"}
@tab @image{images/fl_lawn_j, 12mm} @tab @b{fl_lawn_e3}: texture = @samp{"e3"}
@item @image{images/fl_lawn_i2, 12mm} @tab @b{fl_lawn_e2}: texture = @samp{"e2"}
@tab @image{images/fl_lawn_j2, 12mm} @tab @b{fl_lawn_e4}: texture = @samp{"e4"}
@item @image{images/fl_lawn, 12mm} @tab @b{fl_lawn}: texture = @samp{"a"}
@end multitable
@end table

@c ----------------- Marble Floor --------------------
@node fl_marble
@subsection fl_marble
@obindex fl_marble

Light red brown marbled floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.4 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_marble, 12mm} @b{fl_marble}
@item @image{images/fl_marble_framed, 12mm} @b{fl_marble_framed}
@end table
@end table

@c ----------------- Metal Floor --------------------
@node fl_metal
@subsection fl_metal
@obindex fl_metal

Grey metal floor with rivets. Several different textures exist with horizontal
or vertical aligned joists and various rivets.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{friction}
@item @b{texture}, @ @ @i{values}: integer number, 1 <= n <= 7  ; @ @ @i{default}: random; @ @ @i{access}: @code{none}  @ @ @xref{texture}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/fl_metal, 12mm} @tab @b{fl_metal}: texture = @samp{random}
@tab @image{images/fl_metal_framed, 12mm} @tab @b{fl_metal_framed}: texture = @samp{random}
@item @image{images/fl_metal, 12mm} @tab @b{fl_metal_1}: texture = @code{1}
@tab @image{images/fl_metal_framed, 12mm} @tab @b{fl_metal_1_framed}: texture = @code{1}
@item @image{images/fl_metal_2, 12mm} @tab @b{fl_metal_2}: texture = @code{2}
@tab @image{images/construction, 12mm} @tab @b{fl_metal_2_framed}: texture = @code{2}
@item @image{images/fl_metal_3, 12mm} @tab @b{fl_metal_3}: texture = @code{3}
@tab @image{images/construction, 12mm} @tab @b{fl_metal_3_framed}: texture = @code{3}
@item @image{images/fl_metal_4, 12mm} @tab @b{fl_metal_4}: texture = @code{4}
@tab @image{images/construction, 12mm} @tab @b{fl_metal_4_framed}: texture = @code{4}
@item @image{images/fl_metal_5, 12mm} @tab @b{fl_metal_5}: texture = @code{5}
@tab @image{images/construction, 12mm} @tab @b{fl_metal_5_framed}: texture = @code{5}
@item @image{images/fl_metal_6, 12mm} @tab @b{fl_metal_6}: texture = @code{6}
@tab @image{images/construction, 12mm} @tab @b{fl_metal_6_framed}: texture = @code{6}
@item @image{images/fl_metal_7, 12mm} @tab @b{fl_metal_7}: texture = @code{7}
@tab @image{images/construction, 12mm} @tab @b{fl_metal_7_framed}: texture = @code{7}
@end multitable
@end table

@c ----------------- Mortar Floor --------------------
@node fl_mortar
@subsection fl_mortar
@obindex fl_mortar

Very rough brilliant white floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.8 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 7.2 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_mortar, 12mm} @b{fl_mortar}
@item @image{images/fl_mortar_framed, 12mm} @b{fl_mortar_framed}
@end table
@end table

@c ----------------- Pinkbumps Floor --------------------
@node fl_pinkbumps
@subsection fl_pinkbumps
@obindex fl_pinkbumps

Pink floor with white bumps.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.2 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 5.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_pinkbumps, 12mm} @b{fl_pinkbumps}
@item @image{images/fl_pinkbumps_framed, 12mm} @b{fl_pinkbumps_framed}
@end table
@end table

@c ----------------- Plank Floor --------------------
@node fl_plank
@subsection fl_plank
@obindex fl_plank

Floor build up by small diagonal orange brown planks.

When burnt, @code{fl_plank} becomes @ref{fl_abyss}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 5.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_plank, 12mm} @b{fl_plank}
@item @image{images/fl_plank_framed, 12mm} @b{fl_plank_framed}
@end table
@end table

@c ----------------- Platinum Floor --------------------
@node fl_platinum
@subsection fl_platinum
@obindex fl_platinum

Warm light gray floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.6 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_platinum, 12mm} @b{fl_platinum}
@item @image{images/fl_platinum_framed, 12mm} @b{fl_platinum_framed}
@end table
@end table

@c ----------------- Red Floor --------------------
@node fl_red
@subsection fl_red
@obindex fl_red

Warm red, very slippy floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 0.9 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_red, 12mm} @b{fl_red}
@item @image{images/fl_red_framed, 12mm} @b{fl_red_framed}
@end table
@end table

@c ----------------- Redslab Floor --------------------
@node fl_redslab
@subsection fl_redslab
@obindex fl_redslab

Dark red slab floor, that is marbled with black. A matching floor is
@ref{fl_blueslab}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 7.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_redslab, 12mm} @b{fl_redslab}
@item @image{images/fl_redslab_framed, 12mm} @b{fl_redslab_framed}
@end table
@end table

@c ----------------- Rough Floor --------------------
@node fl_rough
@subsection fl_rough
@obindex fl_rough

Rough warm white floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 7.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_rough, 12mm} @b{fl_rough}
@item @image{images/fl_rough_framed, 12mm} @b{fl_rough_framed}
@end table
@end table

@c ----------------- Sahara Floor --------------------
@node fl_sahara
@subsection fl_sahara
@obindex fl_sahara

Bright yellow sandstone floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.4 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_sahara, 12mm} @b{fl_sahara}
@item @image{images/fl_sahara_framed, 12mm} @b{fl_sahara_framed}
@end table
@end table

@c ----------------- Samba Floor --------------------
@node fl_samba
@subsection fl_samba
@obindex fl_samba

Gray bleached wooden floor. Textures with horizontal and vertical aligned plank
exist.

When burnt, @code{fl_samba} becomes @ref{fl_abyss}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.0 @ @ @xref{friction}
@item @b{texture}, @ @ @i{values}: "h", "v"  ; @ @ @i{default}: random; @ @ @i{access}: @code{none}  @ @ @xref{texture}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_samba, 12mm} @b{fl_samba}: texture = @samp{random}
@item @image{images/fl_samba, 12mm} @b{fl_samba_h}: texture = @code{"h"}
@item @image{images/fl_samba_2, 12mm} @b{fl_samba_v}: texture = @code{"v"}
@item @image{images/fl_samba_framed, 12mm} @b{fl_samba_framed}: texture = @samp{random}
@item @image{images/fl_samba_framed, 12mm} @b{fl_samba_h_framed}: texture = @code{"h"}
@item @image{images/construction, 12mm} @b{fl_samba_v_framed}: texture = @code{"v"}
@end table
@end table

@c ----------------- Sand Floor --------------------
@node fl_sand
@subsection fl_sand
@obindex fl_sand

Granular orange gray sand floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_sand, 12mm} @b{fl_sand}
@item @image{images/fl_sand_framed, 12mm} @b{fl_sand_framed}
@end table
@end table

@c ----------------- Space Floor --------------------
@node fl_space
@subsection fl_space
@obindex fl_space

Black space with a few sparkling stars. This floor has neither a friction nor
does it provide an adhesion. All actors do drift for infinity on this floor
until they reach another floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 0.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 0.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_space, 12mm} @b{fl_space}
@end table
@end table

@c ----------------- Stone Floor --------------------
@node fl_stone
@subsection fl_stone
@obindex fl_stone

Granular brown gray floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 1.4 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_stone, 12mm} @b{fl_stone}
@item @image{images/fl_stone_framed, 12mm} @b{fl_stone_framed}
@end table
@end table

@c ----------------- Tigris Floor --------------------
@node fl_tigris
@subsection fl_tigris
@obindex fl_tigris

Red sandstone floor.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_tigris, 12mm} @b{fl_tigris}
@item @image{images/fl_tigris_framed, 12mm} @b{fl_tigris_framed}
@end table
@end table

@c ----------------- White Floor --------------------
@node fl_white
@subsection fl_white
@obindex fl_white

Pure white floor without any yinyang related features.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 4.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_white, 12mm} @b{fl_white}
@item @image{images/fl_white_framed, 12mm} @b{fl_white_framed}
@end table
@end table

@c ----------------- Woven Floor --------------------
@node fl_woven
@subsection fl_woven
@obindex fl_woven

Diagonal woven white floor with black shadows.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_woven, 12mm} @b{fl_woven}
@item @image{images/fl_woven_framed, 12mm} @b{fl_woven_framed}
@end table
@end table

@c ----------------- Special Floor --------------------
@node Special Floors
@section Special Floors

@menu
* fl_abyss::          Deep black Chasm
* fl_bridge::         Abyss Bridge
* fl_fake::           Fake mimicking other Floors
* fl_forward::        Conveyor Floor
* fl_hay::            Floodable Hay
* fl_ice::            Slippery frozen water
* fl_inverse::        Accelerate into the inverse direction
* fl_rock::           Floodable Rock Floor
* fl_scales::         Weight dependent Trigger
* fl_slope::          Slopes in various shapes
* fl_swamp::          Sticky sinkable Floor
* fl_thief::          Hidden Thief
* fl_water::          Sinkable Water
* fl_wood::           Floodable Wood Floor
* fl_yinyang::        Player dependent Adhesion
@end menu

@c ----------------- Abyss Floor --------------------
@node fl_abyss
@subsection fl_abyss
@obindex fl_abyss

Pure black abyss into which all rolling balls do fall and shatter. An abyss
chasm can be crossed by jumping. @ref{Actors} protected by an activated
@ref{it_umbrella} can pass and even move on an abyss as it provides useful
@samp{adhesion} and @samp{friction}. Another comparable floor barrier is
@ref{fl_water}.

Many floors disintegrate on fire or on a dissolving @ref{it_crack} into an
abyss. The abyss itself is indestructible. It does neither burn nor crack.

Some stones fall into abyss, too. @ref{st_box} will build floors on which all
actors can move and pass the former abyss filled grid.

By default, @code{fl_abyss} can't burn. However, when it burns (e.g. by
@ref{it_burnable}_oil), it does not create @ref{it_burnable}_ash in the end by
default (i.e., @ref{noash} is true by default). In particular, when
@code{burnable} is set to @code{true}, an abyss may reignite arbitrarily often.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{friction}
@item @b{indestructible}, @ @ @i{values}: bool ; @ @ @i{default}: true; @ @ @i{access}: @code{none}  @ @ @xref{indestructible}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@item @b{noash}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{noash}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_abyss, 12mm} @b{fl_abyss}
@end table
@end table

@c ----------------- Bridge Floor --------------------
@node fl_bridge
@subsection fl_bridge
@obindex fl_bridge

A bridge is a variable floor that can be passed when being @code{CLOSED} but
being impassable for marbles like @ref{fl_abyss} when being opened. Floor
bridges come in several flavors. They can be grey or wooden brown, they can
pop up in the center or emerge from one side. The flavor string is a combination
of a color character and an emerging direction character. Note that not all
combinations do exist.

Bridges can be opened and closed via messages and state set operations like
@ref{st_door}.

But a unique feature of bridges is to close on a solid stone being pushed onto
them. Thus stones do not fall into the visible abyss of an opened bridge, but
can be pushed over them. But as soon as the stone leaves the bridge it opens
again. Thus a user will notice the closing and opening bridge on stone pushes.

To be more precise after a stone leaving a bridge, it switches into the state
that it would have had if the stone would never have been on top of it. That
means that if a stone gets pushed onto an open bridge and the bridge receives
a @code{"close"} or @code{"toggle"} message while the stone is being on top the
bridge remains closed when the stone is pushed away.

A bridge being set adjusts its state according to the @ref{Snapshot Principle}.
It checks for solid stones being on top of it and auto closes accordingly.

Only the brown (wooden) bridges are burnable by default. Open bridges are never
burnable, regardless of the @ref{burnable}-attribute.

@table @asis

@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{CLOSED}, @code{OPEN}; @ @ @i{default}: @code{OPEN} @ @ @xref{state}
The state as visible and responsible for the actor ability to pass.
@item @b{flavor}, @ @ @i{values}: @code{"gc"}, @code{"bw"}, @code{"bs"}, @code{"be"}, @code{"bn"}; @ @ @i{default}: @code{"gc"}
The type of the bridge.
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 5.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: depends on @code{flavor} @ @ @xref{burnable}
True if flavor is @code{"b*"}, false otherwise.
@end table

@item @b{Messages:}
@table @asis
@item @b{open} @ @ @xref{open}
Opens a closed bridge that is not covered by a solid stone. Otherwise the
explicit open request will be registered and executed as soon as the stone
is pushed away.
@item @b{close} @ @ @xref{close}
Closes an open bridge. If the bridge is already closed by a covering solid
stone, the request will be registered and the bridge will not open when the
stone is pushed away.
@item @b{signal} @ @ @xref{signal}
A signal of value 1 sends an open message, a signal of value 0 sends a close
message.
@item @b{toggle} @ @ @xref{toggle}
A toggle causes a change of the state if no stone is on top, or the registered
explicit state if a solid stone currently covers the bridge.
@end table


@item @b{Variants:}
@table @asis
@item @image{images/fl_bridge_gc_closed, 12mm} @b{fl_bridge} flavor = @code{"gc"}
@item @image{images/fl_bridge_gc_closed, 12mm} @b{fl_bridge_gc} flavor = @code{"gc"}
@item @image{images/fl_bridge_bw_closed, 12mm} @b{fl_bridge_bw} flavor = @code{"bw"}
@item @image{images/fl_bridge_bw_closed, 12mm} @b{fl_bridge_bs} flavor = @code{"bs"}
@item @image{images/fl_bridge_bw_closed, 12mm} @b{fl_bridge_be} flavor = @code{"be"}
@item @image{images/fl_bridge_bw_closed, 12mm} @b{fl_bridge_bn} flavor = @code{"bn"}
@end table

@end table

@c ----------------- Fake Floor --------------------
@node fl_fake
@subsection fl_fake
@obindex fl_fake

A floor that mimics other floors, but does not act like them.

In contrast to @ref{fl_abyss} the fake abyss is just a standard floor that lets
pass any actor without any harm.

A fake trigger looks similar to an @ref{it_trigger} but is just a standard floor
without any special features.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{friction}
@item @b{flavor}, @ @ @i{values}: @code{"abyss"}, @code{"trigger"}; @ @ @i{default}: @code{"abyss"}; @ @ @i{access}: @code{none}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: depends on @code{flavor} @ @ @xref{burnable}
True if flavor is @code{"trigger"}, false otherwise.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_abyss, 12mm} @b{fl_fake_abyss}: flavor = @code{"abyss"}
@item @image{images/fl_fake_trigger, 12mm} @b{fl_fake_trigger}: flavor = @code{"trigger"}
@end table
@end table

@c ----------------- Forward Floor --------------------
@node fl_forward
@subsection fl_forward
@obindex fl_forward

The forward floor pushes stones on it in the direction it shows. In this
respect, it is similar to @ref{st_rotator}. Actors and items on it are
not pushed. 

Forward floors come in several flavors, which define the base floor,
adhesion, friction and burnability. They all share a flashing violet
double chevron, showing in the direction stones are pushed.

If the stone on top of the forward floor is blocked by another stone,
it will not move. This might create race conditions. Please be very
careful when using forward floors and @ref{st_boulder} or @ref{st_stoneimpulse},
because race conditions might be resolved in a different way in 
future versions of Enigma.

@table @asis
@item @b{Attributes:}

@table @asis
@atindex orientation
@item @b{flavor}, @ @ @i{values}: @code{bridgewood}, @code{bright}, @code{darkgray}, @code{platinum}, @code{rough}
@i{default}: @code{darkgray}.
The base floor type.
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: depends on @code{flavor}
@xref{adhesion}.
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: depends on @code{flavor}
@xref{friction}.
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: depends on @code{flavor}
@xref{burnable}.

True if flavor is @code{"bridgewood"}, false otherwise.
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{0.6}
Number of seconds between two pushes. The interval might be 0.0, in which case the
forward floor is deactivated. Otherwise, the interval must be larger or equal 0.2 seconds.
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{WEST}
The direction the chevron points and stones are pushed.
@end table

@item @b{Messages:}

@table @asis
@msindex orientate
@item @b{orientate}, @ @ @i{value type}: direction
Change the current direction. The @ref{st_fourswitch}
provides a compatible action which allows you to set a forward floor as
target and this message as action.
@item @b{flip}
Turn direction into the reverse of the current direction.
@end table

@item @b{Action:}
none

@item @b{Variants:}
@multitable @columnfractions .90
@item @image{images/fl_forward_d_darkgray, 12mm} @b{fl_forward}
@item @image{images/fl_forward_d_bridge_bw_closed, 12mm} @b{fl_forward_bridgewood}: flavor = @code{"bridgewood"}
@item @image{images/fl_forward_a_bridge_bw_closed, 12mm} @b{fl_forward_bridgewood_n}: flavor = @code{"bridgewood"}, orientation = @code{"NORTH"}
@item @image{images/fl_forward_b_bridge_bw_closed, 12mm} @b{fl_forward_bridgewood_e}: flavor = @code{"bridgewood"}, orientation = @code{"EAST"}
@item @image{images/fl_forward_c_bridge_bw_closed, 12mm} @b{fl_forward_bridgewood_s}: flavor = @code{"bridgewood"}, orientation = @code{"SOUTH"}
@item @image{images/fl_forward_d_bridge_bw_closed, 12mm} @b{fl_forward_bridgewood_w}: flavor = @code{"bridgewood"}, orientation = @code{"WEST"}
@item @image{images/fl_forward_d_bright, 12mm} @b{fl_forward_bright}: flavor = @code{"bright"}
@item @image{images/fl_forward_a_bright, 12mm} @b{fl_forward_bright_n}: flavor = @code{"bright"}, orientation = @code{"NORTH"}
@item @image{images/fl_forward_b_bright, 12mm} @b{fl_forward_bright_e}: flavor = @code{"bright"}, orientation = @code{"EAST"}
@item @image{images/fl_forward_c_bright, 12mm} @b{fl_forward_bright_s}: flavor = @code{"bright"}, orientation = @code{"SOUTH"}
@item @image{images/fl_forward_d_bright, 12mm} @b{fl_forward_bright_w}: flavor = @code{"bright"}, orientation = @code{"WEST"}
@item @image{images/fl_forward_d_darkgray, 12mm} @b{fl_forward_darkgray}: flavor = @code{"darkgray"}
@item @image{images/fl_forward_a_darkgray, 12mm} @b{fl_forward_darkgray_n}: flavor = @code{"darkgray"}, orientation = @code{"NORTH"}
@item @image{images/fl_forward_b_darkgray, 12mm} @b{fl_forward_darkgray_e}: flavor = @code{"darkgray"}, orientation = @code{"EAST"}
@item @image{images/fl_forward_c_darkgray, 12mm} @b{fl_forward_darkgray_s}: flavor = @code{"darkgray"}, orientation = @code{"SOUTH"}
@item @image{images/fl_forward_d_darkgray, 12mm} @b{fl_forward_darkgray_w}: flavor = @code{"darkgray"}, orientation = @code{"WEST"}
@item @image{images/fl_forward_d_platinum, 12mm} @b{fl_forward_platinum}: flavor = @code{"platinum"}
@item @image{images/fl_forward_a_platinum, 12mm} @b{fl_forward_platinum_n}: flavor = @code{"platinum"}, orientation = @code{"NORTH"}
@item @image{images/fl_forward_b_platinum, 12mm} @b{fl_forward_platinum_e}: flavor = @code{"platinum"}, orientation = @code{"EAST"}
@item @image{images/fl_forward_c_platinum, 12mm} @b{fl_forward_platinum_s}: flavor = @code{"platinum"}, orientation = @code{"SOUTH"}
@item @image{images/fl_forward_d_platinum, 12mm} @b{fl_forward_platinum_w}: flavor = @code{"platinum"}, orientation = @code{"WEST"}
@item @image{images/fl_forward_d_rough, 12mm} @b{fl_forward_rough}: flavor = @code{"rough"}
@item @image{images/fl_forward_a_rough, 12mm} @b{fl_forward_rough_n}: flavor = @code{"rough"}, orientation = @code{"NORTH"}
@item @image{images/fl_forward_b_rough, 12mm} @b{fl_forward_rough_e}: flavor = @code{"rough"}, orientation = @code{"EAST"}
@item @image{images/fl_forward_c_rough, 12mm} @b{fl_forward_rough_s}: flavor = @code{"rough"}, orientation = @code{"SOUTH"}
@item @image{images/fl_forward_d_rough, 12mm} @b{fl_forward_rough_w}: flavor = @code{"rough"}, orientation = @code{"WEST"}
@end multitable

@end table

@c ----------------- Hay Floor --------------------
@node fl_hay
@subsection fl_hay
@obindex fl_hay

A hay floor is in most aspects a standard floor, that exists in a framed
variation, too.

The framed variant is the successor of a fallen @ref{st_box}_hay. It may be
flooded by a @ref{fl_water} stream without the attribute @samp{floodable} being
set to @samp{true} as the flood passes below this floor. The framed wood
acts like a bridge over a flood stream and the water will continue to spread to
neighboring grids, while the framed wood is still passable for actors. In fact
a framed wood can even operate as a flood source, but we do not recommend this
usage. @pxref{Flood Spreading}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{FLOODING}; @ @ @i{default}: @code{IDLE} @ @ @xref{state}
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{0.2}
Number of seconds .
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.5 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 5.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_hay, 12mm} @b{fl_hay}
@item @image{images/fl_hay_framed, 12mm} @b{fl_hay_framed}: faces = @code{"nesw"}
@end table
@end table

@c ----------------- Ice Floor --------------------
@node fl_ice
@subsection fl_ice
@obindex fl_ice

An ice floor is very slippery frozen water. The user can increase the effective
friction by carrying an @ref{it_pin} in the player's inventory.

Ice is a standard floor in most aspects. But an @ref{it_dynamite} will leave
an @ref{it_crack}_water instead of a meditation hollow, and nearby fire heat
will melt the ice to @ref{fl_water} (see @ref{Heat-Transformation}).

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 0.1 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 0.1 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_ice, 12mm} @b{fl_ice}
@end table
@end table

@c ----------------- Inverse Floor --------------------
@node fl_inverse
@subsection fl_inverse
@obindex fl_inverse

Inverse floors accelerate all actors into the opposite direction of the applied
mouse input force. In all other aspects they are just standard floors.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: -2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 3.0 @ @ @xref{friction}
@item @b{flavor}, @ @ @i{values}: @code{"white"}, @code{"gray"}; @ @ @i{default}: @code{"white"}; @ @ @i{access}: @code{none}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_inverse_white, 12mm} @b{fl_inverse}: flavor = @code{"white"}
@item @image{images/fl_inverse_white, 12mm} @b{fl_inverse_white}: flavor = @code{"white"}
@item @image{images/fl_inverse_gray, 12mm} @b{fl_inverse_gray}: flavor = @code{"gray"}
@end table
@end table

@c ----------------- Rock Floor --------------------
@node fl_rock
@subsection fl_rock
@obindex fl_rock

A rock floor is in most aspects a standard floor, that exists in a framed
variation, too.

The framed variant is the successor of a fallen @ref{st_box}_rock. It may be
flooded by a @ref{fl_water} stream without the attribute @samp{floodable} being
set to @samp{true} as the flood passes below this floor. The framed wood
acts like a bridge over a flood stream and the water will continue to spread to
neighboring grids, while the framed wood is still passable for actors. In fact
a framed wood can even operate as a flood source, but we do not recommend this
usage. @pxref{Flood Spreading}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{FLOODING}; @ @ @i{default}: @code{IDLE} @ @ @xref{state}
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{0.2}
Number of seconds .
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.2 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_rock, 12mm} @b{fl_rock}
@item @image{images/fl_rock_framed, 12mm} @b{fl_rock_framed}: faces = @code{"nesw"}
@end table
@end table

@c ----------------- Scales Floor --------------------
@node fl_scales
@subsection fl_scales
@obindex fl_scales

The scales floor is a trigger that reacts on the mass load of actors and items
atop or any stones that may press it. It performs actions when it is initially
pressed and again when it releases. A pressed trigger is in state @samp{ON} and
will send an action value of @samp{true}, a released trigger is in state
@samp{OFF} and will send an action value of @samp{false}.

Only actors moving on the floor can press scales. An actor jumping over a
scale will not press it. An actor jumping on a scale will release and press
it again. But anyway the mass of all actors and items atop will be measured and
compared to the given @code{min} attribute. The default triggering mass is 1.8.
This mass is given by two @ref{ac_marble} or three @ref{ac_pearl}. Any item
like @ref{it_weight} or weights in an @ref{it_bag} that are either dropped on
top of scales or carried by any actor in the player's inventory is added to the
actor's basic mass.

Just solid stones will press the scales when pushed onto it. Floating, hollow
stones will generally not press the scales with the exception of the hollow,
central puzzle stone (@pxref{st_puzzle}).

There is no way to set the state of a trigger manually. But the state can
nevertheless be read. At initialization a scales floor that is pressed by
objects will start in state @samp{ON} without sending actions due to the
@ref{Snapshot Principle}.

Scales trigger with a click sound.

Scales are given in several flavors. They are similar to the @ref{it_trigger}
in respect to their features. Visually they look similar to frames, but are
well distinguishable. It is deprecated to use invisible @ref{it_trigger} on
a framed floor as a substitution for scales.

Alternative items that react just on actors are @ref{it_sensor} and
@ref{it_cross}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF} @ @ @xref{state}
The current switch state - @samp{ON} for pressed scales, @samp{OFF} for a
released scales.
@item @b{flavor}, @ @ @i{values}: @code{"brick"}, @code{"bridgewood"}, @code{"concrete"}, @code{"darkgray"}, @code{"gray"}, @code{"platinum"}; @ @ @i{default}: @code{"darkgray"}
The base floor type of the scales.
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 4.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: depends on @code{flavor} @ @ @xref{burnable}
True if flavor is @code{"bridgewood"}, false otherwise.
@item @b{min} @ @ @i{values}: positive float number; @ @ @i{default}: @code{+1.8}
Mass unit is the mass of an @ref{ac_marble}
@end table

@item @b{Messages:} none
@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/fl_scales_brick, 12mm} @b{fl_scales_brick}: flavor = @code{"brick"}
@item @image{images/fl_scales_bridge_bw_closed, 12mm} @b{fl_scales_bridgewood}: flavor = @code{"bridgewood"}
@item @image{images/fl_scales_concrete, 12mm} @b{fl_scales_concrete}: flavor = @code{"concrete"}
@item @image{images/fl_scales_darkgray, 12mm} @b{fl_scales_darkgray}: flavor = @code{"darkgray"}
@item @image{images/fl_scales_gray, 12mm} @b{fl_scales_gray}: flavor = @code{"gray"}
@item @image{images/fl_scales_platinum, 12mm} @b{fl_scales_platinum}: flavor = @code{"platinum"}
@end table

@end table

@c ----------------- Slope Floor --------------------
@node fl_slope
@subsection fl_slope
@obindex fl_slope

A floor suited to build larger hills, gradient areas, wall brims, staircases
or tubes that channelize actors.

Slope floors are basically described by their @samp{slope} and their @samp{shape}.
The slope is the orientation of the force applied to actors on top. The eight
main orientations and @samp{NODIR}, that causes no force to be applied at all, are
currently supported.

The shape describes the intended usage, which causes a proper visual
representation. There are planar slopes falling just into a horizontal or
vertical direction (@code{"pw"}, @code{"ps"}, @code{"pe"}, @code{"pn"}),
inner and outer edges falling into a diagonal direction (@code{"inw"},
@code{"isw"}, @code{"ise"}, @code{"ine"}, @code{"onw"}, @code{"osw"},
@code{"ose"}, @code{"one"}), tube center parts falling into a horizontal or
vertical direction (@code{"tw"}, @code{"ts"}, @code{"te"}, @code{"tn"}) and
tube left and right sides that accelerate actors into the main tube direction
and back to the tube center at the same time (@code{"twl"}, @code{"tsl"},
@code{"tel"}, @code{"tnl"}, @code{"twr"}, @code{"tsr"}, @code{"ter"},
@code{"tnr"}).

Note that several shapes do currently use an identical visual representation.
But they differ in their usage and different slope force orientations are
assigned by default when you use the variant suffices. It is strongly
recommended to use always the shape of the intended usage as the images might
be improved in the future and should fit to your level.

The force applied to actors on the floor grid is given per default by the
global attribute @ref{SlopeStrength}. You may override this default by an
explicit value for the slope floor attribute @samp{strength}. In very special
cases you may even define individual force components @samp{force_x} and
@samp{force_y}, which will override all other slope force attributes.

@table @asis

@item @b{Attributes:}

@table @asis
@item @b{slope}, @ @ @i{values}: @code{NODIR}, @code{WEST}, @code{SOUTH}, @code{EAST}, @code{NORTH}, @code{NORTHWEST}, @code{SOUTHWEST}, @code{SOUTHEAST}, @code{NORTHEAST}; @ @ @i{default}: @code{NODIR}
The orientation of the force. Note that setting this attribute does not
automatically assign a fitting @samp{shape}. This attribute is neglected if
@samp{force_x} or @samp{force_y} attributes are set.

@item @b{shape}, @ @ @i{values}: @code{""}, @code{"pw"}, @code{"ps"}, @code{"pe"}, @code{"pn"}, @code{"inw"}, @code{"isw"}, @code{"ise"}, @code{"ine"}, @code{"onw"}, @code{"osw"}, @code{"ose"}, @code{"one"}, @code{"tw"}, @code{"ts"}, @code{"te"}, @code{"tn"}, @code{"twl"}, @code{"tsl"}, @code{"tel"}, @code{"tnl"}, @code{"twr"}, @code{"tsr"}, @code{"ter"}, @code{"tnr"}; @ @ @i{default}: @code{""}
The intended usage as described above. Note that setting this attribute does
not automatically assign the proper @samp{slope}.

@item @b{strength} @ @ @i{values}: float number; @ @ @i{default}: @code{25.0} @ @ @xref{SlopeStrength}
@item @b{force_x} @ @ @i{values}: float number; @ @ @i{default}: @code{0.0} @ @ @xref{force_x}
@item @b{force_y} @ @ @i{values}: float number; @ @ @i{default}: @code{0.0} @ @ @xref{force_y}
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 4.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}

@end table

@item @b{Messages:} None

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/fl_slope_f, 12mm} @tab @b{fl_slope} slope = @samp{NODIR}, shape = @code{""} @tab @tab
@item @image{images/fl_slope_4, 12mm} @tab @b{fl_slope_pw} slope = @samp{WEST}, shape = @code{"pw"}
@tab @image{images/fl_slope, 12mm} @tab @b{fl_slope_ps} slope = @samp{SOUTH}, shape = @code{"ps"}
@item @image{images/fl_slope_3, 12mm} @tab @b{fl_slope_pe} slope = @samp{EAST}, shape = @code{"pe"}
@tab @image{images/fl_slope_2, 12mm} @tab @b{fl_slope_pn} slope = @samp{NORTH}, shape = @code{"pn"}
@item @image{images/fl_slope_c4, 12mm} @tab @b{fl_slope_inw} slope = @samp{NORTHWEST}, shape = @code{"inw"}
@tab @image{images/fl_slope_c3, 12mm} @tab @b{fl_slope_isw} slope = @samp{SOUTHWEST}, shape = @code{"isw"}
@item @image{images/fl_slope_c, 12mm} @tab @b{fl_slope_ise} slope = @samp{SOUTHEAST}, shape = @code{"ise"}
@tab @image{images/fl_slope_c2, 12mm} @tab @b{fl_slope_ine} slope = @samp{NORTHEAST}, shape = @code{"ine"}
@item @image{images/fl_slope_b4, 12mm} @tab @b{fl_slope_onw} slope = @samp{NORTHWEST}, shape = @code{"onw"}
@tab @image{images/fl_slope_b2, 12mm} @tab @b{fl_slope_osw} slope = @samp{SOUTHWEST}, shape = @code{"osw"}
@item @image{images/fl_slope_b, 12mm} @tab @b{fl_slope_ose} slope = @samp{SOUTHEAST}, shape = @code{"ose"}
@tab @image{images/fl_slope_b3, 12mm} @tab @b{fl_slope_one} slope = @samp{NORTHEAST}, shape = @code{"one"}
@item @image{images/fl_slope_f, 12mm} @tab @b{fl_slope_tw} slope = @samp{WEST}, shape = @code{"tw"}
@tab @image{images/fl_slope_f, 12mm} @tab @b{fl_slope_ts} slope = @samp{SOUTH}, shape = @code{"ts"}
@item @image{images/fl_slope_f, 12mm} @tab @b{fl_slope_te} slope = @samp{EAST}, shape = @code{"te"}
@tab @image{images/fl_slope_f, 12mm} @tab @b{fl_slope_tn} slope = @samp{NORTH}, shape = @code{"tn"}
@item @image{images/fl_slope_2, 12mm} @tab @b{fl_slope_twl} slope = @samp{NORTHWEST}, shape = @code{"twl"}
@tab @image{images/fl_slope_4, 12mm} @tab @b{fl_slope_tsl} slope = @samp{SOUTHWEST}, shape = @code{"tsl"}
@item @image{images/fl_slope, 12mm} @tab @b{fl_slope_tel} slope = @samp{SOUTHEAST}, shape = @code{"tel"}
@tab @image{images/fl_slope_3, 12mm} @tab @b{fl_slope_tnl} slope = @samp{NORTHEAST}, shape = @code{"tnl"}
@item @image{images/fl_slope, 12mm} @tab @b{fl_slope_twr} slope = @samp{SOUTHWEST}, shape = @code{"twr"}
@tab @image{images/fl_slope_3, 12mm} @tab @b{fl_slope_tsr} slope = @samp{SOUTHEAST}, shape = @code{"tsr"}
@item @image{images/fl_slope_2, 12mm} @tab @b{fl_slope_ter} slope = @samp{NORTHEAST}, shape = @code{"ter"}
@tab @image{images/fl_slope_4, 12mm} @tab @b{fl_slope_tnr} slope = @samp{NORTHWEST}, shape = @code{"tnr"}
@end multitable
@end table

@c ----------------- Swamp Floor --------------------
@node fl_swamp
@subsection fl_swamp
@obindex fl_swamp

A swamp is very sticky floor caused by a high friction. Additionally ball like
actors will sink in swamp. But the sink speed is limited and gives the user
a certain time, defined by the global attribute @ref{SwampSinkTime}. When
an actor moves faster than 6 grids per second, the actor starts raising out of
the swamp. Jumping in a swamp raises an actor, too.

A swamp is indestructible to the aspect that @ref{it_crack} will not spread
onto it. But fire starting to burn nearby will dry out the swamp to
@ref{fl_dunes} (@pxref{Heat-Transformation}). A swamp itself may be a successor of
a @ref{fl_water} heated by a fire.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 13.0 @ @ @xref{friction}
@item @b{indestructible}, @ @ @i{values}: bool ; @ @ @i{default}: true; @ @ @i{access}: @code{none}  @ @ @xref{indestructible}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_swamp, 12mm} @b{fl_swamp}
@end table
@end table

@c ----------------- Thief Floor --------------------
@node fl_thief
@subsection fl_thief
@obindex fl_thief

A thief steals the item on its position plus an item from the player's inventory
when it is entered by an owned actor. Unfortunately the thief floor is visually
indistinguishable from an @ref{fl_bluegray} and has even the same
@samp{friction} and @samp{adhesion} values.

The item is not directly stolen at the moment of entering the grid. The entering
itself just causes the thief to emerge from his hiding-place. The thief steals
from the actor that did conjure him at the moment of maximum visibility. He takes
a random item from the owner's inventory. But he just will steal an item if
the actor is not shielded due to an activated @ref{it_umbrella}.

Thieves have an addiction to alcohol. Thus they get drunken and inactive if
they happen to steal a bottle filled with stuff.

Thieves have an enemy - the @ref{st_chess}. If a chess stone is pushed onto
a thief it will capture the thief, sober or drunken. The thief vanishes leaving
an inactive standard floor and the chess stone jumps onto its position. But the
thief will leave behind on the grid all stolen items in his own @ref{it_bag}.
If the thief has not stolen any items he leaves no empty bag.

@table @asis
@item @b{Attributes:} none
@table @asis
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.5 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 4.5 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Messages:} none

@item @b{Action:}  none

@item @b{Variants:}
@table @asis
@item @image{images/fl_bluegray, 12mm} @b{fl_thief}: hidden
@item @image{images/fl_thief, 12mm} @b{fl_thief}: showing up at the moment when stealing items
@item @image{images/fl_thief_capture, 12mm} @b{fl_thief}: when being captured
@item @image{images/fl_thief_drunken, 12mm} @b{fl_thief}: drunken thief
@end table
@end table

@c ----------------- Water Floor --------------------
@node fl_water
@subsection fl_water
@obindex fl_water

Besides @ref{fl_abyss} water is the second natural floor barrier for ball like
actors, as they can not easily pass it.

Both, @ref{ac_marble} and @ref{ac_pearl}, will sink in water, usually at once,
but the time amount can be configured by the global attribute @ref{WaterSinkTime}.
Unlike @ref{fl_swamp} water does not raise fast moving actors. But jumping
within water raises an actor. Jumping completely over a water chasm is of course
a more standard way to cross it. Actors protected by an activated
@ref{it_umbrella} can pass and even move on water without restrictions.

Some stones fall into water, too. @ref{st_box} will build floors on which all
actors can move and pass the former water filled grid.

Water itself is indestructible to the aspect that @ref{it_crack} will not spread
onto it. But a fire starting to burn nearby will dry out the water to
@ref{fl_swamp} (see @ref{Heat-Transformation}).

The standard water is static, its @samp{state} is @samp{IDLE}. It will not
spread to adjacent floors. But you can set up flood streams that will fill areas
or flow through given paths. You just need to define the area by setting the
attribute @samp{floodable} to @samp{true} on the affected floors. But static
water lakes do not require an additional @samp{floodable} attribute, as they
are floodable by default.

As soon as you add a @samp{fl_water_source} or set the @samp{state} to
@samp{FLOODING}, the water starts to spread to floodable neighboring grids with
a speed defined by the attribute @samp{interval}. The speed will be inherited to
floors flooded by a stream.

As a flood can be influenced by many obstacles and may sink some stones itself,
you will find a complete discussion in the section @ref{Flood Spreading}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{FLOODING}; @ @ @i{default}: @code{IDLE} @ @ @xref{state}
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{0.2}
Number of seconds .
@item @b{indestructible}, @ @ @i{values}: bool ; @ @ @i{default}: true; @ @ @i{access}: @code{none}  @ @ @xref{indestructible}
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 1.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 5.0 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_water, 12mm} @b{fl_water}: state = @code{IDLE}
@item @image{images/fl_water, 12mm} @b{fl_water_source}: state = @code{FLOODING}
@end table
@end table

@c ----------------- Wood Floor --------------------
@node fl_wood
@subsection fl_wood
@obindex fl_wood

A wooden floor is in most aspects a standard floor, that exists in textures
with horizontal or vertical panels, or random. All textures come in a framed
variation, too.

The framed variant is the successor of a fallen @ref{st_box}_wood. It may be
flooded by a @ref{fl_water} stream without the attribute @samp{floodable} being
set to @samp{true} as the flood passes below this floor. The framed wood
acts like a bridge over a flood stream and the water will continue to spread to
neighboring grids, while the framed wood is still passable for actors. In fact
a framed wood can even operate as a flood source, but we do not recommend this
usage. @pxref{Flood Spreading}.

When burnt, @code{fl_wood} becomes @ref{fl_abyss}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{FLOODING}; @ @ @i{default}: @code{IDLE} @ @ @xref{state}
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{0.2}
Number of seconds .
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 6.4 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: true @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_wood, 12mm} @b{fl_wood}: texture = random
@item @image{images/fl_wood_3, 12mm} @b{fl_wood_h}: texture = @code{"h"}
@item @image{images/fl_wood, 12mm} @b{fl_wood_v}: texture = @code{"v"}
@item @image{images/fl_wood_framed, 12mm} @b{fl_wood_framed}: texture = random, faces = @code{"nesw"}
@item @image{images/fl_wood_framed, 12mm} @b{fl_wood_framed_h}: texture = @code{"h"}, faces = @code{"nesw"}
@item @image{images/fl_wood_framed_2, 12mm} @b{fl_wood_framed_v}: texture = @code{"v"}, faces = @code{"nesw"}
@end table
@end table

@c ----------------- Yinyang Floor --------------------
@node fl_yinyang
@subsection fl_yinyang
@obindex fl_yinyang

A floor that lets move just actors assigned to one player. A basic floor color
of dark gray corresponds to @samp{YIN} and lets accelerate just actors that
are controlled by this first player. White colored yinyang floors correspond
to @samp{YANG} and let accelerate just actors controlled by this second player.

The floor image with 4 rivets in the corners shows an additional yinyang symbol
to visualize that not the color of the actor is essential but the controlling
player. In large areas of this floor this symbol is disturbing and it can be
switched off by the attribute @samp{invisible}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{YIN}, @code{YANG}; @ @ @i{default}: @code{YIN} @ @ @xref{state}
@item @b{invisible} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: 2.0 @ @ @xref{adhesion}
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: 5.2 @ @ @xref{friction}
@item @b{burnable}, @ @ @i{values}: boolean; @ @ @i{default}: false @ @ @xref{burnable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_yinyang_yin, 12mm} @b{fl_yinyang}: state = @code{YIN}
@item @image{images/fl_yinyang_yin, 12mm} @b{fl_yinyang_yin}: state = @code{YIN}
@item @image{images/fl_yinyang_yang, 12mm} @b{fl_yinyang_yang}: state = @code{YANG}
@end table
@end table

@c ===================  Items  =======================

@node Item Objects
@chapter Item Objects

@menu
* Item Overview::
* Item Attributes::
* Liftable Items::
* Static Items::
@end menu

@c ----------------- Item Overview --------------------
@node Item Overview
@section Item Overview

@multitable @columnfractions .08 .25 .08 .25 .09 .25
@item @image{images/it_bag, 12mm} @tab @yref{it_bag}
@tab @image{images/it_banana, 12mm} @tab @yref{it_banana}
@tab @image{images/st_blocker_4, 12mm} @tab @yref{it_blocker}
@item @image{images/it_bomb, 12mm} @tab @yref{it_bomb}_black
@tab @image{images/it_bomb_b, 12mm} @tab @yref{it_bomb}_white
@tab @image{images/it_bottle_idle, 12mm} @tab @yref{it_bottle}
@item @image{images/it_bottle_broken, 12mm} @tab @yref{it_bottle}_broken
@tab @image{images/st_brake, 12mm} @tab @yref{it_brake}
@tab @image{images/it_brush, 12mm} @tab @yref{it_brush}
@item @image{images/it_burnable_ash, 12mm} @tab @yref{it_burnable}_ash
@tab @image{images/it_burnable_burning, 12mm} @tab @yref{it_burnable}_burning
@tab @image{images/it_burnable_fireproof, 12mm} @tab @yref{it_burnable}_fireproof
@item @image{images/it_burnable_oil, 12mm} @tab @yref{it_burnable}_oil
@tab @image{images/it_cherry, 12mm} @tab @yref{it_cherry}
@tab @image{images/it_coffee, 12mm} @tab @yref{it_coffee}
@item @image{images/it_coin_s, 12mm} @tab @yref{it_coin}_s
@tab @image{images/it_coin_m, 12mm} @tab @yref{it_coin}_m
@tab @image{images/it_coin_l, 12mm} @tab @yref{it_coin}_l
@item @image{images/it_crack_abyss, 12mm} @tab @yref{it_crack}_abyss
@tab @image{images/it_crack_water, 12mm} @tab @yref{it_crack}_water
@tab @image{images/it_cross, 12mm} @tab @yref{it_cross}
@item @image{images/it_death, 12mm} @tab @yref{it_death}
@tab @image{images/it_document, 12mm} @tab @yref{it_document}
@tab @image{images/it_drop, 12mm} @tab @yref{it_drop}
@item @image{images/it_dynamite, 12mm} @tab @yref{it_dynamite}
@tab @image{images/it_explosion, 12mm} @tab @yref{it_explosion}
@tab @image{images/it_extinguisher, 12mm} @tab @yref{it_extinguisher}
@item @image{images/it_extralife, 12mm} @tab @yref{it_extralife}
@tab @image{images/it_flag_black, 12mm} @tab @yref{it_flag}_black
@tab @image{images/it_flag_white, 12mm} @tab @yref{it_flag}_white
@item @image{images/it_floppy, 12mm} @tab @yref{it_floppy}
@tab @image{images/it_glasses, 12mm} @tab @yref{it_glasses}
@tab @image{images/it_glasses_broken, 12mm} @tab @yref{it_glasses}_broken
@item @image{images/it_hammer, 12mm} @tab @yref{it_hammer}
@tab @image{images/it_key, 12mm} @tab @yref{it_key}
@tab @image{images/it_landmine, 12mm} @tab @yref{it_landmine}
@item @image{images/it_laser, 12mm} @tab @yref{it_laserbeam}
@tab @image{images/it_magicwand, 12mm} @tab @yref{it_magicwand}
@tab @image{images/it_magnet_off, 12mm} @tab @yref{it_magnet}
@item @image{images/it_meditation_bump, 12mm} @tab @yref{it_meditation}_bump
@tab @image{images/it_meditation_caldera, 12mm} @tab @yref{it_meditation}_caldera
@tab @image{images/it_meditation_dent, 12mm} @tab @yref{it_meditation}_dent
@item @image{images/it_meditation_hill, 12mm} @tab @yref{it_meditation}_hill
@tab @image{images/it_meditation_hollow, 12mm} @tab @yref{it_meditation}_hollow
@tab @image{images/it_meditation_volcano, 12mm} @tab @yref{it_meditation}_volcano
@item @image{images/it_pencil, 12mm} @tab @yref{it_pencil}
@tab @image{images/it_pin, 12mm} @tab @yref{it_pin}
@tab @image{images/it_pipe_e, 12mm} @tab @yref{it_pipe}
@item @image{images/it_puller, 12mm} @tab @yref{it_puller}
@tab @image{images/it_ring, 12mm} @tab @yref{it_ring}
@tab @image{images/it_rubberband, 12mm} @tab @yref{it_rubberband}
@item @image{images/it_seed, 12mm} @tab @yref{it_seed}
@tab @image{images/it_sensor, 12mm} @tab @yref{it_sensor}
@tab @image{images/it_sensor_exit, 12mm} @tab @yref{it_sensor}_exit
@item @image{images/it_shogun_m, 12mm} @tab @yref{it_shogun}
@tab @image{images/it_spade, 12mm} @tab @yref{it_spade}
@tab @image{images/it_spoon, 12mm} @tab @yref{it_spoon}
@item @image{images/it_springboard, 12mm} @tab @yref{it_springboard}
@tab @image{images/it_spring_2, 12mm} @tab @yref{it_spring}_drop
@tab @image{images/it_spring, 12mm} @tab @yref{it_spring}_keep
@item @image{images/it_squashed, 12mm} @tab @yref{it_squashed}
@tab @image{images/it_strip_b2, 12mm} @tab @yref{it_strip}_ew
@tab @image{images/it_surprise, 12mm} @tab @yref{it_surprise}
@item @image{images/it_sword, 12mm} @tab @yref{it_sword}
@tab @image{images/it_trap, 12mm} @tab @yref{it_trap}
@tab @image{images/it_trigger, 12mm} @tab @yref{it_trigger}
@item @image{images/it_umbrella, 12mm} @tab @yref{it_umbrella}
@tab @image{images/it_vortex, 12mm} @tab @yref{it_vortex}
@tab @image{images/it_weight, 12mm} @tab @yref{it_weight}
@item @image{images/it_wormhole, 12mm} @tab @yref{it_wormhole}
@tab @image{images/it_wrench, 12mm} @tab @yref{it_wrench}
@tab @image{images/it_yinyang, 12mm} @tab @yref{it_yinyang}
@end multitable

@c ----------------- Item Attributes --------------------
@node Item Attributes
@section Item Attributes

@menu
* fireproof::         -
* freezable::         Affinity to be frozen in ice
* liftable::          Allowance for actors to pick up
* portable::          Ability to be added to the inventory
@end menu


@c ----------------- fireproof --------------------
@node fireproof
@subsection fireproof


@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table


@c ----------------- freezable --------------------
@node freezable
@subsection freezable

Describes the affinity of an item to be frozen by an @ref{st_ice}. All
@ref{portable} items a freezable. But some otherwise static items may be
freezable, too.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read only
@end table


@c ----------------- liftable --------------------
@node liftable
@subsection liftable

Describes the ability of @ref{Actors} to pick up an item from a floor. Note
that some items can be added to the player's inventory and can be dropped onto
a floor but nevertheless can not be picked up later on.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read only
@end table


@c ----------------- portable --------------------
@node portable
@subsection portable

Determines whether an item can be added to the player's inventory. All
@ref{liftable} items are portable. Portable items that are not liftable can
either be added to the inventory by means of the world @ref{add} method or
by an actor hitting a variant of @ref{st_dispenser}.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read only
@end table


@c ----------------- Liftable Items --------------------
@node Liftable Items
@section Liftable Items

@menu
* it_bag::             Portable Item Container
* it_banana::          Transformable Banana
* it_bottle::          Bottle of Booze
* it_brake::           Portable Stone Brake
* it_brush::           Brush for Painting and Sweeping
* it_cherry::          Source of Invisibility
* it_coffee::          Cup of Coffee
* it_coin::            Enigma's currency
* it_document::        Readable Text Document
* it_drop::            Magic Transformation Elixir
* it_dynamite::        Exploder
* it_extinguisher::    Fire Extinguisher
* it_extralife::       Another Life or Glasses
* it_flag::            Respawn Position Marker
* it_floppy::          Lock opening uncoded Floppy
* it_glasses::         Glasses to spot certain objects
* it_hammer::          Stone breaking Hammer
* it_key::             Lock opening coded Key
* it_magicwand::       Wizard's Tools
* it_pencil::          Pencil to mark Objects
* it_pin::             Friction increasing crampon
* it_pipe::            Pipe for Transmissions
* it_puller::          Stone pulling item
* it_ring::            Position Exchange Tool
* it_rubberband::      Unconnected Rubberband
* it_seed::            Seeds for Wood, Volcano Stones
* it_spade::           Shuffle for Meditation flattening
* it_spoon::           Controlled Suicide Tool
* it_spring::          Portable Spring
* it_surprise::        Random Transforming item
* it_sword::           Knight defeating Sword
* it_umbrella::        Death Protection Item
* it_weight::          Portable Mass
* it_wrench::          Tool for mechanical Stones
* it_yinyang::         Player toggling Switch
@end menu

@c ----------------- Bag Item --------------------
@node it_bag
@subsection it_bag
@obindex it_bag

A bag is a portable container for other objects. The player can fill it with
up to 13 other items, including other empty or filled bags.

The bag allows a player to carry in total more than 13 items in his inventory.
Nevertheless most items carried in a bag can not directly be applied. Just the
@ref{it_weight} does apply its mass even when carried in a bag. On the other
hand bags offer the user the possibility to pick up and drop items that can not
be dropped otherwise as they would be activated. E.g. an @ref{it_cherry} can
not be dropped without application, but if it is contained in a bag the bag
can be dropped and the cherry can be extracted later on. A bag is useful to
transfer multiple items via @ref{st_mail}, too.

As long as an @code{it_bag} is at the first place in the inventory, new items
are put into the bag instead of the inventory, until the bag is full (13 items).
The player can drop an @code{it_bag} anytime.  When picked up again, items from
the bag are put back into the inventory (until it is full).

The quite complex rules of pick up in detail:

@enumerate
@item
Inventory and bag are limited concerning pickups to 13 items.

@item
Both are generally LIFO (last item picked up is first item out), but the
inventory content can be rotated.

@item
If you pick up any item besides a bag and your first inventory item is not a bag
the item is added to the inventory.

@item
If you pick up any item besides a non-empty bag and your first inventory item is
a bag the item is added to the first inventory bag (this includes non-empty bags
being added into first inventory bags!)

@item
You empty a bag by dropping it and picking it up again with any item at the
first inventory position but a bag. As many items as possible are taken from the
bag and added to the inventory.

@item
Empty bags are never put into other bags (this would cause unresolvable
recursion problems). They will only be added as items directly to the inventory.

@item
If the "picked up" bag can not empty its contents to the inventory or a bag at
the first inventory position is full the bag is not picked up and keeps the
remaining items.

@end enumerate

You can add items directly to a bag by usage of the world @ref{add} method.

Bags are used by @ref{st_thief} and @ref{fl_thief} to carry their stolen
items. When the thieves are captured by @ref{st_chess} the bag remains on the
grid position filled up with the stolen items.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@item @b{mass} @ @ @i{values}: positive float number; @ @ @i{default}: @code{0.0}; @ @ @i{access}: @code{read only}
Sum of masses of all contained items. Currently just the @ref{it_weight} has a
mass.
@end table

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_bag, 12mm} @b{it_bag}
@end table
@end table

@c ----------------- Banana Item --------------------
@node it_banana
@subsection it_banana
@obindex it_banana

A portable item without direct usage. But it transforms into an @ref{it_cherry}
when hit by a laser beam.

When a stone is pushed over it an @ref{it_squashed} remains as remnants.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_banana, 12mm} @b{it_banana}
@end table
@end table

@c ----------------- Bottle Item --------------------
@node it_bottle
@subsection it_bottle
@obindex it_bottle

A bottle can be filled either with booze or with a message. When a bottle
breaks the remnants are lethal sherds.

A bottle filled with booze makes any ball like actor that activates it drunken.
The control of actor gets difficult as it will likely no longer move straight
into the intended direction. Fortunately the period of drunkenness lasts just
5 seconds per default. But you can set this time by the attribute
@samp{interval} to other values. The bottle will be dropped on activation.
Activation of several bottles in sequence will lead to longer periods of
drunkenness as the intervals will sum up.

Alternatively you can fill the bottle with a message by the attribute
@samp{text}. Like @ref{it_document} the message gets displayed on activation.
Of course the actor does not get drunken in this case.

When a stone gets pushed over a bottle it will break to sherds. These
remnants are lethal to @ref{ac_marble} and @ref{ac_pearl} when entering the
affected grid. But of course they can jump over the broken bottle or pass it
while being protected by an activated @ref{it_umbrella}. Unlike @ref{it_death}
the broken bottle can be removed by an actor by activation of an @ref{it_brush}
while jumping over it, or passing it with protection. But a broken bottle can
not be picked up and is not portable.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{BROKEN}; @ @ @i{default}: @code{BROKEN} @ @ @xref{state}
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{5.0}
Number of seconds that the actor becomes drunken.
@item @b{text}, @ @ @i{values}: string;
Either the text to be displayed or just a key word for identification on
@ref{Internationalization (i18n)}.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
Just an @samp{IDLE} bottle is liftable, a @samp{BROKEN} one is not liftable.
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
Just an @samp{IDLE} bottle is portable, a @samp{BROKEN} one is not portable.
@end table

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_bottle_idle, 12mm} @b{it_bottle}: state = @code{IDLE}
@item @image{images/it_bottle_idle, 12mm} @b{it_bottle_idle}: state = @code{IDLE}
@item @image{images/it_bottle_broken, 12mm} @b{it_bottle_broken}: state = @code{BROKEN}
@end table

@end table

@c ----------------- Brake Item --------------------
@node it_brake
@subsection it_brake
@obindex it_brake

The brake is a stone that can be picked up as an item by actors. The
@ref{st_brake} can be used to stop a running @ref{st_boulder} or a
@ref{st_lightpassenger}, what likely has given this object its name.

When an actor passes below the brake stone it will pick up the object like
other items. The brake will be added as a brake item to its inventory.
Unlike other items the brake can be dropped even on grids that are already
occupied by an item. But you can not drop the brake beneath another stone like
a @ref{it_seed}.

On dropping the brake item it transforms immediately to an @ref{st_brake} without
killing an item positioned on the grid. The brake stone will press an
@ref{it_trigger} beneath, what makes the brake item a portable trigger key.

The item itself will never exist on the world grid. It exists just as part of
the player inventory or item containers like @ref{it_bag}.

Due to the @ref{Snapshot Principle} you should never instantiate this item. Do
set an @ref{st_brake} to the world grid positions instead. This item is listed
for your understanding what happens to a picked up brake and for identifying
an @ref{Object Kind} @samp{it_brake} in an inventory or a container.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
Even though being freezable a brake will never freeze as an item, as it is
always converted to an @ref{st_brake} on being dropped or placed onto a floor.
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/st_brake, 12mm} @b{it_brake}
@end table

@end table

@c ----------------- Brush Item --------------------
@node it_brush
@subsection it_brush
@obindex it_brush

A brush that is useful to paint some stones and sweep away some otherwise
static items.

Stones must be hit with the brush revealed as the first item in the inventory.
To sweep away nasty items the actor must activate the brush while being on the
grid, or while jumping or flying over it:

@itemize @bullet
@item @ref{st_actorimpulse}, invisible - makes invisible variant visible
@item @ref{st_blur}, magic -  transforms to @ref{st_passage}
@item @ref{st_flat}, burnable - transforms to @ref{st_flat}
@item @ref{st_flat}, moveburnable - transforms to @ref{st_flat}_movable
@item @ref{st_ghost}, purplemarble - transforms to @ref{st_purplemarble}
@item @ref{st_ghost}, break - transforms to @ref{st_break}_oxydc
@item @ref{st_lightpassenger}, off - reactivates to state @samp{ON}
@item @ref{it_bottle}, broken - remove from floor
@item @ref{it_burnable}, ash - remove from floor
@item @ref{it_burnable}, fireproof - remove from floor
@item @ref{it_cross} - remove from floor
@item @ref{it_squashed} - remove from floor
@end itemize

The brush is sensitive to laser light and dissolves with an @ref{it_explosion}_nil
leaving no remnants when being hit by light.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_brush, 12mm} @b{it_brush}
@end table

@end table

@c ----------------- Cherry Item --------------------
@node it_cherry
@subsection it_cherry
@obindex it_cherry

A magic item that makes the activating actor for 8 seconds invisible. But not
all actors become invisible. Just the ball like actors @ref{ac_marble} and
@ref{ac_pearl} do vanish.

An invisible actor can walk through most kinds of glass
(@pxref{Transparent Stones}) and as being invisible they do no longer attract
hostile @ref{ac_rotor} and @ref{ac_top}.

When several cherries are activated in sequence each does prolong the actor's
time of invisibility by additional 8 seconds.

Other actors drop the cherry as an @ref{it_squashed} on activation. Sending a
cherry via an @ref{st_mail} results in an  @ref{it_squashed}, too. This
gives you the control that a cherry added to one player's inventory can not be
easily transfered to other actors assigned to the other player. Just
@ref{st_thief} and @ref{fl_thief} are able to steal the cherry undamaged.

When a stone is pushed over a cherry an @ref{it_squashed} remains as remnants.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_cherry, 12mm} @b{it_cherry}
@end table
@end table

@c ----------------- Coffee Item --------------------
@node it_coffee
@subsection it_coffee
@obindex it_coffee

A totally passive cup of coffee. It can be picked up and be dropped many times.
It blocks laser light, prohibits @ref{it_crack} spreading but it burns on fire
and is blown away on @ref{it_bomb} explosions.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_coffee, 12mm} @b{it_coffee}
@end table
@end table

@c ----------------- Coin Item --------------------
@node it_coin
@subsection it_coin
@obindex it_coin

A coin activates an @ref{st_coinslot} when inserted by hitting the stone with
the coin as first item in the players inventory. The time interval of activity
of the coinslot depends on the coin type that is represented by its
@samp{state}. Small, medium and large coin variants do exist.

When hit by a moving stone the coin type changes from small to medium and
from medium to large.

A laser beam transforms a small coin into an @ref{it_umbrella}, a medium coin
into an @ref{it_hammer} and a large coin into an @ref{it_extralife}.

A coin that comes into existence on an illuminated grid position will not
transform due to already existing laser beams. But it will transform on the first
additional beam and on laser beams that are switched off and on again.

@table @asis

@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{SMALL}, @code{MEDIUM}, @code{LARGE}; @ @ @i{default}: @code{SMALL}; @ @ @i{access}: @code{read only} @ @ @xref{state}
Represents the coin type with @samp{SMALL} being a coin of 2 cents, @samp{MEDIUM}
being a coin of 5 cents and @samp{LARGE} being a coin of 10 cents..
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_coin_s, 12mm} @b{it_coin}: state = @code{SMALL}
@item @image{images/it_coin_s, 12mm} @b{it_coin_s}: state = @code{SMALL}
@item @image{images/it_coin_m, 12mm} @b{it_coin_m}: state = @code{MEDIUM}
@item @image{images/it_coin_l, 12mm} @b{it_coin_l}: state = @code{LARGE}
@end table

@end table

@c ----------------- Document Item --------------------
@node it_document
@subsection it_document
@obindex it_document

This item looks like a piece of paper and contains a text message that can be
displayed by activating the item. It is destroyed by explosions from
@ref{it_bomb}, @ref{st_dispenser}, @ref{it_dynamite} and by burning fire.
The document is sensitive to laser light and dissolves with an
@ref{it_explosion}_nil leaving no remnants when being hit by light.

Other message carrying objects are @ref{st_document} and @ref{it_bottle}.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{text}, @ @ @i{values}: string;
Either the text to be displayed or just a key word for identification on
@ref{Internationalization (i18n)}.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}
@table @asis
@item @b{ignite}
Burn and destroy the document.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_document, 12mm} @b{it_document}
@end table
@end table

@c ----------------- Drop Item --------------------
@node it_drop
@subsection it_drop
@obindex it_drop

The drop is a magic elixir for temporary actor transformations. On activation
the actor transforms into another kind, lives for 5 seconds with all qualities
of this kind and then transforms back to its old kind. The drop gets consumed
by its activation. Generally it is not possible to prolong the transformation
by activation of several drops.

Note that this object is currently just defined for the following actors:

@itemize @bullet
@item @ref{ac_marble} transforms to @ref{ac_rotor}.
@end itemize

Providing a drop in a level with @ref{ac_pearl} will likely cause
incompatibilities with future Enigma versions.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_drop, 12mm} @b{it_drop}
@end table

@end table

@c ----------------- Dynamite Item --------------------
@node it_dynamite
@subsection it_dynamite
@obindex it_dynamite

Dynamite is an explosive that can be picked up and that can be easily ignited
at any free grid position. It ignites on drop, or if positioned on the floor in
@samp{IDLE} state it ignites on laser light, nearby fire and other nearby
explosions as those caused by @ref{it_bomb}, @ref{st_dispenser}, or other
dynamite. A falling @ref{ot_cannonball} lets it explode immediately without prior
ignition.

On ignition its fuse starts burning. During this @samp{ACTIVE} state the
dynamite can longer be picked up. After a short time the dynamite explodes
causing on the 8 neighboring positions items to ignite and some stones like
@ref{st_break} to dissolve, too. The explosion leaves at its position an
@ref{it_meditation}_hollow on all floor kinds besides @ref{fl_ice} where an
@ref{it_crack}_water remains.

Generally there is no direct way to stop a burning dynamite in order to prevent
the explosion. It is even not allowed to reset the @samp{state} attribute to
@samp{IDLE}. But when the user pushes an @ref{st_ice} over an @samp{ACTIVE}
dynamite it will freeze and stop burning, returning to state @samp{IDLE}.

Dynamite items will be added to the inventory when an actor hits a
@ref{st_dispenser}_dynamite.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{ACTIVE}; @ @ @i{default}: @code{IDLE} @ @ @xref{state}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
Just @samp{IDLE} dynamite can be added to the inventory, burning @samp{ACTIVE}
ones are not portable.
@end table

@item @b{Messages:}
@table @asis
@item @b{explode}
Direct explosion without burning fuse.
@item @b{ignite}
Ignite the fuse.
@item @b{heat}
Ignite the fuse.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_dynamite, 12mm} @b{it_dynamite}: state = @code{IDLE}
@item @image{images/it_dynamite_burning, 12mm} @b{it_dynamite_burning}: state = @code{ACTIVE}
@end table

@end table

@c ----------------- Extinguisher Item --------------------
@node it_extinguisher
@subsection it_extinguisher
@obindex it_extinguisher

A fire extinguisher that allows to extinguish burning fire and to protect areas
with extinguishing foam of upcoming fire. @xref{Fire Spreading}.

A full loaded extinguisher allows two applications. The first one covers the
nearest 13 grids, whereas the second one covers just 5 grids, the actor position
itself and the 4 direct neighbor positions. The foam is an @ref{it_burnable} of
kind @samp{fireproof} which can be cleaned with an @ref{it_brush} or by a
@ref{Flood Spreading}.

The load is given by the attribute @samp{state} of the extinguisher and is
visible for the user by a color spot. Green is a @samp{FULL} extinguisher,
yellow a @samp{MEDIUM} filled extinguisher and red an @samp{EMPTY} extinguisher.

Extinguishers themselves are fireprotected as long as they are not empty.

The @samp{toggle} message refills an extinguisher by one load until it is
@samp{FULL} again.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{EMPTY}, @code{MEDIUM}, @code{FULL}; @ @ @i{default}: @code{FULL} @ @ @xref{state}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}
@table @asis
@item @b{toggle} @ @ @xref{toggle}
A toggle causes a refill by one load.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_extinguisher, 12mm} @b{it_extinguisher}: state = @code{FULL}
@item @image{images/it_extinguisher, 12mm} @b{it_extinguisher_full}: state = @code{FULL}
@item @image{images/it_extinguisher_2, 12mm} @b{it_extinguisher_medium}: state = @code{MEDIUM}
@item @image{images/it_extinguisher_3, 12mm} @b{it_extinguisher_empty}: state = @code{EMPTY}
@end table

@end table

@c ----------------- Extralife Item --------------------
@node it_extralife
@subsection it_extralife
@obindex it_extralife

An extralife transforms into @ref{it_glasses} when hit by a laser beam and is
itself a laser transformation result of an @samp{it_coin_l} (@pxref{it_coin}).
The global variable @ref{ExtralifeGlasses} describes what the new glasses are
able to spot.

An extralife that comes into existence on an illuminated grid position will not
be destroyed due to already existing laser beams. But it will be destroyed on
the first additional beam and on laser beams that are switched off and on again.

If another item transforms into an extralife this new extralife will be immune to
light destruction for a short latency period to avoid repeated item
transformations.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_extralife, 12mm} @b{it_extralife}
@item @image{images/it_extralife, 12mm} @b{it_extralife_new}: An extralife that is immune to light destruction for a short latency period.
@end table

@end table

@c ----------------- Flag Item --------------------
@node it_flag
@subsection it_flag
@obindex it_flag

Flags do mark the place where killed actors will be resurrected. Flags exist
in two colors, @samp{BLACK} and @samp{WHITE}. Each can be used to define the
respawn position of matching colored @ref{ac_marble}s and @ref{ac_pearl}s.

As a level can contain many flags of the same @samp{color} the respawn position
can not be defined by the flag position itself. The respawn position is the
position of the last dropped flag of a given color. Additionally the respawn
position gets cleared when after the last drop any flag of the same color gets
picked up again. When no flag defined respawn position exists the actors will be
resurrected at their initial position or the last secure position, if the global
attribute @ref{AutoRespawn} is set to @code{true}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{color} @ @ @i{values}: @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{BLACK}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_flag_black, 12mm} @b{it_flag}: color = @code{BLACK}
@item @image{images/it_flag_black, 12mm} @b{it_flag_black}: color = @code{BLACK}
@item @image{images/it_flag_white, 12mm} @b{it_flag_white}: color = @code{WHITE}
@end table
@end table

@c ----------------- Floppy Item --------------------
@node it_floppy
@subsection it_floppy
@obindex it_floppy

A floppy activates an @ref{st_floppy} when inserted by hitting the stone with
the floppy as first item in the player's inventory.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_floppy, 12mm} @b{it_floppy}
@end table

@end table

@c ----------------- Glasses Item --------------------
@node it_glasses
@subsection it_glasses
@obindex it_glasses

Glasses help a marble to spot certain other objects that are otherwise invisible
or indistinguishable.

To be effective glasses must be hold in the top level of a player's inventory.
That means that the glasses must be shown in the inventory and not be buried
in an @ref{it_bag} that is part of the inventory. Of course glasses just help
those actors that are attached to the player wearing the glasses.

Glasses can make invisible @ref{st_death} visible, can uncover invisible
passages by making hollow stones transparent, can make inactive
@ref{st_lightpassenger} be distinguishable from @ref{st_darkglass}, can make
invisible @ref{it_sensor}, @ref{it_trap} and @ref{st_actorimpulse} be visible.

All these features are configurable by the constants @samp{SPOT_DEATH},
@samp{SPOT_HOLLOW}, @samp{SPOT_LIGHTPASSENGER}, @samp{SPOT_SENSOR},
@samp{SPOT_TRAP} and @samp{SPOT_ACTORIMPULSE}. You can set the @samp{state}
attribute to a sum of these constants that should apply to given glasses. The
default is for backward compatibility
@samp{SPOT_DEATH + SPOT_HOLLOW + SPOT_LIGHTPASSENGER}. When a player wears
several glasses he spots everything that any of the glasses could spot.

Glasses break when a stone is pushed over them. Broken glasses spot nothing.

Glasses result from the laser light transformation of @ref{it_extralife}. The
features of such new glasses are determined by the global variable
@ref{ExtralifeGlasses}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: positive numbers; @ @ @i{default}: @code{SPOT_DEATH + SPOT_HOLLOW + SPOT_LIGHTPASSENGER} @ @ @xref{state}
A sum of the constants @samp{SPOT_DEATH}, @samp{SPOT_HOLLOW},
@samp{SPOT_LIGHTPASSENGER}, @samp{SPOT_SENSOR}, @samp{SPOT_ACTORIMPULSE},
@samp{SPOT_TRAP}. @samp{SPOT_NOTHING} is the state of a broken glasses.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_glasses, 12mm} @b{it_glasses} Active glasses item.
@item @image{images/it_glasses_broken, 12mm} @b{it_glasses_broken} Broken glasses that spot nothing.
@end table

@end table

@c ----------------- Hammer Item --------------------
@node it_hammer
@subsection it_hammer
@obindex it_hammer

The hammer is used to destroy some stones, see @ref{Breakable Stones} and
@ref{st_lightpassenger}.

It transforms into @ref{it_sword} when hit by a laser beam and is itself a
laser transformation result of an @ref{it_sword} and an @samp{it_coin_m}
(@pxref{it_coin}).

An hammer that comes into existence on an illuminated grid position will not
transform due to already existing laser beams. But it will transform on the first
additional beam and on laser beams that are switched off and on again.

If another item transforms into an hammer this new hammer will be immune to
further light transformations for a short latency period to avoid unstable
flickering of repeated item transformations.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_hammer, 12mm} @b{it_hammer} A standard hammer item.
@item @image{images/it_hammer, 12mm} @b{it_hammer_new} A hammer that is immune to light transformations for a short latency period.
@end table

@end table

@c ----------------- Key Item --------------------
@node it_key
@subsection it_key
@obindex it_key

A key activates an @ref{st_key} when inserted by hitting the stone with
the key as first item in the player's inventory.

Usually the @samp{code} of the key is not visually unveiled. But if you
set @samp{invisible} to the value @samp{false} the code becomes visible for
number code values @samp{1} to @samp{8}. The code is just visible, when the
key is part of the inventory. This helps the user to distinguish multiple keys
in the inventory and to assign them to the matching @ref{st_key}s.

An @samp{invisible} key reveals its code when being inserted in a matching,
unveiled @ref{st_key}. The code remains visible, when the user withdraws the
key from the stone and adds it to his inventory.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{code}, @ @ @i{values}: number or string; @ @ @i{default}: @code{1}
The code of a key must match that of an @ref{st_key} to unlock it.
@item @b{invisible} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
A visible key unveils its @samp{code} by a color spot when being lifted.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_key, 12mm} @b{it_key}
@end table
@end table

@c ----------------- MagicWand Item --------------------
@node it_magicwand
@subsection it_magicwand
@obindex it_magicwand

The wizard's tool, that allows to do all sort of magic things if it is the
wielded item in the player's inventory:

@itemize @bullet
@item @ref{st_blur}, magic - transforms to @ref{st_passage},
@item @ref{st_boulder} - changes orientation of a boulder,
@item @ref{st_chess} - changes the color of a chess stone,
@item @ref{st_ghost}, greenbrown - transforms to @ref{st_greenbrown},
@item @ref{st_magic}, brick - transforms to a @ref{st_rawglass},
@item @ref{st_oneway} - changes orientation of a oneway,
@item @ref{st_puzzle} - scrambles blue puzzle stones instead of pushing, causes complete
clusters to explode,
@item @ref{st_rubberband} - makes rubberband stones movable,
@item @ref{st_stoneimpulse}, movable - avoid pulsing on pushes.
@end itemize

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none
@item @b{Action:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_magicwand, 12mm} @b{it_magicwand}
@end table

@end table

@c ----------------- Pencil Item --------------------
@node it_pencil
@subsection it_pencil
@obindex it_pencil

An item to mark floors and stones.

An activated pencil scratches an @ref{it_cross} on most floors. As the pencil
gets consumed by this operation the cross takes the pencils identity on
this @ref{Object Transformation}. But on @ref{fl_ice} the pencil makes a small
@ref{it_crack} as it is so sharp. On indestructible floors like @ref{fl_abyss},
@ref{fl_water} and @ref{fl_swamp} and on @ref{fl_bridge} the pencil can not
be activated at all. Any existing item on the floor does prevent a pencil
application, too. The actor can only mark a floor if it is on the floor and not
flying. During a jump an actor will just drop the pencil as an item.

On actor hits with a revealed pencil on a @ref{st_flat} the stones gets marked
burnable. Again the pencil is consumed on this operation. Both the plain and
the movable variants can be marked.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_pencil, 12mm} @b{it_pencil}
@end table

@end table

@c ----------------- Pin Item --------------------
@node it_pin
@subsection it_pin
@obindex it_pin

A pin is a friction increasing item that can be used as a crampon on @ref{fl_ice}.
When it is picked up and is added to the inventory it significantly increases
the floor friction applied to all actors owned by the inventory's owner.

Pins do just increase friction as long as they are directly part of the
inventory. A pin contained within an @ref{it_bag}, being part of the inventory,
has no influence on the friction. Two or more pins do not apply more friction
than a single pin. As soon as the last pin is dropped the friction returns
to its standard values.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_pin, 12mm} @b{it_pin}
@end table

@end table

@c ----------------- Pipe Item --------------------
@node it_pipe
@subsection it_pipe
@obindex it_pipe

Pipe items are used to build item transporting pipes connected to an
@ref{st_mail}.

Pipe items are described by their @samp{connections} to neighbor grids. A pipe
is build up of items with fitting connections.

Even though there exist pipe ending items with just one connection there is
currently no known usage of them besides decoration.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{connections}, @ @ @i{values}: string; @ @ @i{default}: @code{"ew"}
Describes the pipe connections to the neighbor grids. The string is a substring of
@code{"nesw"} listing the existing connections. The sequence of the sides, north,
east, south, west, is guaranteed on read access but arbitrary on write access.
Currently only pipes with one or two connections do exist.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none
@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_pipe_e, 12mm} @b{it_pipe} connections = @code{"ew"} The horizontal pipe.
@item @image{images/it_pipe_f, 12mm} @b{it_pipe_w} connections = @code{"w"}
@item @image{images/it_pipe_b, 12mm} @b{it_pipe_s} connections = @code{"s"}
@item @image{images/it_pipe_d, 12mm} @b{it_pipe_sw} connections = @code{"sw"}
@item @image{images/it_pipe, 12mm} @b{it_pipe_e} connections = @code{"e"}
@item @image{images/it_pipe_e, 12mm} @b{it_pipe_ew} connections = @code{"ew"} The horizontal pipe.
@item @image{images/it_pipe_c, 12mm} @b{it_pipe_es} connections = @code{"es"}
@item @image{images/it_pipe_g, 12mm} @b{it_pipe_n} connections = @code{"n"}
@item @image{images/it_pipe_i, 12mm} @b{it_pipe_nw} connections = @code{"nw"}
@item @image{images/it_pipe_j, 12mm} @b{it_pipe_ns} connections = @code{"ns"} The vertical pipe.
@item @image{images/it_pipe_h, 12mm}@b{it_pipe_ne} connections = @code{"ne"}
@end table
@end table

@c ----------------- Puller Item --------------------
@node it_puller
@subsection it_puller
@obindex it_puller

A puller item looks like a white arrow. It can be picked up. But when being
dropped it gets activated and whirls around. The actor should leave the grid
immediately as the puller will finally dissolve in a lethal explosion.

But the main purpose of the puller is its ability to pull stones. The arrow
@samp{orientation} indicates the direction into which a stone will be pulled
when the item is dropped in front. The pull takes place immediately at the end
of the short explosion. It is a full blown stone pull, that will pull others
stones connected to the directly affected stone via @ref{ot_wire}, too. With
the explosion the puller item ceases to exist.

@table @asis
@item @b{Attributes:}
@table @asis
@atindex orientation
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{WEST}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none
@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_puller_4, 12mm} @b{it_puller} orientation = @code{WEST}
@item @image{images/it_puller_4, 12mm} @b{it_puller_w} orientation = @code{WEST}
@item @image{images/it_puller_3, 12mm} @b{it_puller_s} orientation = @code{SOUTH}
@item @image{images/it_puller_2, 12mm} @b{it_puller_e} orientation = @code{EAST}
@item @image{images/it_puller, 12mm} @b{it_puller_n} orientation = @code{NORTH}
@end table
@end table

@c ----------------- Ring Item --------------------
@node it_ring
@subsection it_ring
@obindex it_ring

The ring is a magic position exchange item. On activation the ring gets dropped
onto the grid and the actor gets warped either to the actors respawn position
or to the position of another actor that is warped to the initiators position in
exchange.

Note that this object is currently just defined in the following cases:

@itemize @bullet
@item just one arbitrary actor owned by player @samp{YIN} - the actor gets
warped to its respawn position.
@item just an @ref{ac_marble}_black owned by player @samp{YIN} and an
@ref{ac_marble}_white owned by player @samp{YANG} - both actors exchange their
position.
@end itemize

Providing a ring in any other case will likely cause incompatibilities with
future Enigma versions.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_ring, 12mm} @b{it_ring}
@end table

@end table

@c ----------------- Rubberband Item --------------------
@node it_rubberband
@subsection it_rubberband
@obindex it_rubberband

A portable @ref{ot_rubberband} that gets connected to the bearer on activation.

As the rubberband's @samp{anchor1} is given by the activator itself, just the
@samp{anchor2} reference can be configured by this item. It can be any stone
or actor reference.

Of special interest may be the usage of dynamic nearest object references
(@pxref{Object Naming}). A marble will be able to connect to the nearest
object out of a given group.

If @samp{anchor2} does not exist, the @samp{it_rubberband} will be dropped.

The other attributes describe the force and length parameters of the
@ref{ot_rubberband}, that will be created on application of the item. In fact
the item's identity will be transferred to its successor
(@pxref{Object Transformation}). After creation of the life rubberband the
action message will be send to the target. Note that it is actually the
@ref{ot_rubberband} as the successor that sends the message.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{anchor2} @ @ @i{values}: actor or stone object; @ @ @i{default}: @code{nil}
Object reference or name of an actor or a stone that the rubber will be
connected to. The reference will be evaluated on item activation.
@item @b{strength} @ @ @i{values}: number; @ @ @i{default}: @code{10.0}
The force strength.
@item @b{length} @ @ @i{values}: positive number or @code{AUTOLENGTH}; @ @ @i{default}: @code{1.0}
The natural length above which forces are applied.
@item @b{threshold} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The length smaller than the natural length below which inverted forces are applied.
@item @b{min} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The minimum length at which actors bounce.
@item @b{max} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The maximum length at which actors bounce.
@item @b{scissor} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Rubberband cutting behaviour on connection. On a value of @code{true} the
activation of this rubberband will cut all existing rubberbands which are
currently connected to the activating actor.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none
@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
On successful activation of this item the action message is send with a value of
@samp{true}. Note that the parameter @samp{sender} will report the new
@ref{ot_rubberband}.

@item @b{Variants:}
@table @asis
@item @image{images/it_rubberband, 12mm} @b{it_rubberband}
@end table
@end table


@c ----------------- Seed Item --------------------
@node it_seed
@subsection it_seed
@obindex it_seed

Stone seeds are items that start growing and finally transforming to stones
on activation. There are different @samp{flavor}s of seeds that all look the
same, but do grow to different stones. While a @code{"wood"} seed grows to an
@ref{st_box}_wood, a @code{"hay"} seed grows to an @ref{st_box}_hay, a
@code{"greenbrown"} seed grows to an unmovable @ref{st_greenbrown} and a
@code{"volcano"} seed grows to an active @ref{st_volcano}.

Seeds can be dropped on any item free grid position, even beneath another stone
that will get killed by the seed successor stone.

Seeds get automatically activated when being dropped, when hit by a laser beam
or a stone being pushed on them. You can activate them by @samp{grow} and
@samp{signal} messages, too.

The identity of the seed gets transferred to the emerging stone including the
attribute @samp{secure}.

The only method of handling seeds without activation are containment within a
@ref{it_bag} or sending them via @ref{st_mail} to a destination grid.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{flavor}, @ @ @i{values}: @code{"wood"}, @code{"hay"}, @code{"greenbrown"}, @code{"volcano"}; @ @ @i{default}: @code{"wood"}
The type of the resulting stone.
@item @b{secure} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
This attribute is transferred to the resulting stone. The @ref{st_volcano} and
@ref{st_box} make use of it.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}
@table @asis
@item @b{grow}
Start growing the seed.
@item @b{signal} @ @ @xref{signal}
Start growing the seed.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_seed, 12mm} @b{it_seed} flavor = @code{"wood"}
@item @image{images/it_seed, 12mm} @b{it_seed_wood} flavor = @code{"wood"}
@item @image{images/it_seed, 12mm} @b{it_seed_hay} flavor = @code{"hay"}
@item @image{images/it_seed, 12mm} @b{it_seed_greenbrown} flavor = @code{"greenbrown"}
@item @image{images/it_seed, 12mm} @b{it_seed_volcano} flavor = @code{"volcano"}
@end table

@end table

@c ----------------- Spade Item --------------------
@node it_spade
@subsection it_spade
@obindex it_spade

A spade activated while being on the grid position of an @ref{it_meditation}
will flatten this by one degree and will finally eliminate it completely.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_spade, 12mm} @b{it_spade}
@end table

@end table

@c ----------------- Spoon Item --------------------
@node it_spoon
@subsection it_spoon
@obindex it_spoon

Dropping a spoon is a medieval synonym for dying. The poor people had nothing
besides a wooden spoon. They never dropped it. They had to peg out to give away
their spoon.

Thus an Enigma spoon shatters the actor who drops it. When a player owns
multiple actors just the active one gets killed. This is an essential difference
to pressing F3, what shatters all actors of all players. When providing a spoon
you may sometimes want to revoke the ability to commit a global suicide by
pressing F3. You can do this by setting the global variable @ref{AllowSuicide}
to @samp{false}.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_spoon, 12mm} @b{it_spoon}
@end table

@end table

@c ----------------- Spring Item --------------------
@node it_spring
@subsection it_spring
@obindex it_spring

Springs let @ref{Flying Actors} jump on activation.

There are two types of portable springs. A thin one that is kept in the
inventory on activation and can thus be used multiple times in sequence. And
a thick, condensed one that gets dropped on activation. A static jump
facility that can not be picked up by an actor is the @ref{it_springboard}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_spring, 12mm} @b{it_spring}
@item @image{images/it_spring, 12mm} @b{it_spring_keep}
@item @image{images/it_spring_2, 12mm} @b{it_spring_drop}
@end table
@end table

@c ----------------- Surprise Item --------------------
@node it_surprise
@subsection it_surprise
@obindex it_surprise

An item that transforms into a random item as soon as the player drops it.

The replacement item is a random one out of a given selection. You can set
the @samp{selection} attribute with tokens of strings. Every string needs either
to be an @ref{Object Kind} or a tile key prefixed by an equal sign @samp{=}.

@example
ti["m"] = @{"it_magicwand"@}
ti["e"] = @{"it_extralife"@}
ti["s"] = @{"it_surprise", selection=@{"it_seed", "=m", "=e", "=e"@}@}
@end example

The replacement item is randomly chosen out of the given selection. By listing
an item several times you can take influence on the likelihood.

The tile declarations referenced by a key may even contain objects besides
items. But you should make rare and proper usage of this feature.

The surprise item will perform its action after being dropped but before
being replaced. You can use this action to modify the selection or to
set objects on your own.

The surprise item is killed by any replacement item set to the grid position.
If your selection does not resolve to an item you may need to add @samp{"it_nil"}
to the replacement tile declaration.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{selection}, @ @ @i{values}: tokens of item kinds and tile keys; @ @ @i{default}: @code{@{"it_umbrella", "it_spring_keep", "it_dynamite", "it_coffee", "it_hammer"@}}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}
@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/it_surprise, 12mm} @b{it_surprise}
@end table

@end table

@c ----------------- Sword Item --------------------
@node it_sword
@subsection it_sword
@obindex it_sword

The sword is used to neutralize @ref{st_knight}.

It transforms into @ref{it_hammer} when hit by a laser beam and is itself a
laser transformation result of an @ref{it_hammer}.

A sword that comes into existence on an illuminated grid position will not
transform due to already existing laser beams. But it will transform on the first
additional beam and on laser beams that are switched off and on again.

If another item transforms into a sword this new sword will be immune to
further light transformations for a short latency period to avoid unstable
flickering of repeated item transformations.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_sword, 12mm} @b{it_sword} A standard sword item.
@item @image{images/it_sword, 12mm} @b{it_sword_new} A sword that is immune to light transformations for a short latency period.
@end table

@end table

@c ----------------- Umbrella Item --------------------
@node it_umbrella
@subsection it_umbrella
@obindex it_umbrella

An activated umbrella temporarily protects a marble from @ref{st_death},
@ref{st_knight}, @ref{st_thief}, @ref{fl_abyss}, @ref{fl_water},
@ref{fl_swamp}, @ref{fl_thief}, @ref{it_death}, @ref{it_trap},
broken @ref{it_bottle}, explosions, moving stones and all other internal
@samp{shatter} and @samp{fall} events; in other words, from all lethal
situations and thieves. The protection lasts for 10 seconds. Multiple umbrellas
activated in sequence will prolong the protection period.

An umbrella gets destroyed when hit by a laser beam and is itself a
laser transformation result of an @samp{it_coin_s}(@pxref{it_coin}).

An umbrella that comes into existence on an illuminated grid position will not
be destroyed due to already existing laser beams. But it will be destroyed on
the first additional beam and on laser beams that are switched off and on again.

If another item transforms into an umbrella this new umbrella will be immune to
light destruction for a short latency period to avoid repeated item
transformations.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_umbrella, 12mm} @b{it_umbrella} A standard umbrella item.
@item @image{images/it_umbrella, 12mm} @b{it_umbrella_new} An umbrella that is immune to light destruction for a short latency period.
@end table

@end table

@c ----------------- Weight Item --------------------
@node it_weight
@subsection it_weight
@obindex it_weight

A weight is an item with a mass, that defaults to the mass of 10 @ref{ac_marble}s.
When it is picked up it is added to the inventory and increases the mass of
all actors owned by the inventory's owner.

Weights can easily be picked up, but the player can not drop them. Just indirect
methods like hitting @ref{st_mail}, @ref{st_thief} or crossing a @ref{fl_thief}
may remove this item from the inventory.

The inventories mass is always updated to the mass of all weights kept in the
inventory or contained in any @ref{it_bag} contained in the inventory.

@table @asis

@item @b{Attributes:} none
@table @asis
@item @b{mass} @ @ @i{values}: positive float number; @ @ @i{default}: @code{+10.0}
Mass unit is the mass of an @ref{ac_marble}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_weight, 12mm} @b{it_weight}
@end table

@end table

@c ----------------- Wrench Item --------------------
@node it_wrench
@subsection it_wrench
@obindex it_wrench

A wrench wielded as first item in the players inventory causes some objects
to react on actor hits. An @ref{st_rotator} changes its turning direction.
A green @ref{st_turnstile} rotates backwards when hit. An @ref{st_window}
face pushed with a wrench will swap to the opposite side of the stone if
possible.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_wrench, 12mm} @b{it_wrench}
@end table

@end table

@c ----------------- Yinyang Item --------------------
@node it_yinyang
@subsection it_yinyang
@obindex it_yinyang

A special switch that allows the user to toggle the @ref{Player and Inventory}
between @code{YIN} and @code{YANG}.

On activation this item does not get dropped but remains unchanged in the
inventory.

If a level has been declared to be a full blown two player network level in
@ref{<modes>}, but is currently played on a single computer both players
get automatically an yinyang item added to their inventory to allow all actors
to be controlled at every point of time.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_yinyang, 12mm} @b{it_yinyang}
@end table

@end table

@c ----------------- Static Items --------------------
@node Static Items
@section Static Items

@menu
* it_blocker::         Shrinked Blocker Stone
* it_bomb::            Big Explosive Charge
* it_burnable::        Fire State
* it_crack::           Crack in the Floor
* it_cross::           Floor Switch for patient Actors
* it_death::           Impassable grid blocker
* it_explosion::       Short Explosion Animation
* it_landmine::        Buried Explosive
* it_laserbeam::           Laser Beam
* it_magnet::          Actor attracting Magnet
* it_meditation::      Hills and Hollows
* it_sensor::          Floor Switch for passing Actors
* it_shogun::          Dot for Shogun Stones
* it_springboard::     Static Spring
* it_squashed::        Remnant of squashed Fruits
* it_strip::           Narrow Bridge
* it_trap::            Invisible, covered Abyss
* it_trigger::         Floor Switch for Actors and Stones
* it_vortex::          Teleport of Marbles
* it_wormhole::        Teleport of Actors
@end menu


@c ----------------- Blocker Item --------------------
@node it_blocker
@subsection it_blocker
@obindex it_blocker

A door like object that grows to @ref{st_blocker} when an @ref{st_boulder}
passes. When the boulder did shrink and pass the blocker again it stays in its
item like open state until it is passed again by a boulder which causes it to
grow again to a blocker stone.

It fully supports the messages of any door like object and can be opened and
closed by any switch like object. Note that due to the transformation between
stone and item during opening and closing you should name the blocker
(@pxref{name}) and address the blocker by this name. The complete identity
with all attributes including any user attributes will be transferred between
stone and item. E.g. @code{@{it_switch, target="myblocker", action="toggle"@}}
will open and close a given blocker multiple times.

Note that the blocker is the only door object that allows a stone to be pushed
through. Just boulders cause the growing. Any other stone keeps the open state.

Another unique door feature is the closing of a blocker item caused by a
passing actor if the autoclose attribute is set to true.

Note that a dropped @ref{it_brake} destroys this item.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{0}, @code{1}; @ @ @i{default}: @code{1} @ @ @xref{state}
Use CLOSED and OPEN macros as values. The item represents the open state
and will always return state 1. But you can set its state what is equivalent
to sending an open message in case of value 1 and a close message in case of
value 0.

@atindex autoclose
@item @b{autoclose} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
A true value causes any actor passing this item to close and grow the blocker.

@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
A signal of value 1 sends an open message, a signal of value 0 sends a close
message.
@item @b{toggle} @ @ @xref{toggle}
A toggle causes a close message.
@item @b{close} @ @ @xref{close}
A close message takes immediate effect if the item is not covered by a stone.
The item transforms to a new growing @ref{st_blocker}. If it is covered by a
stone of whatever kind it will be marked as unlocked. The closing process starts
when the stone moves away.
@item @b{open} @ @ @xref{open}
As the item is open this message takes only effect if it is currently covered
by a stone and marked as unlocked. That means it should grow as soon as the
stone moves away what happens when an @ref{st_boulder} passes an idle blocker
item. In this case an open message locks the blocker again to avoid a growing
when the stone moves away.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
Sends an action at the moment the blocker reaches the open state. That means
an @ref{st_blocker} did open and did generate this blocker item as its
successor. The value will be @code{true} to express the open state.

@item @b{Variants:}
@table @asis
@item @image{images/st_blocker_4, 12mm} @b{it_blocker}
A standard blocker item.
@item @image{images/st_blocker_4, 12mm} @b{it_blocker_new}
A blocker that just finished shrinking. Mainly used internally as the direct
successor of an @ref{st_blocker}. But it may be useful to generate an initial
snapshot of a moving boulder over a blocker line, too. See example levels.
@end table

@end table

@c ----------------- Bomb Item --------------------
@node it_bomb
@subsection it_bomb
@obindex it_bomb

A bomb is an explosive that can not be picked up. It ignites on laser light,
nearby fire and other nearby explosions as those caused by other @ref{it_bomb}s,
@ref{it_dynamite}, @ref{st_dispenser} exploding directly above a bomb, or simply
by a solid stone being pushed over them (just a few stones like @ref{st_shogun},
@ref{st_box}_hay do not cause bombs to ignite). A falling @ref{ot_cannonball}
lets it explode immediately without prior ignition.

On ignition its fuse starts burning. After a short time the bomb explodes
causing on the 8 neighboring positions items to ignite and some stones like
@ref{st_break} to dissolve, too. An already burning floor however might get
extinguished by a neighboring bomb explosion.

@samp{BLACK} bombs will cause destructible items on the 4 neighboring positions
to be blown away, and dissolve the floor beneath to a @ref{fl_abyss}.

@samp{WHITE} bombs will cause destructible items on the 8 neighboring positions
to be blown away, and dissolve the floor beneath and the 8 neighboring
positions to @ref{fl_abyss}.

Bomb items will be added to the inventory when an actor hits a
@ref{st_dispenser}_bombblack or @ref{st_dispenser}_bombwhite.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{ACTIVE}; @ @ @i{default}: @code{IDLE} @ @ @xref{state}
@item @b{color} @ @ @i{values}: @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{BLACK}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
Just bombs in @samp{state} @samp{IDLE} are portable, burning @samp{ACTIVE} ones
can not be added to the inventory or an @ref{it_bag}.
@end table

@item @b{Messages:}
@table @asis
@item @b{explode}
Direct explosion without burning fuse.
@item @b{ignite}
Ignite the fuse.
@item @b{heat}
Ignite the fuse.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_bomb, 12mm} @b{it_bomb}: color = @code{BLACK}
@item @image{images/it_bomb, 12mm} @b{it_bomb_black}: color = @code{BLACK}
@item @image{images/it_bomb_b, 12mm} @b{it_bomb_white}: color = @code{WHITE}
@end table

@end table

@c ----------------- Burnable Item --------------------
@node it_burnable
@subsection it_burnable
@obindex it_burnable

A legacy item representing the fire state and handling the visible animation.
This item is nowadays mainly an internal system item as the @ref{Fire Spreading}
with its attributes and messages is mainly handled by the @ref{Floor Objects}.
But it may be essential for your understanding to be aware of this object in
all its variants. You may also need to make use of all variants on level
initialization due to the @ref{Snapshot Principle}.

The following variants do exist:
@itemize @bullet
@item @samp{invisible} - allow a floor tile to catch fire, and to ignite on
explosions; set the attributes @ref{burnable} and @ref{ignitable} on the floor
instead.
@item @samp{oil} - is the visible variant of the invisible burnable item.
@item @samp{ignited} - carries the starting-animation of fire; send the
@samp{setfire} message to a floor or set the floor with attribute
@samp{initfire} instead.
@item @samp{burning} - carries the animation of burning fire. Use setfire instead.
@item @samp{ash} - the unburnable remnant of a fire.
@item @samp{fireproof} - the extinguisher foam that protects from fire.
@end itemize

Note that you are not allowed to set or change the @samp{state} of a burnable
item. But you can investigate the kind of a burnable.

Besides by @ref{Fire Spreading} the user can interact with burnable items with
the following other objects:
@itemize @bullet
@item @ref{it_extinguisher} sprays @samp{fireproof} foam
@item @ref{it_brush} removes @samp{ash} and @samp{fireproof}
@item @ref{st_ice} removes all burnable besides @samp{oil} when being pushed over them
@end itemize

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: integer numbers between 0 and 5; @ @ @i{default}: @code{0}; @ @ @i{access}: @code{read only}  @ @ @xref{state}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}
@table @asis
@item @b{ignite} @ @ @xref{ignite}
Ignites the floor beneath.
@item @b{extinguish}
Changes burnable immediately to extinguisher foam.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/fl_white, 12mm} @b{it_burnable}: state = @code{0}
@item @image{images/fl_white, 12mm} @b{it_burnable_invisible}: state = @code{0}
@item @image{images/it_burnable_oil, 12mm} @b{it_burnable_oil}: state = @code{1}
@item @image{images/fl_white, 12mm} @b{it_burnable_ignited}: state = @code{2}
@item @image{images/it_burnable_burning, 12mm} @b{it_burnable_burning}: state = @code{3}
@item @image{images/it_burnable_ash, 12mm} @b{it_burnable_ash}: state = @code{4}
@item @image{images/it_burnable_fireproof, 12mm} @b{it_burnable_fireproof}: state = @code{5}
@end table

@end table

@c ----------------- Crack Item --------------------
@node it_crack
@subsection it_crack
@obindex it_crack

A legacy item that features a crack in the floor. A crack increases every time
an actor enters and finally dissolves the floor either into an @ref{fl_abyss}
or an @ref{fl_water}. The color of the fissures shows the upcoming new floor
kind and corresponds to the attribute @samp{flavor}.

The progress of the floor destruction is described by the attribute @samp{state}.
On every crack event the state advances by one and a cracking @samp{LARGE} crack
finally dissolves giving an actor on top just enough time to leave the grid at
once. Of course an actor jumping over a crack does not causes change on the
crack itself.

You can control the crack progress by the two attributes @samp{spreading} and
@samp{fragility}. Where as the first attribute describes the likelihood that the
crack spreads to a neighboring crack free grid, does the second attribute
describe the likelihood that an existing crack advances its state.

An actor entering a crack causes the crack itself to advance its state with the
given likelihood. A default @samp{abyss} crack causes existing cracks on any of
the 4 neighboring grid positions to advance their states, too. But a
@samp{water} crack does not advance neighboring cracks. Both do cause a spread
with the given likelihood of an invisible crack to any of the 4 neighboring grid
positions in case no crack or any other items exists on it.

Let us have another look on a spreading crack. An actor entering a crack causes
an invisible crack on the next grid. If the actor continues to move to this grid
the invisible crack advances to a small visible one, of course just with the
given likelihood. Note that this first and just this first crack progress takes
place with the likelihood of spreading, too. That means even if the fragility is
zero the invisible crack gets visible.

Another special feature is the behaviour of a large crack. An actor entering
causes it to dissolve. But this causes neither a spreading nor a crack advancing
on neighboring grids. This feature is essential to allow an actor to walk over
a path of large cracks, as the next grid may not dissolve on an actor entering
the one before.

Common attribute patterns besides the default ones are:
@itemize @bullet
@item @samp{spreading=0, fragility=0} - a fake crack that neither spreads nor dissolves
@item @samp{spreading=0, fragility=1} - a crack that dissolves and causes neighbor cracks to dissolve, but does not spread to new floors
@end itemize

Both attributes are inherited to new cracks during the process of spreading.
If not set they take as default the value of the global attributes. For a maximum
control you can set individual floors their own @ref{fragility (floor)}. These
values supersede the global @ref{Fragility} default.

Indestructible floors like @ref{fl_abyss}, @ref{fl_water}, @ref{fl_swamp} will
never crack. As any other item cracks do block laser light and prohibit other items to be
dropped on the same grid. Nearby fire, explosions and hitting
@ref{ot_cannonball}s will dissolve a crack by another step.

On the other hand @ref{st_ice} will putty any existing crack when being pushed
over it.

@table @asis

@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{INVISIBLE}, @code{SMALL}, @code{MEDIUM}, @code{LARGE}; @ @ @i{default}: @code{SMALL} @ @ @xref{state}
@item @b{flavor}, @ @ @i{values}: @code{"abyss"}, @code{"water"}; @ @ @i{default}: @code{"abyss"}
@item @b{spreading} @ @ @i{values}: positive number between 0.0 and 1.0; @ @ @i{default}: @code{0.5}, @ @ @xref{CrackSpreading}
@item @b{fragility} @ @ @i{values}: positive number between 0.0 and 1.0; @ @ @i{default}: @code{1.0}, @ @ @xref{Fragility}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}

@table @asis
@item @b{crack}
@item @b{toggle} @ @ @xref{toggle}
@item @b{ignite} @ @ @xref{ignite}
@item @b{heat} @ @ @xref{heat}
@end table

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/it_crack_abyss, 12mm}@tab  @b{it_crack}: state = @code{SMALL}, flavor = @code{"abyss"}
@tab @image{images/it_crack_water, 12mm}@tab  @b{it_crack}: state = @code{SMALL}, flavor = @code{"water"}
@item @image{images/fl_white, 12mm}@tab  @b{it_crack_i}: state = @code{INVISIBLE}, flavor = @code{"abyss"}
@tab @image{images/fl_white, 12mm}@tab  @b{it_crack_i}: state = @code{INVISIBLE}, flavor = @code{"water"}
@item @image{images/it_crack_abyss, 12mm}@tab  @b{it_crack_s}: state = @code{SMALL}, flavor = @code{"abyss"}
@tab @image{images/it_crack_water, 12mm}@tab  @b{it_crack_s}: state = @code{SMALL}, flavor = @code{"water"}
@item @image{images/it_crack_abyss_2, 12mm}@tab  @b{it_crack_m}: state = @code{MEDIUM}, flavor = @code{"abyss"}
@tab @image{images/it_crack_water_2, 12mm}@tab  @b{it_crack_m}: state = @code{MEDIUM}, flavor = @code{"water"}
@item @image{images/it_crack_abyss_3, 12mm}@tab  @b{it_crack_l}: state = @code{LARGE}, flavor = @code{"abyss"}
@tab @image{images/it_crack_water_3, 12mm}@tab  @b{it_crack_l}: state = @code{LARGE}, flavor = @code{"water"}
@end multitable

@end table

@c ----------------- Cross Item --------------------
@node it_cross
@subsection it_cross
@obindex it_cross

An eye-catching cross spot that can detect actors staying on it for a given
time. When an actor remains on top of the cross for the given @samp{interval}
without any other actor leaving or passing the cross grid the cross will perform
its action. Similar, but instant sensors for actors are @ref{it_sensor} and
@ref{it_trigger}

A cross can be drawn with an @ref{it_pencil} and it can be removed with an
@ref{it_brush}.

An @ref{st_lightpassenger} moving onto a cross item will switch off.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{0}, @code{1}; @ @ @i{access}: @code{read only} @ @ @xref{state}
The current state - @samp{0} for the last event being an actor leaving the cross,
@samp{1} for the last event being an actor entering the cross.

@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{10.0}
Number of seconds that the actor must stay on the sensor to cause an action.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
@item @b{Variants:}
@table @asis
@item @image{images/it_cross, 12mm} @b{it_cross}
@end table
@end table

@c ----------------- Death Item --------------------
@node it_death
@subsection it_death
@obindex it_death

This item shatters any marble that tries to pass the grid. Even jumping marbles
will be shattered. Just marbles protected by an activated @ref{it_umbrella} can
pass without taking harm. Apart from that an @samp{it_death} barrier can only be
passed by walking around the complete barrier or by warping through an
@ref{it_vortex}, an @ref{it_wormhole} or by means of an @ref{it_ring}.

The death item is the most secure barrier object. Comparable objects are
@ref{it_bottle}_broken, @ref{fl_abyss}, @ref{fl_water}, @ref{it_trap} or simply
any solid wall of stones. Usually these alternatives should be favored. The
death item should mainly be used when all other alternatives are too insecure.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_death, 12mm} @b{it_death}
@end table

@end table

@c ----------------- Explosion Item --------------------
@node it_explosion
@subsection it_explosion
@obindex it_explosion

An intermediate short living system item representing and visualizing an
explosion. There are very few acceptable usages of this item besides the
internal setting due to explosions of @ref{it_bomb}, @ref{it_dynamite},
@ref{it_landmine} and @ref{ot_cannonball}.

All explosions do shatter ball like actors.

The following variants do exist:
@itemize @bullet
@item @samp{nil} - no remnants.
@item @samp{hollow} - leave an @ref{it_meditation}_hollow.
@item @samp{crack} - make an @ref{it_crack}_water.
@item @samp{debris} - dissolve the floor to @ref{SubSoil}, which defaults to @ref{fl_abyss}
@end itemize

Note that you are not allowed to set or change the @samp{state} of an explosion
item. But you can investigate the kind of an explosion.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: integer numbers between 0 and 3; @ @ @i{default}: @code{0}; @ @ @i{access}: @code{read only}  @ @ @xref{state}
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_explosion, 12mm} @b{it_explosion}: state = @code{0}
@item @image{images/it_explosion, 12mm} @b{it_explosion_nil}: state = @code{0}
@item @image{images/it_explosion, 12mm} @b{it_explosion_hollow}: state = @code{1}
@item @image{images/it_explosion, 12mm} @b{it_explosion_crack}: state = @code{2}
@item @image{images/it_explosion, 12mm} @b{it_explosion_debris}: state = @code{3}
@end table

@end table

@c ----------------- Landmine Item --------------------
@node it_landmine
@subsection it_landmine
@obindex it_landmine

A static item that explodes on actors stepping onto its critical center part and
on stones being pushed onto the mine.

The landmine explodes shattering nearby marbles on the same grid and leaves an
hollow @ref{it_meditation} behind.

Actors can jump over a landmine and pass carefully between two adjacent
landmines without activating the mines. Landmines do neither react on nearby
explosions, nor fire, nor laserbeams.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Action:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_landmine, 12mm} @b{it_landmine}
@end table

@end table

@c ----------------- Laserbeam Item --------------------
@node it_laserbeam
@subsection it_laserbeam
@obindex it_laserbeam

A beam of laser light. This item is caused by an @ref{st_laser} that is switched
on. The beam is automatically calculated and the items are set by the engine.
You can not set laser beam items on your own. But you may detect a beam as an
item being located on the item layer. You are free to replace a laser beam item
by another item. This causes automatically a recalculation of the laser light.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_laser, 12mm} @b{it_laserbeam} can not be instantiated by levels
@end table
@end table

@c ----------------- Magnet Item --------------------
@node it_magnet
@subsection it_magnet
@obindex it_magnet

Attracts or repels actors in its @samp{range} with a force proportional to the
@samp{strength} and the inverse of the squared distance. A magnet can be
switched @samp{ON} and @samp{OFF}.

Note that no forces are applied to actors at a distance smaller than 0.05 grids
to avoid extraordinary large forces.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF} @ @ @xref{state}
The current magnet state - @samp{ON} for an active magnet, @samp{OFF} for an
inactive magnet.

@item @b{range} @ @ @i{values}: float number greater or equal 0; @ @ @i{default}: @code{10.0} @ @ @xref{MagnetRange}
The distance up to which the magnet applies forces to actors.

@item @b{strength} @ @ @i{values}: float number; @ @ @i{default}: @code{+30.0} @ @ @xref{MagnetStrength}
A scalar factor for magnet forces. Positive numbers are attracting forces
where as negative numbers are repelling forces.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
A signal of value 1 switches the magnet on, a value of 0 switches the magnet off.
@item @b{toggle} @ @ @xref{toggle}
A toggle causes a change in the magnet activity state.
@item @b{on} @ @ @xref{on}
Switches the magnet on.
@item @b{off} @ @ @xref{off}
Switches the magnet off.
@end table

@item @b{Action:}
none

@item @b{Variants:}
@table @asis
@item @image{images/it_magnet_off, 12mm} @b{it_magnet} state = @samp{OFF}.
@item @image{images/it_magnet_on, 12mm} @b{it_magnet_on} state = @samp{ON}.
@item @image{images/it_magnet_off, 12mm} @b{it_magnet_off} state = @samp{OFF}.
@end table

@end table

@c ----------------- Meditation Item --------------------
@node it_meditation
@subsection it_meditation
@obindex it_meditation

Meditation items are small round areas of flatness imperfection. All actors will
experience the slope forces that can be modified by the global scalar factor
@ref{MeditationStrength}. There are different shapes of meditation items that
are named according to their shape: @code{MEDITATION_CALDERA},
@code{MEDITATION_HOLLOW}, @code{MEDITATION_DENT}, @code{MEDITATION_BUMP},
@code{MEDITATION_HILL}, @code{MEDITATION_VOLCANO}.

Of special interest are @ref{ac_pearl}s resting on a meditation item. They are
counted as meditating after staying continuously for one second within the round
area of the item. One of the two @ref{Ending Conditions} of the game is that all
meditation marbles come to rest on mediation items.

As meditation items can dynamically be generated during the game by exploding
@ref{it_landmine} or @ref{it_dynamite} it may be necessary for an author to
mark those meditation items that are required to be filled with meditation
marbles. You do this by setting the @samp{essential} attribute to @code{true}.
Please make rare and obvious usage of this attribute, as the player can not
distinguish essential from not essential meditation items by their images.

Meditation items can transform into other shapes by various means.

First a user can push a solid stone over a meditation item or activate an
@ref{it_spade} on it. Both actions flatten the meditation, either
@code{MEDITATION_VOLCANO} -> @code{MEDITATION_HILL} -> @code{MEDITATION_BUMP}
-> @code{it_nil} or @code{MEDITATION_CALDERA} -> @code{MEDITATION_HOLLOW} ->
@code{MEDITATION_DENT} -> @code{it_nil}.

Secondly you can send a @code{"flip"} message to a meditation item which
transforms hollow like items into their hill like counterparts and vice versa:
@code{MEDITATION_VOLCANO} <-> @code{MEDITATION_CALDERA}, @code{MEDITATION_HILL}
<-> @code{MEDITATION_HOLLOW}, @code{MEDITATION_BUMP} <-> @code{MEDITATION_DENT}.

Third a @code{"signal"} message flips on a @code{1} value all meditations to
their hill like counterparts, keeping hill like meditations unchanged, and on a
@code{0} value to their hollow like counterparts, keeping hollow like meditations
unchanged.

A fourth message is @code{"toggle"}. It transforms @code{MEDITATION_HOLLOW} <->
@code{MEDITATION_VOLCANO}, @code{MEDITATION_CALDERA} <-> @code{MEDITATION_HILL},
@code{MEDITATION_BUMP} <-> @code{MEDITATION_DENT}.

Of course you can change the state by setting the attribute anytime in any sequence
you like. Essentialness is kept on shape transformations and mediation actor
counting is updated and continues.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{MEDITATION_CALDERA}, @code{MEDITATION_HOLLOW}, @code{MEDITATION_DENT}, @code{MEDITATION_BUMP}, @code{MEDITATION_HILL}, @code{MEDITATION_VOLCANO}; @ @ @i{default}: @code{MEDITATION_HOLLOW} @ @ @xref{state}
The shape of the meditation.
@item @b{essential} @ @ @i{values}: @code{DISPENSABLE}, @code{INDISPENSABLE}; @ @ @i{default}: @code{DISPENSABLE}
Essentialness of being filled with a meditation marble to fulfill the
@ref{Ending Conditions}.
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: @code{nil} @ @ @xref{friction}
Deviating friction that defaults to floor friction.
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: @code{nil} @ @ @xref{adhesion}
Deviating adhesion that defaults to floor adhesion.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}
@table @asis
@item @b{flip}
Shape transformation. See text above.
@item @b{shovel}
Shape transformation like an activated @ref{it_spade}. See text above.
@item @b{signal} @ @ @xref{signal}
Shape transformation. See text above.
@item @b{toggle}
Shape transformation. See text above.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/it_meditation_hollow, 12mm} @b{it_meditation} state = @code{MEDITATION_HOLLOW}
@item @image{images/it_meditation_caldera, 12mm} @b{it_meditation_caldera} state = @code{MEDITATION_CALDERA}
@item @image{images/it_meditation_hollow, 12mm} @b{it_meditation_hollow} state = @code{MEDITATION_HOLLOW}
@item @image{images/it_meditation_dent, 12mm} @b{it_meditation_dent} state = @code{MEDITATION_DENT}
@item @image{images/it_meditation_bump, 12mm} @b{it_meditation_bump} state = @code{MEDITATION_BUMP}
@item @image{images/it_meditation_hill, 12mm} @b{it_meditation_hill} state = @code{MEDITATION_HILL}
@item @image{images/it_meditation_volcano, 12mm} @b{it_meditation_volcano} state = @code{MEDITATION_VOLCANO}
@end table

@end table

@c ----------------- Sensor Item --------------------
@node it_sensor
@subsection it_sensor
@obindex it_sensor

The sensor item is a switch on top of a floor that reacts on actors passing it.
It performs actions on actors either entering or exiting the sensor's grid
depending on its attribute @samp{exit}. It will send the causing actor as action
value, which evaluates like @samp{true} in Lua, but nevertheless the @ref{inverse}
attribute can be used to send an action value of @samp{false} instead.

Any actors passing the grid, either on the floor or jumping over it will be
detected.

Sensors do not cause any noise. Visible sensors will nevertheless flash on
passing actors. You can make the trigger invisible by setting its attribute.
Be aware that the user will still notice that actors cannot drop items onto the
same grid position.

The level author can configure @ref{it_glasses} by addition of
@samp{SPOT_SENSOR} to show invisible sensor items. An actor with such an
@ref{it_glasses} in its inventory will be able to spot invisible sensor items.
With the global attribute @ref{ExtralifeGlasses} even glasses generated by laser
lighting an @ref{it_extralife} can be configured not to show invisible sensor
items.

Alternative objects that react on actors are @ref{it_trigger} and
@ref{it_cross}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{invisible} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
An invisible sensor is totally transparent. But the user may notice it, as actors
cannot drop items onto the same grid position.
@item @b{exit} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
React either on an actor exiting or entering the grid.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/it_sensor, 12mm} @b{it_sensor}: exit = @code{false}
@item @image{images/it_sensor_exit, 12mm} @b{it_sensor_exit}: exit = @code{true}
@end table

@end table


@c ----------------- Shogun Dot Item --------------------
@node it_shogun
@subsection it_shogun
@obindex it_shogun

A dot like, blue animated sensor item for @ref{st_shogun} stones. The dot comes
in three variations matching the different hole sizes of shogun stones.

Shogun dots detect stacks of @ref{st_shogun} that contain all variations from
small up to the size of the dot. Thus the small dot requires just a single small
shogun stone, the middle sized dot requires a stack of a small shogun beneath
a middle sized shogun stone, whereas the large dot requires a stack of all three
shogun stones on top.

There is no way to set the state of a dot manually. But the state can
nevertheless be read. At initialization a dot with a matching shogun stack on
top will start in state @samp{ON} without sending actions due to the
@ref{Snapshot Principle}.

Note that a dot is freezable by an @ref{st_ice} and can thus be relocated to
another position.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{OFF}, @code{ON}; @ @ @i{default}: @code{OFF}; @ @ @i{access}: @code{read only}  @ @ @xref{state}
The current state of the dot - @samp{ON} for a matching @ref{st_shogun} stack
on top, @samp{OFF} otherwise.
@item @b{flavor}, @ @ @i{values}: @code{"s"}, @code{"m"}, @code{"l"}; @ @ @i{default}: @code{"s"}
A string describing the hole size. @code{"s"} for a small hole, @code{"m"} for
a medium hole, @code{"l"} for a large hole.

@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Action:}  @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/it_shogun_s, 12mm} @b{it_shogun}: flavor = @code{"s"}
@item @image{images/it_shogun_s, 12mm} @b{it_shogun_s}: flavor = @code{"s"}
@item @image{images/it_shogun_m, 12mm} @b{it_shogun_m}: flavor = @code{"m"}
@item @image{images/it_shogun_l, 12mm} @b{it_shogun_l}: flavor = @code{"l"}
@end table

@end table

@c ----------------- Springboard Item --------------------
@node it_springboard
@subsection it_springboard
@obindex it_springboard

A static jump facility that lets @ref{Flying Actors} jump on passing its center
square. A springboard can catapult any number of actors anytime with an idle
reloading time after an activation.

A springboard positioned on top of a floor can not be picked up. But nevertheless
as being portable, it can be added to the initial inventory, to an @ref{it_bag}
or can be picked up as a result of a @ref{it_surprise}.

Another catapulting, but liftable item is @ref{it_spring}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_springboard, 12mm} @b{it_springboard}
@end table

@end table

@c ----------------- Squashed Item --------------------
@node it_squashed
@subsection it_squashed
@obindex it_squashed

The remnants of fruits like @ref{it_cherry} and @ref{it_banana} after pushing
a stone over it.

The squashed remnants are scarcely visible on some floor types. The player can
not pick them up. But it can be wiped away by application of an @ref{it_brush},
by a nearby exploding @ref{it_bomb} or by an @ref{st_ice} being pushed over it.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:} none
@item @b{Variants:}
@table @asis
@item @image{images/it_squashed, 12mm} @b{it_squashed}
@end table
@end table

@c ----------------- Strip Item --------------------
@node it_strip
@subsection it_strip
@obindex it_strip

These items cover a small strip of the ground below them and provide a narrow
bridge for the marble to safely pass @ref{fl_abyss}, @ref{fl_swamp},
@ref{fl_water}, or any other floor.

A strip connects zero, what is just a central small unconnected square, or up
to 4 neighboring floor grids. A marble can pass from one connected floor to
another connected floor via the strip.

Any stone on a directly neighboring grid can be touched or hit by a large marble
and prevents it from falling off the strip on this side. Small marbles can not
touch neighboring stones and will not be protected from falling.

Per default an actor on a covering strip is exposed to the same friction and
adhesion as on the floor below. But strips can provide its own deviating
values for these factors.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{connections}, @ @ @i{values}: string; @ @ @i{default}: @code{nil}
Describes the connections to the neighbor grids. The string is a substring of
@code{"nesw"} listing the existing connections. The sequence of the sides, north,
east, south, west, is guaranteed on read access but arbitrary on write access.
@item @b{friction}, @ @ @i{values}: number; @ @ @i{default}: @code{nil} @ @ @xref{friction}
Deviating friction that defaults to floor friction.
@item @b{adhesion}, @ @ @i{values}: number; @ @ @i{default}: @code{nil} @ @ @xref{adhesion}
Deviating adhesion that defaults to floor adhesion.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/it_strip, 12mm}@tab @b{it_strip}: connections = @code{""}
@tab @image{images/it_strip_2, 12mm}@tab @b{it_strip_w}: connections = @code{"w"}
@item @image{images/it_strip_3, 12mm}@tab @b{it_strip_s}: connections = @code{"s"}
@tab @image{images/it_strip_4, 12mm}@tab @b{it_strip_sw}: connections = @code{"sw"}
@item @image{images/it_strip_b, 12mm}@tab @b{it_strip_e}: connections = @code{"e"}
@tab @image{images/it_strip_b2, 12mm}@tab @b{it_strip_ew}: connections = @code{"ew"}
@item @image{images/it_strip_b3, 12mm}@tab @b{it_strip_es}: connections = @code{"es"}
@tab @image{images/it_strip_b4, 12mm}@tab @b{it_strip_esw}: connections = @code{"esw"}
@item @image{images/it_strip_c, 12mm}@tab @b{it_strip_n}: connections = @code{"n"}
@tab @image{images/it_strip_c2, 12mm}@tab @b{it_strip_nw}: connections = @code{"nw"}
@item @image{images/it_strip_c3, 12mm}@tab @b{it_strip_ns}: connections = @code{"ns"}
@tab @image{images/it_strip_c4, 12mm}@tab @b{it_strip_nsw}: connections = @code{"nsw"}
@item @image{images/it_strip_d, 12mm}@tab @b{it_strip_ne}: connections = @code{"ne"}
@tab @image{images/it_strip_d2, 12mm}@tab @b{it_strip_new}: connections = @code{"new"}
@item @image{images/it_strip_d3, 12mm}@tab @b{it_strip_nes}: connections = @code{"nes"}
@tab @image{images/it_strip_d4, 12mm}@tab @b{it_strip_nesw}: connections = @code{"nesw"}
@end multitable
@end table

@c ----------------- Trap Item --------------------
@node it_trap
@subsection it_trap
@obindex it_trap

A classical trap that is camouflaged by a floor image. Any marble stepping onto
this trap will break the trap and fall into the trap's abyss. But marbles can
jump unharmed over a trap. Movable stones can be pushed over a trap without any
reaction.

Any marble falling into a trap causes it to break and to become visible by the
remnants of the trap. The trap can be opened by messages, too.

The level author can configure @ref{it_glasses} by addition of
@samp{SPOT_TRAP} to show invisible traps. An actor with such an
@ref{it_glasses} in its inventory will be able to spot invisible traps.
With the global attribute @ref{ExtralifeGlasses} even glasses generated by laser
lighting an @ref{it_extralife} can be configured to show invisible traps.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{CLOSED}, @code{OPEN}; @ @ @i{default}: @code{CLOSED} @ @ @xref{state}
A @samp{CLOSED} trap is intact and invisible, an @samp{OPEN} trap is broken and
visible.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table
@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Opens the trap on value @samp{1}
@item @b{toggle} @ @ @xref{toggle}
Opens the trap.
@item @b{open} @ @ @xref{open}
Opens the trap.
@end table
@item @b{Variants:}
@table @asis
@item @image{images/it_trap, 12mm} @b{it_trap}
@end table

@end table

@c ----------------- Trigger Item --------------------
@node it_trigger
@subsection it_trigger
@obindex it_trigger

The trigger item is a switch on top of a floor that reacts on actors and
stones on top of it that may press it. It performs actions when it is initially
pressed and again when it releases after the last object left it. A pressed
trigger is in state @samp{ON} and will send an action value of @samp{true}, a
released trigger is in state @samp{OFF} and will send an action value of
@samp{false}.

Only actors moving on the floor will press triggers. An actor jumping over a
trigger will not press it. An actor jumping on a trigger will release and press
it again.

Just solid stones will press the trigger when pushed onto it. Floating, hollow
stones will generally not press the trigger with the exception of the hollow,
central puzzle stone (@pxref{st_puzzle}).

There is no way to set the state of a trigger manually. But the state can
nevertheless be read. At initialization a trigger that is pressed by objects
will start in state @samp{ON} without sending actions due to the
@ref{Snapshot Principle}.

You can make the trigger invisible by setting its attribute. Be aware that it
still produces its click-sounds and the user will notice that actors cannot drop
items onto the same grid position.

Alternative items that react just on actors are @ref{it_sensor} and
@ref{it_cross}. Another switch that reacts on the actor's mass and stones are
the @ref{fl_scales}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{access}: @code{read only} @ @ @xref{state}
The current switch state - @samp{ON} for a pressed trigger, @samp{OFF} for a
released trigger.

@item @b{invisible} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
An invisible trigger is totally transparent. But the user may notice it, as actors
cannot drop items onto the same grid position.

@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:} none

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
@item @b{Variants:}
@table @asis
@item @image{images/it_trigger, 12mm} @b{it_trigger}
@end table

@end table


@c ----------------- Vortex Item --------------------
@node it_vortex
@subsection it_vortex
@obindex it_vortex

Teleports @ref{ac_marble} and @ref{ac_pearl} to a given @samp{destination}.
Unlike @ref{it_wormhole} it does not teleport other @ref{Actors}.

In the simplest case, a vortex is connected to a single destination given by
an object or a position. If the destination is not blocked by a stone the
actor will be teleported to the destination.

If multiple destination addresses are given, the actor will be teleported
to the single destinations in sequence. Blocked destinations are indicated by
sparkles. Finally the actor exists on the first unblocked destination. If no
unblocked destination exists the marble exists at the starting vortex. A level
author can write nice puzzle which require the user to block destinations to
reach the final destination of a vortex.

Vortices can be @samp{OPEN} or @samp{CLOSED}. Of course an actor can enter just
an open vortex. Closed vortices at the destination are opened automatically.
By default such vortices remain open. By usage of the attribute @samp{autoclose}
you can configure a vortex to close after an actor has been emitted. This helps
the user to leave the vortex by keeping the marble from being reinserted into
the vortex. Of course an autoclose disables the user to return, too. If this
is not your intention you set additionally the attribute @samp{autoopen} to
@code{true}. The vortex will reopen again when the marble leaves the closed
vortex. If the user did directly jump out of the vortex, it will reopen when
the user enters the vortex grid again.

Actors are emitted by vortices in a jumping fashion. The user can accelerate
the actor for a short period and the actor may jump out of a vortex into the
desired direction.

Vortex teleportation takes a short amount of time and the involved vortices are
blocked for other teleporting request during this process. Thus it is no problem
to set up destinations of vortices that build a cycle.

Rubberbands bound to teleported actors are cut by default. The attribute
@samp{scissor} allows you to control the cutting behaviour.

But the teleporting feature of a vortex is not limited to actors. A water
flood will spread through a vortex, too. In contrast to actors the flood will
spread to all destinations at the same time. Of course a closed vortex on
either side of the teleportation will block a flood from spreading. But the
flood continues as soon as the vortices are opened again. Destinations will
not be blocked by stones for a flood penetrating the grid from beneath, but
may block the water from spreading further from the destination grid positions.
All important details are explained in section @ref{Flood Spreading}.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{OPEN}, @code{CLOSED}; @ @ @i{default}: @code{OPEN} @ @ @xref{state}
The visual state of a vortex. An @samp{OPEN} vortex may still be busy due
to ongoing teleportations and may not accept a marble.

@item @b{destination}, @ @ @i{values}: tokens or position; @ @ @i{default}: @code{nil} @ @ @xref{destination}
The destination of the teleport given by an object or a position.

@item @b{autoclose}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Flag that indicates whether the vortex should be closed after a teleport.

@item @b{autoopen}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Flag that indicates whether the vortex should open when an actor enters the grid
or leaves the vortex.

@item @b{scissor}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Rubberband cutting behaviour on teleporting.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}
@table @asis
@item @b{signal} @ @ @xref{signal}
Opens the vortex on value @samp{1}, and closes the vortex on value @samp{0}.
@item @b{toggle} @ @ @xref{toggle}
Opens a closed vortex and closes an open vortex if possible.
@item @b{open} @ @ @xref{open}
Tries to open the vortex.
@item @b{close} @ @ @xref{close}
Tries to close the vortex.
@end table

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_vortex, 12mm} @b{it_vortex}:  state = @code{OPEN}.
@item @image{images/it_vortex, 12mm} @b{it_vortex_open}: state = @code{OPEN}.
@item @image{images/it_vortex_4, 12mm} @b{it_vortex_closed}: state @samp{CLOSED}.
@end table
@end table

@c ----------------- Wormhole Item --------------------
@node it_wormhole
@subsection it_wormhole
@obindex it_wormhole

Teleports @ref{Actors} of any kind to a given @samp{destination}. Unlike
@ref{it_vortex} every wormhole has a unique destination. But of course the
destination may be another wormhole which instantly teleports the actor again.
An infinite circle of wormholes that are connected by destinations is forbidden.

A wormhole can attract or repel actors in its @samp{range} with a force
proportional to the @samp{strength} and the inverse of the squared distance.
The force can be switched @samp{ON} and @samp{OFF} and is represented by its
external @samp{state}. Note that no forces are applied to actors at a distance
smaller than 0.05 grids to avoid extraordinary large forces.

Rubberbands bound to teleported actors are cut by default. The attribute
@samp{scissor} allows you to control the cutting behaviour.

After teleporting an actor, the wormhole's teleporting ability may be switched
off for a short latency period given by @samp{interval}. A latency separates
actors traveling through a wormhole and avoids overlapping actors at the
destination.

But the teleporting feature of a wormhole is not limited to actors. A water
flood will spread through a wormhole, too. Of course all actor related
attributes described above have no influence on the flood. Just the
@samp{destination} is important as explained in details in @ref{Flood Spreading}.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{ON} @ @ @xref{state}
The current force state - @samp{ON} for a force applying wormholes, @samp{OFF}
for force neutral wormholes.
@item @b{destination}, @ @ @i{values}: tokens or position; @ @ @i{default}: @code{nil} @ @ @xref{destination}
The destination of the teleport given by an object or a position.
@item @b{range} @ @ @i{values}: float number greater or equal 0; @ @ @i{default}: @code{10.0} @ @ @xref{WormholeRange}
The distance up to which the wormhole applies forces to actors.
@item @b{strength} @ @ @i{values}: float number; @ @ @i{default}: @code{+30.0} @ @ @xref{WormholeStrength}
A scalar factor for the wormhole force. Positive numbers are attracting forces
where as negative numbers are repelling forces.
@item @b{scissor}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Rubberband cutting behaviour on teleporting.
@item @b{interval} @ @ @i{values}: float number greater or equal 0; @ @ @i{default}: @code{0.0}
The latency time after a teleport during which no further teleports take place.
@item @b{freezable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{freezable}
@item @b{liftable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{liftable}
@item @b{portable}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: @code{read only} @ @ @xref{portable}
@end table

@item @b{Messages:}
@table @asis
@item @b{signal} @ @ @xref{signal}
A signal of value 1 switches the wormhole force on, a value of 0 switches the
wormhole force off.
@item @b{toggle} @ @ @xref{toggle}
A toggle causes a change in the wormhole force activity state.
@item @b{on} @ @ @xref{on}
Switches the wormhole on.
@item @b{off} @ @ @xref{off}
Switches the wormhole off.
@end table

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/it_wormhole, 12mm} @b{it_wormhole}: state = @code{ON}.
@item @image{images/it_wormhole, 12mm} @b{it_wormhole_on}: state = @code{ON}.
@item @image{images/fl_white, 12mm} @b{it_wormhole_off}: state @code{OFF}.
@end table
@end table


@c ===================  Stones  =======================
@node Stone Objects
@chapter Stone Objects

@menu
* Stone Overview::
* Stone Attributes::
* Standard Stones::
* Cluster Stones::
* Special Stones::
* Stone Feature Summaries::     Tables of transparent, breakable, ... stones
@end menu

@c ----------------- Stone Overview --------------------
@node Stone Overview
@section Stone Overview

@multitable @columnfractions .08 .25 .08 .25 .09 .25
@item @image{images/st_actorimpulse, 12mm} @tab @yref{st_actorimpulse}
@tab @image{images/st_ancient, 12mm} @tab @yref{st_ancient}
@tab @image{images/st_barrier, 12mm} @tab @yref{st_barrier}
@item @image{images/st_beads, 12mm} @tab @yref{st_beads}
@tab @image{images/st_blocker, 12mm} @tab @yref{st_blocker}
@tab @image{images/st_boulder, 12mm} @tab @yref{st_boulder}
@item @image{images/st_bluegray, 12mm} @tab @yref{st_bluegray} or @yref{st_thief}
@tab @image{images/st_bluesand, 12mm} @tab @yref{st_bluesand}
@tab @image{images/st_blur_cross, 12mm} @tab @yref{st_blur}_cross
@item @image{images/st_blur_straight, 12mm} @tab @yref{st_blur}_straight
@tab @image{images/st_box_hay, 12mm} @tab @yref{st_box}_hay
@tab @image{images/st_box_rock, 12mm} @tab @yref{st_box}_rock
@item @image{images/st_box_wood, 12mm} @tab @yref{st_box}_wood
@tab @image{images/st_brake, 12mm} @tab @yref{st_brake}
@tab @image{images/st_break_black, 12mm} @tab @yref{st_break}_black
@item @image{images/st_break_boulder, 12mm} @tab @yref{st_break}_boulder
@tab @image{images/st_break_bug, 12mm} @tab @yref{st_break}_bug
@tab @image{images/st_break_oxydc, 12mm} @tab @yref{st_break}_oxydc
@item @image{images/st_break_plain, 12mm} @tab @yref{st_break}_plain
@tab @image{images/st_break_white, 12mm} @tab @yref{st_break}_white
@tab @image{images/st_brick, 12mm} @tab @yref{st_brick}
@item @image{images/st_brownie, 12mm} @tab @yref{st_brownie}
@tab @image{images/st_brownmarble, 12mm} @tab @yref{st_brownmarble}
@tab @image{images/st_brownpyramid, 12mm} @tab @yref{st_brownpyramid}
@item @image{images/st_camouflage, 12mm} @tab @yref{st_camouflage}
@tab @image{images/st_charge_minus, 12mm} @tab @yref{st_charge}_minus
@tab @image{images/st_charge_plus, 12mm} @tab @yref{st_charge}_plus
@item @image{images/st_charge_zero, 12mm} @tab @yref{st_charge}_zero
@tab @image{images/st_chess_black, 12mm} @tab @yref{st_chess}_black
@tab @image{images/st_chess_white, 12mm} @tab @yref{st_chess}_white
@item @image{images/st_coinslot, 12mm} @tab @yref{st_coinslot}
@tab @image{images/st_concrete, 12mm} @tab @yref{st_concrete}
@tab @image{images/st_darkglass, 12mm} @tab @yref{st_darkglass}
@item @image{images/st_darkgray, 12mm} @tab @yref{st_darkgray}
@tab @image{images/st_death, 12mm} @tab @yref{st_death}
@tab @image{images/st_disco, 12mm} @tab @yref{st_disco}_light
@item @image{images/st_disco_2, 12mm} @tab @yref{st_disco}_medium
@tab @image{images/st_disco_3, 12mm} @tab @yref{st_disco}_dark
@tab @image{images/st_document, 12mm} @tab @yref{st_document}
@item @image{images/st_door_d_ew_g, 12mm} @tab @yref{st_door}_d (ew)
@tab @image{images/st_door_d_ns_7, 12mm} @tab @yref{st_door}_d (ns)
@tab @image{images/st_dispenser_bombblack, 12mm} @tab @yref{st_dispenser}_bombblack
@item @image{images/st_dispenser_bombwhite, 12mm} @tab @yref{st_dispenser}_bombwhite
@tab @image{images/st_dispenser_dynamite, 12mm} @tab @yref{st_dispenser}_dynamite
@tab @image{images/st_dispenser_extralife, 12mm} @tab @yref{st_dispenser}_extralife
@item @image{images/st_oxydc_open, 12mm} @tab @yref{st_fake}_oxydc (open)
@tab @image{images/st_flash, 12mm} @tab @yref{st_flash}
@tab @image{images/st_flat, 12mm} @tab @yref{st_flat}
@item @image{images/st_floppy_off, 12mm} @tab @yref{st_floppy}_off
@tab @image{images/st_floppy_on, 12mm} @tab @yref{st_floppy}_on
@tab @image{images/st_fourswitch, 12mm} @tab @yref{st_fourswitch}
@item @image{images/st_granite, 12mm} @tab @yref{st_granite}
@tab @image{images/st_grate_cross, 12mm} @tab @yref{st_grate}_cross
@tab @image{images/st_grate_framed, 12mm} @tab @yref{st_grate}_framed
@item @image{images/st_greenbrown, 12mm} @tab @yref{st_greenbrown}
@tab @image{images/st_greengray, 12mm} @tab @yref{st_greengray}
@tab @image{images/st_ice, 12mm} @tab @yref{st_ice}
@item                            @tab @yref{st_invisible} or @yref{st_ghost}
@tab @image{images/st_inkwell, 12mm} @tab @yref{st_inkwell_black}
@tab @image{images/st_inkwell_5, 12mm} @tab @yref{st_inkwell_empty}
@item @image{images/st_inkwell_9, 12mm} @tab @yref{st_inkwell_white}
@tab @image{images/st_jamb_black, 12mm} @tab @yref{st_jamb}_black
@tab @image{images/st_jamb_white, 12mm} @tab @yref{st_jamb}_white
@item @image{images/st_key_off, 12mm} @tab @yref{st_key}_off
@tab @image{images/st_key_on, 12mm} @tab @yref{st_key}_on
@tab @image{images/st_knight, 12mm} @tab @yref{st_knight}
@item @image{images/st_laser_d, 12mm} @tab @yref{st_laser}
@tab @image{images/st_lightglass, 12mm} @tab @yref{st_lightglass}
@tab @image{images/st_lightpassenger, 12mm} @tab @yref{st_lightpassenger}
@item @image{images/st_mail, 12mm} @tab @yref{st_mail}
@tab @image{images/st_metal, 12mm} @tab @yref{st_metal}
@tab @image{images/st_mirror_static_2, 12mm} @tab @yref{st_mirror}_triangle
@item @image{images/st_mirror_static_b2, 12mm} @tab @yref{st_mirror}_triangle
@tab @image{images/st_mirror_static_c2, 12mm} @tab @yref{st_mirror}_slab
@tab @image{images/st_mirror_static_d2, 12mm} @tab @yref{st_mirror}_slab
@item @image{images/st_mirror_static_e2, 12mm} @tab @yref{st_mirror}_sheets
@tab @image{images/st_monoflop, 12mm} @tab @yref{st_monoflop}
@tab @image{images/st_monoflop_2, 12mm} @tab @yref{st_monoflop}
@item @image{images/st_oneway, 12mm} @tab @yref{st_oneway}
@tab @image{images/st_oneway_b, 12mm} @tab @yref{st_oneway}_black
@tab @image{images/st_oneway_c, 12mm} @tab @yref{st_oneway}_white
@item @image{images/st_oxyda, 12mm} @tab @yref{st_oxyd}_a
@tab @image{images/st_oxydb, 12mm} @tab @yref{st_oxyd}_b or @yref{st_quake} @* or @yref{st_laserswitch}
@tab @image{images/st_oxydc, 12mm} @tab @yref{st_oxyd}_c
@item @image{images/st_oxydd, 12mm} @tab @yref{st_oxyd}_d
@tab @image{images/st_oxyde, 12mm} @tab @yref{st_oxyd}_e
@tab @image{images/st_panel, 12mm} @tab @yref{st_panel}
@item @image{images/st_passage_black_square, 12mm} @tab @yref{st_passage}_black
@tab @image{images/st_passage_black_slash, 12mm} @tab @yref{st_passage}_black
@tab @image{images/st_passage_black_cross, 12mm} @tab @yref{st_passage}_black
@item @image{images/st_passage_black_frame, 12mm} @tab @yref{st_passage}_black
@tab @image{images/st_passage_white_square, 12mm} @tab @yref{st_passage}_white
@tab @image{images/st_passage_white_slash, 12mm} @tab @yref{st_passage}_white
@item @image{images/st_passage_white_cross, 12mm} @tab @yref{st_passage}_white
@tab @image{images/st_passage_white_frame, 12mm} @tab @yref{st_passage}_white
@tab @image{images/st_pebble, 12mm} @tab @yref{st_pebble}
@item @image{images/st_pinkbumps, 12mm} @tab @yref{st_pinkbumps}
@tab @image{images/st_plaster, 12mm} @tab @yref{st_plaster}
@tab @image{images/st_plop_slate, 12mm} @tab @yref{st_plop}_slate
@item @image{images/st_portal_horse, 12mm} @tab @yref{st_portal}
@tab @image{images/st_pull, 12mm} @tab @yref{st_pull}
@tab @image{images/st_purplegray, 12mm} @tab @yref{st_purplegray}
@item @image{images/st_purplemarble, 12mm} @tab @yref{st_purplemarble}
@tab @image{images/st_puzzle_blue_3, 12mm} @tab @yref{st_puzzle}_blue or @yref{st_turnstilearm}_n
@tab @image{images/st_puzzle_blue_d3, 12mm} @tab @yref{st_puzzle}_blue
@item @image{images/st_puzzle_blue_hollow_d3, 12mm} @tab @yref{st_puzzle}_blue
@tab @image{images/st_puzzle_yellow_d3, 12mm} @tab @yref{st_puzzle}_yellow
@tab @image{images/st_puzzle_yellow_hollow_d3, 12mm} @tab @yref{st_puzzle}_yellow
@item @image{images/st_rawglass, 12mm} @tab @yref{st_rawglass}
@tab @image{images/st_rawglass_quad, 12mm} @tab @yref{st_rawglass}_quad
@tab @image{images/st_redbrown, 12mm} @tab @yref{st_redbrown}
@item @image{images/st_redfiber, 12mm} @tab @yref{st_redfiber}
@tab @image{images/st_redmarble, 12mm} @tab @yref{st_redmarble}
@tab @image{images/st_redrock, 12mm} @tab @yref{st_redrock}
@item @image{images/st_rotator_ccw, 12mm} @tab @yref{st_rotator}_ccw
@tab @image{images/st_rotator_cw, 12mm} @tab @yref{st_rotator}_cw
@tab @image{images/st_rubberband, 12mm} @tab @yref{st_rubberband}
@item @image{images/st_scissors, 12mm} @tab @yref{st_scissors}
@tab @image{images/st_shogun, 12mm} @tab @yref{st_shogun}_s
@tab @image{images/st_shogun_2, 12mm} @tab @yref{st_shogun}_m
@item @image{images/st_shogun_4, 12mm} @tab @yref{st_shogun}_l
@tab @image{images/st_spitter_idle, 12mm} @tab @yref{st_spitter}
@tab @image{images/st_stoneimpulse, 12mm} @tab @yref{st_stoneimpulse}
@item @image{images/st_stoneimpulse_hollow, 12mm} @tab @yref{st_stoneimpulse}_hollow
@tab @image{images/st_surprise, 12mm} @tab @yref{st_surprise}
@tab @image{images/st_swap, 12mm} @tab @yref{st_swap}
@item @image{images/st_switch, 12mm} @tab @yref{st_switch}
@tab @image{images/st_switch_black, 12mm} @tab @yref{st_switch}_black
@tab @image{images/st_switch_white, 12mm} @tab @yref{st_switch}_white
@item @image{images/st_thief, 12mm} @tab @yref{st_thief}
@tab @image{images/st_thief_capture, 12mm} @tab @yref{st_thief}
@tab @image{images/st_thief_drunken, 12mm} @tab @yref{st_thief}
@item @image{images/st_tigris, 12mm} @tab @yref{st_tigris}
@tab @image{images/st_timer_3, 12mm} @tab @yref{st_timer}
@tab @image{images/st_timer, 12mm} @tab @yref{st_timer}
@item @image{images/st_turnstile, 12mm} @tab @yref{st_turnstile}
@tab @image{images/st_turnstile_green, 12mm} @tab @yref{st_turnstile}_green
@tab @image{images/st_window_blue_3, 12mm} @tab @yref{st_window}
@item @image{images/st_window_green_3, 12mm} @tab @yref{st_window}
@tab @image{images/st_woven, 12mm} @tab @yref{st_woven}
@tab @image{images/st_yellow, 12mm} @tab @yref{st_yellow}
@item @image{images/st_yinyang, 12mm} @tab @yref{st_yinyang}
@tab @image{images/st_yinyang_inactive, 12mm} @tab @yref{st_yinyang}_inactive
@end multitable


@c ----------------- Stone Attributes --------------------
@node Stone Attributes
@section Stone Attributes

@menu
* breakable::              -
* freeze_check (stone)::   Freeze Checking
* hit_*::                  -
* hollow::                 -
* hovering::               -
* movable::                -
* transparent::            -
@end menu


@c ----------------- breakable --------------------
@node breakable
@subsection breakable


@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- freeze_check --------------------
@node freeze_check (stone)
@subsection freeze_check (stone)

If @code{true}, allows for @ref{Freeze Checking} for this stone. Note that
Freeze Checking only works on those floors that have additionally set
@code{freeze_check = true} on their own, see @ref{freeze_check (floor)}.

@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- hit_* --------------------
@node hit_*
@subsection hit_*

A set of attributes that allow you to distort hit forces. Objects like
@ref{st_flash}, @ref{st_spitter} and @ref{st_actorimpulse} apply forces that
are either based on the hit velocity or the position.

By usage of a simple @samp{hit_strength} factor you can increase, decrease or
invert the default factor. Note that you must not set this attribute, if you
want to use the default.

By setting the four attributes @samp{hit_distortion_xx}, @samp{hit_distortion_xy},
@samp{hit_distortion_yx} and @samp{hit_distortion_yy} you can describe a
matrix to set up a new direction. These attributes default to 1, 0, 0, 1.
A 90 degree clockwise turn is described by 0, 1, -1, 0.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ ?
@item @b{Default:} @ @ factor - @code{nil}, xx, yy - @code{1}, xy, yx - @code{0}
By default no hit factor is applied. The hit matrix is the neutral one.
@item @b{Access:} @ @ read/write
@item @b{Support:} @ @ by some stones
@end table

@c ----------------- hollow --------------------
@node hollow
@subsection hollow


@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- hovering --------------------
@node hovering
@subsection hovering


@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- movable --------------------
@node movable
@subsection movable

An attribute that describes if a stone is movable by actor impulses. It is
supported by all stones.

Note that this attribute is not listed in the individual stone description
if the stone is generally not movable.

@table @asis
@item @b{Type:} @ @ bool
@item @b{Values:} @ @ @code{true}, @code{false}
@item @b{Default:} @ @ usually @code{false}
If a stone exists only in a movable variant this attribute will default to
@samp{true}.
@item @b{Access:} @ @ read/sometimes write
This attribute is only writable for objects that exist in both variations.
@item @b{Support:} @ @ by all stones
@end table

@c ----------------- transparent --------------------
@node transparent
@subsection transparent


@table @asis
@item @b{Type:} @ @ boolean
@item @b{Values:} @ @ @code{false}, @code{true}
@item @b{Default:} @ @ @code{false}
@item @b{Access:} @ @ read/write
@end table



@c ----------------- Standard Stones --------------------
@node Standard Stones
@section Standard Stones

A standard stone is a passive wall stone. It might exist in a hollow or
movable variant but provides no additional features.

@menu
* st_ancient::         rough green rock
* st_bluegray::        light blue gray stone
* st_brownie::         golden, hay stack like stone
* st_brownmarble::     brown gray marble
* st_camouflage::      military green camouflage stone
* st_concrete::        polished light gray stone
* st_darkgray::        dark gray rock
* st_granite::         light gray rock
* st_greengray::       light green gray rock
* st_invisible::       invisible stone
* st_metal::           metal stone
* st_pinkbumps::       pink stone with heavy bumps
* st_purplegray::      dark purple gray rock
* st_purplemarble::    purple marble
* st_redbrown::        brown stone with light red touches
* st_redmarble::       red white marbled stone
* st_redrock::         dark red rock
* st_tigris::          red sandstone
* st_woven::           yellow gray woven stone
* st_yellow::          yellow stone with red green stripes

@end menu

@c ----------------- Ancient Stone --------------------
@node st_ancient
@subsection st_ancient
@obindex st_ancient

A rough green gray rock that looks ancient.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_ancient, 12mm} @b{st_ancient}
@end table
@end table

@c ----------------- Bluegray Stone --------------------
@node st_bluegray
@subsection st_bluegray
@obindex st_bluegray

A light blue gray stone that exists in all two variants. This stone is visually
indistinguishable from a @ref{st_thief}.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_bluegray, 12mm} @b{st_bluegray}
@item @image{images/st_bluegray, 12mm} @b{st_bluegray_hollow}
@end table
@end table

@c ----------------- Brownie Stone --------------------
@node st_brownie
@subsection st_brownie
@obindex st_brownie

A golden, hay stack like stone that exists just in a movable variant.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_brownie, 12mm} @b{st_brownie}
@end table
@end table

@c ----------------- Brownmarble Stone --------------------
@node st_brownmarble
@subsection st_brownmarble
@obindex st_brownmarble

A brown gray marble like stone.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_brownmarble, 12mm} @b{st_brownmarble}
@end table
@end table

@c ----------------- Camouflage Stone --------------------
@node st_camouflage
@subsection st_camouflage
@obindex st_camouflage

A military green camouflage stone that exists in all three variants.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_camouflage, 12mm} @b{st_camouflage}
@item @b{st_camouflage_hollow}
@item @b{st_camouflage_movable}
@end table
@end table

@c ----------------- Concrete Stone --------------------
@node st_concrete
@subsection st_concrete
@obindex st_concrete

A polished light gray stone.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_concrete, 12mm} @b{st_concrete}
@end table
@end table

@c ----------------- Darkgray Stone --------------------
@node st_darkgray
@subsection st_darkgray
@obindex st_darkgray

A dark gray rock that exists in all two variants.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_darkgray, 12mm} @b{st_darkgray}
@item @b{st_darkgray_hollow}
@end table
@end table

@c ----------------- Granite Stone --------------------
@node st_granite
@subsection st_granite
@obindex st_granite

A light gray rock like stone that exists in all three variants.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_granite, 12mm} @b{st_granite}
@item @b{st_granite_hollow}
@item @b{st_granite_movable}
@end table
@end table

@c ----------------- Greengray Stone --------------------
@node st_greengray
@subsection st_greengray
@obindex st_greengray

A light green gray rock.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_greengray, 12mm} @b{st_greengray}
@end table
@end table

@c ----------------- Invisible Stone --------------------
@node st_invisible
@subsection st_invisible
@obindex st_invisible

An invisible stone that exists in all three variants. Please make rare usage
of this stone as it may be very annoying to users to guess that a stone
exists that he can not see. Use it to maintain the WYSIWYG expected behaviour.

Invisibility is not equal to laser transparency. In fact this stone is not
laser transparent. And invisibility does not mean that an invisible actor can
pass (@pxref{Transparent Stones}).

@table @asis
@item @b{Variants:}
@table @asis
@item @b{st_invisible}
@item @b{st_invisible_hollow}
@item @b{st_invisible_movable}
@end table
@end table

@c ----------------- Metal Stone --------------------
@node st_metal
@subsection st_metal
@obindex st_metal

A metal stone that exists in two variants.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_metal, 12mm} @b{st_metal}
@item @b{st_metal_hollow}
@end table
@end table

@c ----------------- Pinkbump Stone --------------------
@node st_pinkbumps
@subsection st_pinkbumps
@obindex st_pinkbumps

A pink stone with heavy white bumps.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_pinkbumps, 12mm} @b{st_pinkbumps}
@end table
@end table

@c ----------------- Purplegray Stone --------------------
@node st_purplegray
@subsection st_purplegray
@obindex st_purplegray

A dark purple gray rock.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_purplegray, 12mm} @b{st_purplegray}
@end table
@end table

@c ----------------- Purplemarble Stone --------------------
@node st_purplemarble
@subsection st_purplemarble
@obindex st_purplemarble

A purple marble stone.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_purplemarble, 12mm} @b{st_purplemarble}
@end table
@end table

@c ----------------- Redbrown Stone --------------------
@node st_redbrown
@subsection st_redbrown
@obindex st_redbrown

A brown stone with light red touches that exists in all three variants.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_redbrown, 12mm} @b{st_redbrown}
@item @b{st_redbrown_hollow}
@item @b{st_redbrown_movable}
@end table
@end table

@c ----------------- Redmarble Stone --------------------
@node st_redmarble
@subsection st_redmarble
@obindex st_redmarble

A red white marbled stone.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_redmarble, 12mm} @b{st_redmarble}
@end table
@end table

@c ----------------- Redrock Stone --------------------
@node st_redrock
@subsection st_redrock
@obindex st_redrock

A dark red rock.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_redrock, 12mm} @b{st_redrock}
@end table
@end table

@c ----------------- Tigris Stone --------------------
@node st_tigris
@subsection st_tigris
@obindex st_tigris

A red sandstone like @ref{fl_tigris}.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_tigris, 12mm} @b{st_tigris}
@end table
@end table

@c ----------------- Woven Stone --------------------
@node st_woven
@subsection st_woven
@obindex st_woven

A yellow gray woven stone.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_woven, 12mm} @b{st_woven}
@end table
@end table

@c ----------------- Redmarble Stone --------------------
@node st_yellow
@subsection st_yellow
@obindex st_yellow

A yellow stone with red green stripes. This stone fits visually to the
@ref{st_coinslot}.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_yellow, 12mm} @b{st_yellow}
@end table
@end table


@c ----------------- Cluster Stones --------------------
@node Cluster Stones
@section Cluster Stones

A cluster stone is a passive wall stone like a simple stone. But several
cluster stones adjacent to each other can visually build a cluster and look
like a single big stone with a one common outer face.

@menu
* Cluster Features::   Common Attributes and Features
* st_bluesand::        big sand stone look
* st_brick::           brick wall look
* st_panel::           wooden panel look
@end menu

@c ----------------- Cluster Features --------------------
@node Cluster Features
@subsection Cluster Features

For each cluster stone there exist 16 different variations that represent all
needed combinations of inner and outer faces to build arbitrary shaped big
blocks.

There exist two methods of describing a special variation. You can either give
the inner faces, the @samp{connections}, those sides that should be adjacent to
other stones of the same cluster. Or you can give the outer faces, the
@samp{faces}, that build the common outer face of the resulting big block.

As it is a tedious work to set up larger blocks by their single stones with
appropriate faces you can rely on an automatic clustering feature. Just
set the @samp{cluster} attribute of all single stones of a big block to the
same number and the faces will be set up automatically to form a large block.

You can build a screen of arbitrary big blocks and it is proven that there will
never be the need of more than 4 different cluster numbers (the "4 color
theorem"). But for convenience you are free to use additional cluster numbers
as you like. Note that the autoclustering is quite dynamic. A single cluster
stone with fitting cluster number that is swapped at the side of an existing
block with the same cluster number will melt and join the block like seen in
"Terminator 2".

We recommend making use of the autoclustering feature by setting the
@samp{cluster} attribute and using the @samp{faces} attribute where necessary.
@samp{connections} attribute and explicit naming of variations by a suffix
are deprecated, but will continue to be supported.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{connections}, @ @ @i{values}: string; @ @ @i{default}: @code{nil}
Describes the inner faces of stone. The string is a substring of @code{"nesw"}
listing the inner faces. The sequence of the sides, north, east, south, west,
is guaranteed on read access but arbitrary on write access.

@item @b{faces} @ @ @i{values}: string; @ @ @i{default}: @code{nil}
Describes the outer faces of stone. The string is a substring of @code{"nesw"}
listing the outer faces. The sequence of the sides, north, east, south, west,
is guaranteed on read access but arbitrary on write access.

@item @b{cluster} @ @ @i{values}: number; @ @ @i{default}: @code{nil}
If set to a number all adjacent cluster stones of the same base type with
the identical cluster number will build a big block. This attribute supersedes
any explicitly given face description.

@end table
@end table

@c ----------------- Bluesand Stone --------------------
@node st_bluesand
@subsection st_bluesand
@obindex st_bluesand

A standard cluster stone with the @ref{Cluster Features}. It is recommended
to use @samp{st_bluesand} with the attributes @samp{cluster} and @samp{faces}.

@table @asis
@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_bluesand, 12mm}@tab @b{st_bluesand}: connections = @code{""}
@tab @image{images/st_bluesand_2, 12mm}@tab @b{st_bluesand_w}: connections = @code{"w"}
@item @image{images/st_bluesand_3, 12mm}@tab @b{st_bluesand_s}: connections = @code{"s"}
@tab @image{images/st_bluesand_4, 12mm}@tab @b{st_bluesand_sw}: connections = @code{"sw"}
@item @image{images/st_bluesand_b, 12mm}@tab @b{st_bluesand_e}: connections = @code{"e"}
@tab @image{images/st_bluesand_b2, 12mm}@tab @b{st_bluesand_ew}: connections = @code{"ew"}
@item @image{images/st_bluesand_b3, 12mm}@tab @b{st_bluesand_es}: connections = @code{"es"}
@tab @image{images/st_bluesand_b4, 12mm}@tab @b{st_bluesand_esw}: connections = @code{"esw"}
@item @image{images/st_bluesand_c, 12mm}@tab @b{st_bluesand_n}: connections = @code{"n"}
@tab @image{images/st_bluesand_c2, 12mm}@tab @b{st_bluesand_nw}: connections = @code{"nw"}
@item @image{images/st_bluesand_c3, 12mm}@tab @b{st_bluesand_ns}: connections = @code{"ns"}
@tab @image{images/st_bluesand_c4, 12mm}@tab @b{st_bluesand_nsw}: connections = @code{"nsw"}
@item @image{images/st_bluesand_d, 12mm}@tab @b{st_bluesand_ne}: connections = @code{"ne"}
@tab @image{images/st_bluesand_d2, 12mm}@tab @b{st_bluesand_new}: connections = @code{"new"}
@item @image{images/st_bluesand_d3, 12mm}@tab @b{st_bluesand_nes}: connections = @code{"nes"}
@tab @image{images/st_bluesand_d4, 12mm}@tab @b{st_bluesand_nesw}: connections = @code{"nesw"}
@end multitable
@end table

@c ----------------- Brick Stone --------------------
@node st_brick
@subsection st_brick
@obindex st_brick

A standard cluster stone with the @ref{Cluster Features}. It is recommended
to use @samp{st_brick} with the attributes @samp{cluster} and @samp{faces}.

@table @asis
@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_brick, 12mm}@tab @b{st_brick}: connections = @code{""}
@tab @image{images/st_brick_2, 12mm}@tab @b{st_brick_w}: connections = @code{"w"}
@item @image{images/st_brick_3, 12mm}@tab @b{st_brick_s}: connections = @code{"s"}
@tab @image{images/st_brick_4, 12mm}@tab @b{st_brick_sw}: connections = @code{"sw"}
@item @image{images/st_brick_b, 12mm}@tab @b{st_brick_e}: connections = @code{"e"}
@tab @image{images/st_brick_b2, 12mm}@tab @b{st_brick_ew}: connections = @code{"ew"}
@item @image{images/st_brick_b3, 12mm}@tab @b{st_brick_es}: connections = @code{"es"}
@tab @image{images/st_brick_b4, 12mm}@tab @b{st_brick_esw}: connections = @code{"esw"}
@item @image{images/st_brick_c, 12mm}@tab @b{st_brick_n}: connections = @code{"n"}
@tab @image{images/st_brick_c2, 12mm}@tab @b{st_brick_nw}: connections = @code{"nw"}
@item @image{images/st_brick_c3, 12mm}@tab @b{st_brick_ns}: connections = @code{"ns"}
@tab @image{images/st_brick_c4, 12mm}@tab @b{st_brick_nsw}: connections = @code{"nsw"}
@item @image{images/st_brick_d, 12mm}@tab @b{st_brick_ne}: connections = @code{"ne"}
@tab @image{images/st_brick_d2, 12mm}@tab @b{st_brick_new}: connections = @code{"new"}
@item @image{images/st_brick_d3, 12mm}@tab @b{st_brick_nes}: connections = @code{"nes"}
@tab @image{images/st_brick_d4, 12mm}@tab @b{st_brick_nesw}: connections = @code{"nesw"}
@end multitable
@end table
@c ----------------- Panel Stone --------------------
@node st_panel
@subsection st_panel
@obindex st_panel

A standard cluster stone with the @ref{Cluster Features}. It is recommended
to use @samp{st_panel} with the attributes @samp{cluster} and @samp{faces}.

@table @asis
@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_panel, 12mm}@tab  @b{st_panel}: connections = @code{""}
@tab @image{images/st_panel_2, 12mm}@tab @b{st_panel_w}: connections = @code{"w"}
@item @image{images/st_panel_3, 12mm}@tab @b{st_panel_s}: connections = @code{"s"}
@tab @image{images/st_panel_4, 12mm}@tab @b{st_panel_sw}: connections = @code{"sw"}
@item @image{images/st_panel_b, 12mm}@tab @b{st_panel_e}: connections = @code{"e"}
@tab @image{images/st_panel_b2, 12mm}@tab @b{st_panel_ew}: connections = @code{"ew"}
@item @image{images/st_panel_b3, 12mm}@tab @b{st_panel_es}: connections = @code{"es"}
@tab @image{images/st_panel_b4, 12mm}@tab @b{st_panel_esw}: connections = @code{"esw"}
@item @image{images/st_panel_c, 12mm}@tab @b{st_panel_n}: connections = @code{"n"}
@tab @image{images/st_panel_c2, 12mm}@tab @b{st_panel_nw}: connections = @code{"nw"}
@item @image{images/st_panel_c3, 12mm}@tab @b{st_panel_ns}: connections = @code{"ns"}
@tab @image{images/st_panel_c4, 12mm}@tab @b{st_panel_nsw}: connections = @code{"nsw"}
@item @image{images/st_panel_d, 12mm}@tab @b{st_panel_ne}: connections = @code{"ne"}
@tab @image{images/st_panel_d2, 12mm}@tab @b{st_panel_new}: connections = @code{"new"}
@item @image{images/st_panel_d3, 12mm}@tab @b{st_panel_nes}: connections = @code{"nes"}
@tab @image{images/st_panel_d4, 12mm}@tab @b{st_panel_nesw}: connections = @code{"nesw"}
@end multitable
@end table


@c ----------------- Special Stones --------------------
@node Special Stones
@section Special Stones

@menu
* st_actorimpulse::    Bumper Stone
* st_barrier::         Barrier for item carrying actors
* st_beads::           Frame of Glass Beads
* st_blocker::         Shrinkable Blocker
* st_blur::            Passage of yet undetermined color
* st_boulder::         Moving Arrow Boulder
* st_box::             Movable, Floor building Box
* st_brake::           Brake for moving Boulders
* st_break::           Breakable Stone of various Flavors
* st_brownpyramid::   Brown gray pyramid shaped stone
* st_chameleon::       Floor Mimic
* st_charge::          Electrical Charger
* st_chess::           Movable Chess Knight Stone
* st_coinslot::        Coin Driven Switch
* st_darkglass::       Semitransparent metal framed Glass
* st_death::           Skull Stone
* st_disco::           Light shading Stone
* st_dispenser::       Item Dispenser
* st_document::        Text displaying Stone
* st_door::            Door of various Flavors
* st_fake::            Fake mimicking other Stones
* st_flash::           Partner Marble pushing Stone
* st_flat::            Featured Gypsum Stone
* st_floppy::          Floppy Driven Switch
* st_fourswitch::      Four Orientation Switch
* st_ghost::           Invisible Transforming Stone
* st_grate::           Hovering metal Grate
* st_greenbrown::      Mainly brown seedable stone
* st_ice::             Item and Floor freezing Ice block
* st_inkwell::         Marble Recoloring Stone
* st_jamb::            Colored Door Jamb
* st_key::             Key Driven Switch
* st_knight::          Sword Bearing Knight Stone
* st_laser::           Light emitting Laser
* st_laserflop::       Light sensitive Monoflop
* st_laserswitch::     Light sensitive Switch
* st_lightglass::      Transparent metal framed Glass
* st_lightpassenger::  Stone pushed by Light
* st_magic::           Magic Transforming Stone
* st_mail::            Mail office for Item transportation
* st_mirror::          Mirrors of all flavors
* st_monoflop::        Monoflop Switch
* st_oneway::          Oneway Passage
* st_oxyd::            Game Target Stone
* st_passage::         Color dependent Passage
* st_pebble::          Third in the Rock-Paper-Scissors Trio
* st_plaster::         Gypsum sculptured Stone
* st_plop::            Movable stone ceasing by a Plop
* st_polarswitch::     Transparency Switch for Light Beams
* st_portal::          Gate just passable by some Actor kinds
* st_pull::            Pullable Stone
* st_puzzle::          Clusterable Puzzle Stones
* st_quake::           Oxyd closing Stone
* st_rawglass::        Transparent Glass Block
* st_redfiber::        Woven Fiber in a metal Frame
* st_rotator::         Rotating Stone Impulser
* st_rubberband::      Rubberband generator
* st_scissors::        Scissors cutting rubberbands
* st_shogun::          Stackable Hole Stones
* st_spitter::         Cannonball spitting Stone
* st_stoneimpulse::    Neighbor Pushing pulsing Stone
* st_surprise::        Random Transforming Stone
* st_swap::            Neighbor Swapping Stone
* st_switch::          Classical on/off Switch
* st_thief::           Item Thief
* st_timer::           Animated Timer
* st_turnstile::       Turnstile Pivot
* st_turnstilearm::    Turnstile Arm
* st_volcano::         Spreading Volcano
* st_window::          Faced Window
* st_yinyang::         Player Switch
@end menu


@c ----------------- Actorimpulse Stone --------------------
@node st_actorimpulse
@subsection st_actorimpulse
@obindex st_actorimpulse

An active bumper for actors and some stones like @ref{st_boulder}. The
actorimpulse stone can be made invisible while idle to introduce some surprise
effects.

Actors that hit this stone will not be reflected just passively. An additional
force will be applied to them that can even be distorted. By default the actors
are just pushed away from the center of the stone. A global attribute
@ref{ActorimpulseStrength} gives a default force that can be overridden by the
stone attribute @samp{strength}.

For sophisticated usage you can distort this force by usage of the @ref{hit_*}
attributes. Note that the @samp{hit_factor} overrides a @samp{strength}
attribute.

An actorimpulse stone can be configured by the @samp{invisible} attribute to
be hidden while being idle. While pulsing any actorimpulse is visible. An
invisible actorimpulse can be made permanently visible by hitting it with a
revealed @ref{it_brush} in the player's inventory. The level author can configure
@ref{it_glasses} by addition of @samp{SPOT_ACTORIMPULSE} to show otherwise
invisible actorimpulse stones. With the global attribute @ref{ExtralifeGlasses}
even glasses generated by laser lighting an @ref{it_extralife} can be configured
to show invisible actorimpulse stones.

An @ref{st_boulder} hitting an actorimpulse stone will revert its orientation
and return in the incoming direction.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{invisible} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
An invisible actorimpulse stone is totally transparent. But the user will
notice it, as actors will bounce with additional impulses.
@item @b{strength} @ @ @i{values}: float number; @ @ @i{default}: @code{+200.0} @ @ @xref{ActorimpulseStrength}
A scalar factor for the impulse force. Positive numbers are attracting forces
where as negative numbers are repelling forces.
@item @b{hit_strength} @ @ @i{values}: float number; @ @ @i{default}: @code{nil} @ @ @xref{hit_*}
A @samp{hit_strength} overrides a given @samp{strength} attribute.
@item @b{hit_distortion_xx} @ @ @i{values}: float number; @ @ @i{default}: @code{+1.0} @ @ @xref{hit_*}
@item @b{hit_distortion_xy} @ @ @i{values}: float number; @ @ @i{default}: @code{0.0} @ @ @xref{hit_*}
@item @b{hit_distortion_yx} @ @ @i{values}: float number; @ @ @i{default}: @code{0.0} @ @ @xref{hit_*}
@item @b{hit_distortion_yy} @ @ @i{values}: float number; @ @ @i{default}: @code{+1.0} @ @ @xref{hit_*}
@end table

@item @b{Messages:} none

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}

@table @asis
@item @image{images/st_actorimpulse, 12mm} @b{st_actorimpulse}: invisible = @code{false}
@item @image{images/fl_white, 12mm} @b{st_actorimpulse_invisible}: invisible = @code{true}
@end table

@end table

@c ----------------- Barrier Stone --------------------
@node st_barrier
@subsection st_barrier
@obindex st_barrier

The barrier stone blocks actors that carry a given item kind in their inventory.
By blocking all entries to a given room by barriers of the same @samp{flavor}
you can assure that no actor can use the given item kind within the room, even
when the item is available outside of the room. The barrier acts like customs
service. The barrier performs a deep check investigating not only the top level
of the actor's inventory. Every @ref{it_bag} will be checked recursively, too,
ensuring that no instance of the searched item can pass the barrier.

The @samp{flavor} attribute determines the blocked item kind. The string
@code{"all"} blocks any item. Any string containing an @ref{Object Kind}
will block items of just the given kind. Of course you can use just kinds of
@ref{portable} items. E.g. a @samp{flavor} of @code{"it_flag_white"} will just
block actors that carry a white @ref{it_flag}, while @code{"it_flag"} would
block actors carrying flags of any color. The blocked item kind is indicated on
top of the barrier stone.

Be aware that barrier stones can be circumvented with two actors exchanging
their positions by @ref{it_yinyang} usage. As the player can not drop the
@ref{it_yinyang} it is no use to add an additional barrier stone for this item.
Multiple actors assigned to a single player are another potential shortcut of
barrier stones.

As barrier stones are usually bound to their initial position to fulfill their
item blocking task, they are kept from being swapped or pulled by the
@samp{static} attribute's default of @code{true}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"all"}, any portable item kind string; @ @ @i{default}: @code{"all"}
The item kind to be searched for.
@item @b{static} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Static barriers are neither swappable nor pullable.
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_barrier, 12mm} @b{st_barrier}: flavor=@code{"all"}
@end table
@end table

@c ----------------- Beads Stone --------------------
@node st_beads
@subsection st_beads
@obindex st_beads

A stone framed by glass beads. Like other @ref{Transparent Stones} it is
passable for invisible actors, but it is not transparent to laser beams.

Like @ref{st_oneway} the beads stone does not detain visible actors once they
entered the grid and lets them leave on any side.

@table @asis
@item @b{Attributes:} none

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_beads, 12mm} @b{st_beads}
@end table

@end table

@c ----------------- Blocker Stone --------------------
@node st_blocker
@subsection st_blocker
@obindex st_blocker

A door like object that shrinks to @ref{it_blocker} when hit by an
@ref{st_boulder}. When the boulder did pass the blocker stays in its item like
open state until it is passed again by a boulder which causes it to grow again
to a blocker stone.

It fully supports the messages of any door like object and can be opened and
closed by any switch like object. Note that due to the transformation between
stone and item during opening and closing you should name the blocker
(@pxref{name}) and address the blocker by this name. The complete identity
with all attributes including any user attributes will be transferred between
stone and item. E.g. @samp{@{st_switch, target="myblocker", action="toggle"@}}
will open and close a given blocker multiple times.

Note that the blocker is the only door object that allows a stone to be pushed
through. Just boulders cause the growing. Any other stone keeps the open state.

Be aware that the @ref{it_brake} destroys an @ref{it_blocker}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{OPEN}, @code{CLOSED}; @ @ @i{default}: @code{CLOSED} @ @ @xref{state}
The stone represents the closed state and will always return state @samp{CLOSED}.
But you can set its state what is equivalent to sending an open message in case
of value @samp{OPEN} and a close message in case of value @samp{CLOSED}.

@atindex autoclose
@item @b{autoclose} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
This attribute is irrelevant to the blocker stone itself. But it is transferred
to the @ref{it_blocker} when the blocker opens.

@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
A signal of value 1 sends an open message, a signal of value 0 sends a close
message.
@item @b{toggle} @ @ @xref{toggle}
A toggle causes an open unless the blocker stone is in the shrinking process.
In this case it causes a close message.
@item @b{open} @ @ @xref{open}
Starts an opening by shrinking the blocker. Note that during the shrinking
process the blocker still reports to be closed. The shrinking process can
be reverted by a close message.
@item @b{close} @ @ @xref{close}
A close message takes only effect on a blocker stone that is in the shrinking
process. The shrinking is stopped immediately and reverted to grow the blocker
again to full size.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
Sends an action at the moment the blocker reaches the closing state. That means
an @ref{it_blocker} did close and did generate this blocker stone as its
successor. The value will be @samp{false} to express the closing state.

@item @b{Variants:}
@table @asis
@item @image{images/st_blocker, 12mm}  @b{st_blocker}
A standard blocker stone.
@item @image{images/st_blocker, 12mm}  @b{st_blocker_new}
A blocker that just starts growing. Mainly used internally as the direct
successor of an @ref{it_blocker}. But it may be useful to generate an initial
snapshot of a moving boulder over a blocker line, too. See example levels.
@end table

@end table

@c ----------------- Blur Stone --------------------
@node st_blur
@subsection st_blur
@obindex st_blur

A gray stone that transforms on an actor hit into a @ref{st_passage} depending
on the color of actor. The color of the passage may be the same as
the color of the actor or be of the opposite color. The flavor of the passage
is always @code{"square"}.

In the first case the blur stone is pure gray and its  @samp{flavor} is called
@code{"straight"} due to the straight color preserving transformation. The
touching actor will be able to pass the passage straight away.

In the second case the blur stone has an added white and black symbol to notify
the player that, on touching the stone with a colored actor, this actor will not
be able to pass the resulting passage. There are two flavors of such blur stones
- @code{"cross"} which transform unconditionally on an actor hit to the opposite
colored @ref{st_passage} and flavor @code{"magic"} which transforms just on
actors hitting the blur stone with a revealed @ref{it_magicwand} or
@ref{it_brush} in their inventory.

For colorless actors a blur stone is just a standard stone without any special
features.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"straight"}, @code{"cross"}, @code{"magic"}; @ @ @i{default}: @code{"straight"}
The blur subkind.
@end table

@item @b{Messages:} none
@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_blur_straight, 12mm} @b{st_blur}: flavor = @code{"straight"}
@item @image{images/st_blur_straight, 12mm} @b{st_blur_straight}: flavor = @code{"straight"}
@item @image{images/st_blur_cross, 12mm} @b{st_blur_cross}: flavor = @code{"cross"}
@item @image{images/st_blur_cross, 12mm} @b{st_blur_magic}: flavor = @code{"magic"}
@end table

@end table

@c ----------------- Boulder Stone --------------------
@node st_boulder
@subsection st_boulder
@obindex st_boulder

This solid stone moves into the direction shown by the arrow on its picture.
A marble blocking its way is shattered. When a stone blocks its way, the boulder
triggers it by a sequence of two internal messages. Some stones give way like
@ref{st_blocker}, @samp{st_break_boulder} (@pxref{st_break}), others change their
state like @ref{st_oxyd}, @ref{st_stoneimpulse}, @ref{st_quake},
@ref{st_mirror}, @ref{st_fourswitch}, @ref{st_volcano}. A third category
switches temporarily into another state on the first message sent when the
boulder reaches a grid and switches back on the second message sent when the
boulder gives up like @ref{st_passage}, @ref{st_flat}, @ref{st_lightpassenger}.

Items getting beneath a moving boulder may react like on any other stone move
on top of them. Additionally @ref{it_blocker} will be released to grow again
to a blocking stone.

Boulder stones fall into @ref{fl_abyss}, but cross @ref{fl_water}
unchanged.

@ref{it_magicwand} and lasers reverse its orientation. An @ref{st_actorimpulse}
reverts the orientation if the boulder hits it frontally. An @ref{st_rotator}
changes its orientation according to the rotator's direction. An
@ref{st_stoneimpulse} pushes a boulder away.

@table @asis
@item @b{Attributes:}

@table @asis
@atindex orientation
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH}
The orientation of the boulder that is shown by its arrow. It determines the
direction that the boulder will take on its next move.
@item @b{counterclock} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
The standard turning direction is clockwise. Use this attribute to revert the
direction.
@end table

@item @b{Messages:}

@table @asis
@msindex orientate
@item @b{orientate}, @ @ @i{value type}: direction
Change the orientation to the given orientation value. The @ref{st_fourswitch}
provides a compatible action which allows you to set a boulder as
target and this message as action.
@item @b{turn}
Turn orientation in turning direction as defined by attribute
@samp{counterclock}.
@item @b{turnback}
Turn orientation in opposite turning direction as defined by attribute
@samp{counterclock}.
@item @b{flip}
Turn orientation into the reverse of the current orientation.
@end table

@item @b{Action:}
none

@item @b{Variants:}

@table @asis
@item @image{images/st_boulder, 12mm} @b{st_boulder}
@item @image{images/st_boulder, 12mm} @b{st_boulder_n}: orientation = @code{NORTH}
@item @image{images/st_boulder_b, 12mm} @b{st_boulder_e}: orientation = @code{EAST}
@item @image{images/st_boulder_c, 12mm} @b{st_boulder_s}: orientation = @code{SOUTH}
@item @image{images/st_boulder_d, 12mm} @b{st_boulder_w}: orientation = @code{WEST}
@end table

@end table

@c ----------------- Box Stone --------------------
@node st_box
@subsection st_box
@obindex st_box

A movable, floor building stone of various flavors.

This very common stone is well known in its default flavor @code{"wood"}. But it
exists in the flavors @code{"hay"} and @code{"rock"}, too. The flavor
@code{"wood"} has a random wood tile orientation. You can set wooden boxes of
given tile orientation by the variants @code{st_box_wood_h} and
@code{st_box_wood_v}.

The flavors @code{"wood"} and @code{"hay"} may originate from a growing
@ref{it_seed}. Due to the @ref{Snapshot Principle} special box variants exist
just for usage in level initialization: @code{st_box_wood_growing} and
@code{st_box_hay_growing}.

All variants can easily be pushed around, do press @ref{it_trigger}s and do fall
into @ref{fl_abyss}, @ref{fl_water} and @ref{fl_swamp} by building a framed floor
of the kind indicated by their @samp{flavor} attribute. All boxes will fall on
the first occasion. Even if they receive two push impulses at the same time by
@ref{ot_wire} they fall on the first grid. Thus it is impossible to push a box
over a ditch. Boxes will fall if the floor beneath them vanishes. E.g. an
@ref{it_bomb} explosion beneath a box may change the floor to @ref{fl_abyss} or
a flood stream may change the floor to @ref{fl_water}. In all these cases the
box above falls immediately building its kind of floor.

Note that all boxes do actively support @ref{Flood Spreading}. That means that
they let an arriving flood stream flow beneath them. In case the floor beneath
the box is floodable it will change to water and the box will fall. The new built
floor itself conserves the flood stream feature and will let the stream flood
neighboring floodable floors, too. (@pxref{fl_wood}, @ref{fl_hay}, @ref{fl_rock}).

The box flavors do differ in some small but essential features. Whereas the
flavors @code{"wood"} and @code{"rock"} do cause an @ref{it_bomb} to explode
when being pushed over it, a @code{"hay"} flavored box does not ignite bombs.

According to their flavor @code{"wood"} and @code{"hay"} will burn on fire.
But @code{"rock"} flavored boxes are fire resistant and fire blocking.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"wood"}, @code{"hay"}, @code{"rock"}; @ @ @i{default}: @code{"wood"}; @ @ @i{access}: read only
@item @b{secure} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
This attribute is inherited to a floor build by a falling box and guarantees
then secure fire burning.
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_box_wood, 12mm} @b{st_box}: flavor=@code{"wood"}
@item @image{images/st_box_wood, 12mm} @b{st_box_wood}: flavor=@code{"wood"}
@item @image{images/st_box_wood, 12mm} @b{st_box_wood_h}: flavor=@code{"wood"}
@item @image{images/st_box_wood_2, 12mm} @b{st_box_wood_v}: flavor=@code{"wood"}
@item @image{images/st_box_wood_growing, 12mm} @b{st_box_wood_growing}: flavor=@code{"wood"}
@item @image{images/st_box_hay, 12mm} @b{st_box_hay}: flavor=@code{"hay"}
@item @image{images/st_box_hay_4, 12mm} @b{st_box_hay_growing}: flavor=@code{"hay"}
@item @image{images/st_box_rock, 12mm} @b{st_box_rock}: flavor=@code{"rock"}
@end table

@end table

@c ----------------- Brake Stone --------------------
@node st_brake
@subsection st_brake
@obindex st_brake

The brake stone can be used to block a running @ref{st_boulder} or a
@ref{st_lightpassenger}, what likely has given this object its name. But unlike
all other blocking stones the brake can be picked up as an item by actors and
dropped anywhere else.

When an actor passes a brake stone, rolling on the floor or while jumping, it
will pick up the object like other items. The brake will be added as an
@ref{it_brake} to its inventory. Unlike other items the brake can be dropped
even on grids that are already occupied by an item. But you can not drop the
brake beneath another stone like an @ref{it_seed}.

On dropping the brake item it transforms immediately back to an @ref{st_brake}
without killing the item positioned on the grid. Just one exception is a brake
being dropped on top of an @ref{it_blocker} what results in an elimination of
the blocker. On the other hand a brake stone will press an @ref{it_trigger}
beneath, what makes the brake item a portable trigger key.

The brake stone explodes when it is exposed to laser light or an @ref{it_bomb}
explosion on a direct neighbor grid.

@table @asis
@item @b{Attributes:} none

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:} none
@table @asis
@item @image{images/st_brake, 12mm} @b{st_brake}
@end table
@end table

@c ----------------- Break Stone --------------------
@node st_break
@subsection st_break
@obindex st_break

A stone of various flavors that is breakable under various conditions. The
stone may be breakable by actors of some kind, with or without an item, by an
igniting explosion on a neighboring grid and in most cases by laser light.
Besides being breakable the stone is a standard stone. The different flavors let
this stone appear in quite different outlooks.

The flavor @code{"plain"} is a grey stone that is breakable by any actor hit
with a revealed @ref{it_hammer} and by a laser beam hitting any side.

The flavors @code{"black"} and @code{"white"} look similar to the @code{"plain"}
variant just with a small colored ball sitting on top. But these variants are
just breakable by any actors of matching color. Of course the actors need a
revealed @ref{it_hammer}. Laser beams do break the stone, too.

The flavor @code{"oxydc"} looks like a cracked @ref{st_oxyd} of flavor
@code{"c"}. Like the @code{"plain"} variant it is breakable by any actor hit
with a revealed @ref{it_hammer} and by a laser beam hitting any side.

The flavor @code{"boulder"} looks like a yellowish version of flavor
@code{"oxydc"}. It is breakable under the same conditions plus additionally by
an @ref{st_boulder} hitting on one of its sides.

The flavor @code{"bug"} looks like an @ref{st_flat} with a bug symbol on top.
It is just breakable by an @ref{ac_bug}. No other actor and no laser light will
break it.

The flavor @code{"laser"} looks identical to an @ref{st_flat}. It is not
breakable by actors. Just laser light beams on one of its faces will break this
variant.

All but the variant @code{"bug"} will break on neighboring ignitions like those
caused by an exploding @ref{it_dynamite} on a direct neighboring position or an
exploding black @ref{it_bomb} on a diagonal neighboring position.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"plain"}, @code{"black"}, @code{"white"}, @code{"oxydc"}, @code{"boulder"}, @code{"bug"}, @code{"laser"}; @ @ @i{default}: @code{"plain"}; @ @ @i{access}: read only
@end table

@item @b{Messages:}
@table @asis
@item @b{ignite}
Break stone with exception of flavor @code{"bug"}.
@end table

@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_break_plain, 12mm} @b{st_break}: flavor=@code{"plain"}
@item @image{images/st_break_plain, 12mm} @b{st_break_plain}: flavor=@code{"plain"}
@item @image{images/st_break_black, 12mm} @b{st_break_black}: flavor=@code{"black"}
@item @image{images/st_break_white, 12mm} @b{st_break_white}: flavor=@code{"white"}
@item @image{images/st_break_oxydc, 12mm} @b{st_break_oxydc}: flavor=@code{"oxydc"}
@item @image{images/st_break_boulder, 12mm} @b{st_break_boulder}: flavor=@code{"boulder"}
@item @image{images/st_break_bug, 12mm} @b{st_break_bug}: flavor=@code{"bug"}
@item @image{images/st_flat, 12mm} @b{st_break_laser}: flavor=@code{"laser"}
@end table

@end table

@c ----------------- Brownpyramid Stone --------------------
@node st_brownpyramid
@subsection st_brownpyramid
@obindex st_brownpyramid

A brown gray pyramid shaped stone. This stone is just standard stone besides
the fact that it can be destroyed by an @ref{ot_cannonball} emitted by an
@ref{st_spitter} that happens to fall on its top.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_brownpyramid, 12mm} @b{st_brownpyramid}
@end table
@end table

@c ----------------- Chameleon Stone --------------------
@node st_chameleon
@subsection st_chameleon
@obindex st_chameleon

A stone that has no own image but mimics the floor beneath. Thus it is fairly
invisible. But as it shows the same image as the floor it hides items and even
actors on the grid. The stone is hovering, thus it does not press any
@ref{it_trigger} and lets pass any actors and laser light, too.

Please make rare usage of this stone in Enigma 1.1* as the current display
engine does not really support this stone. All dynamic floors and floor changes
do cause faulty displays. Thus use it currently only in patterns without any
floor dynamics.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/fl_white, 12mm} @b{st_chameleon}
@end table
@end table

@c ----------------- Charge Stone --------------------
@node st_charge
@subsection st_charge
@obindex st_charge

An electrical charger for actors. The image reflects the sign of the
@samp{charge} attribute.

Any actor hitting this stone will recharge its @ref{charge} attribute to the
value given by the stone's @samp{charge} attribute.

The stone itself does not cause any electrical forces. It is neither attracting
nor repelling for charged actors. Electrical forces applied to actors just
depend on the charges of different actors and the global attribute
@ref{ElectricStrength}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{charge} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{0.0}
The charge applied to hitting actors.
@end table

@item @b{Messages:} none

@item @b{Action:}  none

@item @b{Variants:}

@table @asis
@item @image{images/st_charge_zero, 12mm} @b{st_charge}: charge = @code{0.0}
@item @image{images/st_charge_zero, 12mm} @b{st_charge_zero}: charge = @code{0.0}
@item @image{images/st_charge_plus, 12mm} @b{st_charge_plus}: charge = @code{+1.0}
@item @image{images/st_charge_minus, 12mm} @b{st_charge_minus}: charge = @code{-1.0}
@end table

@end table

@c ----------------- Chess Stone --------------------
@node st_chess
@subsection st_chess
@obindex st_chess

A chess stone is like a chess knight. It exists in the two colors black and
white, it can jump and make a chess knight move. It can even beat stones at
the target position.

A black chess can only be moved with a black marble, a white one with white
marbles. The jump direction is given by the marble hit direction. It moves
two grid steps into the direction, into which other movable stones move just one
grid, plus one grid step vertical. The vertical direction is given by the
marbles vertical velocity component.

When there is a chess stone of opposite color or an @ref{st_thief} at the target
position of a knight move, this stone is captured and destroyed.

When hit with a revealed @ref{it_magicwand}, a chess stone changes color.

Chess stones fall into @ref{fl_abyss} and sink in @ref{fl_swamp}, but cross
@ref{fl_water} undamaged.

A chess stone that jumps onto a @ref{fl_thief} captures and inactivates the
thief.

Chess stones can't jump over or into fire (see @ref{Fire Spreading}). At least,
a chess knight is brave enough not to panic when fire starts to burn beneath.
Note that fire can't ignite the floor below a chess stone. In this
context it acts like an immovable stone. In the same sense, they don't act on
stone impulses of @ref{st_stoneimpulse} or @ref{it_puller}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{color} @ @ @i{values}: @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{BLACK}
The color of the chess stone
@item @b{movable} @ @ @i{values}: @code{true}; @ @ @i{default}: @code{true} @ @ @xref{movable}
Read only attribute that states the ability of a chess stone to move.
@end table

@item @b{Messages:}

@table @asis
@item @b{flip}
Flip the color of the stone.
@item @b{move}, @ @ @i{value type}: position; @ @ @i{values}: @code{NNE}, @code{NEE}, @code{SEE}, @code{SSE}, @code{SSW}, @code{SWW}, @code{NWW}, @code{NNW}
Jump into the given direction.
@end table

@item @b{Action:}  none

@item @b{Variants:}

@table @asis
@item @image{images/st_chess_black, 12mm} @b{st_chess}: color = @code{BLACK}
@item @image{images/st_chess_black, 12mm} @b{st_chess_black}: color = @code{BLACK}
@item @image{images/st_chess_white, 12mm} @b{st_chess_white}: color = @code{WHITE}
@end table

@end table

@c ----------------- Coinslot Stone --------------------
@node st_coinslot
@subsection st_coinslot
@obindex st_coinslot

A switch that is activated by insertion of an @ref{it_coin}. Just actors
assigned to a player can insert coins out of their item inventory by hitting
the coinslot with the coin being the first item. Depending on the coin type the
coinslot remains in state @samp{ON} for a given @samp{interval} before switching
back to state @samp{OFF}. Multiple inserted coins do prolong the activity
interval.

Standard not @samp{instant} coinslots do activate after the insertion process
of the coin. No additional coins can be inserted while another coin is being
inserted. This prevents unintended multiple coin insertions. On the other hand
the player has to insert additional coins early enough to prolong the active
state without temporarily switching back to @samp{OFF} state. If the first
interval runs off while the next coin did not yet finish its insertion the
coinslot will first switch @samp{OFF} and switch @samp{ON} when the next coin
is completely inserted.

The activity interval of a coin insertion depends on the type of the coin. For
each type you can set the interval by the @samp{interval_*} attributes. You
can reject the insertion of a coin type by setting its interval to
@samp{COIN_REJECT}. The coin will not be taken from the player's inventory. By
a value of @samp{COIN_IGNORE} on the interval attribute the coinslot will fetch
the coin but will not act at all.

Coinslots configured as @samp{instant} do activate immediately when the actor
hits the stone. On every actor hit a coin is inserted independent of the last
insertion.

The @samp{state} of a coinslot can be requested but it can not be set, neither
by attribute nor by messages.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF}; @i{access}: @code{read only}  @ @ @xref{state}
Current activity state of the coinslot.
@item @b{instant} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
A default coinslot switches to active state after insertion of a coin and allows
the insertion of just one coin at a time.
@item @b{interval_s} @ @ @i{values}: positive number, @code{COIN_REJECT}, @code{COIN_IGNORE}; @ @ @i{default}: @code{3.0}
Number of additional active seconds on insertion of a small @ref{it_coin}.
@item @b{interval_m} @ @ @i{values}: positive number, @code{COIN_REJECT}, @code{COIN_IGNORE}; @ @ @i{default}: @code{6.0}
Number of additional active seconds on insertion of a medium @ref{it_coin}.
@item @b{interval_l} @ @ @i{values}: positive number, @code{COIN_REJECT}, @code{COIN_IGNORE}; @ @ @i{default}: @code{12.0}
Number of additional active seconds on insertion of a large @ref{it_coin}.
@end table

@item @b{Messages:} none

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}

@table @asis
@item @image{images/st_coinslot, 12mm} @b{st_coinslot}: instant = @code{false}
@item @image{images/st_coinslot, 12mm} @b{st_coinslot_instant}: instant = @code{true}
@end table

@end table

@c ----------------- Darkglass Stone --------------------
@node st_darkglass
@subsection st_darkglass
@obindex st_darkglass

A metal framed semi transparent glass stone. It exists in static, movable and
hollow variants and is just transparent to laser light in its hollow variant.
Like other @ref{Transparent Stones} it is passable for invisible actors as long
as it is not @samp{movable}.

A @ref{st_lightpassenger} in state @samp{OFF} looks identical to a darkglass
stone

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{hollow} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{hollow}
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{movable}
@end table

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_darkglass, 12mm} @b{st_darkglass}: hollow = @code{false}, movable = @code{false}
@item @image{images/st_darkglass, 12mm} @b{st_darkglass_hollow}: hollow = @code{true}, movable = @code{false}
@item @image{images/st_darkglass, 12mm} @b{st_darkglass_movable}: hollow = @code{false}, movable = @code{true}
@end table

@end table

@c ----------------- Death Stone --------------------
@node st_death
@subsection st_death
@obindex st_death

Shatters any @ref{ac_marble} and @ref{ac_pearl} that hits or even just touches
it. Just marbles and pearls protected by an activated @ref{it_umbrella} will
bounce unharmed as other actors do which will not die anyway.

Death stones can be configured by the @samp{invisible} attribute to
be hidden while being idle. When hit by an actor any death stone becomes
temporary visible. An actor with unbroken standard @ref{it_glasses} in its
inventory will be able to spot invisible death stones.

The level author can configure @ref{it_glasses} by elimination of
@samp{SPOT_DEATH} not to show invisible death stones. With the global attribute
@ref{ExtralifeGlasses} even glasses generated by laser lighting an
@ref{it_extralife} can be configured not to show invisible actorimpulse stones.

A death stone can also be movable. Of course ball like actors can not push it.
But other actors can push it. A movable death stone can be connected by an
@ref{ot_wire} to another movable stone that allows to control it. Furtheron
all stones emitting stone impulses like @ref{st_stoneimpulse}, @ref{st_rotator},
@ref{st_lightpassenger} can move it. And finally a pushing @ref{st_boulder}
will move it until an obstacle stops the death stone.

A movable death stone looks identical to the static default version. But from
time to time it will show its animation and can thus be identified by the user.
The interval of the animations is determined by the attribute @samp{interval},
but will randomly vary up to 20% from the given value. When the @samp{interval}
equals zero no animation will reveal the movable death. But any @ref{it_glasses}
capable of @samp{SPOT_DEATH} will show the movable death in a lighter stone
color than the static ones.

A @samp{movable} death can not be @samp{invisible} at the same time. If you set
both attributes the last attribute set wins and resets the first one.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF}; @i{access}: @code{read only}  @ @ @xref{state}
Current activity state of the death stone. A stone is usually activated by
a hitting actor.
@item @b{invisible} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Invisible death stones show only when hit by an actor or been toggled by a message.
Setting this attribute to @samp{true} sets @samp{movable} to @samp{false}.
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @xref{movable}
Movable death stone. Setting this attribute to @samp{true} sets @samp{invisible}
to @samp{false}.
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{10.0}
Number of seconds to show animation on movable death.
@end table

@item @b{Messages:}
@table @asis
@item @b{toggle} @ @ @xref{toggle}
Temporarily activate the stone to show its animation and to get visible for this
period.
@end table

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_death, 12mm} @b{st_death}: invisible = @code{false}
@item @image{images/fl_white, 12mm} @b{st_death_invisible}: invisible = @code{true}
@item @image{images/st_death_light, 12mm} @b{st_death_movable}: movable = @code{true}
@end table

@end table

@c ----------------- Disco Stone --------------------
@node st_disco
@subsection st_disco
@obindex st_disco

A free passable stone, which darkens everything that is underneath the stone.
It looks like a tinted glass that occurs in several shades. It likely got its
name from the possibility to switch between the shade grades.

The disco stone comes in three variants, @samp{LIGHT}, @samp{MEDIUM} and
@samp{DARK}. The dark variant is pure black, that shows neither actors, items or
the floor. You can switch between these variants by messages and state attribute
access. The messages @code{"lighten"} and @code{"darken"} change the shade
by one degree. The message @code{"signal"} turns the disco light full on or off,
independent of the previous state. The standard @code{"toggle"} switches from
light -> medium -> dark -> light.

Note: unlike the old API versions of this stone, it does no longer support
recursive shading of neighboring disco stones. Make use of object groups by
@ref{Object Naming} to shade groups of arbitrary composition by a single message.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{LIGHT}, @code{MEDIUM}, @code{DARK}; @ @ @i{default}: @code{LIGHT} @ @ @xref{state}
The shading grade.
@end table

@item @b{Messages:}
@table @asis
@item @b{lighten}
Lighten by one degree.
@item @b{darken}
Darken by one degree.
@item @b{signal} @ @ @xref{signal}
Switch to @samp{LIGHT} on a value of @code{1}. Switch to @samp{DARK} on a value
of @code{0}.
@item @b{toggle} @ @ @xref{toggle}
Darken by degree or switch from @samp{DARK} to @samp{LIGHT}
@end table

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_disco, 12mm} @b{st_disco}: state = @code{LIGHT}
@item @image{images/st_disco, 12mm} @b{st_disco_light}: state = @code{LIGHT}
@item @image{images/st_disco_2, 12mm} @b{st_disco_medium}: state = @code{MEDIUM}
@item @image{images/st_disco_3, 12mm} @b{st_disco_dark}: state = @code{DARK}
@end table

@end table

@c ----------------- Dispenser Stone --------------------
@node st_dispenser
@subsection st_dispenser
@obindex st_dispenser

An item dispenser in some item flavors.

On every actor hit the dispenser adds a new item given by the attribute
@samp{flavor}, namely @ref{it_bomb} in color black or white, @ref{it_dynamite}
or @ref{it_extralife} to the inventory of the actor's owner. Of course an item
will just be added if the inventory is capable of adding a further item.
Additionally the dispenser's @samp{stock} must supply a further item. The
default stock of 1000 items should be enough for usual demands. But you can
limit the supply to just a few counted items. This @samp{stock} attribute gets
decremented every time an actor takes an item.

The dispenser stone does break on adjacent @ref{it_bomb} explosions and
adjacent dispenser stone breaks. On its break it will itself cause adjacent
@ref{it_dynamite} to ignite, @ref{it_bomb} positioned beneath itself to
explode, and of course neighboring dispensers to break. Dispenser stones will
neither break on actor hits, even with a revealed hammer, nor on laser light
beams.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"bombblack"}, @code{"bombwhite"}, @code{"dynamite"}, @code{"extralife"}; @ @ @i{default}: @code{"bombblack"};
@item @b{stock}, @ @ @i{values}: integer numbers; @ @ @i{default}: @code{1000}: @ @ @xref{state}
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_dispenser_bombblack, 12mm} @b{st_dispenser}: flavor=@code{"bombblack"}
@item @image{images/st_dispenser_bombblack, 12mm} @b{st_dispenser_bombblack}: flavor=@code{"bombblack"}
@item @image{images/st_dispenser_bombwhite, 12mm} @b{st_dispenser_bombwhite}: flavor=@code{"bombwhite"}
@item @image{images/st_dispenser_dynamite, 12mm} @b{st_dispenser_dynamite}: flavor=@code{"dynamite"}
@item @image{images/st_dispenser_extralife, 12mm} @b{st_dispenser_extralife}: flavor=@code{"extralife"}
@end table

@end table

@c ----------------- Document Stone --------------------
@node st_document
@subsection st_document
@obindex st_document

This stone can display a text message when touched. Other message
carrying items are @ref{it_document} and @ref{it_bottle}.

In addition, this is the paper member of the rock-paper-scissors trio,
the other two stones being @ref{st_scissors} and @ref{st_pebble}.
When @code{st_document} is touched, each @code{st_pebble} bordering
it or being connected to it by a wire is destroyed. Similarly,
when an @code{st_scissors} is touched, that borders or is connected to
an @code{st_document}, the @code{st_document} will break.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{text}, @ @ @i{values}: string;
Either the text to be displayed or just a key word for identification on
@ref{Internationalization (i18n)}. It may be empty (then no text is displayed).
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_document, 12mm} @b{st_document}
@end table
@end table

@c ----------------- Door Stone --------------------
@node st_door
@subsection st_door
@obindex st_door

Doors are stones that let actors pass or block them to enter the grid, depending
on their state. Doors can be opened and closed by the standard set of messages.
Doors do not open or close instantly. They need a small amount of time. Actors
can pass only doors that are completely open.

There are several flavors of doors. The variants @code{"a"} to @code{"c"}
represent grid filling block doors. Flavor @code{"a"} looks in the closed state
like @ref{st_oxyd} of flavor @code{"a"} and in the opened state like an
@ref{st_grate} of flavor @code{"cross"}. Flavor @code{"b"} looks in the closed
state like @ref{st_flat} but opens to an invisible, free passable, but still
existing and grid blocking stone. Flavor @code{"c"} looks in the closed state
like @ref{st_flat} and in the opened state like an @ref{st_grate} of flavor
@code{"framed"}. The flavor @code{"d"} represents a faces based door, that
opens or blocks just the given faces of the grid. Currently just the
combinations of two parallel aligned door faces, aka horizontal and vertical
doors, are supported.

As door grids can be entered on unfaced sides you should block these faces by
impassable stones. If you do not block these entries or even allow marbles to
warp into a door, the actors will be free to leave the doors even if they are
closed. But marbles will shatter on the door grid when doors are closed. This
behaviour is a legacy Enigma feature.

Doors are stones that are even present if they are not visible in the @code{OPEN}
state. This means you can not push or move any other stone through an open door.
The @ref{st_blocker} is a quite compatible door alternative that allows stones
to pass in its open state.

All doors are hovering and will not press @ref{it_trigger}s. Thus you can detect
passing actors by positioning a trigger beneath a door. Doors will neither press
@ref{fl_bridge} and will thus take no influence on the bridge.

Laser light will pass any open door, but will be blocked by closed faces. Closed
doors of type @code{"d"} let light pass if the faces are parallel aligned to
the light without intervening the light.

Just doors of type @code{"d"} allow an actor to knock on its closed faces.
This causes an action that might open the door or do anything else. A common
target is @ref{st_jamb} that evaluated the color of the knocking actor.
The door has to be completely closed; opening or closing doors do not
cause an action on knocking.

Doors do support @ref{Flood Spreading} and @ref{Fire Spreading} through open
faces and generally in @samp{OPEN} state.

@table @asis

@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{OPEN}, @code{CLOSED}; @ @ @i{default}: @code{CLOSED}; @ @ @xref{state}
The open state of the door. On read access it reports if the door is completely
opened and passable for actors. Note that a door reaches the state @samp{OPEN}
after the finish of the opening animation, what is an essential amount of time
after the initiating @code{"open"} message. But on a @code{"close"} message the
state turns immediately to @samp{CLOSED} as actors are blocked immediately. On
write access a state change causes a proper message and may occur with a delay,
too.

@item @b{flavor} @ @ @i{values}: @code{"a"}, @code{"b"}, @code{"c"}, @code{"d"}; @ @ @i{default}: @code{"d"}
Representing different door types as described above. Block based flavors
@code{"a"}, @code{"b"}, @code{"c"} and the face based flavor @code{"d"}.

@item @b{faces} @ @ @i{values}: string; @ @ @i{default}: @code{"nesw"}
Describes the door faces of the stone. The string is a substring of
@code{"nesw"} listing the faces. The sequence of the sides, north, east, south,
west, is guaranteed on read access but arbitrary on write access. Note that
the supported face combinations depend on the flavor. All but flavor @code{"d"}
do always provide all 4 faces. Flavor @code{"d"} currently supports the face
combinations @code{"ns"} and @code{"ew"}, in other words horizontal and
vertical aligned door faces, with the first combination being the default.

@end table

@item @b{Messages:}
@table @asis
@item @b{open} @ @ @xref{open}
Opens a closed door or reverses the process of a closing door.
@item @b{close} @ @ @xref{close}
Closes an open door or reverses the process of an opening door.
@item @b{signal} @ @ @xref{signal}
Opens at value @samp{1}, and closes at value @samp{0}.
@end table

@item @b{Action:}
Just flavor @code{"d"} doors will perform an action on an actor touching a face
of a closed door. The action value will be the actor object, which can be
evaluated on its kind. This action value fits the @samp{hit} messages of
objects like @ref{st_jamb}. The door has to be completely closed; opening or
closing doors do not cause an action on knocking.

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_oxyda, 12mm}@tab  @b{st_door_a}: flavor = @code{"a"}, state = @code{CLOSED}
@tab @image{images/st_grate_cross, 12mm}@tab  @b{st_door_a}: flavor = @code{"a"}, state = @code{OPEN}
@item @image{images/st_flat, 12mm}@tab  @b{st_door_b}: flavor = @code{"b"}, state = @code{CLOSED}
@tab @image{images/fl_white, 12mm}@tab  @b{st_door_b}: flavor = @code{"b"}, state = @code{OPEN}
@item @image{images/st_flat, 12mm}@tab  @b{st_door_c}: flavor = @code{"c"}, state = @code{CLOSED}
@tab @image{images/st_grate_framed, 12mm}@tab  @b{st_door_c}: flavor = @code{"c"}, state = @code{OPEN}
@item @image{images/st_door_d_ns_7, 12mm}@tab  @b{st_door_d}: flavor = @code{"d"}, faces = @code{"ns"}, state = @code{CLOSED}
@tab @image{images/st_door_d_ns, 12mm}@tab  @b{st_door_d}: flavor = @code{"d"}, faces = @code{"ns"}, state = @code{OPEN}
@item @image{images/st_door_d_ew_g, 12mm}@tab  @b{st_door_d}: flavor = @code{"d"}, faces = @code{"ew"}, state = @code{CLOSED}
@tab @image{images/st_door_d_ew, 12mm}@tab  @b{st_door_d}: flavor = @code{"d"}, faces = @code{"ew"}, state = @code{OPEN}
@end multitable

@end table

@c ----------------- Fake Stone --------------------
@node st_fake
@subsection st_fake
@obindex st_fake

A stone that mimics other stones, but does not act like them.

In contrast to @ref{st_magic} the fake stone does not transform but remains
all time a passive variant of the stone that it models. The stone does look
like another stone of the kind given by the attribute @samp{flavor}. The fake
stone may even mimic state dependent behaviour with state dependent models
and animations.

The flavor @code{"quake"} mimics a @ref{st_quake} including the pulsing
animation on actor hits and state changes, but does not cause any @ref{st_oxyd}
to close.

The flavors @code{"oxyda"}, @code{"oxydb"}, @code{"oxydc"}, @code{"oxydd"},
@code{"oxyde"} mimic @ref{st_oxyd} of appropriate flavor, but they are just
passive stones. Nevertheless they are aware of a state @samp{OPEN} and will
display the corresponding base image of the open oxyd stone, of course without
any color spot.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"quake"}, @code{"oxyda"}, @code{"oxydb"}, @code{"oxydc"}, @code{"oxydd"}, @code{"oxyde"}; @ @ @i{default}: @code{"quake"};
@item @b{state}, @ @ @i{values}: @code{CLOSED}, @code{OPEN}; @ @ @i{default}: @code{CLOSED}: @ @ @xref{state}
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_oxydb, 12mm} @b{st_fake_quake}: flavor=@code{"quake"}, state=@code{IDLE}
@tab @image{images/st_quake_3, 12mm} @b{st_fake_quake}: flavor=@code{"quake"}, state=@code{ACTIVE}
@item @image{images/st_oxyda, 12mm} @b{st_fake_oxyda}: flavor=@code{"oxyda"}, state=@code{CLOSED}
@tab @image{images/st_oxyda_open, 12mm} @b{st_fake_oxyda}: flavor=@code{"oxyda"}, state=@code{OPEN}
@item @image{images/st_oxydb, 12mm} @b{st_fake_oxydb}: flavor=@code{"oxydb"}, state=@code{CLOSED}
@tab @image{images/st_oxydb_open, 12mm} @b{st_fake_oxydb}: flavor=@code{"oxydb"}, state=@code{OPEN}
@item @image{images/st_oxydc, 12mm} @b{st_fake_oxydc}: flavor=@code{"oxydc"}, state=@code{CLOSED}
@tab @image{images/st_oxydc_open, 12mm} @b{st_fake_oxydc}: flavor=@code{"oxydc"}, state=@code{OPEN}
@item @image{images/st_oxydd, 12mm} @b{st_fake_oxydd}: flavor=@code{"oxydd"}, state=@code{CLOSED}
@tab @image{images/st_oxydb_open, 12mm} @b{st_fake_oxydd}: flavor=@code{"oxydd"}, state=@code{OPEN}
@item @image{images/st_oxydb, 12mm} @b{st_fake_oxyde}: flavor=@code{"oxyde"}, state=@code{CLOSED}
@tab @image{images/st_oxydb_open, 12mm} @b{st_fake_oxyde}: flavor=@code{"oxyde"}, state=@code{OPEN}
@end multitable

@end table

@c ----------------- Flash Stone --------------------
@node st_flash
@subsection st_flash
@obindex st_flash

A stone symbolized by a yellow flash, that forwards actors' hits as a force to
matching partner actors.

Just @ref{ac_marble} actors are affected. A black hitting marble will push
the first white marble, and vice versa. The hitting marble's velocity is
multiplied to a distortion matrix given by four single attributes. The default
matrix does maintain the direction. The resulting vector is again multiplied
by a linear strength factor. The resulting force vector is applied to the
partner marble. If no matching marble exists no forces are applied. The hitting
marble bounces on the flash stone as on any other standard stone.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{hit_strength} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{20.0}; @ @ @xref{hit_*}
@item @b{hit_distortion_xx} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{1.0}; @ @ @xref{hit_*}
@item @b{hit_distortion_xy} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{0.0}; @ @ @xref{hit_*}
@item @b{hit_distortion_yx} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{0.0}; @ @ @xref{hit_*}
@item @b{hit_distortion_yy} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{1.0}; @ @ @xref{hit_*}
@end table

@item @b{Messages:} none

@item @b{Action:}  none

@item @b{Variants:}
@table @asis
@item @image{images/st_flash, 12mm} @b{st_flash}:
@end table
@end table

@c ----------------- Flat Stone --------------------
@node st_flat
@subsection st_flat
@obindex st_flat

A flat gypsum stone with many variants and features.

Besides the standard features of a movable, hollow or breakable stone the flat
stone provides some very special features and variant transformations.

Movable and breakable flat stones will fall into @ref{fl_abyss}. But just the
movable variant will fall into @ref{fl_water} and @ref{fl_swamp}.

A laser beam will shatter a breakable variant. Further on it transforms a plain flat
stone, and just this variant, into a cracked variant, which is visually
distinguishable by small cracks. But further laser light will not break a
cracked variant. Ignitions and explosions will shatter breakable, cracked and
movable variants. An actor with a revealed @ref{it_hammer} is able to shatter
both the breakable and the cracked variant. Note that the visually
indistinguishable @ref{st_break}_laser breaks on a laser hit, too, but without
being breakable by actors.

An actor with a revealed @ref{it_pencil} will mark a plain or movable variant
as burnable what is hinted for the player by a fire symbol on the flat stone
surface. A burnable flat stone burns on fire, but just the immovable, burnable
variant reacts on heating by self destruction. All burnable variants can be
cleaned by an actor hit with an @ref{it_brush}. The fire symbol vanishes and
the stone does not longer react on fire and heating.

Last but not least an @ref{st_boulder} hitting a plain or hollow variant of the
flat stone toggles the @samp{hollow} attribute twice within a short period. The
time is sufficient for a fast actor to pass an otherwise solid plain flat stone.
By proper fast redirection of the boulder a user can enforce permanent changes
of the hollow state.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{hollow} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{hollow}
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{movable}
@item @b{breakable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{breakable}
@item @b{burnable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{burnable}
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_flat, 12mm} @b{st_flat}:
@item @image{images/st_flat, 12mm} @b{st_flat_hollow}: hollow=@code{true}
@item @image{images/st_flat, 12mm} @b{st_flat_movable}: movable=@code{"true"}
@item @image{images/st_flat, 12mm} @b{st_flat_breakable}: breakable=@code{"true"}
@item @image{images/st_flat_cracked, 12mm} @b{st_flat_cracked}:
@item @image{images/st_flat_fire, 12mm} @b{st_flat_burnable}: burnable=@code{"true"}
@item @image{images/st_flat_fire, 12mm} @b{st_flat_moveburnable}: movable=@code{"true"}, burnable=@code{"true"}
@item @image{images/st_flat_break, 12mm} @b{st_flat_breaking}: breakable=@code{"true"}
@end table
@end table

@c ----------------- Floppy Stone --------------------
@node st_floppy
@subsection st_floppy
@obindex st_floppy

A switch that is activated by insertion of an @ref{it_floppy}. Just actors
assigned to a player can insert a floppy out of their item inventory by hitting
the floppy switch with a floppy being the first item.

On a second hit the switch is deactivated and the inserted floppy is returned
to the player's inventory.

Floppy stones are often used as openers for an adjacent @ref{st_door} that is
declared as its @samp{target}. But there is the inherent danger that an actor
passing the door accidentially hits the neighboring floppy stone, causing the floppy
to be pulled out again and the door to be closed immediately. Of couse this
would shatter any @ref{ac_marble} or @ref{ac_pearl}. But a @samp{secure} floppy
stone checks that the hitting actor is not positioned on one of the floppy stone's
target positions. It refuses any actions caused by such critical hits. Note
that in case the target is a callback function that closes the adjacent door,
there will be still no protection. A floppy stone with @samp{secure} value
@samp{false} would accept any hits and shatter marbles as it has been standard
on older Enigma releases and is still in modes besides Enigma.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF}; @ @ @xref{state}
Current activity state of the floppy stone.
@item @b{secure} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Protect actors on target positions by neglecting their hits.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}, and off at value @samp{0}.
@item @b{on} @ @ @xref{on}
@item @b{off} @ @ @xref{off}
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/st_floppy_off, 12mm} @b{st_floppy} with state=@code{OFF}
@item @image{images/st_floppy_on, 12mm} @b{st_floppy} with state=@code{ON}
@end table
@end table

@c ----------------- Fourswitch Stone --------------------
@node st_fourswitch
@subsection st_fourswitch
@obindex st_fourswitch

A switch that points into one of the four orientations and turning on every
switching event. The most common event is an actor hitting this stone. But
@ref{st_boulder} will trigger this switch, too. Of course other objects can send
messages on actions to make this switch turning.

When turning its pointer on a switching event it performs the action given by
the @samp{action/target}-pair. This can be either a common pair or a
state/orientation dependent pair allowing you to issue different messages
dependent on the pointing orientation.

@table @asis
@item @b{Attributes:}

@table @asis
@atindex state
@item @b{state}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH} @ @ @xref{state}
@item @b{counterclock} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
The standard turning direction is clockwise. Use this attribute to revert the
direction.
@item @b{inverse} @ @ @xref{inverse}
Note that the action value is inverted in its boolean interpretation. This means
that an inverted action value is @emph{not} the reverse orientation and should
not be used as an orientation value at all.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Note that the fourswitch reacts just on value @code{1}. Values of @code{0} are
simply ignored. Use message toggle if you need turns on any message value.
@item @b{toggle} @ @ @xref{toggle}
Note that a toggle turns the fourswitch independent of a message value.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
Performs an action on each turn. If just a pair of global @samp{target/action}
attributes are given, the action message is sent to the target with a value of
the new orientation. This value suits any message of the target that expects
an orientation value, and the @ref{signal} message, that translates the
orientation value to a 1 for @samp{NORTH}, @samp{SOUTH} and a 0 for
@samp{EAST}, @samp{WEST}.

If state dependent target/action pairs are given instead, namely
@samp{target_0/action_0} for the state @samp{WEST},... , @samp{target_3/action_3}
for the state @samp{NORTH}, two actions will be performed: first for the state
representing the old orientation the given action messages will be sent with
a value of 0, then for the state representing the new orientation the given
action messages will be sent with a value of 1. This allows you to switch on
and off alternative sources by a fourswitch.

@item @b{Variants:}
@table @asis
@item @image{images/st_fourswitch, 12mm} @b{st_fourswitch}
@end table
@end table

@c ----------------- Ghost Stone --------------------
@node st_ghost
@subsection st_ghost
@obindex st_ghost

An invisible stone that transforms into a visible stone on actor hits with
properly revealed tools.

Similar to @ref{st_magic} this stone does transform to another kind, but it
is initially always invisible, what gave it its name. Invisibility is not
equal to laser transparency. In fact one flavor of this ghost stone is not
laser transparent. And invisibility does not mean that an invisible actor can
pass a ghost stone. (@pxref{Transparent Stones})

The ghost stone transforms to another stone of the kind given by its
attribute @samp{flavor}. The tool necessary to cause this transformation depends
on the flavor.

The flavor @code{"purplemarble"} transforms to an @ref{st_purplemarble} on a hit
with a revealed @ref{it_brush}. This flavor is not laser transparent.

The flavor @code{"greenbrown"} transforms to an @ref{st_greenbrown} on a hit
with a revealed @ref{it_magicwand}.

The flavor @code{"break"} transforms to an @ref{st_break} of variant
@samp{st_break_oxydc} on a hit with a revealed @ref{it_brush}.


@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"purplemarble"}, @code{"greenbrown"}, @code{"break"}; @ @ @i{default}: @code{"purplemarble"}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@multitable @columnfractions .08 .52 .40
@item @image{images/fl_white, 12mm}@tab @b{st_ghost}: flavor=@code{"purplemarble"} @tab@image{images/st_purplemarble, 12mm}
@item @image{images/fl_white, 12mm}@tab @b{st_ghost_purplemarble}: flavor=@code{"purplemarble"} @tab@image{images/st_purplemarble, 12mm}
@item @image{images/fl_white, 12mm}@tab @b{st_ghost_greenbrown}: flavor=@code{"greenbrown"} @tab@image{images/st_greenbrown, 12mm}
@item @image{images/fl_white, 12mm}@tab @b{st_ghost_break}: flavor=@code{"break"} @tab@image{images/st_break_plain, 12mm}
@end multitable
@end table

@c ----------------- Grate Stone --------------------
@node st_grate
@subsection st_grate
@obindex st_grate

Hovering metal grate in different flavors that let all actors pass but block
stones from moving over a grid position.

The different flavors are just for decorative purposes, but @code{"cross"}
variant looks identical to an open @ref{st_door} of flavor @code{"a"}, whereas
@code{"framed"} variant looks identical to an open @ref{st_door} of flavor
@code{"b"}.

In contrast to opened doors grates do bounce actors that are flying due to a
jump.

As a hovering stone grates do not press @ref{it_trigger}s and let laser light
pass. Grates allow @ref{Flood Spreading} and @ref{Fire Spreading}, too.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"cross"}, @code{"framed"}; @ @ @i{default}: @code{"cross"}
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_grate_cross, 12mm} @b{st_grate}: flavor=@code{"cross"}
@item @image{images/st_grate_cross, 12mm} @b{st_grate_cross}: flavor=@code{"cross"}
@item @image{images/st_grate_framed, 12mm} @b{st_grate_framed}: flavor=@code{"framed"}
@end table

@end table

@c ----------------- Greenbrown Stone --------------------
@node st_greenbrown
@subsection st_greenbrown
@obindex st_greenbrown

A mainly brown stone that is just a standard stone besides
the fact that it can originate from two other objects.

On one hand an @ref{it_seed} of flavor @code{"fake"} will grow to a standard,
unmovable greenbrown. Just for level initialization purpose you can even set
a variant @samp{st_greenbrown_growing} due to the @ref{Snapshot Principle}.

On the other hand a @ref{st_ghost} of flavor @code{"greenbrown"} will transform
to standard, unmovable greenbrown on an actor hit with a revealed
@ref{it_magicwand}.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_greenbrown, 12mm} @b{st_greenbrown}
@item @image{images/st_greenbrown, 12mm} @b{st_greenbrown_hollow}
@item @image{images/st_greenbrown, 12mm} @b{st_greenbrown_movable}
@item @image{images/st_greenbrown_4, 12mm} @b{st_greenbrown_growing}
@end table
@end table

@c ----------------- Ice Stone --------------------
@node st_ice
@subsection st_ice
@obindex st_ice

A block of ice is a movable stone that freezes some items when being pushed
over them. Of course a floor of @ref{fl_water} will freeze, too, when ice is
being pushed over it. But a block of ice can be destroyed by explosions and by
heating fire leaving either @ref{fl_ice} or @ref{fl_water}.

When an ice block without frozen item is pushed onto a grid with a
@ref{freezable} item, the ice will freeze the item and will move it beneath
itself on subsequent pushes. All items that the user can carry in his inventory
are @ref{freezable} and even some @ref{Static Items} like @ref{it_magnet},
@ref{it_springboard}, etc. But a few items react in a special manner when an
ice block is pushed onto them:
@itemize @bullet
@item @ref{it_squashed} and @ref{it_burnable}, with the exception of
@samp{it_burnable_oil}, dissolve to nothing.
@item @ref{it_crack} will vanish as the ice is putty for the cracked floors
@item @ref{it_seed} will not start growing, even though the ice is pushed as a
solid stone on top.
@item @ref{it_bomb} will explode and destroy the ice block as well as the floor.
@item @ref{it_dynamite} is very special - a burning dynamite gets extinguished
by an ice block and becomes frozen in its idle state.
@end itemize

But what happens when an ice block with a frozen item gets pushed onto a grid
with another item? The stronger item wins and survives beneath the ice block
on the new position while the weaker item will be killed. The sequence from
weak to strong is quite simple:
@itemize @bullet
@item static items that get anyway wiped out by an ice block
@item @ref{Liftable Items}
@item @ref{portable} items that are not @ref{liftable}
@item @ref{freezable} items that are not @ref{portable}
@item @ref{Static Items} that are not @ref{freezable}
@end itemize
When the two items are of the same category the already frozen item wins. This
last rule ensures that the user can not free frozen items by dropping a liftable
item out of his inventory in front of an ice block before pushing it.

An ice block looks like a bluish version of @ref{st_rawglass}. But it has just
one feature in common. It is transparent to laser light. Of course you can not
freeze laser beams, even though they are implemented in the item layer. Laser
light will interact even with frozen items and can ignite @ref{it_dynamite} or
@ref{it_bomb}. Even though being light transparent invisible actors can not
pass it (@pxref{Transparent Stones}).

Ice blocks shatter on nearby @ref{it_bomb} and @ref{it_dynamite} explosions and
on @ref{ot_cannonball} hits. The ice will spread to the four direct neighboring
grid positions and will cover these and the originating position with
@ref{fl_ice}. Just @ref{fl_abyss} will not be covered by this ice floor and
remains unchanged. Thus an exploding bomb leaves an @ref{fl_abyss} at its
position, even when an ice blocks shatters nearby.

A fire starting to burn on a direct neighbor position will eventually melt the
ice block by its @ref{Heat-Transformation}. The ice will melt to an
@ref{fl_water}. Just in case the ice block melts over an @ref{fl_abyss} the
floor remains unchanged. The ice heating is no secure feature, as the heat burst
occurs just once for each fire. Thus a user may be able to push an ice block
aside a fire without heat transformation. Furtheron the melting takes time.
Any intermediate nearby explosion can still shatter the melting ice block.

@table @asis
@item @b{Messages:}

@table @asis
@item @b{ignite} @ @ @xref{ignite}
Shatter the ice block.
@item @b{heat} @ @ @xref{heat}
Melt the ice block
@end table

@item @b{Variants:}
@table @asis
@item @image{images/st_ice, 12mm} @b{st_ice}
@end table
@end table

@c ----------------- Inkwell Stone --------------------
@node st_inkwell
@subsection st_inkwell
@obindex st_inkwell

The inkwell stone can recolor marbles. The color change on the marble
is instant. The following transformations are possible, each transformation
is reversible:

@code{st_inkwell_empty} + @code{ac_marble_black}
-> @code{st_inkwell_black} + @code{ac_marble_glass}

@code{st_inkwell_black} + @code{ac_marble_glass}
-> @code{st_inkwell_empty} + @code{ac_marble_black}

@code{st_inkwell_empty} + @code{ac_marble_white}
-> @code{st_inkwell_white} + @code{ac_marble_glass}

@code{st_inkwell_white} + @code{ac_marble_glass}
-> @code{st_inkwell_empty} + @code{ac_marble_white}

In particular, a colored marble will not tranform if it touches a
full @code{st_inkwell}; and a glass marble will not transform if it
touches an empty @code{st_inkwell}. If you want to transform a black
marble into a white one or vice versa, you will need two @code{st_inkwell}s.

Please note that inkwell stones will recolor @ref{ac_pearl} as well, as soon
as they are introduced to Enigma. As of now, an error will be shown when
@ref{ac_pearl} touches an inkwell stone.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state} @ @ @i{values}: @code{INKWELL_BLACK}, @code{INKWELL_EMPTY}, @code{INKWELL_WHITE}; @ @ @i{default}: @code{INKWELL_EMPTY}
@end table

@table @asis
@item @b{Messages:}

none
@end table

@item @b{Variants:}
@table @asis
@item @image{images/st_inkwell_5, 12mm} @b{st_inkwell}
@item @image{images/st_inkwell, 12mm} @b{st_inkwell_black}
@item @image{images/st_inkwell_5, 12mm} @b{st_inkwell_empty}
@item @image{images/st_inkwell_9, 12mm} @b{st_inkwell_white}
@end table
@end table

@c ----------------- Jamb Stone --------------------
@node st_jamb
@subsection st_jamb
@obindex st_jamb

A colored door jamb that allows coupled opening and closing on adjacent
@ref{st_door}s. Especially doors of flavor @code{"d"} can be opened by proper
colored actors by door knocking.

The stone looks like 4 brown door jambs each with a colored ball on top. It fits
to the 2 faced @code{"d"} variant of @ref{st_door}. These doors can be
configured to send the message @code{"hit"} to the adjacent jambs as their
targets. Whenever an actor knocks the door, the jamb receives the message and
checks the actor for matching color. On success it sends opening signals to
the door being knocked and to a door being located on the opposite side of the
jamb. Additionally doors located on the remaining two adjacent positions of the
jamb will receive a closing signal. E.g.:

@example
ti["n"] = @{"st_door_d", "north", target="jamb", action="hit"@}
ti["e"] = @{"st_door_d", "east", target="jamb", action="hit"@}
ti["s"] = @{"st_door_d", "south", target="jamb", action="hit"@}
ti["w"] = @{"st_door_d", "west", target="jamb", action="hit"@}
ti["J"] = @{"st_jamb", "jamb"@}
ti["@@"] = @{"st_marble"@}
wo(ti, " ", @{
  " n ",
  "wJe",
  " s@@"
@}
@end example

The black marble touching the east door will open the east and the west door,
and will close the north and south door at the same time. The black marble
touching the south door will open the south and the north door, and will close
the west and east door.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{color} @ @ @i{values}: @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{BLACK}
@end table

@item @b{Messages:}

@table @asis
@item @b{hit}
The message value must be an object reference of an actor. The color of the
actor must match the jamb color to cause an action. The sender's position must
either match the x or the y coordinate of the jamb, too.

@item @b{signal} @ @ @xref{signal}
This message is just kept for backward compatibility issues. Do not use it in
new API levels as it depends on other internal attributes not set for new API
levels.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}

@table @asis
@item @image{images/st_jamb_black, 12mm} @b{st_jamb}: color=@code{BLACK}
@item @image{images/st_jamb_black, 12mm} @b{st_jamb_black}: color=@code{BLACK}
@item @image{images/st_jamb_white, 12mm} @b{st_jamb_white}: color=@code{WHITE}
@end table

@end table

@c ----------------- Key Stone --------------------
@node st_key
@subsection st_key
@obindex st_key

A switch that is activated by insertion of an @ref{it_key}. Just actors
assigned to a player can insert a key out of their item inventory by hitting
the key switch with a key being the first item. Just keys with a matching
@samp{code} are accepted.

On a second hit the switch is deactivated and the inserted key is returned
to the player's inventory.

Key stones are often used as openers for an adjacent @ref{st_door} that is
declared as its @samp{target}. But there is the inherent danger that an actor
passing the door accidentially hits the neighboring key stone, causing the key
to be pulled out again and the door to be closed immediately. Of couse this
would shatter any @ref{ac_marble} or @ref{ac_pearl}. But a @samp{secure} key
stone checks that the hitting actor is not positioned on one of the key stones
target positions. It refuses any actions caused by such critical hits. Note
that in case the target is a callback function that closes the adjacent door,
there will be still no protection. A key stone with @samp{secure} value
@samp{false} would accept any hits and shatter marbles as it has been standard
on older Enigma releases and is still in modes besides Enigma.

Usually the @samp{code} of the key stone is not visually unveiled. But if you
set @samp{invisible} to the value @samp{false} the code becomes visible for
number code values @samp{1} to @samp{8}. This helps the user to distinguish
the stones and to assign the correct @ref{it_key} when multiple instances are
present.

An @samp{invisible} key stone reveals its code when a matching, unveiled
@ref{it_key} gets inserted.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF}; @ @ @xref{state}
Current activity state of the key stone.
@item @b{code}, @ @ @i{values}: number or string; @ @ @i{default}: @code{1}:
The code that is required to activate this switch.
@item @b{secure} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Protect actors on target positions by neglecting their hits.
@item @b{invisible} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
A visible key stone unveils its @samp{code} by a color spot.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}, and off at values @samp{0}.
@item @b{on} @ @ @xref{on}
@item @b{off} @ @ @xref{off}
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/st_key_off, 12mm} @b{st_key} with state=@code{OFF}
@item @image{images/st_key_on, 12mm} @b{st_key} with state=@code{ON}
@end table
@end table
@c ----------------- Knight Stone --------------------
@node st_knight
@subsection st_knight
@obindex st_knight

A sword bearing knight stone that shatters all marbles that hit it, as long as
they are not protected by an activated @ref{it_umbrella} or wield an
@ref{it_sword}.

By hitting @samp{st_knight} with an @ref{it_sword} four times, the knight stone
spits out a cheeky remark and can be passed thereafter, even without a sword.

A beaten knight stone is transparent to laser light.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{0} to @code{4}; @ @ @i{default}: @code{0}; @i{access}: @code{read only} @ @ @xref{state}
Current hit count of the knight stone. Starting uninjured at state @samp{0}
the knight is beaten after 4 hits.
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_knight, 12mm} @b{st_knight}
@end table

@end table

@c ----------------- Laser Stone --------------------
@node st_laser
@subsection st_laser
@obindex st_laser

The laser stone is the only object that is capable of emitting light beams.
Per default laser stones are switched off. The @samp{state} attribute represents
the activity of the laser and can be set initially to @samp{ON}. A laser is
orientated to one direction into which the light will be emitted.

Lasers have a latency that protect them from infinite fast switching cycles. This
allows you to toggle a laser with an @ref{st_laserswitch} that is illuminated
by the laser itself. During the latency period pending switch requests will be
registered but will be executed with a certain small delay. Note that several
pending requests may even neutralize and revoke each other.

An initially switched on laser will not cause actions with its light beam due
to the @ref{Snapshot Principle}. If you have need of the actions you may switch
on the laser by a message in the @samp{postinit} function
(@xref{Level Initialization}). E.g. a flickering laser caused by a laser that
illuminates a @ref{st_laserswitch} which toggles the laser needs to be switched
on by a message.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF} @ @ @xref{state}
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH}
The orientation of the laser. It determines the direction that the laser will
emit light if it is switched on.
@item @b{counterclock} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
The standard turning direction is clockwise. Use this attribute to revert the
direction.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switch the laser on at value @samp{1} and off at value @samp{0}.
@item @b{on} @ @ @xref{on}
@item @b{off} @ @ @xref{off}
@item @b{turn}
Turn orientation in turning direction as defined by attribute
@samp{counterclock}.
@item @b{turnback}
Turn orientation in opposite turning direction as defined by attribute
@samp{counterclock}.
@end table

@item @b{Action:} none

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_laser_d, 12mm}@tab @b{st_laser_w}: orientation = @code{WEST}, state = @code{OFF}
@tab @image{images/st_laser_d6, 12mm}@tab @b{st_laser_w}: orientation = @code{WEST}, state = @code{ON}
@item @image{images/st_laser_c, 12mm}@tab @b{st_laser_s}: orientation = @code{SOUTH}, state = @code{OFF}
@tab @image{images/st_laser_c6, 12mm}@tab @b{st_laser_s}: orientation = @code{SOUTH}, state = @code{ON}
@item @image{images/st_laser_b, 12mm}@tab @b{st_laser_e}: orientation = @code{EAST}, state = @code{OFF}
@tab @image{images/st_laser_b6, 12mm}@tab @b{st_laser_e}: orientation = @code{EAST}, state = @code{ON}
@item @image{images/st_laser, 12mm}@tab @b{st_laser_n}: orientation = @code{NORTH}, state = @code{OFF}
@tab @image{images/st_laser_6, 12mm}@tab @b{st_laser_n}: orientation = @code{NORTH}, state = @code{ON}
@end multitable
@end table

@c ----------------- Laserflop Stone --------------------
@node st_laserflop
@subsection st_laserflop
@obindex st_laserflop

A switch that is triggered by actor hits and laser light. It switches instantly
to state @samp{ON} and when it is no longer illuminated it switches back to
state @samp{OFF} after a given @samp{interval}. Repetitive actor hits and
continuing laser light will prolong the @samp{ON} state until a trailing
@samp{interval} after the last hit has been expired. A similar object without
light sensitiveness is the @ref{st_monoflop}.

The single state cycle, called monoflop, can be initiated by @samp{on} and
@samp{signal} messages. But an activated monoflop cannot be stopped by
messages or state setting.

At initialization a laserflop that is exposed to laser light will start in state
@samp{ON} without sending actions due to the @ref{Snapshot Principle}.

A laserflop that is moved or swapped in or out of a laser beam will act on
the light change with proper actions.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF}; @ @ @xref{state}
Represents the activity state. The state of a new object can be set, but an
active laserflop cannot be set to state @samp{OFF}.
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{1.8}
Number of seconds to return to state @samp{OFF} after the last hit.

@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}. A value of @samp{0} is ignored.
@item @b{on} @ @ @xref{on}
Switches the laserflop on like on an actor hit.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
@item @b{Variants:}
@table @asis
@item @image{images/st_monoflop, 12mm} @b{st_laserflop}: state = @code{OFF}
@item @image{images/st_monoflop_2, 12mm} @b{st_laserflop}: state = @code{ON}
@end table

@end table

@c ----------------- Laserswitch Stone --------------------
@node st_laserswitch
@subsection st_laserswitch
@obindex st_laserswitch

A switch that is exclusively triggered by laser light. It switches instantly to
state @samp{ON} when a laser beam hits the stone from any direction. It switches
instantly back to state @samp{OFF} when it is no longer illuminated.

There is no way to set the state of this stone manually. But the state
can nevertheless be read. At initialization a laserswitch that is exposed to
laser light will start in state @samp{ON} without sending actions due to the
@ref{Snapshot Principle}.

A laserswitch that is moved or swapped in or out of a laser beam will act on
the light change with proper actions.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF}; @i{access}: @code{read only} @ @ @xref{state}

@end table

@item @b{Messages:} none

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@table @asis
@item @image{images/st_oxydb, 12mm} @b{st_laserswitch}: state = @code{OFF}
@item @image{images/st_quake_3, 12mm} @b{st_laserswitch}: state = @code{ON}
@end table
@end table

@c ----------------- Lightglass Stone --------------------
@node st_lightglass
@subsection st_lightglass
@obindex st_lightglass

A metal framed transparent glass stone. It exists in static, movable and
hollow variants and is by its very nature transparent to laser light. Like other
@ref{Transparent Stones} it is passable for invisible actors as long as it is
not @samp{movable}.

A @ref{st_magic} of variant @code{st_magic_oxyda} transforms on actor hits to
a movable lightglass stone

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{hollow} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{hollow}
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{movable}
@end table

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_lightglass, 12mm} @b{st_lightglass}: hollow = @code{false}, movable = @code{false}
@item @image{images/st_lightglass, 12mm} @b{st_lightglass_hollow}: hollow = @code{true}, movable = @code{false}
@item @image{images/st_lightglass, 12mm} @b{st_lightglass_movable}: hollow = @code{false}, movable = @code{true}
@end table

@end table

@c ----------------- Lightpassenger Stone --------------------

@node st_lightpassenger
@subsection st_lightpassenger
@obindex st_lightpassenger

The light passenger skates on a laser beam, and may push up to one
movable stone in front of it. Opposing laser beams are ignored.
When another laser beam crosses the actual laser beam on which the
passenger skates, the passenger switches beams. If it is initially
lighted by two rectangular beams, one of them will be chosen by
random. The light passenger's skating ability can be turned off
and on.

When a stone is in its way, the passenger sends an impulse to the
blocking stone, which may move it, but it may also have other effects;
e.g., a turnstile turns around and an impulse-stone starts pulsing,
but it does not open oxyds (this is intended).

The light passenger can't be pushed by actors, but, e.g., by
@ref{st_stoneimpulse}.

The speed of the light passenger can be changed with the
@samp{interval}-attribute (default 50 ms, which is quite fast) and may
include the floor friction and local gradient via
@samp{friction} and @samp{gradient}. The resulting interval results as

@example
interval  =  base * (1 + stone_friction * floor_friction) / (1 + stone_gradient * floor_gradient)
@end example

with @samp{base} the value of the @samp{interval}-attribute,
@samp{floor_friction} the friction of the floor below the light passenger,
and @samp{floor_gradient} the parallel part of the force of the floor,
i.e., the sum of gradient-force and @code{force_x/y}-attributes.

The light passenger can be switched on and off by messages (see below), and
appears as @samp{st_darkglass} when inactive. A player with an @ref{it_glasses}
in his inventory that includes the @samp{SPOT_LIGHTPASSENGER} feature is able
to distinguish the switched off lightpassenger from an @samp{st_darkglass}.
The variant @samp{st_lightpassenger_off} is deactivated from the beginning.
A lightpassenger that moves onto an @ref{it_cross} switches off immediately. A
switched off lightpassenger can be switched on by an actor hit with a revealed
@ref{it_brush} in the inventory. Such a touch with a brush does wipe out a
cross beneath the lightpassenger, too.

An @ref{st_boulder} hitting a lightpassenger toggles the lightpassenger's state
for a short period.

When an active @samp{st_lightpassenger} is trapped between exactly two
opposing light beams or light beams from all four directions, it
starts blinking.  In this state, it can be destroyed with
@ref{it_hammer}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{ON}; @ @ @xref{state}
Represents the activity state.
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{0.05}
The base interval for movements.
@item @b{friction} @ @ @i{values}: positive number; @ @ @i{default}: @code{0.0}
Stone friction of the speed of the light passenger.
@item @b{gradient} @ @ @i{values}: positive number; @ @ @i{default}: @code{0.0}
Stone gradient of the speed of the light passenger.

@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}. A value of @samp{0} is ignored.
@item @b{on} @ @ @xref{on}
Switch the lightpassenger on.
@item @b{off} @ @ @xref{off}
Switch the lightpassenger off.
@end table

@item @b{Variants:}

@table @asis
@item @image{images/st_lightpassenger, 12mm} @b{st_lightpassenger}: state = @code{ON}
@item @image{images/st_lightpassenger, 12mm} @b{st_lightpassenger_on}: state = @code{ON}
@item @image{images/st_darkglass, 12mm} @b{st_lightpassenger_off}: state = @code{OFF}
@end table

@end table

@c ----------------- Magic Stone --------------------
@node st_magic
@subsection st_magic
@obindex st_magic

A stone that mimics one stone, but transforms on actor hits into another stone.

Like @ref{st_fake} this stone does initially look like another stone of a kind
given by the attribute @samp{flavor}. But on an actor hit with or without tool
it transforms to another stone, which provides its own set of features.

The flavor @code{"brick"} just transforms on a hit with a revealed
@ref{it_magicwand} into a static @ref{st_rawglass}.

The flavor @code{"oxyda"} transforms on any hit into a movable
@ref{st_lightglass}.

The flavor @code{"oxydc"} transforms on any hit into a movable
@ref{st_rawglass}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"brick"}, @code{"oxyda"}, @code{"oxydc"}; @ @ @i{default}: @code{"brick"}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_brick, 12mm} @b{st_magic}: flavor=@code{"brick"}
@item @image{images/st_brick, 12mm} @b{st_magic_brick}: flavor=@code{"brick"}
@item @image{images/st_oxyda, 12mm} @b{st_magic_oxyda}: flavor=@code{"oxyda"}
@item @image{images/st_oxydc, 12mm} @b{st_magic_oxydc}: flavor=@code{"oxydc"}
@end table

@end table

@c ----------------- Mail Stone --------------------
@node st_mail
@subsection st_mail
@obindex st_mail

When hit by an actor, a mail stone takes the first item out of the player's
inventory and drops it at its exit, or the exit of the appending @ref{it_pipe}.
If this position is blocked (e.g., by another item), no item is taken from
inventory. The @ref{it_brake} is the only item that gets delivered even if
another item is positioned at the end of the pipe as it emerges the pipe as an
@ref{st_brake} stone. An @ref{it_pipe} end piece with just one fitting connection
closes a mail pipe completely, rejecting any item insertion.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH}
The orientation of the mail stone. It determines the neighbor's grid position
onto which the item will be dropped, or where the pipe starts.
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_mail, 12mm} @b{st_mail}: orientation = @code{NORTH}
@item @image{images/st_mail_3, 12mm} @b{st_mail_w}: orientation = @code{WEST}
@item @image{images/st_mail_4, 12mm} @b{st_mail_s}: orientation = @code{SOUTH}
@item @image{images/st_mail_2, 12mm} @b{st_mail_e}: orientation = @code{EAST}
@item @image{images/st_mail, 12mm} @b{st_mail_n}: orientation = @code{NORTH}
@end table

@end table

@c ----------------- Mirror Stone --------------------
@node st_mirror
@subsection st_mirror
@obindex st_mirror

Mirror stones redirect and fork laser beams. They exist in different shapes.
You can set the shape by the attribute @samp{flavor} or by using the
appropriate subkind. There are two planar versions called @samp{slab} and
@samp{sheets}, and a @samp{triangle} version.

The mirror panes can either be non-transparent or semi-transparent. Even though
you set this feature with the attribute @samp{transparent} you should be aware
that even with a value of @samp{true} the mirror is not fully transparent. E.g.
a @samp{slab} mirror will block any laser light that is parallel to its shape
as the short ends are no mirrors at all. For this reason we provide the second
planar version called @samp{sheets}, which lets light parallel to its sheets
pass.

Mirrors hit by an actor or impulsed by an @ref{st_stoneimpulse} will move if
their attribute @samp{movable} is set to true. Mirrors that are not movable
will differ slightly in a darker color.

Mirrors hit or just touched will turn their mirror panes by 90 degrees. The
standard turning direction is clockwise. But this standard can be changed
by the attribute @samp{counterclock}. An @ref{st_boulder} hitting a mirror
will turn it in its standard direction, too.

A mirror can be turned into the opposite direction either by a message
@samp{turnback} or by an actor with a revealed @ref{it_wrench} in its
inventory.

Mirrors moved by stone pushing impulses issued by @ref{it_puller},
@ref{st_stoneimpulse},... or send by @ref{ot_wire} will move without being turned.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"slab"}, @code{"sheets"}, @code{"triangle"}; @ @ @i{default}: @code{"slab"}
Mirror panes either set up as a triangle or as a side opaque slab or
as a mandatory semi-transparent pair of sheets.
@item @b{state}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH}; @ @ @xref{state}
The orientation of the mirror. For a triangular mirror it is the triangle's
pointing direction. For a planar mirror it is the reflection direction of an
incoming northbound beam.
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}, @code{RANDOMDIR}; @ @ @i{default}: @code{NORTH}
The orientation of the mirror. For a triangular mirror it is the triangle's
pointing direction. For a planar mirror it is the reflection direction of an
incoming northbound beam. The value @code{RANDOMDIR} is just evaluated when the
mirror is being set. From this point of time the mirror will report a random
orientation out of the other 4 real orientations.
@item @b{transparent} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Semitransparency of the mirror panes.
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false} @ @ @xref{movable}
Movability on actor hits and stone impulses.
@item @b{counterclock} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
The standard turning direction is clockwise. Use this attribute to revert the
direction.
@end table

@item @b{Messages:}

@table @asis
@msindex orientate
@item @b{orientate}, @ @ @i{value type}: orientation
Change the orientation to the given orientation value. The @ref{st_fourswitch}
provides a compatible action which allows you to set a mirror as
target and this message as action.
@item @b{turn}
Turn the orientation in turning direction as defined by attribute
@samp{counterclock}.
@item @b{turnback}
Turn the orientation in opposite turning direction as defined by attribute
@samp{counterclock}.
@item @b{signal} @ @ @xref{signal}
Turn the orientation in turning direction as defined by attribute
@samp{counterclock} on value @samp{1}. A value of @samp{0} is ignored.

@end table

@item @b{Action:} none

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_mirror_static, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{NORTH}, transparent = @code{false}, movable = @code{false}
@tab @image{images/st_mirror_movable, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{NORTH}, transparent = @code{false}, movable = @code{true}
@item @image{images/st_mirror_static_2, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{EAST}, transparent = @code{false}, movable = @code{false}
@tab @image{images/st_mirror_movable_2, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{EAST}, transparent = @code{false}, movable = @code{true}
@item @image{images/st_mirror_static_3, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{SOUTH}, transparent = @code{false}, movable = @code{false}
@tab @image{images/st_mirror_movable_3, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{SOUTH}, transparent = @code{false}, movable = @code{true}
@item @image{images/st_mirror_static_4, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{WEST}, transparent = @code{false}, movable = @code{false}
@tab @image{images/st_mirror_movable_4, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{WEST}, transparent = @code{false}, movable = @code{true}
@item @image{images/st_mirror_static_b, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{NORTH}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_b, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{NORTH}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_b2, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{EAST}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_b2, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{EAST}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_b3, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{SOUTH}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_b3, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{SOUTH}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_b4, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{WEST}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_b4, 12mm}@tab @b{st_mirror_triangle}: flavor=@code{triangle}, state = @code{WEST}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_c, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{NORTH}, transparent = @code{false}, movable = @code{false}
@tab @image{images/st_mirror_movable_c, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{NORTH}, transparent = @code{false}, movable = @code{true}
@item @image{images/st_mirror_static_c2, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{EAST}, transparent = @code{false}, movable = @code{false}
@tab @image{images/st_mirror_movable_c2, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{EAST}, transparent = @code{false}, movable = @code{true}
@item @image{images/st_mirror_static_c3, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{SOUTH}, transparent = @code{false}, movable = @code{false}
@tab @image{images/st_mirror_movable_c3, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{SOUTH}, transparent = @code{false}, movable = @code{true}
@item @image{images/st_mirror_static_c4, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{WEST}, transparent = @code{false}, movable = @code{false}
@tab @image{images/st_mirror_movable_c4, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{WEST}, transparent = @code{false}, movable = @code{true}
@item @image{images/st_mirror_static_d, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{NORTH}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_d, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{NORTH}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_d2, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{EAST}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_d2, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{EAST}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_d3, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{SOUTH}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_d3, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{SOUTH}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_d4, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{WEST}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_d4, 12mm}@tab @b{st_mirror_slab}: flavor=@code{slab}, state = @code{WEST}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_e, 12mm}@tab @b{st_mirror_sheets}: flavor=@code{sheets}, state = @code{NORTH}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_e, 12mm}@tab @b{st_mirror_sheets}: flavor=@code{sheets}, state = @code{NORTH}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_e2, 12mm}@tab @b{st_mirror_sheets}: flavor=@code{sheets}, state = @code{EAST}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_e2, 12mm}@tab @b{st_mirror_sheets}: flavor=@code{sheets}, state = @code{EAST}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_e3, 12mm}@tab @b{st_mirror_sheets}: flavor=@code{sheets}, state = @code{SOUTH}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_e3, 12mm}@tab @b{st_mirror_sheets}: flavor=@code{sheets}, state = @code{SOUTH}, transparent = @code{true}, movable = @code{true}
@item @image{images/st_mirror_static_e4, 12mm}@tab @b{st_mirror_sheets}: flavor=@code{sheets}, state = @code{WEST}, transparent = @code{true}, movable = @code{false}
@tab @image{images/st_mirror_movable_e4, 12mm}@tab @b{st_mirror_sheets}: flavor=@code{sheets}, state = @code{WEST}, transparent = @code{true}, movable = @code{true}
@end multitable

@end table

@c ----------------- Monoflop Stone --------------------
@node st_monoflop
@subsection st_monoflop
@obindex st_monoflop

A switch that is triggered by actor hits. It switches instantly to
state @samp{ON} and after a given @samp{interval} back to state @samp{OFF}.
Repetitive actor hits will prolong the @samp{ON} state until a trailing
@samp{interval} after the last hit has been expired. A switch similar to
the monoflop is the @ref{st_laserflop}, which is additionally light sensitive.

The single state cycle, called monoflop, can be initiated by @samp{on} and
@samp{signal} messages. But an activated monoflop cannot be stopped by
messages or state setting.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF}; @ @ @xref{state}
Represents the activity state. The state of a new object can be set, but an
active monoflop cannot be set to state @samp{OFF}.
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{1.8}
Number of seconds to return to state @samp{OFF} after the last hit.

@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}. A values of @samp{0} is ignored.
@item @b{on} @ @ @xref{on}
Switch the monoflop on like on an actor hit.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/st_monoflop, 12mm} @b{st_monoflop}: state = @code{OFF}
@item @image{images/st_monoflop_2, 12mm} @b{st_monoflop}: state = @code{ON}
@end table
@end table

@c ----------------- Oneway Stone --------------------
@node st_oneway
@subsection st_oneway
@obindex st_oneway

A stone with one special face, that allows actors just to pass from inside
to outside but not vice versa. The other faces can generally be passed in both
directions. As most times it is more important to be aware of the passages that
are blocked, you may remember that the oneway's arrow points to the side that
can not be entered.

Three variants of the oneway do exist. A neutral, green-grey colored one that
lets any actor pass according to the above rules, and additionally a black and
a white colored oneway. These last oneways will let pass only marbles of
matching color. All other actors will reflect from all four sides.

All oneways can only be passed by actors moving on the floor. Jumping actors
will bounce on every side.

The @samp{orientation} of a neutral oneway can be flipped to the opposite
direction by an actor hitting it with a revealed @ref{it_magicwand}. All
oneway variations will change their orientation on messages @samp{signal} and
@samp{flip}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH} @ @ @xref{state}
The orientation of the oneway as shown by the arrow.
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH}
The orientation of the oneway as shown by the arrow.
@item @b{color} @ @ @i{values}: @code{nil}, @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{nil}
The color of the oneway that needs to match the actor's color to allow passing.
The default @samp{nil} color is a greengrey oneway that matches all actors,
marbles of any color as well as all other actors.
@end table

@item @b{Messages:}

@table @asis
@item @b{orientate}, @ @ @i{value type}: orientation
Change the orientation to the given orientation value. The @ref{st_fourswitch}
provides a compatible action which allows you to set a oneway as
target and this message as action.
@item @b{flip},
Flip the orientation to the opposite direction.
@item @b{signal} @ @ @xref{signal}
Flip the orientation to the opposite direction.
@end table

@item @b{Action:} none

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_oneway, 12mm}@tab  @b{st_oneway}: orientation = @code{EAST}
@tab @image{images/st_oneway_2, 12mm}@tab @b{st_oneway}: orientation = @code{NORTH}
@item @image{images/st_oneway_3, 12mm}@tab @b{st_oneway}: orientation = @code{SOUTH}
@tab @image{images/st_oneway_4, 12mm}@tab @b{st_oneway}: orientation = @code{WEST}
@item @image{images/st_oneway_b, 12mm}@tab @b{st_oneway_black}: color = @code{BLACK}; orientation = @code{EAST}
@tab @image{images/st_oneway_b2, 12mm}@tab @b{st_oneway_black}: color = @code{BLACK}; orientation = @code{NORTH}
@item @image{images/st_oneway_b3, 12mm}@tab @b{st_oneway_black}: color = @code{BLACK}; orientation = @code{SOUTH}
@tab @image{images/st_oneway_b4, 12mm}@tab @b{st_oneway_black}: color = @code{BLACK}; orientation = @code{WEST}
@item @image{images/st_oneway_c, 12mm}@tab @b{st_oneway_white}: color = @code{WHITE}; orientation = @code{EAST}
@tab @image{images/st_oneway_c2, 12mm}@tab @b{st_oneway_white}: color = @code{WHITE}; orientation = @code{NORTH}
@item @image{images/st_oneway_c3, 12mm}@tab @b{st_oneway_white}: color = @code{WHITE}; orientation = @code{SOUTH}
@tab @image{images/st_oneway_c4, 12mm}@tab @b{st_oneway_white}: color = @code{WHITE}; orientation = @code{WEST}
@end multitable
@end table

@c ----------------- Oxyd Stone --------------------
@node st_oxyd
@subsection st_oxyd
@obindex st_oxyd

The main target stones of the game. Opening all regular oxyd stones is the
standard goal of the existing @ref{Ending Conditions}. Regular oxyds stones show
a color spot when opening. Pairs of same colored stones have to be opened in
sequence, otherwise the first one closes again.

Even though most levels make use of just a single pair of each color, there
is no limit on a single color. If you like you can define 3 pairs of blue oxyds
together with 2 yellow pairs. You do this by setting explicit @samp{oxydcolor}
attributes to the oxyds.

For standard levels the @samp{oxydcolor} can be set to its default @samp{OXYD_AUTO}.
This causes an automatic coloring by pairs of colors in the standard color
sequence.

There is no limit on the number of used oxyd pairs. There exist 12 different
regular colors for oxyds. But per default just the first 8 colors will be
assigned to @samp{OXYD_AUTO} colored oxyds. The colors will repeat from the
9th pair giving the user the possibility to build arbitrary couples within a
single color. With the world attribute @ref{MaxOxydColor} you can lower or
increase this limit. By setting this attribute to @samp{OXYD_GREEN} you can
enforce the engine to assign just the first three colors. Be careful in usage
of more than 8 colors as levels can get incredibly difficult.

The number of auto colored oxyds should usually be even as a single remaining
oxyd of a color keeps a level from being solvable. In case of an uneven number
one oxyd stone gets colored to @samp{OXYD_FAKE} and does not participate in the
stone opening procedure. But still you can set uneven number of oxyds of a given
color if you do not use auto coloring but use explicit color values. Same thing
happens if you delete a single oxyd during the running game. In both cases
Enigma reacts with an error message by default. You can suppress this exception
by setting @ref{AllowSingleOxyds} to @code{true}. In this case it is the author's
responsibility to guarantee that the level can be solved.

Usually oxyds are shuffled by a @samp{wo:shuffleOxyd()} statement after setting
of all oxyds. All @samp{CLOSED} oxyds that are not explicitly excluded by the
@samp{noshuffle} attribute take place in shuffling. But you can define
arbitrary rules to limit and influence the shuffling process to guarantee
solvability and fairness (@pxref{shuffleOxyd}).

Oxyds are opened either by an actor hit, an additional laser beam, an
@ref{st_boulder} triggering, an @ref{ot_cannonball} emitted from an
@ref{st_spitter} or a message call. A single opened oxyd is in the
state @samp{OPEN}. If a matching second oxyd is opened both switch to the state
@samp{OXYDPAIR}. Note that this state can be requested, but it can not be set
directly.

Single opened oxyds close on a not matching partner oxyd being opened and on
@samp{close} messages and state setting operations. But oxyds being part of
an opened pair will not be closed this way.

All oxyds including pairs will close on the @samp{closeall} messages that is
issued by @ref{st_quake} and oxyds colored @samp{OXYD_QUAKE} on actor hits.

Closed oxyds can have different looks. Their visual representation is defined
by their @samp{flavor}. Most flavors do hide the oxyd color in the closed state.
Only flavor @code{"e"} starts with hidden color, but once opened returns to
a closed image with a peep hole that lets the player still see the color.

For each flavor exists an identical looking simple stone: @samp{st_fake_oxyda},
@samp{st_fake_oxydb}, @samp{st_fake_oxydc}, @samp{st_fake_oxydd},
@samp{st_fake_oxyde} (@pxref{st_fake}). If you like an identical looking pseudo
stone that takes part in the oxyd shuffling you can use an oxyd of color
@samp{OXYD_FAKE}.

During the game oxyds can be reshuffled. Just those oxyds that are still closed
will take part in the new shuffle process. Oxyd shuffling rules will still be
guaranteed for these partial in game reshuffles. It can be initiated either
by a @samp{shuffle} message that is send to any of the oxyd objects, or by
usage of an oxyd of color @samp{OXYD_BOLD}. If such a special oxyd is opened,
e.g. by an actor hit, it shuffles all remaining oxyds including itself.

At initialization an oxyd that is exposed to laser light will start in state
@samp{CLOSED}. As it is the gaming target it is a certain exception to the
@ref{Snapshot Principle}.

An oxyd that is swapped in or out of a laser beam will act on the light change
with proper actions.

Every opened oxyd causes an action call. The action call for an opened oxyd pair
occurs just once when the second oxyd starts opening, whereas the bold and quake
oxyd will perform the action after completion of their task and animation. Thus
you are allowed to kill quake and bold oxyds within their action as long as you
properly set @ref{safeaction} to @code{true}.

For a replacement of an opened pair of oxyd stones, what can be seen in the
"opal" levels, the action call is not directly suitable, because the second
oxyd did not yet show its matching color. Furtheron you would have to keep track
of the oxyds to find the matching partner for the second oxyd. For this reason
you can directly declare replacements that should be set when an oxyd pair
is opened. The replacement takes place as soon as the second oxyd finishes the
opening animation. Like the @ref{st_surprise} the oxyd allows you to set
the @samp{selection} attribute with tokens of strings. Every string needs either
to be an @ref{Object Kind} or a tile key prefixed by an equal sign @samp{=}.

@example
ti["n"] = @{"st_nil"@}
ti["g"] = @{"st_granite"@}
ti["s"] = @{"st_oxyd_e", selection=@{"=n", "=g"@}@}
@end example

The first token defines the replacement for the oxyd stone that has been opened
first, the last token defines the replacement for the matching oxyd stone that
has been opened afterwards. In case of a single token both oxyd stones are being
replaced by equivalent stones.

The tile declarations referenced by a key may even contain objects besides
stone. But you should make rare and proper usage of this feature.

The oxyd stone is killed by any replacement stone set to the grid position.
If your selection does not resolve to a stone you may need to add @code{"st_nil"}
to the replacement tile declaration.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{CLOSED}, @code{OPEN}, @code{OXYDPAIR}; @ @ @i{default}: @code{CLOSED} @ @ @xref{state}

@item @b{flavor}, @ @ @i{values}: @code{"a"}, @code{"b"}, @code{"c"}, @code{"d"}, @code{"e"}; @ @ @i{default}: @code{"b"}
The flavor only affects the visual representation of the stone. Mainly the
closed state and the way of opening differ in the following way:
@table @asis
@item @code{"a"} bronze, pyramid like stone that opens like a flower
@item @code{"b"} black, flat stone that opens by a fade animation
@item @code{"c"} blue, flat stone that opens by a concentric animation
@item @code{"d"} dark blue, pyramid like stone that opens like a flower
@item @code{"e"} black, flat stone that provides a peep hole after closing
@end table
@item @b{oxydcolor}, @ @ @i{values}: @code{OXYD_AUTO}, @code{OXYD_FAKE}, @code{OXYD_QUAKE}, @code{OXYD_BOLD}, @code{OXYD_BLUE}, @code{OXYD_RED}, @code{OXYD_GREEN}, @code{OXYD_YELLOW}, @code{OXYD_CYAN}, @code{OXYD_PURPLE}, @code{OXYD_WHITE}, @code{OXYD_BLACK}, @code{OXYD_GRAY}, @code{OXYD_ORANGE}, @code{OXYD_PINE}, @code{OXYD_BROWN}; @ @ @i{default}: @code{OXYD_AUTO}
@multitable @columnfractions .08 .17 .08 .17 .08 .17 .08 .17
@item @image{images/st_oxyd_colordots, 10mm}@tab @code{OXYD_BLUE}
@tab @image{images/st_oxyd_colordots_2, 10mm}@tab @code{OXYD_RED}
@tab @image{images/st_oxyd_colordots_3, 10mm}@tab @code{OXYD_GREEN}
@tab @image{images/st_oxyd_colordots_4, 10mm}@tab @code{OXYD_YELLOW}
@item @image{images/st_oxyd_colordots_b, 10mm}@tab @code{OXYD_CYAN}
@tab @image{images/st_oxyd_colordots_b2, 10mm}@tab @code{OXYD_PURPLE}
@tab @image{images/st_oxyd_colordots_b3, 10mm}@tab @code{OXYD_WHITE}
@tab @image{images/st_oxyd_colordots_b4, 10mm}@tab @code{OXYD_BLACK}
@item @image{images/st_oxyd_colordots_c, 10mm}@tab @code{OXYD_GRAY}
@tab @image{images/st_oxyd_colordots_c2, 10mm}@tab @code{OXYD_ORANGE}
@tab @image{images/st_oxyd_colordots_c3, 10mm}@tab @code{OXYD_PINE}
@tab @image{images/st_oxyd_colordots_c4, 10mm}@tab @code{OXYD_BROWN}
@item @image{images/st_oxyd_colordots_d3, 10mm}@tab @code{OXYD_BOLD}
@tab @image{images/st_oxyd_colordots_d4, 10mm}@tab @code{OXYD_QUAKE}
@end multitable
@item @b{noshuffle} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
@item @b{static} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Static oxyds are neither swappable nor pullable.
@item @b{selection}, @ @ @i{values}: tokens of stone kinds and tile keys; @ @ @i{default}: no replacement
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Try open at value @samp{1}, and close at values @samp{0}.
@item @b{open} @ @ @xref{open}
@item @b{close} @ @ @xref{close}
@item @b{closeall}
Closes all opened oxyds if sent to any object instance.
@item @b{peepall}
All closed oxyds of flavor @code{"e"} will show a peep hole if this message is
sent to any oxyd object instance.
@item @b{shuffle}
Reshuffles all closed oxyds if sent to any object instance.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
Whenever a @code{CLOSED} oxyd gets opened an action with value @code{true} is
performed. The action is performed directly after the oxyds own reaction on being
opened, like checking gaming ending conditions, reshuffling or closing all oxyds,
did finish. Additionally an action with value @code{false} is performed after
an oxyd changes from an open state to @code{CLOSED}. Note that no action is
performed on state changes form @code{OPEN} to @code{OXYDPAIR}.

@item @b{Variants:}

@table @asis
@item @image{images/st_oxydb, 12mm} @b{st_oxyd}: flavor = @code{"b"}
@item @image{images/st_oxyda, 12mm} @b{st_oxyd_a}: flavor = @code{"a"}
@item @image{images/st_oxydb, 12mm} @b{st_oxyd_b}: flavor = @code{"b"}
@item @image{images/st_oxydc, 12mm} @b{st_oxyd_c}: flavor = @code{"c"}
@item @image{images/st_oxydd, 12mm} @b{st_oxyd_d}: flavor = @code{"d"}
@item @image{images/st_oxyde, 12mm} @b{st_oxyd_e}: flavor = @code{"e"}
@end table

@end table

@c ----------------- Passage Stone --------------------
@node st_passage
@subsection st_passage
@obindex st_passage

A black or white colored stone of different shapes that lets pass only actors of
matching color.

The shape is described by the attribute @samp{flavor}. The shape does not
affect the behaviour, but may be important for the visibility of actors and
items beneath.

Passage stones react on @samp{signal} and @samp{toggle} messages and
@ref{st_boulder} arriving on one of its sides. In both cases the passage stone
recolors to the opposite color. In case of a boulder the recoloring is of a
quite short period, as this stone recolors the passage twice. The period in
between is long enough for an actor to pass or to redirect the boulder before
sending the second recoloring message.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{color} @ @ @i{values}: @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{BLACK}
The color of the passage that determines which actors can pass.
@item @b{state}, @ @ @i{values}: @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{BLACK} @ @ @xref{state}
The state is a synonym for color.
@item @b{flavor} @ @ @i{values}: @code{"square"}, @code{"slash"}, @code{"cross"}, @code{"frame"}; @ @ @i{default}: @code{"square"}
The passage shape.
@end table

@item @b{Messages:}
@table @asis
@item @b{signal} @ @ @xref{signal}
Switch color of the passage.
@end table

@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_passage_black_square, 12mm} @b{st_passage}: color = @code{BLACK}, flavor = @code{"square"}
@item @image{images/st_passage_black_square, 12mm} @b{st_passage_black}: color = @code{BLACK}, flavor = @code{"square"}
@item @image{images/st_passage_black_slash, 12mm} @b{st_passage_black}: color = @code{BLACK}, flavor = @code{"slash"}
@item @image{images/st_passage_black_cross, 12mm} @b{st_passage_black}: color = @code{BLACK} - flavor = @code{"cross"}
@item @image{images/st_passage_black_frame, 12mm} @b{st_passage_black}: color = @code{BLACK} - flavor = @code{"frame"}
@item @image{images/st_passage_white_square, 12mm} @b{st_passage_white}: color = @code{WHITE}, flavor = @code{"square"}
@item @image{images/st_passage_white_slash, 12mm} @b{st_passage_white}: color = @code{WHITE} - flavor = @code{"slash"}
@item @image{images/st_passage_white_cross, 12mm} @b{st_passage_white}: color = @code{WHITE} - flavor = @code{"cross"}
@item @image{images/st_passage_white_frame, 12mm} @b{st_passage_white}: color = @code{WHITE} - flavor = @code{"frame"}
@end table

@end table

@c ----------------- Pebble Stone --------------------
@node st_pebble
@subsection st_pebble
@obindex st_pebble

This is the rock member of the rock-paper-scissors trio,
the other two stones being @ref{st_document} and @ref{st_scissors}.
When @code{st_pebble} is touched, each @code{st_scissors} bordering
it or being connected to it by a wire is destroyed. Similarly,
when an @code{st_document} is touched, that borders or is connected to
an @code{st_pebble}, the @code{st_pebble} will break.

@table @asis

@item @b{Attributes:} none

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_pebble, 12mm} @b{st_pebble}
@end table
@end table

@c ----------------- Plaster Stone --------------------
@node st_plaster
@subsection st_plaster
@obindex st_plaster

A sculptured gypsum stone that exists in various variations of basic stone
attributes.

Unlike the similar looking @ref{st_flat} has no special features and behaves
like a standard stone.

But it provides breakable variants. Like @ref{st_break} it is breakable by
laser light, neighboring ignitions like those caused by an exploding
@ref{it_dynamite} on a direct neighboring position or an exploding black
@ref{it_bomb} on a diagonal neighboring position. It breaks on actor hits with
a revealed @ref{it_hammer}, too. But unlike @ref{st_break} it offers a
variant that is breakable and movable at the same time. Of course a possible
break supersedes a possible push condition.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{hollow} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{hollow}
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{movable}
@item @b{breakable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{breakable}
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_plaster, 12mm} @b{st_plaster}:
@item @image{images/st_plaster, 12mm} @b{st_plaster_hollow}: hollow=@code{true}
@item @image{images/st_plaster, 12mm} @b{st_plaster_movable}: movable=@code{"true"}
@item @image{images/st_plaster, 12mm} @b{st_plaster_breakable}: breakable=@code{"true"}
@item @image{images/st_plaster, 12mm} @b{st_plaster_movebreakable}: movable=@code{"true"}, breakable=@code{"true"}
@end table

@end table

@c ----------------- Plop Stone --------------------
@node st_plop
@subsection st_plop
@obindex st_plop

A movable stone that ceases to exist with a plop.

This stone behaves like any other standard movable stone. But unlike other
stones it can cease under some conditions. And if it ceases it does it with
a plop and some sparkles.

Currently there is just one flavor called @code{"slate"} according to its
dark blue grey color. It falls and ceases to exist if pushed on @ref{fl_water},
@ref{fl_abyss} or @ref{fl_swamp}. Unlike @ref{st_box} it does not build a floor.

@table @asis
@item @b{Variants:}
@table @asis
@item @image{images/st_plop_slate, 12mm} @b{st_plop}
@item @image{images/st_plop_slate, 12mm} @b{st_plop_slate}
@end table
@end table

@c ----------------- Polarswitch Stone --------------------
@node st_polarswitch
@subsection st_polarswitch
@obindex st_polarswitch

A special on/off switch that toggles its state on actors hitting the stone.
Of course other objects can send messages on actions to make this switch turning.

The main purpose of this switch is its ability to switch crossing laser beams.
While the switch is not transparent in its default off state, it switches to
a transparent on state.

The switch looks like an @ref{st_darkglass} in its opaque off state and like
an @ref{st_lightglass} in its transparent on state. Like other
@ref{Transparent Stones} it is passable for invisible actors.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF} @ @ @xref{state}
An @samp{OFF} state is not transparent, an @samp{ON} state is transparent.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}, and off at values @samp{0}.
@item @b{on} @ @ @xref{on}
@item @b{off} @ @ @xref{off}
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/st_darkglass, 12mm} @b{st_polarswitch}: state = @code{OFF}
@item @image{images/st_lightglass, 12mm} @b{st_polarswitch}: state = @code{ON}
@end table
@end table

@c ----------------- Portal Stone --------------------
@node st_portal
@subsection st_portal
@obindex st_portal

A gate that is just passable for some special kind of actors. Like
@ref{st_grate} it uses metallic frames but it does not let pass actors of all
kinds.

The portal stone lets just pass actors of the kind given by its attribute
@samp{flavor}.

The flavor @code{"horse"} lets just pass an @ref{ac_horse}.

The flavor @code{"pearl"} lets just pass an @ref{ac_pearl}.

The flavor @code{"glass"} lets just pass the glass flavor of @ref{ac_marble}.

As of Enigma 1.30, all of these flavors share a common image.
Please note however, that future versions of Enigma might introduce
different images for different flavors of @samp{st_portal}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{flavor} @ @ @i{values}: @code{"horse"}, @code{"pearl"}, @code{"glass"}; @ @ @i{default}: @code{"horse"}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_portal_horse, 12mm} @b{st_portal}: flavor=@code{"horse"}
@item @image{images/st_portal_horse, 12mm} @b{st_portal_horse}: flavor=@code{"horse"}
@item @image{images/st_portal_horse, 12mm} @b{st_portal_pearl}: flavor=@code{"pearl"}
@item @image{images/st_portal_horse, 12mm} @b{st_portal_glass}: flavor=@code{"glass"}
@end table

@end table

@c ----------------- Pull Stone --------------------
@node st_pull
@subsection st_pull
@obindex st_pull

A pull stone changes its position on an initiating impulse into the reverse
direction of the impulse. Thus it can not be pushed like other movable stones.
But when an actor hits a pull stone it acts like being pulled. If another stone
is located on the destination grid, both stones will exchange their positions.
The exchange will also be performed when the pull stone receives a stone impulse
via an @ref{ot_wire} or a neighboring @ref{st_stoneimpulse}. A similar stone is
the @ref{st_swap}, that exchanges with stones in the forward direction of the
initiating impulse.

Actors on the destination grid, including an initiating hitting actor, are
pulled through it, not caged under them. The actors reappear on the old grid
position of the pull stone with their old velocities.

The pull stone is laser light transparent like other glass like stones.

An existing stone exchange partner is not mandatory. But if a stone is located
on the destination position of a pull stone some conditions must be met for a
stone exchange. Connected @ref{Cluster Stones} building a block, @ref{st_oxyd}
configured as being @samp{static}, and another @ref{st_swap} or pull stone that
is currently engaged in an own stone exchange operation will refuse swapping.

Stone exchanges will not cause item hit transformations as caused by push moved
stones. But the exchanged stones will react on the new floor, e.g. causing
@ref{st_box} to sink into water.

Further on the exchange is atomic concerning @ref{it_trigger} detection and
laser light transparency. If the exchanged stone is not transparent, the light
will pass on every time slice just on one of the two grids. If the exchanged
stone is floating and does not press @ref{it_trigger}s, the pull stone will
press just one trigger, releasing the trigger of the old position before
pressing the new position's trigger like any other stone being pushed from one
grid to the next.

@table @asis
@item @b{Attributes:} none

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_pull, 12mm} @b{st_pull}
@end table
@end table

@c ----------------- Puzzle Stone --------------------
@node st_puzzle
@subsection st_puzzle
@obindex st_puzzle

Puzzle stones can construct large clusters of stones, that move together and can
be destroyed together. There are two colors, blue and yellow puzzle stones,
which behave different. Each of these color families again consists of 16
variants that differ in the location of sockets to which neighboring puzzle
stones can be attached. Further on there are hollow variants of all colors and
connections.

A cluster is complete as soon as all sockets of all stones are connected to
matching sockets of adjacent puzzle stones of the same color, but independent
of being hollow or solid. A cluster fragment still has at least one stone with
an open stub. A single puzzle stone with no open sockets counts as a complete
cluster.

Puzzle stone offer manifold features. A complete cluster can explode and
dissolve. Cluster fragments and complete clusters can move and will sink on some
floors building bridges. Rows and columns of adjacent, identical colored puzzle
stones, connected and unconnected ones, can shift rotate thus allowing the
player to rearrange and sort the puzzle.

Blue puzzle stones can be moved as single stones, cluster fragments and
complete clusters by an actor pushing or a stone impulse by @ref{ot_wire} or
@ref{st_stoneimpulse}. Of course all new positions of the moving puzzle must be
free of other stones. If all new positions are @ref{fl_water} the blue puzzle
will sink and leave an object of the kind given by the global attribute
@ref{FallenPuzzle}. The replacement defaults to @ref{fl_gray} building a bridge
over the water. The user can prohibit the sinking of the puzzle into water by
pushing with a revealed @ref{it_magicwand}. If all new positions are
@ref{fl_abyss} just complete blue clusters will sink and build a bridge. If all
new positions are either abyss or water with at least one abyss floor just
complete blue clusters will sink. Note that puzzles just sink on moves. Moving
a blue fragment besides another fragment on abyss so that both fragments build
a complete cluster will not sink the new cluster. It will sink as a whole on the
next move. If two or more stones of a cluster receive wire impulses originating
from a single event, the whole cluster will move multiple times. But it will
sink on the first opportunity.

Just single unconnected yellow puzzle stones can be moved by actors. They will
neither sink in @ref{fl_water} nor fall in @ref{fl_abyss}. Any yellow cluster of
two or more stones can not be moved by actor hits. But on receiving stone
impulses they move like blue puzzles.

All puzzle stone moves do not cause standard item transformations, like
@ref{it_coin} value changes, @ref{it_bomb} explosions, etc. But they all are not
floating and thus do press @ref{it_trigger}s and close @ref{fl_bridge}s.

Hollow puzzle stones let pass actors, either moving on the floor or jumping,
and laser light without any interaction, too.

Complete clusters can explode and dissolve. A precondition is that the cluster
is isolated from any adjacent, same colored further puzzle stone. Such clusters
explode on an additional new laser beam hitting one of its solid stones. Yellow
ones explode on any actor hit. Blue ones only on actor hits with a revealed
@ref{it_magicwand}. Additionally complete clusters will explode when an
@ref{ot_cannonball} emitted by an @ref{st_spitter} happens to fall on top of
one of the puzzle stones of the cluster.

Exploding puzzles will stay in place and do not interact any more. The exploding
stones are lethal for actors hitting them, but an actor can start an explosion
beneath a hollow puzzle stone and stay beneath this hollow exploding stone
without harm until the puzzle dissolved.

Puzzles can be rearranged by column and row rotations. Blue puzzles react just
on actor hits with a revealed wand, yellow ones on any actor hit. All colors
do rotate on laser light hits. All rotations can originate only on a solid
puzzle stone. All subsequent puzzle stones of the same color will shift away
with the last puzzle of the line returning to the origin. This operation is
called @code{"push_rotate"} and can be initiated by a message, too.

In case of actor hits possible explosions precede moves, which precede rotation
operations. Thus you need to touch a blue puzzle row carefully with a revealed
wand if the row is part of a movable cluster fragment. If the speed is
sufficient for a hit operation, the cluster will move instead of an expected
row rotation. An actor hit on a blue puzzle that did neither cause an explosion
or a rotation will be propagated by an @ref{ot_wire} connected to this puzzle
stone. Hits on yellow puzzle stones will never propagate to @ref{ot_wire}
connected other stones.

Like @ref{Cluster Stones} puzzles accept a @samp{cluster} attribute. A new set
puzzle stone autoconnects to adjacent, same colored puzzle stones belonging to
the same cluster. But once set the puzzle stone will of course not change its
connections on subsequent moves or rotations. But as a level author you need to
think of possible puzzle stones pushed to positions neighboring an area on which
a puzzle might be set during the running game. The new set stones may
autoconnect to such unexpected stones if the color and cluster number fits.

The resolver @ref{res.puzzle} provides easy methods to set and shuffle puzzles.
The attributes @samp{algorithm} and @samp{intensity} are used by the resolver
only.

If you need to shuffle a puzzle of your own, you can make use of the messages
@samp{get_adjacents} which returns the group of color matching, adjacent puzzle
stones, and @samp{pull_rotate} which is the exact inversion of a push rotation.

@table @asis
@item @b{Attributes:}
@item @b{color} @ @ @i{values}: @code{BLUE}, @code{YELLOW}; @ @ @i{default}: @code{BLUE}
The color of the puzzle stubs. Adjacent puzzle stones of matching colors and
connections cluster to fragments.

@item @b{connections}, @ @ @i{values}: string; @ @ @i{default}: @code{nil}
Describes the connection stubs of the puzzle stone. The string is a substring
of @code{"nesw"} listing the stubs. The sequence of the sides, north, east,
south, west, is guaranteed on read access but arbitrary on write access.

@item @b{cluster} @ @ @i{values}: number; @ @ @i{default}: @code{nil}
If set to a number all adjacent puzzle stones of the same color with
the identical cluster number will build a cluster. This attribute supersedes
any explicitly given connection description.

@item @b{hollow} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
A hollow puzzle stone has a hole in its middle and allows actors to pass beneath.

@item @b{algorithm}, @ @ @i{values}: string; @ @ @i{default}: @code{nil}

@item @b{intensity} @ @ @i{values}: number; @ @ @i{default}: @code{3}

@item @b{Messages:}
@table @asis
@item @b{get_adjacents}
Returns the huddle of all adjacent puzzle stones of same color independent of
being connected or not. The huddle is returned as a group.
@item @b{pull_rotate}, @ @ @i{value type}: orientation
Perform a reverse @samp{push_rotate} from this puzzle stone with the line
of puzzle stones into the given direction.
@item @b{push_rotate}, @ @ @i{value type}: orientation
Perform a line rotation as described above from this puzzle stone with the line
of puzzle stones into the given direction.

@end table

@item @b{Action:} none

@item @b{Variants:}

@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_puzzle_blue, 12mm}@tab  @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{""}, hollow = @code{false}
@tab @image{images/st_puzzle_blue_2, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"w"}, hollow = @code{false}
@item @image{images/st_puzzle_blue_3, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"s"}, hollow = @code{false}
@tab @image{images/st_puzzle_blue_4, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"sw"}, hollow = @code{false}
@item @image{images/st_puzzle_blue_b, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"e"}, hollow = @code{false}
@tab @image{images/st_puzzle_blue_b2, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"ew"}, hollow = @code{false}
@item @image{images/st_puzzle_blue_b3, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"es"}, hollow = @code{false}
@tab @image{images/st_puzzle_blue_b4, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"esw"}, hollow = @code{false}
@item @image{images/st_puzzle_blue_c, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"n"}, hollow = @code{false}
@tab @image{images/st_puzzle_blue_c2, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"nw"}, hollow = @code{false}
@item @image{images/st_puzzle_blue_c3, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"ns"}, hollow = @code{false}
@tab @image{images/st_puzzle_blue_c4, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"nsw"}, hollow = @code{false}
@item @image{images/st_puzzle_blue_d, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"ne"}, hollow = @code{false}
@tab @image{images/st_puzzle_blue_d2, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"new"}, hollow = @code{false}
@item @image{images/st_puzzle_blue_d3, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"nes"}, hollow = @code{false}
@tab @image{images/st_puzzle_blue_d4, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"nesw"}, hollow = @code{false}
@item @image{images/st_puzzle_blue_hollow, 12mm}@tab  @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{""}, hollow = @code{true}
@tab @image{images/st_puzzle_blue_hollow_2, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"w"}, hollow = @code{true}
@item @image{images/st_puzzle_blue_hollow_3, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"s"}, hollow = @code{true}
@tab @image{images/st_puzzle_blue_hollow_4, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"sw"}, hollow = @code{true}
@item @image{images/st_puzzle_blue_hollow_b, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"e"}, hollow = @code{true}
@tab @image{images/st_puzzle_blue_hollow_b2, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"ew"}, hollow = @code{true}
@item @image{images/st_puzzle_blue_hollow_b3, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"es"}, hollow = @code{true}
@tab @image{images/st_puzzle_blue_hollow_b4, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"esw"}, hollow = @code{true}
@item @image{images/st_puzzle_blue_hollow_c, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"n"}, hollow = @code{true}
@tab @image{images/st_puzzle_blue_hollow_c2, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"nw"}, hollow = @code{true}
@item @image{images/st_puzzle_blue_hollow_c3, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"ns"}, hollow = @code{true}
@tab @image{images/st_puzzle_blue_hollow_c4, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"nsw"}, hollow = @code{true}
@item @image{images/st_puzzle_blue_hollow_d, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"ne"}, hollow = @code{true}
@tab @image{images/st_puzzle_blue_hollow_d2, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"new"}, hollow = @code{true}
@item @image{images/st_puzzle_blue_hollow_d3, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"nes"}, hollow = @code{true}
@tab @image{images/st_puzzle_blue_hollow_d4, 12mm}@tab @b{st_puzzle_blue}: color = @code{BLUE}, connections = @code{"nesw"}, hollow = @code{true}
@item @image{images/st_puzzle_yellow, 12mm}@tab  @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{""}, hollow = @code{false}
@tab @image{images/st_puzzle_yellow_2, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"w"}, hollow = @code{false}
@item @image{images/st_puzzle_yellow_3, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"s"}, hollow = @code{false}
@tab @image{images/st_puzzle_yellow_4, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"sw"}, hollow = @code{false}
@item @image{images/st_puzzle_yellow_b, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"e"}, hollow = @code{false}
@tab @image{images/st_puzzle_yellow_b2, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"ew"}, hollow = @code{false}
@item @image{images/st_puzzle_yellow_b3, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"es"}, hollow = @code{false}
@tab @image{images/st_puzzle_yellow_b4, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"esw"}, hollow = @code{false}
@item @image{images/st_puzzle_yellow_c, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"n"}, hollow = @code{false}
@tab @image{images/st_puzzle_yellow_c2, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"nw"}, hollow = @code{false}
@item @image{images/st_puzzle_yellow_c3, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"ns"}, hollow = @code{false}
@tab @image{images/st_puzzle_yellow_c4, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"nsw"}, hollow = @code{false}
@item @image{images/st_puzzle_yellow_d, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"ne"}, hollow = @code{false}
@tab @image{images/st_puzzle_yellow_d2, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"new"}, hollow = @code{false}
@item @image{images/st_puzzle_yellow_d3, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"nes"}, hollow = @code{false}
@tab @image{images/st_puzzle_yellow_d4, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"nesw"}, hollow = @code{false}
@item @image{images/st_puzzle_yellow_hollow, 12mm}@tab  @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{""}, hollow = @code{true}
@tab @image{images/st_puzzle_yellow_hollow_2, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"w"}, hollow = @code{true}
@item @image{images/st_puzzle_yellow_hollow_3, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"s"}, hollow = @code{true}
@tab @image{images/st_puzzle_yellow_hollow_4, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"sw"}, hollow = @code{true}
@item @image{images/st_puzzle_yellow_hollow_b, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"e"}, hollow = @code{true}
@tab @image{images/st_puzzle_yellow_hollow_b2, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"ew"}, hollow = @code{true}
@item @image{images/st_puzzle_yellow_hollow_b3, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"es"}, hollow = @code{true}
@tab @image{images/st_puzzle_yellow_hollow_b4, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"esw"}, hollow = @code{true}
@item @image{images/st_puzzle_yellow_hollow_c, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"n"}, hollow = @code{true}
@tab @image{images/st_puzzle_yellow_hollow_c2, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"nw"}, hollow = @code{true}
@item @image{images/st_puzzle_yellow_hollow_c3, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"ns"}, hollow = @code{true}
@tab @image{images/st_puzzle_yellow_hollow_c4, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"nsw"}, hollow = @code{true}
@item @image{images/st_puzzle_yellow_hollow_d, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"ne"}, hollow = @code{true}
@tab @image{images/st_puzzle_yellow_hollow_d2, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"new"}, hollow = @code{true}
@item @image{images/st_puzzle_yellow_hollow_d3, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"nes"}, hollow = @code{true}
@tab @image{images/st_puzzle_yellow_hollow_d4, 12mm}@tab @b{st_puzzle_yellow}: color = @code{YELLOW}, connections = @code{"nesw"}, hollow = @code{true}
@end multitable

@end table

@c ----------------- Quake Stone --------------------
@node st_quake
@subsection st_quake
@obindex st_quake

This stone looks like an @ref{st_oxyd} of flavor @code{"b"}, but it has the
unpleasant habit of quaking when being activated. Unfortunately this closes all
open @ref{st_oxyd}s.

The stone gets activated on an actor hit, on @ref{st_boulder}s hit and on its
destruction.

The player can destroy this troublemaker with an actor that reveals an
@ref{it_hammer}, by directing a laser light onto the quake stone or by a nearby
explosion or ignition.

Of course you can activate and destroy it by messages and state set operations,
too.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{ACTIVE}, @code{BREAKING}; @ @ @i{default}: @code{IDLE}: @ @ @xref{state}
Current state of the quake stone. You can just change the state into legal
follow up states. A breaking state is final.
@end table

@item @b{Messages:}

@table @asis
@item @b{toggle} @ @ @xref{toggle}
Toggles stone from @samp{IDLE} to @samp{ACTIVE}
@item @b{signal} @ @ @xref{signal}
Toggles stone from @samp{IDLE} to @samp{ACTIVE}
@item @b{ignite}
Toggles stone to @samp{BREAKING}
@end table

@item @b{Action:} none

@table @asis
@item @image{images/st_oxydb, 12mm} @b{st_quake}: state = @code{IDLE}
@item @image{images/st_quake_3, 12mm} @b{st_quake}: state = @code{ACTIVE}
@item @image{images/st_quake_break, 12mm} @b{st_quake}: state = @code{BREAKING}
@end table
@end table

@c ----------------- Rawglass Stone --------------------
@node st_rawglass
@subsection st_rawglass
@obindex st_rawglass

A block of raw glass. It exists in static and movable variants and is by its
very nature transparent to laser light. Like other @ref{Transparent Stones} it
is passable for invisible actors.

This stone comes in a second texture variant that looks like being composed
of 4 small rawglasses. This @samp{quad} variant is not movable.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}; @ @ @i{access}: read only @ @ @xref{movable}
@end table

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_rawglass, 12mm} @b{st_rawglass}: movable = @code{false}
@item @image{images/st_rawglass_quad, 12mm} @b{st_rawglass_quad}: movable = @code{false}
@item @image{images/st_rawglass, 12mm} @b{st_rawglass_movable}: movable = @code{true}
@end table

@end table

@c ----------------- Redfiber Stone --------------------
@node st_redfiber
@subsection st_redfiber
@obindex st_redfiber

A metal frame with woven red fiber. Like other @ref{Transparent Stones} it is
passable transparent to laser light. But the redfiber is not passable to any
actors.

@table @asis
@item @b{Attributes:} none

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_redfiber, 12mm} @b{st_redfiber}
@end table

@end table

@c ----------------- Rotator Stone --------------------
@node st_rotator
@subsection st_rotator
@obindex st_rotator

Rotators send impulses to neighboring stones, thus pushing them in the direction
given by the rotation. @ref{st_boulder} additionally change their orientation to
the one they are pushed to.

Rotators can either rotate in clockwise or counterclockwise direction. They can
be movable or unmovable.

The rotator changes its rotation direction when hit by an actor with a revealed
@ref{it_wrench} and by laser beams. Every additional laser beam causes a change
in the rotation direction.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{CW}, @code{CCW}; @ @ @i{default}: @code{CW} @ @ @xref{state}
The rotation direction - @samp{CW} for clockwise as default, or @samp{CCW} for
counter clockwise.
@item @b{counterclock} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
The standard rotation direction is clockwise. Use this attribute to revert the
direction.
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false} @ @ @xref{movable}
@end table

@item @b{Messages:}

@table @asis
@item @b{toggle} @ @ @xref{toggle}
Switches the rotation direction.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/st_rotator_cw, 12mm} @b{st_rotator}: state = @code{CW}
@item @image{images/st_rotator_cw, 12mm} @b{st_rotator_cw}: state = @code{CW}
@item @image{images/st_rotator_ccw, 12mm} @b{st_rotator_ccw}: state = @code{CCW}
@end table
@end table

@c ----------------- Rubberband Stone --------------------
@node st_rubberband
@subsection st_rubberband
@obindex st_rubberband

A rubberband stone attaches a new @ref{ot_rubberband} between actors hitting it
and itself.

No rubberband is attached if the hitting actor is already connected to this
particular stone.

If the attribute @samp{scissor} is @samp{true}, all rubberbands connected to
the hitting actor are removed prior to attaching the direct new connection.

The rubberband stone is static by default. But an actor with a revealed
@ref{it_magicwand} can move it by hitting it. As the actor will get connected by
an @ref{ot_rubberband} at the same time you will usually place an
@ref{st_scissors} near the target place as an opportunity for the marble to free
itself again from the rubberband stone.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{strength} @ @ @i{values}: number; @ @ @i{default}: @code{10.0}
The force strength.
@item @b{length} @ @ @i{values}: positive number or @code{AUTOLENGTH}; @ @ @i{default}: @code{1.0}
The natural length above which forces are applied.
@item @b{threshold} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The length smaller than the natural length below which inverted forces are applied.
@item @b{min} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The minimum length at which actors bounce.
@item @b{max} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The maximum length at which actors bounce.
@item @b{scissor}, @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Rubberband cutting behaviour on connection.
@end table

@item @b{Messages:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_rubberband, 12mm} @b{st_rubberband}
@end table
@end table

@c ----------------- Scissors Stone --------------------
@node st_scissors
@subsection st_scissors
@obindex st_scissors

This stone cuts all @ref{ot_rubberband}s attached to an actor that touches it.
When at least one rubber band is cut, it performs the action given in the
action/target-pair.

In addition, this is the scissors member of the rock-paper-scissors trio,
the other two stones being @ref{st_pebble} and @ref{st_document}.
When @code{st_scissors} is touched, each @code{st_document} bordering
it or being connected to it by a wire is destroyed. Similarly,
when an @code{st_pebble} is touched, that borders or is connected to
an @code{st_scissors}, the @code{st_scissors} will break.

@table @asis
@item @b{Attributes:} none

@item @b{Messages:} none

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
Sends an action message with value @samp{true} on freeing an actor from its
rubberbands.

@item @b{Variants:}
@table @asis
@item @image{images/st_scissors, 12mm} @b{st_scissors}
@end table
@end table

@c ----------------- Shogun Stone --------------------
@node st_shogun
@subsection st_shogun
@obindex st_shogun

Shogun stones are nestable stones like Fukuroma or Matryoshka dolls. The
different basic variations are distinguishable by their central hole. Small,
medium and large ones do exist. In contrast to the Fukuroma dolls you can push
smaller variations beneath the larger ones but not vice versa. You can see
smaller shoguns pushed beneath larger ones through the upper, larger hole.
Thus the player is always aware of the stack of shogun stones positioned on a
single grid.

An actor or a stone impulse hitting a shogun stack will push the smallest shogun
out of the stack. The upper and larger shogun stones can never be moved out of
a stack and larger shogun stones can never be pushed over smaller ones.

@ref{it_shogun} are a special trigger type for shogun stones represented by
animated blue dots. They just react on shogun stacks positioned on top of the
dot items. All shogun sizes must be present from the smallest up to the size
of the dot itself.

Shogun stones press @ref{it_trigger}, too. But all other items that react on
other stones being pushed over them will not react on shogun stones. E.g.
@ref{it_seed} will not grow, @ref{it_bomb} will not explode, @ref{it_coin} will
not transform and @ref{it_cherry} will not smash.

All shogun stones keep their identity even if they are pushed together onto a
single grid. Thus each shogun can be connected independently to @ref{ot_wire}s
or @ref{ot_rubberband}s. On initialization you can set a stack of shogun onto
a grid by setting a single shogun stone with a combined flavor string. The
largest shogun stone of a stack will be positioned onto the grid and all smaller
ones being part of the stack will be contained by the largest one. You can name
the smaller shoguns of a stack by the additional attributes @samp{name_m} and
@samp{name_s}. Every shogun, even those being part of a stack can individually
be killed by sending a @ref{kill} message to it. By setting another stone or
@samp{st_nil} onto the grid currently being occupied by a shogun grid all shogun
stones being part of the stack will be killed.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{flavor}, @ @ @i{values}: @code{"s"}, @code{"m"}, @code{"l"}, @code{"sm"}, @code{"sl"}, @code{"ml"}, @code{"sml"}; @ @ @i{default}: @code{"s"}; @ @ @i{access}: after initialization read only
A string describing the hole sizes of this shogun stone and all smaller shogun
stones that are positioned beneath this stone. @code{"s"} for a small hole, @code{"m"} for
a medium hole, @code{"l"} for a large hole, plus combinations of these
characters for stacks. On initialization all shoguns of this grid's stack will
be set according to this attribute, which can be prior set. After initialization
this attribute is read only and reports the current stack configuration. The
character sequence is guaranteed to be sorted from small to large on read access
but is arbitrary on initial write access.

@item @b{name_m} @ @ @i{values}: string; @ @ @i{default}: @code{nil}
Name of the middle sized shogun as subpart of a stack of a large shogun.

@item @b{name_s} @ @ @i{values}: string; @ @ @i{default}: @code{nil}
Name of the small sized shogun as subpart of a stack of a large or middle sized
shogun.

@end table

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}

@table @asis
@item @image{images/st_shogun, 12mm} @b{st_shogun}: flavor = @code{"s"}
@item @image{images/st_shogun, 12mm} @b{st_shogun_s}: flavor = @code{"s"}
@item @image{images/st_shogun_2, 12mm} @b{st_shogun_m}: flavor = @code{"m"}
@item @image{images/st_shogun_3, 12mm} @b{st_shogun_sm}: flavor = @code{"sm"}
@item @image{images/st_shogun_4, 12mm} @b{st_shogun_l}: flavor = @code{"l"}
@item @image{images/st_shogun_5, 12mm} @b{st_shogun_sl}: flavor = @code{"sl"}
@item @image{images/st_shogun_6, 12mm} @b{st_shogun_ml}: flavor = @code{"ml"}
@item @image{images/st_shogun_7, 12mm} @b{st_shogun_sml}: flavor = @code{"sml"}
@end table

@end table

@c ----------------- Spitter Stone --------------------
@node st_spitter
@subsection st_spitter
@obindex st_spitter

A stone that spits @ref{ot_cannonball}s on actor hits and on proper messages.
The standard spitter is @samp{ACTIVE} showing a slow rotating animation. In
this @samp{state} the spitter reacts on actor hits, while being @samp{IDLE}
it is steady and will spit just on messages.

On an actor hit the spitter checks the owner's inventory for an existing
@ref{it_extralife}. If one exists that is not stuffed in an @ref{it_bag}, it
takes it and spits an @ref{ot_cannonball} according to the actors velocity
and its own hit attributes. The cannonball flies into the resulting direction
with a speed that is proportional to the actor's hit speed.

All cannonballs fly the same period of time. They fly above all other objects
and cross all stone walls. The flight distance is proportional to their initial
speed. On landing they cause actions on some objects and destroy others:

@itemize @bullet
@item @ref{st_oxyd} do open,
@item @ref{st_stoneimpulse} do pulse,
@item @ref{st_yinyang} do toggle,
@item @ref{st_puzzle} do explode completely connected clusters,
@item @ref{st_brownpyramid} do break,
@item @ref{st_spitter} do break, if not being @samp{secure}
@item other stones do remain unmodified and protect items and floors,
@item @ref{it_dynamite} do ignite,
@item @ref{it_crack} do crack,
@item other indestructible items do remain and protect floors,
@item other items are blown away by an @ref{it_explosion}_debris that may destruct the floor,too,
@item floors dissolve via an @ref{it_explosion}_debris if not being indestructible as @ref{fl_water}, @ref{fl_swamp}, @ref{fl_abyss}.
@end itemize

Actors will not be harmed by falling cannonballs.

The spitting can be initiated by the message @code{"hit"}, too. No
@ref{it_extralife} is needed in this case. The hit message takes either a
destination as message value or in case no value is given it evaluates the
@samp{destination} attribute. The second case is suitable for usage of
@samp{hit} as an action message.

The destination can be any value that evaluates to a valid position, object
references and object names included. In case of a @samp{destination}
attribute you can even supply tokens describing a series of destination
positions. The destinations will be targeted by the cannonballs in turn on
a sequence of @samp{hit} actions.

Note that the destruction of target objects can have unexpected side effects
on the destination sequence. If you list three @ref{st_stoneimpulse} as
destinations they will be targeted in the given sequence as none of them
gets destroyed. But if you list three @ref{st_brownpyramid} the first
cannonball destroys the first target, leaving two valid destinations. The
spitter now targets the second target of its list, which happens to evaluate
to the third brown pyramid stone. Finally the destination list has just one
still existing brown pyramid, the second one, as target. This one will be
destroyed on the next spit as the spitter starts again on the first (remaining)
destination when the end of list is reached. This may be no problem if you
want to destroy objects randomly or if you use named destinations with
wildcards. But if you need control about the sequence you need either
destinations targets that get not destroyed or floor object references, as
they represent @ref{Named Positions} that are persistent to object destruction.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{ACTIVE}; @ @ @i{default}: @code{ACTIVE} @ @ @xref{state}
An @samp{ACTIVE} spitter is animated and reacts on actor hits while an @samp{IDLE}
looks steady and does not spit on actor hits.
@item @b{hit_strength} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{1.0}; @ @ @xref{hit_*}
@item @b{hit_distortion_xx} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{1.0}; @ @ @xref{hit_*}
@item @b{hit_distortion_xy} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{0.0}; @ @ @xref{hit_*}
@item @b{hit_distortion_yx} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{0.0}; @ @ @xref{hit_*}
@item @b{hit_distortion_yy} @ @ @i{values}: floating point numbers; @ @ @i{default}: @code{1.0}; @ @ @xref{hit_*}
@item @b{destination}, @ @ @i{values}: tokens or position; @ @ @i{default}: @code{nil} @ @ @xref{destination}
The destination of the cannonball given by an object or a position.
@item @b{secure} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Unsecure spitters do break on a @ref{ot_cannonball} hit.
@end table

@item @b{Messages:}

@table @asis
@item @b{hit}
Spit a cannonball. Takes either a destination as message value or @samp{nil}.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/st_spitter_idle, 12mm} @b{st_spitter}: secure = @code{false}, state = @code{ACTIVE}
@end table

@end table

@c ----------------- Stoneimpulse Stone --------------------
@node st_stoneimpulse
@subsection st_stoneimpulse
@obindex st_stoneimpulse

When being triggered these stones do pulse and send stone pushing impulses to
their direct neighbors. There exist solid, hollow and movable variants of this
stone.

The pulsing can either be triggered by an actor touching or hitting the stone,
by receiving a stone impulse from a neighboring @ref{st_stoneimpulse}, via
@ref{ot_wire} or a dropped @ref{it_puller}. Further on laser light, an
@ref{st_boulder} hitting and of course messages will cause the pulsing, too.

Even though the three major variants can be set by attributes, they are mutual
exclusive. A @samp{hollow} stone is never movable or solid and vice versa. That
means setting one of these basic attributes will reset the others to their
defaults.

A movable stoneimpulse being pushed will pulse due to the actor hit at the
new grid position. Even when it is pushed while pulsing it will continue the
running pulse animation on the new grid and if necessary it will repulse to
guarantee that impulses are sent to the neighboring stones at the new position.

But if an actor with a revealed @ref{it_magicwand} pushes a movable stoneimpulse
it will move without any additional pulse.

In general stoneimpulse stones are very responsive to actor contacts. The
slightest touch is sufficient to cause a pulsing. Hollow stones will shatter
actors beneath it while pulsing.

Hollow stoneimpulse stones are transparent to laserlight and thus do not react.
But all other stones do pulse. A standard not @samp{steady} stoneimpulse will
pulse just one time on each new added light beam. But if you set @samp{steady}
to @code{true} the stone will continue pulsing as long as a single beam hits
one of its sides.

An @ref{st_boulder} that hits a stoneimpulse causes it to pulse once. The
impulse will not backfire onto the @ref{st_boulder}. It will just propagate to
the other three directions. Thus the boulder remains aside the stoneimpulse. But
when the stoneimpulse gets activated otherwise it will push back the boulder,
which will in return hit the stoneimpulse again.

An @ref{ot_cannonball} emitted from an @ref{st_spitter} and now falling onto
a stoneimpulse causes it to pulse, too.

On a chain of stoneimpulse stones the pulsing will propagate along the chain
without backfiring, as the previous stone is still active when its successor
impulses. This feature lets propagate a linear front of impulses through a field
of stoneimpulse stones as expected.

If you want to setup a linear circle of stoneimpulse stones with an impulse
wandering around the circle in one direction forever, you should insert one
@samp{st_stoneimpulse_new} into the chain. According to the
@ref{Snapshot Principle} it is a stone that is just about to start pulsing.
You need to set the attribute @samp{orientation}, which is just evaluated for
new stones when set to the grid. It takes the incoming direction of the impulse
when it reached the new stone. E.g. an orientation of east means that the stone
received an impulse from a stone located west of it which was bound to east.
Thus the stone will emit impulses to all directions but west.

Impulse stones will be destroyed by @ref{it_dynamite} exploding on one of the
eight neighboring grid positions while the stone is enlightened by a laser. But
other explosions, including @ref{it_bomb}, will not effect stoneimpulse stones.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{movable} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Movable stones are not hollow.
@item @b{hollow} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Hollow stones are neither movable, nor steady.
@item @b{steady} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Steady stones send continuous impulses while exposed to laser light. Steady stones
are not hollow.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Pulse at a value of @samp{1}.
@end table

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_stoneimpulse, 12mm} @b{st_stoneimpulse}
@item @image{images/st_stoneimpulse, 12mm} @b{st_stoneimpulse_movable}: movable = @code{true}
@item @image{images/st_stoneimpulse_hollow, 12mm} @b{st_stoneimpulse_hollow}: hollow = @code{true}
@item @image{images/st_stoneimpulse_6, 12mm} @b{st_stoneimpulse_steady}: steady = @code{true}
@item @image{images/st_stoneimpulse, 12mm} @b{st_stoneimpulse_new}:
A stone that is about to pulse when being set.
@end table

@end table

@c ----------------- Surprise Stone --------------------
@node st_surprise
@subsection st_surprise
@obindex st_surprise

A stone that transforms into a random stone as soon as an actor hits it.

The replacement stone is a random one out of a given selection. You can set
the @samp{selection} attribute with tokens of strings. Every string needs either
to be an @ref{Object Kind} or a tile key prefixed by an equal sign @samp{=}.

@example
ti["b"] = @{"st_brake"@}
ti["d"] = @{"st_death"@}
ti["s"] = @{"st_surprise", selection=@{"st_chess", "=b", "=d", "=d"@}@}
@end example

The replacement stone is randomly chosen out of the given selection. By listing
a stone several times you can take influence on the likelihood.

The tile declarations referenced by a key may even contain objects besides
stone. But you should make rare and proper usage of this feature.

Prior replacing the surprise stone the surprise stone will perform its action.
You can use this action to modify the selection or to set objects on your own.

The surprise stone is killed by any replacement stone set to the grid position.
If your selection does not resolve to a stone you may need to add @code{"st_nil"}
to the replacement tile declaration.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{selection}, @ @ @i{values}: tokens of stone kinds and tile keys; @ @ @i{default}: @code{@{"st_grate_cross", "st_death", "st_surprise", "st_lightglass_hollow", "st_knight", "st_thief", "st_flat_breakable", "st_flat_breaking"@}}

@end table

@item @b{Messages:}

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}
@table @asis
@item @image{images/st_surprise, 12mm} @b{st_surprise}
@end table
@end table

@c ----------------- Swap Stone --------------------
@node st_swap
@subsection st_swap
@obindex st_swap

A swap stone can exchange its position with a neighboring stone on the side
in direction of the initiating impulse. It is not freely movable by pushes.
But when an actor hits a swap stone and another stone is located on the opposite
side of the swap stone, both stones will exchange their positions. The swap will
also be performed when the swap stone receives a stone impulse via an
@ref{ot_wire} or a neighboring @ref{st_stoneimpulse}. A similar stone is the
@ref{st_pull}, that exchanges with stones in the reverse direction of the
initiating impulse.

An existing stone exchange partner is mandatory. Nearly all stones can be
swapped. Just connected @ref{Cluster Stones} building a block, @ref{st_oxyd}
configured as being @samp{static}, and another swap stone or @ref{st_pull} that
is currently engaged in an own stone exchange operation will refuse swapping.

Stone exchanges will not cause item hit transformations as caused by push moved
stones. But the exchanged stones will react on the new floor, e.g. causing
@ref{st_box} to sink into water.

Further on the exchange is atomic concerning @ref{it_trigger} detection and
laser light transparency. If the exchanged stone is transparent, the light
will pass on every time slice just on one of the two grids. If the exchanged
stone is floating and does not press @ref{it_trigger}s, the swap stone will
press just one trigger, releasing the trigger of the old position before
pressing the new position's trigger like any other stone being pushed from one
grid to the next.

@table @asis
@item @b{Attributes:} none

@item @b{Messages:} none

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_swap, 12mm} @b{st_swap}
@end table
@end table

@c ----------------- Switch Stone --------------------
@node st_switch
@subsection st_switch
@obindex st_switch

A classical on/off switch that toggles its state on actors hitting the stone.
Of course other objects can send messages on actions to make this switch turning.

Three variants of the switch do exist. A neutral, grey colored one that reacts
on any actor hits, and a black and a white colored switch. These last two
switches will react only if hit by actors of matching color.

If a switch turns on or off there will be a short delay until it reaches the
new state and performs its actions. If you need a switch without delay you
need to set the @samp{instant} attribute.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{OFF} @ @ @xref{state}
@item @b{color} @ @ @i{values}: @code{nil}, @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{nil}
The color of the switch that needs to match the hitting actor to cause a toggle.
The default @samp{nil} color is a grey switch that matches all actors, marbles,
pearls or killers of any color as well as all other actors.
@item @b{instant} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
A default switch requires a short time equivalent to the animation until the
new state is reached and the actions are performed. An instant switch jumps
directly into the new state.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}, and off at values @samp{0}.
@item @b{on} @ @ @xref{on}
@item @b{off} @ @ @xref{off}
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}

@table @asis
@item @image{images/st_switch, 12mm} @b{st_switch}
@item @image{images/st_switch_black, 12mm} @b{st_switch_black}: color = @code{BLACK}
@item @image{images/st_switch_white, 12mm} @b{st_switch_white}: color = @code{WHITE}
@end table

@end table

@c ----------------- Thief Stone --------------------
@node st_thief
@subsection st_thief
@obindex st_thief

A thief steals an item from the player's inventory when it is hit by an owned
actor. Unfortunately the thief is visually indistinguishable from a
@ref{st_bluegray}.

The item is not directly stolen at the moment of the hit. The hit itself just
causes the thief to emerge from his hiding-place. The thief steals from the
actor that did hit the stone at the moment of maximum visibility. He takes
a random item from the owner's inventory. But he just will steal an item if
the actor is not shielded due to an activated @ref{it_umbrella}.

Thieves have an addiction to alcohol. Thus they get drunken and inactive if
they happen to steal a bottle filled with stuff.

Thieves have an enemy - the @ref{st_chess}. If a chess stone is pushed onto
a thief it will capture the thief, sober or drunken. The thief stone vanishes
and the chess stone jumps onto its position. But the thief will leave behind
on the grid all stolen items in his own @ref{it_bag}. If an item happens to
be positioned beneath the captured thief stone, this item will be added to
the thief's bag, too. If the thief has not stolen any items he leaves no empty
bag.

@table @asis
@item @b{Attributes:} none

@item @b{Messages:} none

@item @b{Action:}  none

@item @b{Variants:}
@table @asis
@item @image{images/st_bluegray, 12mm} @b{st_thief}: hidden
@item @image{images/st_thief, 12mm} @b{st_thief}: showing up at the moment when stealing items
@item @image{images/st_thief_capture, 12mm} @b{st_thief}: when being captured
@item @image{images/st_thief_drunken, 12mm} @b{st_thief}: drunken thief
@end table
@end table

@c ----------------- Timer Stone --------------------
@node st_timer
@subsection st_timer
@obindex st_timer

This stone can be used to trigger a delayed single or periodic events. An
active, switched on timer is usually visualized by an animation. An inactive,
switched off timer shows a static image. An alternative to an invisible timer
stone is an @ref{ot_timer} gadget.

Note that this is an exceptional object as its default state is @samp{ON} to
support the most common case of immediately running timers.

A single shot, not looping timer will send an action value of @samp{true}. A
looping timer will alternate the boolean action values starting with value
@samp{true}. You can use @ref{inverse} to start with a value of @samp{false}.

If you stop a timer by switching it off, no further events will be performed.
Restarting the timer by switching it on again will restart the timer like
a new timer.

The time interval to the first event and between subsequent events can be relied
on to an accuracy of 0.01 seconds. But due to performance reasons and visibility
of the reactions timers should not be set to intervals below 0.1 seconds. An
interval of less than 0.01 seconds is not valid for a looping timer.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{ON} @ @ @xref{state}
An @samp{ON} state timer is running. A timer in state @samp{OFF} is reset and
waiting for reactivation.
@item @b{invisible} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
An invisible timer is totally transparent. But the user may notice it, as actors
cannot pass and other stones cannot be moved onto the same grid position.
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{1.0}
Number of seconds until the first and between subsequent events. The interval
must be larger or equal 0.01 seconds for looping timers.
@item @b{loop} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
A looping timer will send periodic events.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}, and off at values @samp{0}.
@item @b{on} @ @ @xref{on}
@item @b{off} @ @ @xref{off}
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
The action value starts with @samp{true} and alternates on every event between
@samp{false} and @samp{true}. A timer that is reset starts again with value
@samp{true}

@item @b{Variants:}
@table @asis
@item @image{images/st_timer_3, 12mm} @b{st_timer}: state = @code{OFF}
@item @image{images/st_timer, 12mm} @b{st_timer}: state = @code{ON}
@end table
@end table

@c ----------------- Turnstile Pivot Stone --------------------
@node st_turnstile
@subsection st_turnstile
@obindex st_turnstile

A turnstile is a stone cluster that consists of a central pivot, this
@samp{st_turnstile}, and up to four neighboring @ref{st_turnstilearm}s of
connecting orientations. When one the arms is hit by an actor or receives a
stone pushing impulse by another object (e.g. @samp{st_rotator}, @samp{ot_wire},
@samp{it_puller}, ...), the whole cluster turns by 90 degrees into the impulse
direction. Of course the turnstile complex just turns if it is not blocked by
other stones in its surrounding. Even movable stones will block turnstiles.

There are two @samp{flavor}s of turnstiles. The common @samp{red} version
pulls only the actor, that did hit the arm. It keeps it behind the
@samp{st_turnstilearm} and shatters all others in its surrounding. Whereas the
@samp{green} version pushes all actors with its attached @samp{st_turnstilearm}s
and keeps them in front of the arms. Just actors being in range of the arms will
be pushed. That means that they need to be in a distance of less than 1.5 grids
to the center of the pivot. Thus actors located at the very edge of the
diagonal grid positions will not be pushed. As actors can not be moved out of
the world, a green turnstile positioned at the level border that moves an arm
to the border will shatter actors instead.

Any actor moved by a turnstile is directly warped to its new position without
touching any grid in between. Thus actors can pass abyss or water floors,
but they will not grab any items located on the grid positions in between.
The relative position of an actor within the grid is maintained during its
circular move. Thus two small actors moved at the same time keep their relative
positioning. It is guaranteed that any moved actors will fall even into a tiny
@ref{it_meditation}_dent that is positioned at the destination grid.

Items in the range of the rotating arms will act like a stone being pushed over
them.

When green turnstiles push actors to a diagonal grid position they will push
away an @ref{st_turnstilearm}, and just this single kind of stone, if it is
located on this target grid. This feature can be used to intertwine several
turnstiles as it can be seen in the level @samp{ZigZag}.

There are two other ways of coupling turnstiles. You can simply set another
@samp{st_turnstile} as the target of a first one and perform a @samp{signal}
action. This will turn both turnstiles in the same direction. But if one is
blocked the rotations will desynchronize.

Another way is the coupling of two @ref{st_turnstilearm}s via an @ref{ot_wire}.
A turnstile will propagate its rotation impulses via a wire that is connected
at one of its arms. Two turnstiles connected by wired arms will resynchronize in their
rotation even if one of them is temporarily blocked.

Turnstiles can be turned by standard messages and attributes. They do even
evaluate the turns and keep the attribute @samp{orientation} up to date for
easy read evaluation of the current turnstile orientation.

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{flavor} @ @ @i{values}: @code{"red"}, @code{"green"}; @ @ @i{default}: @code{"red"}
The distinguishing color of the pivot that signals the behaviour.
@item @b{counterclock} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
The standard turning direction is clockwise. Use this attribute to revert the
direction.
@atindex orientation
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH}
The orientation of the turnstile that is only visible by its arms. Setting
this attribute just defines a new base, but does not turn the turnstile as the
orientation would not be defined. But every rotation does update this attribute
relative to its previous value.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Rotates the turnstile counterclockwise on @samp{1}, and clockwise at values @samp{0}.
@item @b{turn}
Turns in turning direction as defined by attribute @samp{counterclock}.
@item @b{turnback}
Turns in opposite turning direction as defined by attribute @samp{counterclock}.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
At the end of each turn the action is performed with a value of @samp{true}
on counterclock turns and @samp{false} on clockwise turns.

@item @b{Variants:}
@table @asis
@item @image{images/st_turnstile, 12mm} @b{st_turnstile}: flavor = @code{"red"}
@item @image{images/st_turnstile, 12mm} @b{st_turnstile_red}: flavor = @code{"red"}
@item @image{images/st_turnstile_green, 12mm} @b{st_turnstile_green}: flavor = @code{"green"}
@end table
@end table

@c ----------------- Turnstilearm Stone --------------------
@node st_turnstilearm
@subsection st_turnstilearm
@obindex st_turnstilearm

An arm that usually connects to an @ref{st_turnstile} pivot building a turnstile
cluster. The arm's subkind suffix, its state and orientation are named according
to the arm's position within the turnstile cluster. Thus a @samp{NORTH} arm has
a single standard connection of @code{"s"}, the reverse orientation.

As long as a turnstile arm is not connected to a pivot it is a free movable
stone. Intentionally it is visually indistinguishable from a @ref{st_puzzle}
with the same connections. But neither an arm will not connect to other
@ref{st_puzzle} nor a puzzle to a pivot.

An arm is connected to a pivot on a neighboring grid position solely by a
matching connection. It is no longer freely movable. All its impulses will turn
the @ref{st_turnstile} cluster instead.

A special move of an arm is due to actors being moved by another green
@ref{st_turnstile} to its position. The arm receives an impulse by the other
pivot and will either move straight forward or turn its own pivot if being
part of a cluster.

The orientation of an arm can be set by attribute or messages. Neither way will
generate an impulse to turn a connected turnstile cluster. The arm will be
reorientated alone.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH} @ @ @xref{state}
The position of an arm in a turnstile cluster.
@atindex orientation
@item @b{orientation}, @ @ @i{values}: @code{NORTH}, @code{EAST}, @code{SOUTH}, @code{WEST}; @ @ @i{default}: @code{NORTH}
The position of an arm in a turnstile cluster.
@item @b{connections} @ @ @i{values}: string; @ @ @i{default}: @code{"s"}
Describes the @ref{st_puzzle} like connection that is the opposite of the
orientation. The string is a string of a single character describing the
sole connection.
@end table

@item @b{Messages:}

@table @asis
@msindex orientate
@item @b{orientate}, @ @ @i{value type}: orientation
Change the orientation to the given orientation value. The @ref{st_fourswitch}
provides a compatible action which allows you to set an arm as
target and this message as action.
@end table

@item @b{Action:} none

@item @b{Variants:}
@table @asis
@item @image{images/st_puzzle_blue_3, 12mm} @b{st_turnstilearm}: orientation = @code{NORTH}
@item @image{images/st_puzzle_blue_3, 12mm} @b{st_turnstilearm_n}: orientation = @code{NORTH}
@item @image{images/st_puzzle_blue_2, 12mm} @b{st_turnstilearm_e}: orientation = @code{EAST}
@item @image{images/st_puzzle_blue_c, 12mm} @b{st_turnstilearm_s}: orientation = @code{SOUTH}
@item @image{images/st_puzzle_blue_b, 12mm} @b{st_turnstilearm_w}: orientation = @code{WEST}
@end table
@end table

@c ----------------- Volcano Stone --------------------
@node st_volcano
@subsection st_volcano
@obindex st_volcano

A volcano stone spreads slowly to neighboring grid positions filling up
complete areas and will just stop on boundaries set by other stones.

A volcano can either start by the setting of an @samp{ACTIVE} variant, by
an inactive @samp{IDLE} variant being triggered by a message or a hitting
@ref{st_boulder}, or by an @ref{it_seed} of flavor @code{volcano} being dropped
or triggered.

Once being activated a volcano stone spreads randomly to its direct neighbor
positions. Even though the new set volcano seeds can be passed by actors
without harm for a short period of time the volcano gets lethal while growing.
After reaching its full size a volcano remains for a random time in an active,
glowing state spreading to neighbour positions. During this phase an actor
with a revealed @ref{it_hammer} can destroy the active volcano stone.

The spreading of the volcano can be made @samp{secure} by setting this attribute
to @samp{true}. Per default the spreading in not secure and a volcano may
stop spreading with a certain chance anywhere, but especially in narrow gateways.
In contrast a secure volcano remains active until it is guaranteed that all its
neighbor grid positions will be filled with volcano stones.

After its active phase a volcano reaches its final inactive state and can not
be reactivated anymore.

A volcano stone will press any @ref{it_trigger} as soon as it starts growing.

!!Work in progress!! special behaviour on items and floors may yet be added

@table @asis
@item @b{Attributes:}
@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{ACTIVE}; @ @ @i{default}: @code{IDLE} @ @ @xref{state}
Inactive, finished and breaking volcano will report an @samp{IDLE} state,
new, growing and active volcano will report an @samp{ACTIVE} state. An inactive
volcano can be activated by setting the state to @samp{ACTIVE}. All other
attempts to set the state will be silently ignored.
@item @b{secure} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
A secure volcano will spread a complete area with guarantee.
@end table

@item @b{Messages:}
@table @asis
@item @b{toggle} @ @ @xref{toggle}
Activates an inactive volcano stone.
@end table

@item @b{Variants:}
@table @asis
@item @image{images/st_flat, 12mm} @b{st_volcano}: state = @code{IDLE}
@item @image{images/st_flat, 12mm} @b{st_volcano_idle}: state = @code{IDLE}
@item @image{images/st_quake_3, 12mm} @b{st_volcano_active}: state = @code{ACTIVE}
@item @image{images/it_seed, 12mm} @b{st_volcano_new}:
An active volcano starting in the seed like phase.
@item @image{images/st_volcano_growing, 12mm} @b{st_volcano_growing}:
An active volcano starting in the growing phase.
@end table
@end table

@c ----------------- Window Stone --------------------
@node st_window
@subsection st_window
@obindex st_window

A stone made up just of glass window faces. All combinations of window faces with
at least one face are possible. There exist two versions of windows, normal
blue colored glass and green colored safety glass, that is nearly indestructible.
Safety glass is selected by setting the attribute @samp{secure} to @samp{true}.
Every glass face can be weakened by @samp{scratches} which are visible in the
shadows.

All windows are transparent to laser light.

Slowly moving actors will bounce from window faces on any side. They can freely
move within the inner part of the window stone. Invisible actors can even pass
the normal blue window faces, but not the green safety glass faces.

Fast moving actors can blast normal blue window faces into smithereens. But too
strong hits will cause marbles to shatter themselves. An actor can lower the
required speed by adding @ref{it_weight}, by revealing an @ref{it_hammer}, or by
weakening the window faces by prior scratching it with an @ref{it_ring}. Green
safety glass windows will never break on actor attacks and actors will not
shatter on hitting safety glass.

Bomb explosions can shatter window faces, too. Normal blue window faces adjacent
to a bomb explosion will break. Green safety glass faces will break only if
prior weakened by an @ref{it_ring} scratch.

Window faces can be rearranged by actors with a revealed @ref{it_wrench}.
Pushing a face from the outside may move it to the opposite side of the window.
But it will only move to the opposite side if there is not already a window face.
And additionally the grid position adjacent to the opposite side must be free
of a stone. Just another window stone without an adjacent window face is allowed
on this position. The reason is, that the moving window face will push
non static items and any actors positioned on the affected window grid to the
next grid. If this grid is already occupied by an item, the window grid item
will be @ref{it_squashed}.

Window face rearrangements can also be initiated by an @ref{it_puller} dropped
within the window and by the message @samp{inner_pull}.

Windows do support @ref{Flood Spreading} and @ref{Fire Spreading} through open
faces.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{faces} @ @ @i{values}: string; @ @ @i{default}: @code{"s"}
Describes the window faces of the stone. The string is a substring of
@code{"nesw"} listing the faces. The sequence of the sides, north, east, south,
west, is guaranteed on read access but arbitrary on write access.
@item @b{secure} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
Green safety glass is secure, whereas normal blue is not.
@item @b{scratches} @ @ @i{values}: string; @ @ @i{default}: @code{""}
Describes the scratched window faces of the stone. The string is a substring of
@code{"nesw"} listing the affected faces. The sequence of the sides, north, east,
south, west, is guaranteed on read access but arbitrary on write access.
@end table

@item @b{Messages:}

@table @asis
@item @b{inner_pull}, @ @ @i{value type}: orientation
Tries to tear the opposite window face into the given orientation.
@end table

@item @b{Variants:}
@multitable @columnfractions .08 .42 .08 .42
@item @image{images/st_window_blue_3, 12mm}@tab @b{st_window}: faces = @code{"s"}, secure = @code{false}
@tab @image{images/st_window_green_3, 12mm}@tab @b{st_window}: faces = @code{"s"}, secure = @code{true}
@item @image{images/st_window_blue_2, 12mm}@tab @b{st_window_w}: faces = @code{"w"}, secure = @code{false}
@tab @image{images/st_window_green_2, 12mm}@tab @b{st_window_w}: faces = @code{"w"}, secure = @code{true}
@item @image{images/st_window_blue_3, 12mm}@tab @b{st_window_s}: faces = @code{"s"}, secure = @code{false}
@tab @image{images/st_window_green_3, 12mm}@tab @b{st_window_s}: faces = @code{"s"}, secure = @code{true}
@item @image{images/st_window_blue_4, 12mm}@tab @b{st_window_sw}: faces = @code{"sw"}, secure = @code{false}
@tab @image{images/st_window_green_4, 12mm}@tab @b{st_window_sw}: faces = @code{"sw"}, secure = @code{true}
@item @image{images/st_window_blue_b, 12mm}@tab @b{st_window_e}: faces = @code{"e"}, secure = @code{false}
@tab @image{images/st_window_green_b, 12mm}@tab @b{st_window_e}: faces = @code{"e"}, secure = @code{true}
@item @image{images/st_window_blue_b2, 12mm}@tab @b{st_window_ew}: faces = @code{"ew"}, secure = @code{false}
@tab @image{images/st_window_green_b2, 12mm}@tab @b{st_window_ew}: faces = @code{"ew"}, secure = @code{true}
@item @image{images/st_window_blue_b3, 12mm}@tab @b{st_window_es}: faces = @code{"es"}, secure = @code{false}
@tab @image{images/st_window_green_b3, 12mm}@tab @b{st_window_es}: faces = @code{"es"}, secure = @code{true}
@item @image{images/st_window_blue_b4, 12mm}@tab @b{st_window_esw}: faces = @code{"esw"}, secure = @code{false}
@tab @image{images/st_window_green_b4, 12mm}@tab @b{st_window_esw}: faces = @code{"esw"}, secure = @code{true}
@item @image{images/st_window_blue_c, 12mm}@tab @b{st_window_n}: faces = @code{"n"}, secure = @code{false}
@tab @image{images/st_window_green_c, 12mm}@tab @b{st_window_n}: faces = @code{"n"}, secure = @code{true}
@item @image{images/st_window_blue_c2, 12mm}@tab @b{st_window_nw}: faces = @code{"nw"}, secure = @code{false}
@tab @image{images/st_window_green_c2, 12mm}@tab @b{st_window_nw}: faces = @code{"nw"}, secure = @code{true}
@item @image{images/st_window_blue_c3, 12mm}@tab @b{st_window_ns}: faces = @code{"ns"}, secure = @code{false}
@tab @image{images/st_window_green_c3, 12mm}@tab @b{st_window_ns}: faces = @code{"ns"}, secure = @code{true}
@item @image{images/st_window_blue_c4, 12mm}@tab @b{st_window_nsw}: faces = @code{"nsw"}, secure = @code{false}
@tab @image{images/st_window_green_c4, 12mm}@tab @b{st_window_nsw}: faces = @code{"nsw"}, secure = @code{true}
@item @image{images/st_window_blue_d, 12mm}@tab @b{st_window_ne}: faces = @code{"ne"}, secure = @code{false}
@tab @image{images/st_window_green_d, 12mm}@tab @b{st_window_ne}: faces = @code{"ne"}, secure = @code{true}
@item @image{images/st_window_blue_d2, 12mm}@tab @b{st_window_new}: faces = @code{"new"}, secure = @code{false}
@tab @image{images/st_window_green_d2, 12mm}@tab @b{st_window_new}: faces = @code{"new"}, secure = @code{true}
@item @image{images/st_window_blue_d3, 12mm}@tab @b{st_window_nes}: faces = @code{"nes"}, secure = @code{false}
@tab @image{images/st_window_green_d3, 12mm}@tab @b{st_window_nes}: faces = @code{"nes"}, secure = @code{true}
@item @image{images/st_window_blue_d4, 12mm}@tab @b{st_window_nesw}: faces = @code{"nesw"}, secure = @code{false}
@tab @image{images/st_window_green_d4, 12mm}@tab @b{st_window_nesw}: faces = @code{"nesw"}, secure = @code{true}
@end multitable
@end table

@c ----------------- Yinyang Stone --------------------
@node st_yinyang
@subsection st_yinyang
@obindex st_yinyang

A special switch that allows the user to toggle the @ref{Player and Inventory}
between @code{YIN} and @code{YANG}.

In contrast to @ref{it_yinyang} the player can not switch at any point of time
but is limited to situations where he can hit the stone by one of the actors
he controls. Of course other objects can send @code{"toggle"} messages on
actions to this switch, too. Additionally an @ref{ot_cannonball} emitted by
an @ref{st_spitter} that now happens to fall on top of a yinyang stone
activates it, too.

When being activated the yinyang stone switches from the @samp{IDLE} state to
the @samp{ACTIVE} state which is animated by a turning yinyang symbol. By
default the player switch takes place at the end of this animation with the
stone returning to its @samp{IDLE} state.

If you need a yinyang stone that switches without delay you need to set the
@samp{instant} attribute to @samp{true}. The animation is executed after
the switching. Note that even an instant stone variant can not be reactivated
until it returns to its @samp{IDLE} state after the completion of the animation.

By default the yinyang stone loops between its two states @samp{IDLE} and
@samp{ACTIVE}. This means the user can hit the stone many times causing every
time a player toggle action. But if you set @samp{loop} to @samp{false} the
yinyang stone will forward to the state @samp{INACTIVE} after the next
activation. Thus the user can use this stone just once to toggle the players.

You can use an instance of this stone to toggle the player directly at the
start of the level. Use an @samp{ACTIVE} yinyang stone to switch after a short
period of animation, or set additionally @samp{instant} to @samp{true} to switch
the player before the user can act on @code{YIN}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{IDLE}, @code{ACTIVE}, @code{INACTIVE}; @ @ @i{default}: @code{IDLE} @ @ @xref{state}
An @samp{IDLE} yinyang is ready for activation. An @samp{ACTIVE} yinyang is
performing its animation and rejects any further attempts to reactivate. An
@samp{INACTIVE} yinyang reached its final state and can not be reactivated by
actor hits or toggle messages.
@item @b{instant} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{false}
A default yinyang stone toggles the player after a short period of animation.
An instant yinyang switches directly with start of the animation.
@item @b{loop} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
A looping yinyang returns to @samp{IDLE} state after completion of the
@samp{ACTIVE} state. A yinyang with a @samp{loop} value of @samp{false} forwards
to the final @samp{INACTIVE} state
@end table

@item @b{Messages:}

@table @asis
@item @b{toggle} @ @ @xref{toggle}
Activate the yinyang like an actor hitting the stone.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}

@item @b{Variants:}

@table @asis
@item @image{images/st_yinyang, 12mm} @b{st_yinyang}: state = @code{IDLE}
@item @image{images/st_yinyang, 12mm} @b{st_yinyang_active}: state = @code{ACTIVE}
@item @image{images/st_yinyang_inactive, 12mm} @b{st_yinyang_inactive}: state = @code{INACTIVE}
@item @image{images/st_yinyang, 12mm} @b{st_yinyang_instant}: instant = @code{true}, state = @code{IDLE}
@end table
@end table


@c ----------------- Stone Feature Summaries --------------------
@node Stone Feature Summaries
@section Stone Feature Summaries

@menu
* Transparent Stones::
* Breakable Stones::
@end menu

@c ----------------- Transparent Stones --------------------
@node Transparent Stones
@subsection Transparent Stones

Enigma provides a collection of transparent stones, all similar, but with
different features. Some of them may be passed after the use of an
@ref{it_cherry}, others will be just pushed. Some are transparent for lasers,
but not all! This table shows their exact properties.

@multitable {st_lightpassenger} {st_lightpassenger_off_plus} {actor is visible:  } {actor is invisible:  } {lasertransparent:  }
@headitem class @tab kind: @tab actor is visible: @tab actor is invisible: @tab lasertransparent:
@item @ref{st_rawglass} @tab st_rawglass @tab rebound @tab pass @tab yes
@item @ref{st_rawglass} @tab st_rawglass_movable @tab push @tab pass @tab yes
@item @ref{st_lightglass} @tab st_lightglass @tab rebound @tab pass @tab yes
@item @ref{st_lightglass} @tab st_lightglass_movable @tab push @tab push @tab yes
@item @ref{st_lightglass} @tab st_lightglass_hollow @tab pass @tab pass @tab yes
@item @ref{st_darkglass} @tab st_darkglass @tab rebound @tab pass @tab no
@item @ref{st_darkglass} @tab st_darkglass_movable @tab push @tab push @tab no
@item @ref{st_darkglass} @tab st_darkglass_hollow @tab pass @tab pass @tab yes
@item @ref{st_redfiber} @tab st_redfiber @tab rebound @tab rebound @tab yes
@item @ref{st_polarswitch} @tab st_polarswitch_on @tab toggle @tab pass @tab yes
@item @ref{st_polarswitch} @tab st_polarswitch_off @tab toggle @tab pass @tab no
@item @ref{st_beads} @tab st_beads @tab leave @tab pass @tab no
@item @ref{st_lightpassenger} @tab st_lightpassenger_off @tab rebound @tab rebound @tab no
@item @ref{st_ice} @tab st_ice @tab push @tab push @tab yes
@item @ref{st_invisible} @tab st_invisible @tab rebound @tab rebound @tab no
@item @ref{st_invisible} @tab st_invisible_movable @tab push @tab push @tab no
@item @ref{st_invisible} @tab st_invisible_hollow @tab pass @tab pass @tab no
@item @ref{st_ghost} @tab st_ghost_purplemarble @tab rebound @tab rebound @tab no
@item @ref{st_ghost} @tab st_ghost_greenbrown @tab rebound @tab rebound @tab yes
@item @ref{st_ghost} @tab st_ghost_break @tab rebound @tab rebound @tab yes
@end multitable

These entries can be memorized as follows: A stone is transparent for laser
light if it is hollow, but not if it is dark. Exception is @samp{st_beads},
whose irregular sides would scatter the beam. A stone can always be passed by
invisible actors, with three exceptions: @samp{st_redfiber}, whose inside is
filled with red stripes, and the two movables @samp{st_lightglass_movable} and
@samp{st_darkglass_movable} which have a non-glass frame which the actor can
use to move the stone. @code{st_rawglass_movable} does not have such a frame
and can not be moved by an invisible actor.

@c ----------------- Breakable Stones --------------------
@node Breakable Stones
@subsection Breakable Stones

@c ===================  Actors  =======================

@node Actor Objects
@chapter Actor Objects

@menu
* Actor Attributes::    Common attributes
* Actors::              All actors
* Actor Features::      Common noteworthy features
@end menu


@node Actor Attributes
@section Actor Attributes

@menu
* adhesion (actor)::        Effectiveness of mousemotion
* charge::          Initial electrical charge
* controllers::     Mouse
* color::           Color
* essential::
* essential_id::
* owner::           Inventory owner
* velocity_x::      Initial velocity
* velocity_y::      Initial velocity
@end menu


@node adhesion (actor)
@subsection adhesion (actor)

The responsiveness of an actor on mouse movements. It is a scalar factor to
the accelerating force applied to the actor. Note that mouse forces are only
applied to an actor if the @ref{controllers} attribute allows forces at all.
Vice versa you should exclude an actor from mouse forces by usage of the
@ref{controllers} attribute instead of setting its adhesion to zero. The
adhesion may take negative values, too. Such values correspond to inverse forces.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@end table

@node charge
@subsection charge

The initial electrical charge that a new actor starts with when being added to
the world. Actors do charge and recharge by hitting @ref{st_charge}. Hits
of charged actors among themselves do not affect their charge load. Each
actor keeps its charge load.

The electrical force on a charged actor is given by its own load and the load
and position of all other charged actors. Note that a constant global factor
@ref{ElectricStrength} is applied, too. If this factor is negative, equal
charged actors may even attract each other.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@end table

@node controllers
@subsection controllers

The players that can control the actor by their mouse movements.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ @code{CTRL_NONE}, @code{CTRL_YIN}, @code{CTRL_YANG}, @code{CTRL_YINYANG}
@item @b{Default:} @ @ @code{CTRL_NONE}
@item @b{Access:} @ @ read/write
@end table

@node color
@subsection color

The logical color of the actor. All actors besides @ref{ac_marble}s,
@ref{ac_pearl}s and @ref{ac_killer}s will report color @code{nil}. The color of
an actor can not be changed, it is a read only attribute.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ @code{BLACK}, @code{WHITE}, @code{GLASS}, @code{nil}
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read only
@end table

@node essential
@subsection essential

Describes the necessity of an actor to be alive in case of multiple actors being
attached to a player. A value @samp{DISPENSABLE} marks an actor as not essential.
The player may well continue to play with other actors that he controls which
are still alive. A value of @samp{INDISPENSABLE} marks an actor as totally
necessary. If such an actor cannot be resurrected after a death, the player is
essentially dead. A value of @samp{PERKIND} marks an actor as partially
essential. Not the actor itself needs to survive but the number of actors of
its kind controlled by the player need to be larger than the number of actors
with value @samp{PERKIND}. For example, marking 4 out of 5 @ref{ac_pearl} with
@samp{PERKIND} means that the player is dead if 2 pearls are no longer alive.

Of course shattered or sunken actors will first be resurrected if an
@ref{it_extralife} is available and the global attribute @ref{ConserveLevel}
allows a resurrection.

For more details about level restart see @ref{Level Restart}.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ @code{DISPENSABLE}, @code{INDISPENSABLE}, @code{PERKIND}
@item @b{Default:} @ @ @code{}
@item @b{Access:} @ @ read/write
@end table

@node essential_id
@subsection essential_id

Since a player may control actors of different kinds at the same time, the
essentialness of actors is limited to its kind via this id. It is possible to
group actors of different kinds into an essential group via this id. The engine
keeps this id even if actors are transformed into other kinds like on activation
of an @ref{it_drop}.

@table @asis
@item @b{Type:} @ @ string
@item @b{Values:} @ @ any
@item @b{Default:} @ @ @ model name of actor
@item @b{Access:} @ @ read/write
@end table

@node owner
@subsection owner

The player that owns the actor. The owner gets all items picked up by an actor
added to his inventory. The ownership of an actor does not influence the
ability of a player to control the actors movements. Note that you need to
assign the value @code{DEFAULT} in Lua tables to set the value @code{nil} due to
the well known Lua table @ref{Caveats}. The other two values @code{YIN} and
@code{YANG} are common @ref{state values}.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ @code{YIN}, @code{YANG}, @code{nil}
@item @b{Default:} @ @ @code{nil}
@item @b{Access:} @ @ read/write
@end table

@node velocity_x
@subsection velocity_x

The velocity into x direction that a new actor starts with when being added to
the world. Even though this attribute is readable it does not reflect the
current velocity of an actor during runtime.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@end table

@node velocity_y
@subsection velocity_y

The velocity into y direction that a new actor starts with when being added to
the world. Even though this attribute is readable it does not reflect the
current velocity of an actor during runtime.

@table @asis
@item @b{Type:} @ @ number
@item @b{Values:} @ @ float number
@item @b{Default:} @ @ @code{0.0}
@item @b{Access:} @ @ read/write
@end table

@c ----------------- Actors --------------------
@node Actors
@section Actors

@menu
* ac_bug::
* ac_horse::
* ac_killer::
* ac_marble::
* ac_pearl::
* ac_rotor::
* ac_top::
@end menu

@c ----------------- Bug --------------------
@node ac_bug
@subsection ac_bug
@obindex ac_bug

An actor that looks like a small grey ball with two red dots on it. Bugs are
harmless actors that do not affect other actors and they are usually passive.

In contrast to the main actors they can not jump or pass an @ref{it_vortex}, and
will not sink, fall or shatter. Bugs are immortal.

Note that you need to set @samp{controllers} as well as @samp{adhesion} to proper
values if you want a player to control a bug directly. If a bug is owned by a
player @ref{fl_thief} and @ref{st_thief} will steal items from it.

@table @asis
@item @b{Attributes:} common actor attributes
@table @asis
@item @b{adhesion} @ @ @i{values}: number; @ @ @i{default}: @code{0.0}; @ @ @xref{adhesion}
@item @b{controllers} @ @ @i{values}: @code{CTRL_NONE}, @code{CTRL_YIN}, @code{CTRL_YANG}, @code{CTRL_YINYANG}; @ @ @i{default}: @code{CTRL_NONE}; @ @ @xref{controllers}
@item @b{owner} @ @ @i{values}: @code{YIN}, @code{YANG}, @code{nil}; @ @ @i{default}: @code{nil}; @ @ @xref{owner}
@item @b{mass} @ @ @i{values}: positive float number; @ @ @i{default}: @code{0.7}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/ac_bug, 14mm} @b{ac_bug}: color = @code{nil}, controllers = @code{CTRL_NONE}, owner = @code{nil}
@end table

@end table

@c ----------------- Horse --------------------
@node ac_horse
@subsection ac_horse
@obindex ac_horse

A large blue disc like actor. It is called a horse because in some future Enigma
release @ref{ac_marble}s and @ref{ac_pearl}s should be able to ride on it.

In contrast to the main actors it can not jump or pass an @ref{it_vortex}, and
will not sink, fall or shatter. A horse is immortal.

By default a horse is a passive actor. But nevertheless a horse may move along
its own path. A set of attributes let you control the movement in various ways.

The most simple approach just uses the attributes @samp{destination} and
@samp{strength}. You can mark a path marked by an arbitrary number of positions
given as @ref{destination}s. The horse will try to reach the destinations one
in a row with a force given by the strength attribute. As soon as one
destination has been reached the horse targets for the next position and will
start over again as soon as the last position has been reached. In this
@samp{steady} mode the horse is continously accelerated into the direction of
the next destination target. If it misses the destination on the first approach
it will return by a loop again until it finally passes the target position. This
approach is rather crude and not well suited for a precise control needed if the
horse should hit certain stones or move on a well defined trajectory.

Setting @samp{steady} to the value @code{false} causes another accelaration
algorithm that will decelerate the horse on approach to its target position.
This allows a very precise control over the path taken by the horse.

Furtheron you can request anytime the index of the current destination target. You
can even set @samp{destidx} anytime. Note that this index counts the destination
targets starting with 0 and taking every position into account, which might not
be in sync with the destination token number in case a single token part
addresses several positions at a time.

Furtheron you can control the behaviour of the horse when it reaches the last
destination target. It either stops or restarts if the attribute @samp{loop}
is set to @code{true}.

Setting either @samp{destination} to @code{nil}, @samp{destidx} or @samp{strength}
to a negative value causes the horse to stop its automatic travel.

On its move a horse tries to reach the target position. But if the target
position is blocked by a stone, the horse continues its travel targeting the
next destination position as soon as it hits the stone. Thus you can use the
horse to toggle @ref{st_switch} and other active stones.

Whenever the horse reaches a target position it will perform its action. You
can reset the @samp{destination} and other attributes within the callback to
define a new destination target.

Note that you need to set @samp{controllers} as well as @samp{adhesion} to proper
values if you want a player to control a horse directly.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{adhesion} @ @ @i{values}: number; @ @ @i{default}: @code{0.0}; @ @ @xref{adhesion}
@item @b{controllers} @ @ @i{values}: @code{CTRL_NONE}, @code{CTRL_YIN}, @code{CTRL_YANG}, @code{CTRL_YINYANG}; @ @ @i{default}: @code{CTRL_NONE}; @ @ @xref{controllers}
@item @b{owner} @ @ @i{values}: @code{YIN}, @code{YANG}, @code{nil}; @ @ @i{default}: @code{nil}; @ @ @xref{owner}
@item @b{destination}, @ @ @i{values}: position or tokens; @ @ @i{default}: @code{nil} @ @ @xref{destination}
A path given by a sequence of positions.
@item @b{destidx} @ @ @i{values}: integer number; @ @ @i{default}: @code{0}
The index of the targeted destination.
@item @b{loop} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Flag that determines whether @samp{destidx} is reset to its default when the
last destination has been reached.
@item @b{strength} @ @ @i{values}: float number; @ @ @i{default}: @code{+10.0}
A scalar factor for the horse force that drives it to the next destination.
@item @b{steady} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Flag that determines the chosen acceleration algorithm. On steady force the
actor is continuously accelerated in direction to the next destination. If it
misses the destination it will loop. If steady is false the force will switch
its sign as soon as the actor reaches a critical distance. Thus the actor will
reach the destination with nearly no remaining speed.
@item @b{mass} @ @ @i{values}: positive float number; @ @ @i{default}: @code{1.2}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
Performed on every reached destination position or on stone hits when the
destination position is blocked by a stone.

@item @b{Variants:}

@table @asis
@item @image{images/ac_horse, 14mm} @b{ac_horse}: controllers = @code{CTRL_NONE}, owner = @code{nil}
@end table

@end table

@c ----------------- Killer --------------------
@node ac_killer
@subsection ac_killer
@obindex ac_killer

An actor that looks like a white @ref{ac_pearl}, but is a death bringing killer
ball that shatters @ref{ac_marble}s and @ref{ac_pearl}s on contact.

In contrast to the main actors it can not jump or pass an @ref{it_vortex}, and
will not sink, fall or shatter. A killer ball is immortal.

A killer is preset to its standard attribute values, that let both players
control the actor and do assign a higher @samp{adhesion} to it than to
@ref{ac_pearl}s.

Note that even though a killer looks quite dangerous, @ref{fl_thief} and
@ref{st_thief} do steal items from them, if the killer is owned by a player.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{color} @ @ @i{values}: @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{WHITE}; @ @ @i{access}: read only
The color of the killer.
@item @b{adhesion} @ @ @i{values}: number; @ @ @i{default}: @code{2.0}; @ @ @xref{adhesion}
@item @b{controllers} @ @ @i{values}: @code{CTRL_NONE}, @code{CTRL_YIN}, @code{CTRL_YANG}, @code{CTRL_YINYANG}; @ @ @i{default}: @code{CTRL_YINYANG}; @ @ @xref{controllers}
@item @b{owner} @ @ @i{values}: @code{YIN}, @code{YANG}, @code{nil}; @ @ @i{default}: @code{nil}; @ @ @xref{owner}
@item @b{mass} @ @ @i{values}: positive float number; @ @ @i{default}: @code{0.7}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/ac_pearl_white, 14mm} @b{ac_killer}: color = @code{WHITE}, controllers = @code{CTRL_YINYANG}, owner = @code{nil}
@item @image{images/ac_pearl_black, 14mm} @b{ac_killer_black}: color = @code{BLACK}, controllers = @code{CTRL_YINYANG}, owner = @code{nil}
@item @image{images/ac_pearl_white, 14mm} @b{ac_killer_white}: color = @code{WHITE}, controllers = @code{CTRL_YINYANG}, owner = @code{nil}
@end table

@end table

@c ----------------- Marble --------------------
@node ac_marble
@subsection ac_marble
@obindex ac_marble

The main actor in the shape of a large ball, black, white or transparent (glass).
Marbles are versatile actors that can jump, pass @ref{it_vortex}, but on the other hand they
can sink, fall and shatter, too.

As long as the @samp{owner} has an @ref{it_extralife} in his inventory a dying
marble will be resurrected. If no extra life is available a dying actor ends
up in the @samp{state} dead and can no longer be controlled.

The marbles are preset to their standard attribute values. Marbles can be
recolored by using @ref{st_inkwell}, but not by addressing the @samp{color} attribute directly.
The marble's state changes due to events and can be read only, too.

Laser beams shatter black and white marbles, unless they are protected by @ref{it_umbrella}.
Glass marbles are not harmed by laser beams, but break on harsh impacts (particularly
on edges) and therefore cannot push movable stones (unless protected by @ref{it_umbrella}).
Black and white marbles drown in @ref{fl_water} and (though slowly) in @ref{fl_swamp}.
Glass marbles do not drown.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ALIVE}, @code{DEAD}; @ @ @i{default}: @code{ALIVE}; @ @ @i{access}: read only
@xref{state}.
@item @b{color} @ @ @i{values}: @code{BLACK}, @code{WHITE}, @code{GLASS}; @ @ @i{default}: @code{BLACK}; @ @ @i{access}: read only
The color of the marble.
@item @b{adhesion} @ @ @i{values}: number; @ @ @i{default}: @code{1.0}
@xref{adhesion}.
@item @b{controllers} @ @ @i{values}: @code{CTRL_NONE}, @code{CTRL_YIN}, @code{CTRL_YANG}, @code{CTRL_YINYANG}; @ @ @i{default}: @code{CTRL_NONE}
@xref{controllers}.
@item @b{owner} @ @ @i{values}: @code{YIN}, @code{YANG}, @code{nil}
@i{default}: @code{nil}; @ @ @xref{owner}.
@item @b{mass} @ @ @i{values}: positive float number
@i{default}: @code{1.0} for black and white marbles, @code{0.5} for glass marbles; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/ac_marble_black, 14mm}  @b{ac_marble}: color = @code{BLACK}, controllers = @code{CTRL_YIN}, owner = @code{YIN}
@item @image{images/ac_marble_black, 14mm} @b{ac_marble_black}: color = @code{BLACK}, controllers = @code{CTRL_YIN}, owner = @code{YIN}
@item @image{images/ac_marble_white, 14mm} @b{ac_marble_white}: color = @code{WHITE}, controllers = @code{CTRL_YANG}, owner = @code{YANG}
@item @image{images/ac_marble_glass, 14mm} @b{ac_marble_glass}: color = @code{GLASS}, controllers = @code{CTRL_YIN}, owner = @code{YIN}
@end table

@end table

@c ----------------- Pearl --------------------
@node ac_pearl
@subsection ac_pearl
@obindex ac_pearl

The main actor for meditation levels in the shape of a small ball, available
in black and white; glass pearls are planned for 1.30.
Pearls are like marbles versatile actors that
can jump, pass @ref{it_vortex}, but on the other hand they can sink, fall and
shatter, too.

As long as the @samp{owner} has an @ref{it_extralife} in his inventory a dying
marble will be resurrected. If no extra life is available a dying actor ends
up in the @samp{state} dead and can no longer be controlled.

The pearls are preset to their standard attribute values. The pearls state
changes due to events and can be read only.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ALIVE}, @code{DEAD}; @ @ @i{default}: @code{ALIVE}; @ @ @xref{state}; @ @ @i{access}: read only
@item @b{color} @ @ @i{values}: @code{BLACK}, @code{WHITE}; @ @ @i{default}: @code{WHITE}; @ @ @i{access}: read only
The color of the pearl.
@item @b{adhesion} @ @ @i{values}: number; @ @ @i{default}: @code{1.0}; @ @ @xref{adhesion}
@item @b{controllers} @ @ @i{values}: @code{CTRL_NONE}, @code{CTRL_YIN}, @code{CTRL_YANG}, @code{CTRL_YINYANG}; @ @ @i{default}: @code{CTRL_NONE}; @ @ @xref{controllers}
@item @b{owner} @ @ @i{values}: @code{YIN}, @code{YANG}, @code{nil}; @ @ @i{default}: @code{nil}; @ @ @xref{owner}
@item @b{mass} @ @ @i{values}: positive float number; @ @ @i{default}: @code{0.7}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/ac_pearl_white, 14mm} @b{ac_pearl}: color = @code{WHITE}, controllers = @code{CTRL_YINYANG}, owner = @code{YIN}
@item @image{images/ac_pearl_black, 14mm} @b{ac_pearl_black}: color = @code{BLACK}, controllers = @code{CTRL_YINYANG}, owner = @code{YIN}
@item @image{images/ac_pearl_white, 14mm} @b{ac_pearl_white}: color = @code{WHITE}, controllers = @code{CTRL_YINYANG}, owner = @code{YIN}
@end table

@end table

@c ----------------- Rotor --------------------
@node ac_rotor
@subsection ac_rotor
@obindex ac_rotor

A rotating actor build up of 4 greenish cudgels. It is a death bringing actor
that shatters @ref{ac_marble}s and @ref{ac_pearl}s on contact. Its behaviour
is identical to an @ref{ac_top}.

In contrast to the main actors it can not jump or pass an @ref{it_vortex}, and
will not sink, fall or shatter. A rotor is immortal.

Rotors do usually hunt mortal actors trying to shatter them. They accelerate by
force given by the attribute @samp{strength}, but they limit their hunt to
actors in the given @samp{range}. If no attackable actor remains in this range
they return to their initial position if the attribute @samp{gohome} is
@samp{true}.

Note that in case multiple attackable actors are in range the rotor gets
confused and tries to attack the center of its victims. But if you set the
attribute @samp{attacknearest} to @samp{true} the rotor will concentrate just
on the nearest victim. By adjusting the attribute @samp{prefercurrent} you
can instruct the rotors to prefer victims of the current active player with
a certain likelihood.

Note that you need to set @samp{controllers} as well as @samp{adhesion} to proper
values if you want a player to control a rotor directly. If a rotor is owned by a
player @ref{fl_thief} and @ref{st_thief} will steal items from it.

An @ref{ac_marble} will temporarily transform into a rotor when it activates
an @ref{it_drop}. During the 5 seconds of transformation the actor is a real
immortal rotor with the identity inclusive the @samp{essential_id} of the
former marble. After the period is over it transforms back to its original
kind.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{range} @ @ @i{values}: float number; @ @ @i{default}: @code{5.0}
The distance up to which victims are hunted.
@item @b{strength} @ @ @i{values}: float number; @ @ @i{default}: @code{+10.0}
The force that drives the rotor to its victims.
@item @b{gohome} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Behaviour of a rotor without victim in range.
@item @b{attacknearest} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Behaviour of a rotor with multiple victims in range
@item @b{prefercurrent} @ @ @i{values}: float number in range [0.0 - 1.0]; @ @ @i{default}: @code{+0.0}
Likelihood of attack strategy. You will usually use this attribute in
combination with @samp{attacknearest} set to @samp{true}. The Level
@samp{Toreador} is an example of the behavior of such rotors.
@item @b{mass} @ @ @i{values}: positive float number; @ @ @i{default}: @code{0.8}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/ac_rotor, 14mm} @b{ac_rotor}: color = @code{nil}, controllers = @code{CTRL_NONE}, owner = @code{nil}
@end table

@end table

@c ----------------- Top --------------------
@node ac_top
@subsection ac_top
@obindex ac_top

A fast rotating, greenish disk like actor. It is a death bringing actor
that shatters @ref{ac_marble}s and @ref{ac_pearl}s on contact. Its behaviour
is identical to an @ref{ac_rotor}.

In contrast to the main actors it can not jump or pass an @ref{it_vortex}, and
will not sink, fall or shatter. A top is immortal.

Tops do usually hunt mortal actors trying to shatter them. They accelerate by
force given by the attribute @samp{strength}, but they limit their hunt to
actors in the given @samp{range}. If no attackable actor remains in this range
they return to their initial position if the attribute @samp{gohome} is
@samp{true}.

Note that in case multiple attackable actors are in range the top gets
confused and tries to attack the center of its victims. But if you set the
attribute @samp{attacknearest} to @samp{true} the top will concentrate just
on the nearest victim. By adjusting the attribute @samp{prefercurrent} you
can instruct the top to prefer victims of the current active player with
a certain likelihood.

Note that you need to set @samp{controllers} as well as @samp{adhesion} to proper
values if you want a player to control a top directly. If a top is owned by a
player @ref{fl_thief} and @ref{st_thief} will steal items from it.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{range} @ @ @i{values}: float number; @ @ @i{default}: @code{5.0}
The distance up to which victims are hunted.
@item @b{strength} @ @ @i{values}: float number; @ @ @i{default}: @code{+10.0}
The force that drives the top to its victims.
@item @b{gohome} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Behaviour of a top without victim in range.
@item @b{attacknearest} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
Behaviour of a top with multiple victims in range
@item @b{prefercurrent} @ @ @i{values}: float number in range [0.0 - 1.0]; @ @ @i{default}: @code{+0.0}
Likelihood of attack strategy. You will usually use this attribute in
combination with @samp{attacknearest} set to @samp{true}. The Level
@samp{Toreador} is an example of the behavior of such rotors.
@item @b{mass} @ @ @i{values}: positive float number; @ @ @i{default}: @code{0.8}; @ @ @i{access}: read only
@end table

@item @b{Messages:} none

@item @b{Variants:}

@table @asis
@item @image{images/ac_top, 14mm} @b{ac_top}: color = @code{nil}, controllers = @code{CTRL_NONE}, owner = @code{nil}
@end table

@end table

@c ----------------- Actor Features --------------------
@node Actor Features
@section Actor Features

@menu
* Flying Actors::        Flying Actors
@end menu

@c ----------------- Flying Actors --------------------
@node Flying Actors
@subsection Flying Actors

Ball like actors, namely @ref{ac_marble} and @ref{ac_pearl} are able to fly for
short period of time if they get catapulted by some item.

Currently there are portable @ref{it_spring} that let actors jump on activation,
static @ref{it_springboard} that catapult crossing actors and @ref{it_vortex}
that catapult warping actors.

A flying actor can pass lethal grids with @ref{fl_water}, @ref{fl_abyss},
@ref{it_trap} and even laser beams. But most stones will block flying actors,
even some hollow ones like @ref{st_grate} or @ref{st_oneway}. But some others as
@ref{st_door} or hollow @ref{Standard Stones} let flying actors pass.

While flying an actor can not pick up any item. But the actor can still drop
items. Activation of a spring while sinking in @ref{fl_water} or @ref{fl_swamp}
lets the actor jump immediately out of them and starts the sinking process from
scratch anew when landing on such a floor.


@c ===================  Other Objects  =======================

@node Other Objects
@chapter Other Objects

@menu
* Visible Others::    Special gaming objects
* Gadgets::           Tools for plug and play construction of levels
@end menu


@node Visible Others
@section Visible Others

@menu
* ot_cannonball::     Projectile of a Spitter
* ot_rubberband::     Rubberband with forces
* ot_wire::           Stone connection that transfers impulses
@end menu


@c ----------------- Cannonball --------------------
@node ot_cannonball
@subsection ot_cannonball
@obindex ot_cannonball

A short living projectile emitted by an @ref{st_spitter}. It is an internal
object that can not be directly instantiated. It is listed here just for
completeness.

@c ----------------- Rubberband --------------------
@node ot_rubberband
@subsection ot_rubberband
@obindex ot_rubberband

An orange link between two objects that can apply attracting or repelling forces
to them.

The two connected objects are called anchors. The attribute @samp{anchor1} holds
the first object's reference that must be an actor. The @samp{anchor2} references
the second object that can either be another actor or a stone. Both objects
must exist to @ref{add} a rubberband to the world. If the stone sinks, breaks
or is killed otherwise the rubberband will be destroyed, too.

Both anchor objects will update their attributes @ref{rubbers} and @ref{fellows}
to list this rubberband and the connected object for purposes of evaluation.

The force that is applied between the objects can be configured by several
attributes. Every rubberband has a natural @samp{length} at which it does not
apply any force to the actors. The more the rubberband is extended from this
point it applies a force of the given @samp{strength}. A positive strength is
a natural attracting force, whereas a negative strength would repel the actors.

A rubberband that is shorter than its natural @samp{length} would normally not
apply any force. But this special rubber allows you to set a @samp{threshold}
where the rubberband starts to apply the opposite directed forces onto the
actors, like a spring would do. Thus a positive @samp{strength} would lead to a
repelling force, a negative one to an attracting force. A rubberband with a
length in between @samp{threshold} and @samp{length} will apply no forces.
If you set the attribute @samp{length} to the value @code{AUTOLENGTH}, the
length of the rubberband is determined from the distance of its two endpoints
at the time of creation.

In some cases you do want to limit the length of the rubberband. You can do this
by setting @samp{min} and @samp{max} attributes. Actors will bounce on these
limits. Do not try to use artificial large @samp{strength} values instead to
ensure length limits, as this could lead to extreme forces causing unexpected and
unstable actor movements.

If you set @samp{min} or @samp{max} limits, extraordinary events like actor
warping, actor resurrection, moving anchor stones or simply rubberbands that are
created with an off limit length can cause trouble. When such a limit violation
is detected an action is performed with a value @samp{false}. You may want to kill
the rubberband or react in another way by a callback function. The default
handling is an application of a constant force to bring the actors back within
the limits. This force value is given by @ref{RubberViolationStrength} and
defaults to @samp{50.0}. If you really need to assure that the player is not able
to violate the limits any further you may need to increase this constant.

Rubberbands can be cut by @ref{st_scissors}, by an @ref{it_vortex} or
@ref{it_wormhole} with a set @samp{scissors} attribute, by receiving a
@ref{kill} message, by one of the anchors receiving a @ref{disconnect} message
or a stone anchor that ceases to exist.

Rubberbands can be dynamically generated by @ref{it_rubberband} and
@ref{st_rubberband}.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{anchor1} @ @ @i{values}: actor object; @ @ @i{default}: @code{nil}
Object reference or name of an actor that the rubber will be connected to. Note
that the reference will be immediately evaluated and thus the actor must exist
already.
@item @b{anchor2} @ @ @i{values}: actor or stone object; @ @ @i{default}: @code{nil}
Object reference or name of an actor or a stone that the rubber will be
connected to. Note that the reference will be immediately evaluated and thus the
actor or stone must exist already.
@item @b{strength} @ @ @i{values}: number; @ @ @i{default}: @code{10.0}
The force strength.
@item @b{length} @ @ @i{values}: positive number or @code{AUTOLENGTH}; @ @ @i{default}: @code{1.0}
The natural length above which forces are applied.
@item @b{threshold} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The length smaller than the natural length below which inverted forces are applied.
@item @b{min} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The minimum length at which actors bounce.
@item @b{max} @ @ @i{values}: positive number or zero; @ @ @i{default}: @code{0.0}
The maximum length at which actors bounce.
@end table

@item @b{Messages:} none
@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
An action will be performed with value @samp{false} on violation of a min or max
limit. Additionally an action will be performed on behalf of @ref{it_rubberband}
after application and creation of this rubberband with an action value of
@samp{true}.
@end table

@c ----------------- Wirecontrol --------------------
@node ot_wire
@subsection ot_wire
@obindex ot_wire

A wire is a purple wire connecting two stones that transfers every stone pushing
impulse from one stone to the other and vice versa. Thus both stones will move
on the impulse if they are movable at all and not blocked in the direction of
the impulse. The impulses may originate from an actor hitting a stone, an
@ref{it_puller}, an @ref{st_rotator}, an @ref{st_stoneimpulse}.

A single stone can be wired to many other stones. All these @ref{fellows} will
move on an impulse. But the impulses will not be propagated to further stones
that are wired themselves to any of the fellows. Just the direct wired stones
will move.

But you can wire two stones just once. Any subsequent additional wire between
two already wired stones will cut the old wire prior establishing the new one.

You can request the wires connected to a stone by the stone's @ref{wires}
attribute. As it is tedious to evaluate both anchors, every stone supports
an attribute @ref{fellows} that reports the connected objects.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{anchor1} @ @ @i{values}: stone object; @ @ @i{default}: @code{nil}
Object reference or name of a stone that the wire will be connected to. Note
that the reference will be immediately evaluated and thus the stone must exist
already.
@item @b{anchor2} @ @ @i{values}: stone object; @ @ @i{default}: @code{nil}
Object reference or name of a stone that the wire will be connected to. Note
that the reference will be immediately evaluated and thus the stone must exist
already.
@end table

@item @b{Messages:} none
@item @b{Actions:} none
@end table

@node Gadgets
@section Gadgets


@menu
* ot_counter::   Threshold Switch
* ot_timer::     Invisible Timer
@end menu

@c ----------------- Counter Gadget --------------------
@node ot_counter
@subsection ot_counter
@obindex ot_counter

A counter that switches on given thresholds. As a supplement to single switch
like objects as @ref{it_trigger}, @ref{st_switch}, @ref{st_laserswitch},
@ref{st_coinslot}, @ref{st_key}, @ref{st_floppy}, etc. this gadget allows to
react on a given number of these switches to be switched @samp{ON} while the
others being switched @samp{OFF}.

The attribute @samp{state} represents the count of switches in @samp{ON} state.
Due to the @ref{Snapshot Principle} you need to set it to the initial number
of @samp{ON} switches. All switches need to declare the counter gadget as their
@samp{target}. They all need to send a @code{"signal"} message as @samp{action}.
The counter gadget increases or decreases its count state on every received
signal message thus keeping it up to date.

The gadget itself can perform actions by usage of @ref{Object State} dependent
targets and actions.

E.g. let us assume 8 @ref{it_trigger}s and 8 @ref{st_box}es. Two boxes are
initially on top of two triggers. A door should open as soon as the user
succeeds in pushing all boxes onto the triggers.

@example
ti["t"] = @{"it_trigger", target="mycounter", action="signal"@}
ti["b"] = @{"st_box"@}
ti["o"] = ti["t"] .. ti["b"]
ti["d"] = @{"st_door", "mydoor"@}
wo(ti, " ", @{"t t t o t o t t",
             "b b b   b   b b",
	     "      d   @@    "@})
wo:add(@{"ot_counter", "mycounter", state=2, target="mydoor", action_7="close", action_8="open"@})
@end example

Note that it is not sufficient to send an @code{"open"} message on a
@samp{state} count of 8, as this event occurs, when 7 boxes are on top of
triggers and the last trigger is pressed by the actor itself, too. When the
actor leaves the 8th trigger the gadget state decreases its state to 7 and
sends a @code{"close"} message to the door.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: numbers; @ @ @i{default}: 0 @ @ @xref{state}
The count of switches in @samp{ON} state.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Increases state on a value of @samp{1}, and decreases on a value of @samp{0}.
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
Sends an action with value @samp{true} just on explicitly given
@ref{Object State} dependent target or action attributes. No default
@code{"toggle"} actions will be issued on other states.
@end table


@c ----------------- Timer Gadget --------------------
@node ot_timer
@subsection ot_timer
@obindex ot_timer

This gadget can be used to trigger a delayed single or periodic events. It is
nearly identical to the @ref{st_timer}, but does neither require a grid position
nor disturb the user by a pulsing animation.

Note that this is an exceptional object as its default state is @samp{ON} to
support the most common case of immediately running timers.

A single shot, not looping timer will send an action value of @samp{true}. A
looping timer will alternate the boolean action values starting with value
@samp{true}. You can use @ref{inverse} to start with a value of @samp{false}.

If you stop a timer by switching it off, no further events will be performed.
Restarting the timer by switching it on again will restart the timer like
a new timer.

The time interval to the first event and between subsequent events can be relied
on to an accuracy of 0.01 seconds. But due to performance reasons and visibility
of the reactions timers should not be set to intervals below 0.1 seconds. An
interval of less than 0.01 seconds is not valid for a looping timer.

@table @asis
@item @b{Attributes:}

@table @asis
@item @b{state}, @ @ @i{values}: @code{ON}, @code{OFF}; @ @ @i{default}: @code{ON} @ @ @xref{state}
An @samp{ON} state timer is running. A timer in state @samp{OFF} is reset and
waiting for reactivation.
@item @b{interval} @ @ @i{values}: positive number; @ @ @i{default}: @code{1.0}
Number of seconds until the first and between subsequent events. The interval
must be larger or equal 0.01 seconds for looping timers.
@item @b{loop} @ @ @i{values}: @code{true}, @code{false}; @ @ @i{default}: @code{true}
A looping timer will send periodic events.
@end table

@item @b{Messages:}

@table @asis
@item @b{signal} @ @ @xref{signal}
Switches on at value @samp{1}, and off at values @samp{0}.
@item @b{on} @ @ @xref{on}
@item @b{off} @ @ @xref{off}
@end table

@item @b{Action:} @ @ @xref{target}, @ @ @xref{action}
The action value starts with @samp{true} and alternates on every event between
@samp{false} and @samp{true}. A timer that is reset starts again with value
@samp{true}
@end table

@c ===================  Libraries  =======================

@node Libraries
@chapter Libraries

Libraries do contain extensions that are not necessary for every level. By
outsourcing them into separate files they do not get loaded if not used. This
improves the level load time and runtime resource consumption. But as a level
author you have to declare the usage of a library by an XML metadata
@samp{dependency} element within the @ref{<compatibility>} element. The
necessary line of code is listed within every library description.

Some libraries contain collections of useful functions and methods. They are
described in this chapter. Other libraries do contain @ref{Resolvers} and are
described just there.

@menu
* Basic Functions::  About basic lua functions and standard lua libraries.
* liblua::           General methods for tables.
* libmath::          Mathematical algorithms, like random permutations.
* libmap::           Methods for API 2-maps.
* libimport::        Methods for importing external level files.
* libsoko::          A library to interpret Sokoban level files.
@end menu

@node Basic Functions
@section Basic Functions

Enigma supports most Lua 5.1 and above statements, i.e. you can freely use
tables and control structures in your level, as you would expect. However, some
Lua functions have been deactivated for security reasons or to ensure
upwards compatibility. These are @samp{dofile}, @samp{module}, @samp{require}
and most or all functions of the standard libraries @samp{package}, @samp{io}
and @samp{os}. You should use the @ref{<compatibility>}-tag to include external
libraries instead of @samp{require}, @samp{dofile} or @samp{package}, and
@samp{print} for output to stdout instead of @samp{io}. The @samp{print}
function is pretty useful for developing and debugging complex levels, but
should not appear in the level's final version anymore.

Of Lua's built-in mathematical functions you may use any of the following:
@samp{math.abs}, @samp{math.acos}, @samp{math.asin}, @samp{math.atan},
@samp{math.atan2}, @samp{math.ceil}, @samp{math.cos}, @samp{math.cosh},
@samp{math.deg}, @samp{math.exp}, @samp{math.floor}, @samp{math.fmod},
@samp{math.frexp}, @samp{math.huge}, @samp{math.ldexp}, @samp{math.log},
@samp{math.log10}, @samp{math.max}, @samp{math.min}, @samp{math.modf},
@samp{math.pi}, @samp{math.pow}, @samp{math.rad}, @samp{math.random},
@samp{math.sin}, @samp{math.sinh},  @samp{math.sqrt}, @samp{math.tan},
@samp{math.tanh}.

All trigonometric functions use radians, you can use @samp{math.deg} and
@samp{math.rad} to convert between radians and degrees. For the differences
between @samp{math.mod}, @samp{%}, and @samp{math.fmod} see @ref{lib.lua.mod}.

While you have access to nearly all mathematical functions Lua defines, Enigma
uses an own random generator, which you access via @samp{math.random} with the
same syntax as Lua's random generator. To ensure stability in future versions
of Enigma, @samp{math.randomseed} is disabled.

Please read the online manual of
@uref{http://www.lua.org/manual/5.1/, Lua 5.1} for more detailed information.


@node liblua
@section liblua

This library of basic extensions to the Lua language is described as of release
1.

You can load it by adding a @samp{dependency} element to the
@ref{<compatibility>} XML Metadata element as follows:

@example
  <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/liblua}" @i{el}:@b{id}="@var{lib/liblua}" @i{el}:@b{release}="@var{1}" @i{el}:@b{preload}="@var{true}"/>
@end example

@menu
* lib.lua.combine_tables::  Collect entries of anonymous Lua-tables into a common table.
* lib.lua.deep_copy::       Complete copies of Lua-tables.
* lib.lua.mod::             A modulo operation.
* lib.lua.print_table::     Print tables for debug reasons.
* lib.lua.shuffle::         Shuffle arbitrary anonymous Lua-tables.
* lib.lua.to_string::       Takes anything as argument and tries to return a sensible description.
@end menu

@c ----------------- combine_tables --------------------

@node lib.lua.combine_tables
@subsection lib.lua.combine_tables
@findex lib.lua.combine_tables

@samp{combine_tables} combines all entries of a set or table of tables into one
common table (i.e., it joins the subtables). As some of the subtables can have
equally named entries, the first subtable has highest priority, the second
subtable second priority etc.

@table @asis
@item @b{Syntax:}
@b{lib.lua.combine_tables}(@i{overtable})

@b{lib.lua.combine_tables}(@i{table1}, @i{table2}, ...)

@table @asis
@item @i{overtable}
A table of tables: @samp{overtable = @{table1, table2, ...@}}

@item @i{table1}, @i{table2}, ...
Lua tables to be joined.
@end table

@item @b{Syntax Samples:}
@example
all_contacts = lib.lua.combine_tables(telephone_numbers, email_addresses)
@end example

@item @b{Details:}
Just as groups can be joined by @samp{grp1 + grp2}, it can sometimes be
necessary to join anonymous tables, as well.
In most situations, object grouping should be used instead, but when one works
with more abstract data (like names of objects instead of objects, or tables
holding design information), @samp{combine_tables} can be useful.

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- deep_copy --------------------

@node lib.lua.deep_copy
@subsection lib.lua.deep_copy
@findex lib.lua.deep_copy

@samp{deep_copy} returns a copy of its argument, where table entries are
not copied as memory references (like Lua typically does), but complete
(thereby called "deep copy").

@table @asis
@item @b{Syntax:}
@b{lib.lua.deep_copy}(@i{source})

@table @asis
@item @i{source}
The object to be copied.
@end table

@item @b{Syntax Samples:}
@example
a = @{5@}
b = a
c = lib.lua.deep_copy(a)
b[1] = 4
@end example

After these four commands, @samp{a[1]} and @samp{b[1]} will both be @samp{4},
but @samp{c[1]} will still be @samp{5}.

@item @b{Details:}
Metatables are transferred, but not deep-copied.
Userdata (like tiles and positions) is not guaranteed to be deep-copied.

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- mod --------------------

@node lib.lua.mod
@subsection lib.lua.mod
@findex lib.lua.mod

A wrapper for the modulo operation.

@table @asis
@item @b{Syntax:}
@b{lib.lua.mod}(@i{value}, @i{modul})

@table @asis
@item @i{value}, @i{modul}
Numbers. @samp{modul} must be positive (non-zero).
@end table

@item @b{Syntax Samples:}
@example
lib.lua.mod(7*7, 17)
lib.lua.mod(5.3, 1/3)
lib.lua.mod(no["marble"].x, 1)
@end example

@item @b{Details:}
Lua 5.0 used @samp{math.mod} as modulo operation, this function is not
available in Lua 5.1 anymore, and hence not available in Enigma. Lua 5.1
provides @samp{%} and @samp{math.fmod}. Whereas all three operations agree on
positive numbers and zero as @samp{value}, there are differences on negative
numbers:
@example
Lua 5.0:  math.mod(-1, 4) == -1
Lua 5.1:  math.fmod(-1, 4) == -1
Lua 5.1:  (-1)%4 == 3
lib.lua:  lib.lua.mod(-1, 4) == 3
@end example
While the Lua-own modulo functions yield results even for negative
@samp{modul} (with varying signs of the outcome), @samp{lib.lua.mod} will raise
an error if @samp{modul <= 0}, and the result @samp{r} is otherwise guaranteed
to be @code{0 <= r < modul}.

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- print_table --------------------

@node lib.lua.print_table
@subsection lib.lua.print_table
@findex lib.lua.print_table

@samp{print_table} is a debug command, which uses the API's @samp{print}
command to recursively print its argument to the standard output.

@table @asis
@item @b{Syntax:}
@b{lib.lua.print_table}(@i{table}, @i{prefix}, @i{depth})

@table @asis
@item @i{table}
The table to be printed.

@item @i{prefix}
A string which will be printed before the table as a
separator. Can be @samp{nil}.

@item @i{depth}
@samp{nil} in normal use, @samp{-1} if you want to suppress the recursion.
@end table

@item @b{Syntax Samples:}
@example
a = @{1, [5]=2, "Hello", other_table = @{x = 4, y = 5, z = "World"@}@}
lib.lua.print_table(a, nil, -1)
lib.lua.print_table(a, "--> ")
@end example

@item @b{Details:}
@samp{print_table} is recursive, i.e. a table with table
as entries will call @samp{print_table} again. To avoid
infinite loops, @samp{depth} is used internally to count
the depth level of the recursion. The recursion currently
stops on depth 5. Set @samp{depth} to @samp{-1} to stop
recursion entirely.

Use @samp{print_table} only for debugging and testing, it
is not meant as an element of gameplay.
@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- shuffle --------------------

@node lib.lua.shuffle
@subsection lib.lua.shuffle
@findex lib.lua.shuffle

@samp{shuffle} randomly resorts its argument, a numerical table.

@table @asis
@item @b{Syntax:}
@i{result} = @b{lib.lua.shuffle}(@i{source})

@table @asis
@item @i{source}
The table to be shuffled (only the numerical entries will be shuffled).
@end table

@item @b{Syntax Samples:}
@example
orientations = lib.lua.shuffle(@{NORTH, SOUTH, EAST, WEST@})
a = @{1, 2, 3, "r", @{"x", "y", "z"@}, 4@}
b = lib.lua.shuffle(a)
@end example

A typical result for @samp{b} would be
@example
b = @{"r", 4, 2, @{"x", "y", "z"@}, 1, 3@}
@end example

@item @b{Details:}
The result is a permutation of the numerical entries of the source table,
starting with entry 1 and ending with entry @samp{table.getn(@i{source})}. All
other entries will simply be copied into @samp{result}. All copies are shallow
copies, i.e. table-valued and userdata-valued entries (like objects) are not
copied, just references (pointers) to them. Use @ref{lib.lua.deep_copy} to
create a deep copy of the shuffled table, if needed. @samp{result} will use the
same metatable as @samp{source}, and metamethods will be used during the copy
and shuffling process.

Currently, @samp{lib.lua.shuffle} can shuffle only tables. To shuffle groups,
use the group method of the same name:
@example
mygroup:shuffle()
@end example

Shuffling a @ref{libmap}-map results in a map with shuffled rows, i.e. the
x-coordinates of all tile keys are kept constant. Use @ref{Rotating and
Mirroring Maps} to shuffle the columns.

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- to_string --------------------

@node lib.lua.to_string
@subsection lib.lua.to_string
@findex lib.lua.to_string

@samp{to_string} is a debug function. It may take anything as argument, and
tries to return a sensible string describing the type and, if possible, the
content of the argument.

@table @asis
@item @b{Syntax:}
@b{lib.lua.to_string}(@i{arg})

@table @asis
@item @i{arg}
The argument to be described.
@end table

@item @b{Syntax Samples:}
@example
print(lib.lua.to_string(strange_variable))
@end example

@item @b{Details:}
@samp{to_string} is meant for debugging Lua code. Sometimes it happens that a
variable is not what the author expected to be, and selecting the correct
output method becomes try-and-error. @samp{to_string} is a fast shortcut to
this. It returns the content of strings, numbers, booleans, tables, positions,
and groups. It distinguishes ordinary tables from @ref{libmap}-maps. For
objects, it returns their name and position, for position lists, it returns the
total number of positions. It further recognizes nil, tile and tiles.

Use @samp{to_string} only for debugging and testing, it
is not meant as an element of gameplay.

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- libmath --------------------
@node libmath
@section libmath

This library of basic mathematical extensions is described as of release 1.

You can load it by adding a @samp{dependency} element to the
@ref{<compatibility>} XML Metadata element as follows:

@example
  <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/libmath}" @i{el}:@b{id}="@var{lib/libmath}" @i{el}:@b{release}="@var{1}" @i{el}:@b{preload}="@var{true}"/>
@end example

It preloads automatically the library @ref{liblua}.

@menu
* lib.math.combinations::       Calculates all possible combinations of a set.
* lib.math.cubic_polynomial::   Calculates the result of a cubic polynomial.
* lib.math.cyclic_permutation:: Random cyclic permutation.
* lib.math.digits::             Decomposes a number into digits for an arbitrary base.
* lib.math.manhattan_distance:: Calculates the Manhattan distance of positions.
* lib.math.mark_components::    Calculate connected components of a group of floors.
* lib.math.permutation::        Random permutation.
* lib.math.random_vector::      A table with random entries.
* lib.math.steps::              A function to classify a number in intervals.
@end menu

@c ----------------- combinations --------------------

@node lib.math.combinations
@subsection lib.math.combinations
@findex lib.math.combinations

@samp{lib.math.combinations} returns a table of all combinations of
@samp{depth} entries, each of which is chosen from @samp{digits}.

@table @asis
@item @b{Syntax:}
@b{lib.math.combinations}(@i{depth}, @i{digits})

@table @asis
@item @i{depth}
A positive integer.

@item @i{digits}
A positive integer or a table with numerical entries.
@end table

@item @b{Syntax Samples:}
@example
lib.math.combinations(2, 2)
 == @{ @{1, 1@}, @{1, 2@}, @{2, 1@}, @{2, 2@} @}
lib.math.combinations(3, @{7, 8, "a"@})
 == @{ @{7,7,7@}, @{7,7,8@}, @{7,7,"a"@},
       @{7,8,7@}, @{7,8,8@}, @{7,8,"a"@},
       @{7,"a",7@}, @{7,"a",8@}, @{7,"a","a"@},
       @{8,7,7@}, ... @}
@end example

@item @b{Details:}
Mathematically, it builds the leafs of an @samp{#digits}-ary tree
of depth @samp{depth}.

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- cubic_polynomial --------------------

@node lib.math.cubic_polynomial
@subsection lib.math.cubic_polynomial
@findex lib.math.cubic_polynomial

@samp{cubic_polynomial} returns the result of the following polynomial with
coefficients in @samp{a}:
@example
a[10]*y*y*y + a[9]*x*y*y + a[8]*x*x*y + a[7]*x*x*x
  + a[6]*y*y + a[5]*x*y + a[4]*x*x + a[3]*y + a[2]*x + a[1]
@end example

@table @asis
@item @b{Syntax:}
@b{lib.math.cubic_polynomial}(@i{a}, @i{x}, @i{y})

@table @asis
@item @i{a}
A table with numerical entries @samp{a[1]} to @samp{a[10]}. The entries may be
@samp{nil} (i.e. missing), then they are interpreted as zero.

@item @i{x}, @i{y}
Numbers.

@end table

@item @b{Syntax Samples:}
@example
lib.math.cubic_polynomial(@{1, a, b@}, x, y) == a*x + b*y + 1
@end example

@item @b{Details:}
You can use @samp{lib.math.random_vector(10, ...)} and a modulo operation to
easily form a random pattern of a floor, or choose the coefficients to your own
liking. Entries in @samp{a} which are not numbers are considered zero.

@item @b{Full Example:}
This is an excerpt from "Weirdly Wired" and demonstrates the use of
@samp{cubic_polynomial} inside a custom resolver to create random, but
patternlike floors:
@example
[...]
floors = @{ti[" "], ti["a"], ti["b"], ti["c"]@}
polynom = lib.math.random_vector(10, 4)

function myresolver(key, x, y)
  if key == " " then
    return floors[lib.math.cubic_polynomial(a, x, y) % (#floors) + 1]
  elseif
    [...]
  else
    return ti[key]
  end
end

w, h = wo(myresolver, " ", @{
[...]
@end example
"Weirdly Wired" is explained in detail in section @ref{Weirdly Wired}.
@end table

@c ----------------- cyclic_permutation --------------------

@node lib.math.cyclic_permutation
@subsection lib.math.cyclic_permutation
@findex lib.math.cyclic_permutation

@samp{cyclic_permutation} returns a random permutation (i.e. a random shuffling)
of the numbers 1 to @samp{n}, which is cyclic: There exists a closed path from
any number to any other number (see details below).

@table @asis
@item @b{Syntax:}
@b{lib.math.cyclic_permutation}(@i{n})

@table @asis
@item @i{n}
A positive integer.
@end table

@item @b{Syntax Samples:}
@example
lib.math.cyclic_permutation(#no["marbles#*"])
@end example

@item @b{Details:}
A cyclic permutation is a special kind of permutation, which has only one
cycle. The easiest way is to give an example for a cyclic permutation:
@example
8, 1, 2, 9, 3, 7, 4, 6, 10, 5
@end example
We may write this as:
@example
1 -> 8
2 -> 1
3 -> 2
...
@end example
We can now put all of these together into a sequence:
@example
1 -> 8 -> 6 -> 7 -> 4 -> 9 -> 10 -> 5 -> 3 -> 2 -> 1
@end example
This is, the sequence creates a single cycle through all 10 numbers.
This is not always possible with a general permutation.

If you need a fixpoint-free permutation, you might choose to use a cyclic
permutation instead, although not every fixpoint-free permutation is cyclic.

@item @b{Full Example:}
If you want to connect an arbitrary number of meditation marbles with
rubberbands in a cyclic manner, but otherwise randomly, you can use
@samp{lib.math.cyclic_permutation}:
@example
marbles = no["marbles#*"]
p = lib.math.cyclic_permutation(#marbles)

for j = 1, #marbles do
  wo:add(@{"ot_rubberband", anchor1 = marbles[j], anchor2 = marbles[p[j]]@})
end
@end example
If you want to connect them in a linear way, you can either remove a step in
the loop:
@example
[...]
for j = 1, #marbles - 1 do
[...]
@end example
or use @samp{lib.math.permutation} in the following way:
@example
marbles = no["marbles#*"]
p = lib.math.permutation(#marbles)

for j = 1, #marbles - 1 do
  wo:add(@{"ot_rubberband", anchor1 = marbles[p[j]], anchor2 = marbles[p[j+1]]@})
end
@end example
@end table

@c ----------------- digits --------------------

@node lib.math.digits
@subsection lib.math.digits
@findex lib.math.digits

@samp{lib.math.digits} returns a table whose elements are the digits of
@samp{number} in base @samp{base}. @samp{base} can be a positive integer (e.g.
3 to get ternary) as well as a table (then the table entries with numerical
keys will be used as digits).

@table @asis
@item @b{Syntax:}
@b{lib.math.digits}(@i{number}, @i{base} [, @i{zero_is_empty}])

@table @asis
@item @i{number}
A non-negative integer.

@item @i{base}
A positive integer other than 1, or a table with numerical keys.

@item @i{zero_is_empty}
If @code{number} is zero, a table containing the zero-th digit is returned by
default. If @code{zero_is_empty} is @code{true}, an empty table is returned
instead.
@end table

@item @b{Syntax Samples:}
@example
lib.math.digits(13, 2) == @{1, 0, 1, 1@}
lib.math.digits(15, 16) == @{15@}
lib.math.digits(17, 3) == @{2, 2, 1@}
lib.math.digits(17, @{2, "b", 5@}) == @{5, 5, "b"@}
@end example

The following function can be used to get a table with hexadecimal entries:
@example
lib.math.digits(x, @{0,1,2,3,4,5,6,7,8,9,"A","B","C","D","E","F"@})
@end example

@item @b{Details:}

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- manhattan_distance --------------------

@node lib.math.manhattan_distance
@subsection lib.math.manhattan_distance
@findex lib.math.manhattan_distance

@samp{manhattan_distance} calculates the Manhattan distance between two
positions @samp{pos1} and @samp{pos2}, which is
@example
|pos1.x - pos2.x| + |pos1.y - pos2.y|.
@end example

@table @asis
@item @b{Syntax:}
@b{lib.math.manhattan_distance}(@i{pos1}, @i{pos2})

@b{lib.math.manhattan_distance}(@i{x1}, @i{y1}, @i{x2}, @i{y2})

@table @asis
@item @i{pos1}, @i{pos2}
Positions (e.g. object references or tables @samp{@{posx, posy@}}.

@item @i{x1}, @i{y1}, @i{x2}, @i{y2}
Coordinates of the positions @samp{pos1} and @samp{pos2}, respectively.
@end table

@item @b{Syntax Samples:}
@example
lib.math.manhattan_distance(4, 5, 3, 3)
lib.math.manhattan_distance(@{4, 5@}, @{3, 3@})
lib.math.manhattan_distance(no["marble"], no["othermarble"])
@end example

@item @b{Details:}
The Manhattan distance counts the minimal number of pushes necessary to push a
wood stone from one position to another. Its unit balls are squares with the
diagonals parallel to the x- and y-axis (rhombi).

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- mark_components --------------------

@node lib.math.mark_components
@subsection lib.math.mark_components
@findex lib.math.mark_components

@samp{mark_components} calculates the connected components of a group of
floors. Two floors are directly connected if their difference is within a given
polist (or @code{NEIGHBORS_4}, by default). A table is returned holding a
list of groups, each group is a complete connected component.
In turn, an attribute is attached to each floor of the group which holds the
number of its component. The name of this attribute can be chosen freely.

@table @asis
@item @b{Syntax:}
@b{lib.math.mark_components}(@i{group}, @i{attribute_name} [, @i{neighborhood} [,
@i{exclusive_attribute}]])

@table @asis
@item @i{group}
A group of floors.

@item @i{attribute_name}
A non-empty string. Typically, this is the title of a user attribute, so it
should start with an underscore @samp{_}, unless you want to feat the
information directly to a non-user attribute which takes numerical values.

@item @i{neighborhood}
A symmetric polist (see details). Defaults to @code{NEIGHBORS_4}, which results
in a calculation of path-connected components.

@item  @i{exclusive_attribute}
A boolean (@code{false} by default) which can be set to @code{true}, if there is
no other floor which uses an attribute named @i{attribute_name}.
@end table

@item @b{Syntax Samples:}
@example
lib.math.mark_components(all_floors, "_component")
local number = #lib.math.mark_components(all_floors, "_component", NEIGHBORS_CHESS .. NEIGHBORS_4)
local lines = lib.math.mark_components(all_floors, "_linenumber", po(-1, 0) .. po(1, 0), true)
@end example

@item @b{Details:}
@samp{mark_components} returns a Lua-table of groups, the table has natural numbers
as indices counting up starting from @code{1}, s.t. you can access the total
number of components via @samp{#}. Each entry of the table is a subgroup of
@code{group}, a complete connected component. The sequence of the components is
determined by the sequence of the floors in @code{group}.

You have to choose an attribute, as it is used during the calculation.
Note that all prior information saved in this attribute is lost.
Also note that choosing a read-only attribute results in an error.

The chosen neighborhood has to be a symmetric polist, i.e. if it contains the
position @code{po(x, y)} it also has to contain the position @code{po(-x, -y)}
at some point. Mathematically speaking, we analyze the connected components of
an undirected graph, not of a directed graph.

If you know that there is no other floor which uses the attribute
@code{attribute_name}, you may set @samp{exclusive_attribute} to @samp{true}.
This will result in a much faster algorithm.

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- permutation --------------------

@node lib.math.permutation
@subsection lib.math.permutation
@findex lib.math.permutation

@samp{permutation} returns a random permutation (i.e. a random shuffling) of the
numbers 1 to @samp{n}.

@table @asis
@item @b{Syntax:}
@b{lib.math.permutation}(@i{n})

@table @asis
@item @i{n}
A positive integer.
@end table

@item @b{Syntax Samples:}
@example
lib.math.permutation(#no["doors#*"])
@end example

@item @b{Details:}
Permutations give a simple way to randomize a level, e.g. by changing the
assignment of action/target-pairs ("Which trigger to which door?").

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- random_vector --------------------

@node lib.math.random_vector
@subsection lib.math.random_vector
@findex lib.math.random_vector

@samp{random_vector} returns a table of @samp{n} random entries.

@table @asis
@item @b{Syntax:}
@b{lib.math.random_vector}(@i{n}, @i{...})

@table @asis
@item @i{n}
A non-negative integer.

@item @i{...}
Further arguments, which are the same as for @samp{math.random}: Either no
further arguments, then the random numbers will be float values in
@samp{[0,1)}, or with one additional number @samp{p}, then the random numbers
will be integers between 1 and @samp{p} (both included), or two additional
numbers @samp{p, q}, then the random numbers will be integers between @samp{p}
and @samp{q} (both included).
@end table

@item @b{Syntax Samples:}
@example
lib.math.random_vector(4, 3)
@end example
will return a table of 4 random numbers out of @{1,2,3@}, and
@example
lib.math.random_vector(22)
@end example
returns a table of 22 float values between 0.0 and 1.0 (excluding 1.0).

@item @b{Details:}
@samp{random_vector} can be used in conjunction with @samp{cubic_polynomial} to
create random patterns, see @ref{lib.math.cubic_polynomial} and
@ref{Weirdly Wired}.

@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- steps --------------------

@node lib.math.steps
@subsection lib.math.steps
@findex lib.math.steps

@samp{steps} takes a number @samp{d} and a table of numbers as arguments and
returns the index of the first number larger or equal @samp{d}, minus one.
I.e. it classifies @samp{d} into the intervals given by the table, starting
with zero, when @samp{d} is smaller than the first number in the table, one,
when @samp{d} is larger or equal to the first, but smaller than the second
number, and so on.

@table @asis
@item @b{Syntax:}
@b{lib.math.steps}(@i{discriminator}, @i{steps})

@table @asis
@item @i{discriminator}
A number.

@item @i{steps}
A table of numbers.
@end table

@item @b{Syntax Samples:}
@example
number_pairs = lib.math.steps(total_places, @{2, 6, 10, 30@})
@end example

@item @b{Details:}
Negative and non-integer values are allowed. However, the numbers in the
@samp{steps}-table should be monotonously increasing (not necessarily strictly
monotonously), as otherwise the result might be counter-intuitive.

@item @b{Full Example:}
@example
lib.math.steps(x, @{4, 8, 13@})
@end example
returns:
@example
     0  if        x < 4
     1  if   4 <= x < 8
     2  if   8 <= x < 13
     3  if  13 <= x
@end example
@end table


@node libmap
@section libmap

The @samp{libmap} gives the author more possibilities to work with API 2-maps.
Up to now, a map just is a table of strings, as described in
@ref{World Creation}. With @samp{libmap}, you can utilize maps in a more
advanced way.

This library is described as of release 1.

You can load it by adding a @samp{dependency} element to the
@ref{<compatibility>} XML Metadata element as follows:

@example
  <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/libmap}" @i{el}:@b{id}="@var{lib/libmap}" @i{el}:@b{release}="@var{1}" @i{el}:@b{preload}="@var{true}"/>
@end example

It preloads automatically the library @ref{liblua}.

We first give six task-oriented sections, then describe each function in detail.

@menu
* Creating Maps::
* Drawing Maps::
* Rotating and Mirroring Maps::
* Requesting and Changing Single Map Entries::
* Connecting Two Maps::
* Other Map Tasks::
* newMap::
* Map Entry Request:: Index Operator @samp{[]} read and write
* Map Transformation:: Operator @samp{^}
* Map Horizontal Concatenation:: Operator @samp{..}
* Map Vertical Concatenation:: Operator @samp{+}
* Map Fusing:: Operator @samp{*}
* Map Default Keys::
* Map Width and Height::
* lib.map.covers::
* lib.map.defuse::
* lib.map.extend::
* lib.map.match::
* lib.map.paste::
* lib.map.print::
* lib.map.replace::
* lib.map.replace_outside::
* lib.map.sub::
* lib.map.trim::
* Map Transformation Index and MAP_ALL::
* Map Transformation Composition and Powers:: Operators @samp{*} and @samp{^}
* Map Transformation Inverse::                Operator @samp{-}
* Random Map Transformations::
@end menu

@c ----------------- Creating Maps --------------------

@node Creating Maps
@subsection Creating Maps

We start by defining a table of strings representing the level we want to
write in a two-dimensional array of tile keys:

@example
mypremap = @{"# # # # # # # ",
            "o t1  #   t2o ",
            "#     #     # ",
            "#     d2d1# # ",
            "# @@1#     @@2# ",
            "# # #     t1# ",
            "o   d3    t3o ",
            "# # # # # # # "@}
@end example

To not get confused with names, in this section we'll call such a table of
strings a 'premap'. We create a map (in the sense of libmap) by applying
@samp{wo:newMap} to it, with a default key and the premap as arguments:
@example
mymap = wo:newMap("  ", mypremap)
@end example
The default key is saved in @samp{mymap} as well, it's part of a map.

You can use
@example
mymap = wo:newMap(key, height, width)
@end example
to define map of size @samp{height*width}, where every tile key is @samp{key},
and the default key is set to @samp{key} as well. You might even omit
@samp{height} and @samp{width}, then you create a map consisting of only one
character.

@c ----------------- Drawing Maps --------------------

@node Drawing Maps
@subsection Drawing Maps

Just as we could have used the premap with @samp{wo} or @samp{wo:drawMap} to draw
it (see @ref{drawMap}), we can use the newly created map as well:
@example
wo(resolver, mymap)
wo:drawMap(resolver, anchor, mymap)
wo:drawMap(resolver, anchor, ignore, mymap)
@end example
When the @samp{ignore}-attribute for @samp{drawMap} is omitted, the default key
of @samp{mymap} is used instead.

Of course you can draw the map multiple times, even from within a resolver, see
@ref{drawMap} for a full example.

@c ----------------- Rotating and Mirroring Maps --------------------

@node Rotating and Mirroring Maps
@subsection Rotating and Mirroring Maps

We can transform a single map simply by using one of the following commands:
@example
newmap = lib.map.transform(mymap, maptransformation)
newmap = mymap ^ maptransformation
@end example
@samp{maptransformation} can be any of the following constants:
@table @asis
@item @samp{MAP_IDENT}
No transformation.
@item @samp{MAP_ROT_CW}
Rotate 90 degrees clockwise.
@item @samp{MAP_ROT_180}
Rotate 180 degrees (i.e. a point reflection around the midpoint).
@item @samp{MAP_ROT_CCW}
Rotate 90 degrees counter-clockwise.
@item @samp{MAP_FLIP_HORIZONTAL}
Flip each horizontal line, i.e. mirror against a vertical mirror: left and right are swapped.
@item @samp{MAP_FLIP_VERTICAL}
Flip each vertical line, i.e. mirror against a horizontal mirror: up and down are swapped.
@item @samp{MAP_FLIP_SLASH}
Flip each @code{/}-diagonal, i.e. mirror against a @code{\}-mirror: upper-right and
lower-left corners are swapped.
@item @samp{MAP_FLIP_BACKSLASH}
Flip each @code{\}-diagonal, i.e. mirror against a @code{/}-mirror: upper-left
and lower-right corners are swapped.
@end table

When you apply multiple transformations, remember that their sequence
matters. If you use
@example
newmap = mymap ^ maptransformation1 ^ maptransformation2 ^ maptransformation3
@end example
then @code{maptransformation1} acts first on @code{mymap}, then comes
@code{maptransformation2}, and @code{maptransformation3} is
last. However, composing transformations is associative, so you can use
@example
newmap = mymap ^ ((maptransformation1 ^ maptransformation2) ^ maptransformation3)
@end example
or
@example
newmap = (mymap ^ maptransformation1) ^ (maptransformation2 ^ maptransformation3)
@end example
to the same effect. Keep in mind that composing transformations is by far faster than
applying transformations to maps. So the first example is faster than the
second. Due to Lua's sequence of evaluating operators,
@example
newmap = mymap ^ maptransformation1 ^ maptransformation2 ^ maptransformation3
@end example
equals
@example
newmap = mymap ^ (maptransformation1 ^ (maptransformation2 ^ maptransformation3))
@end example
and hence already is the fastest possible sequence.

For composing transformations you may use @code{^} as well as @code{*}. You
can also use @code{maptransformation ^ n} to calculate the n-th power of
@code{maptransformation} for any integer n. The inverse of a transformation is
given by @code{-maptransformation}, so
@example
MAP_ROT_CW * (-MAP_ROT_CW) == MAP_IDENT
@end example

@c ----------------- Requesting and Changing Single Map Entries --------------------

@node Requesting and Changing Single Map Entries
@subsection Requesting and Changing Single Map Entries

Let's take a look at our example again:
@example
mymap = wo:newMap("  ", @{"# # # # # # # ",
                         "o t1  #   t2o ",
                         "#     #     # ",
                         "#     d2d1# # ",
                         "# @@1#     @@2# ",
                         "# # #     t1# ",
                         "o   d3    t3o ",
                         "# # # # # # # "@})
@end example
It's easy to check, what kind of tile key is at position @code{@{1,1@}} (note
that the upper left corner is at position @code{@{0,0@}}):
@example
mymap[@{1, 1@}] == "t1"
@end example
It's similarly easy to change it. Let's say, we want to create a passage
one tile right beside the second marble @samp{@@2}, which is named
@samp{marble2}:
@example
mymap[no["marble2"] + @{1,0@}] = "  "
@end example
Note that the reference to @samp{marble2} only works after the marble has been
set.

Requesting and changing map entries can be used with position lists, object and
group references as well.

You can replace any occurrence of a tile key @samp{tile1} by @samp{tile2} simply
by
@example
mymap:replace(tile1, tile2)
@end example
You can omit @samp{tile2}, then any occurrence of @samp{tile1} will be replaced
by the default key.

You can also search for positions in a map which fulfill given conditions by
using @samp{match}, the return value is a position list. The syntax is simple:
@example
mymap:match()
mymap:match(tilekey)
mymap:match(@{pos1, key1a, key1b, ...@}, @{pos2, key2a, key2b, ...@}, ...)
mymap:match(@{@{pos1, key1a, key1b, ...@}, @{pos2, key2a, key2b, ...@}, ...@})
@end example
The first call will return all positions of the map. The second call will
return all positions with the desired @code{tilekey}. The third and fourth call
will return all positions @code{x} such that @code{x + pos1} is one of the keys
@code{key1a} or @code{key1b} or ..., and such that @code{x + pos2} is one of
the keys @code{key2a}, @code{2b}, ..., and so on. A tile outside of the map is
considered to be a default key.

The resulting position list can then be used to replace the matching tile keys:
@example
mymap[mymap:match(oldkey)] = newkey
@end example
is equivalent to @samp{mymap:replace(oldkey, newkey)} (only slower), and
@example
mymap[mymap:match(@{po(0,0), " "@}, @{NEIGHBORS_4, ".", ":"@})] = "."
@end example
will find all occurrences of @samp{ }, which are completely surrounded by
@samp{.}, or @samp{:}, or mixtures of these, and replace them by @samp{.}. As
all replacements are done after matching, and hence simultaneously, the newly
introduced @samp{.} will not participate in the matching.

@c ----------------- Connecting Two Maps --------------------

@node Connecting Two Maps
@subsection Connecting Two Maps

Given two maps @samp{map1} and @samp{map2}, we can glue them together
horizontally by @samp{map1 .. map2} as well as vertically with @samp{map1 +
map2}. Missing entries will be filled with the default key of the respective
map, the default key of the result will be the one of @samp{map1}. A simple
example:
@example
map1 = wo:newMap(" ", @{"####",
                       "o  #",
                       "# w#",
                       "####"@})
map2 = wo:newMap(".", @{"#######",
                       "#w.#..#",
                       "#..D..#",
                       "#..#.w#",
                       "#######"@})
map1 .. map2 == wo:newMap(" ", @{"###########",
                                "o  ##w.#..#",
                                "# w##..D..#",
                                "#####..#.w#",
                                "    #######"@})
map2 .. map1 == wo:newMap(".", @{"###########",
                                "#w.#..#o  #",
                                "#..D..## w#",
                                "#..#.w#####",
                                "#######    "@})
map1 + map2 == wo:newMap(" ", @{"####   ",
                               "o  #   ",
                               "# w#   ",
                               "####   ",
                               "#######",
                               "#w.#..#",
                               "#..D..#",
                               "#..#.w#",
                               "#######"@})
@end example

It's also possible to paste a map into another map:
@example
map1:paste(map2, pos)
@end example
will paste @samp{map2} into @samp{map1} at position @samp{pos} (relative to
@samp{map1}: @code{@{0,0@}} is the upper left edge). If necessary, @samp{map1}
will be extended such that the whole of @samp{map2} fits into it. You can use
@samp{map1.sub} to reduce its size again (see below) as well as to define
@samp{map2} as a section of another map. During the pasting, any occurrence of
the default key of @samp{map2} will be ignored, i.e. not drawn onto
@samp{map1}. You can change the default key with @samp{map2.defaultkey = ...}
prior to the paste command to circumvent this, or use
@samp{map2:replace(tile)} to replace more tile keys by the default key, such
that they are not drawn as well. You can use an object group or position list
for @samp{pos}, in this case several copies of @samp{map2} will be pasted into
@samp{map1}. In the first case, there is no guarantee about the sequence in
which the maps will be pasted into @samp{map1}. In the second case, a latter
entry in the position list may overwrite the result of earlier entries.

However, there's a fourth possibility: Two maps may represent two different
parts of tile keys. Let's give an example to fuse two tile key layers:
@example
first_char = wo:newMap(".", @{"#######",
                             "#w.#..#",
                             "#..D..#",
                             "#..#.w#",
                             "#######"@})
last_char  = wo:newMap(".", @{"C     C",
                             " 11 22 ",
                             " 11322 ",
                             " 11 22 ",
                             "C     C"@})
first_char * last_char = wo:newMap(" .", @{"#C# # # # # #C",
                                          "# w1.1# .2.2# ",
                                          "# .1.1D3.2.2# ",
                                          "# .1.1# .2w2# ",
                                          "#C# # # # # #C"@})
@end example
The default key of the fused map is the concatenation of the two original
default keys. You can use a string instead of any of the two maps, in this case
the whole tile key layer will consist of this string everywhere:
@example
first_char = wo:newMap(".", @{"#######",
                             "#w.#..#",
                             "#..D..#",
                             "#..#.w#",
                             "#######"@})
first_char * "u" = wo:newMap(" u", @{"#u#u#u#u#u#u#u",
                                    "#uwu.u#u.u.u#u",
                                    "#u.u.uDu.u.u#u",
                                    "#u.u.u#u.uwu#u",
                                    "#u#u#u#u#u#u#u"@})

@end example
Fusing maps can be a mighty technique in combination with the
@ref{res.composer}- and @ref{res.autotile}-resolvers.

A map can also be defused: @samp{map:defuse()} will return a table of maps,
where each map is of keylength one, holding the corresponding subkey character.

@c ----------------- Other Map Tasks --------------------

@node Other Map Tasks
@subsection Other Map Tasks

You can access the default key of a map by @samp{mymap.defaultkey}, and change
it just as easily:
@example
mymap.defaultkey = ".3"
mymap:set_default_key(".3")
@end example
The new default key should have the same length as the old one. However, it is
possible to choose a new key length as long as it fits to the map.

Width and height of a map can be accessed via @samp{mymap.width} and
@samp{mymap.height}. However, these values can be changed only through the
following commands @samp{mymap:extend} and @samp{mymap:sub}.

It's possible to extend a map to a given position, as long as both
coordinates are non-negative:
@example
mymap:extend(@{19, 12@})
@end example
will extend @samp{mymap} up to position @samp{@{19,12@}}. Missing entries will
be filled with the default key. If the map already covers this position, no
change will be done.

If you want to check whether a position @samp{pos} lies inside a map, you can
use @samp{mymap:covers(pos)}, which returns a boolean value. Note that a map
always starts in @samp{@{0,0@}}.

@samp{lib.map.sub} allows you to copy a rectangular area of a map and create a
"submap" this way. @samp{lib.map.sub} uses the same syntax as
@samp{wo:drawRect}, i.e. either
@example
submap = mymap:sub(pos1, pos2)
@end example
with @samp{pos1} being the top left-hand corner and @samp{pos2} the bottom
right-hand corner, or alternatively
@example
submap = mymap:sub(pos1, width, height)
@end example
to define the rectangle by its top left-hand corner and the side lengths of its
area. If the bottom right-hand corner overlaps the area of @samp{mymap}, the
resulting @samp{submap} will still be just the rectangular section of
@samp{mymap}, i.e. width and height can be less than the arguments specified.
Use @samp{submap:extend(width, height)} to ensure the full width and height.
The default key of the submap of course is the default key of the original map.

@samp{lib.map.trim} or @samp{mymap:trim(tilekey)} removes all lines and
columns from the North, South, East, and West that consist of @code{tilekey}
only; it's like trimming a string from white spaces. You can omit
@samp{tilekey}, then the default key is used instead.

@samp{mymap:replace_outside(tile1, tile2)} is a kind of combination of
@samp{replace} and @samp{trim}: All occurrences of @code{tile1}, which are
connected to the border by a path of @samp{tile1}, are replaced by
@code{tile2} (or default key). Example:
@example
map1 = wo:newMap(" ", @{" ##########",
                       "###      ##",
                       "F# D ## # #",
                       "#       # #",
                       "########   "@})
map2 = wo:newMap(" ", map1)
map1:replace_outside(" ", ".")
map2:replace_outside(" ", "#")
map2:replace_outside("#", ".")
@end example
will yield:
@example
map1 = @{".##########",
        "###      ##",
        "F# D ## #.#",
        "#       #.#",
        "########..."@})
map2 = @{"...........",
        "...      ..",
        "F. D ## ...",
        ".       ...",
        "..........."@})
@end example
You can combine @samp{replace_outside} with @samp{match} to remove irrelevant
walls:
@example
map1.defaultkey = "-"
map1:replace_outside(" ")
map1[map1:match(@{@{po(0,0), "#"@}, @{NEIGHBORS_4, "-", "#", "F"@}@})] = "-"
map1:trim()
map1.defaultkey = " "
@end example
will yield:
@example
map1 = @{"---######-",
        "--#      #",
        "F# D ## #-",
        "#       #-",
        "-#######--"@})
@end example

Finally, you can use @samp{mymap:print()} to print @samp{mymap} to standard
output. Similar to @ref{lib.lua.print_table}, this is useful for debugging a
level by taking a look at its maps, but should not appear in the final level.
@samp{mymap:print()} allows several optional arguments:
@example
mymap:print(withXYCounts, left_separator, right_separator)
@end example
If @samp{withXYCounts} is @samp{true}, the map is printed with coordinates on
the top and on the left. @samp{left_separator} and @samp{right_separator} can
be strings to be put between the left coordinate axis and the map, and behind
the map (to analyse space characters).

@c ----------------- newMap --------------------

@node newMap
@subsection newMap
@findex lib.map.newMap

@samp{wo:newMap} takes a default key, and a premap or width and height as
arguments, and returns a libmap-map.

@table @asis
@item @b{Syntax:}
@i{mymap} = @b{wo:newMap}(@i{defaultkey}, @i{premap})

@i{mymap} = @b{wo:newMap}(@i{defaultkey}, @i{width}, @i{height})

@i{mymap} = @b{wo:newMap}(@i{defaultkey})

@table @asis
@item @i{defaultkey}
A non-empty string, which becomes the default key of the new map.

@item @i{premap}
A table of strings. It may have lines of varying length, but each line length
must be divisible by the length of the default key.

@item @i{width}, @i{height}
Positive integers. If width and height are given instead of a premap, a
rectangular map consisting of the default key only is returned.
@end table

If neither a premap, nor width and height are given, a 1x1-map with the default
key is returned.

@item @b{Syntax Samples:}
See @ref{Creating Maps}.

@item @b{Details:}
The syntax with neither premap nor width and height is useful in conjunction
with @ref{Map Fusing}.

A libmap-map is always rectangular. But you may use an ignore-key when you draw
the map with @ref{drawMap} to create arbitrarily shaped areas.

If the premap is not rectangular, missing positions are set to the default key.
However, each line length must be divisible by the default key's length, otherwise
an error is thrown.

You may feed arbitrary tables to @code{wo:newMap}, but only their positive
integer entries are used, all other entries are ignored. You might even skip
lines, like in this example:
@example
wo:newMap(" ", @{[25] = "g"@})
@end example
This will return a map of width 1 and height 25 filled with spaces, except for
the last line, which will be @code{"g"}.

Each libmap-map is a table and can be used as a premap as well. Its default
key is ignored when a libmap-map is considered as a premap. In particular,
you may use @code{wo:newMap} to copy a libmap-map with:
@example
newcopy = wo:newMap(mymap.defaultkey, mymap)
@end example
@end table

@c ----------------- Map Entry Request --------------------

@node Map Entry Request
@subsection Map Entry Request
@findex lib.map.get
@findex lib.map.set

You may request and set single entries within a libmap-map, using the
index-operator @samp{[]}.

@table @asis
@item @b{Syntax:}
@i{entry} = @i{mymap}@b{[}@i{posarg}@b{]}

@i{entry} = @b{lib.map.get}(@i{mymap}, @i{posarg})

@i{mymap}@b{[}@i{posarg}@b{]} = @b{newentry}

@b{lib.map.set}(@i{mymap}, @i{posarg}, @i{newentry})

@table @asis
@item @i{entry}, @i{newentry}
Non-empty strings of the same length as the default key of @code{mymap}.

@item @i{mymap}
A libmap-map.

@item @i{posarg}
A position, object, group, position list, string, or table (interpretable as
single position).
@end table

@item @b{Syntax Samples:}
See @ref{Requesting and Changing Single Map Entries}.

@item @b{Details:}
A read-access with a group or position list will return a table of all key
entries at the positions in the group or position list, in their corresponding
sequence. Empty groups and position lists will return empty tables.

Correspondingly, a write-access with a group or position list changes the key
at each position in the group or position list to the given string.

A read-access with a string invokes a @ref{Positions Repository Request} to
retrieve a named position, unless the string equals one of @code{"type"},
@code{"width"}, @code{"height"}, @code{"defaultkey"}, or @code{"keylength"},
which return the corresponding properties of the map instead.

A write-access with a string similarly is interpreted as access to a named
position, unless the string equals @code{"defaultkey"}, see
@ref{Map Default Keys}. A write-access to a non-existing position throws an
error.

You may request any position outside of the scope of the map, even with
negative coordinates. If you do so, the default key is returned. This accounts
for non-existing positions as well (for example positions of items in the
inventory, or the position of a string which doesn't describe a named position).

If you try to set an entry to a position with a negative coordinate an error
is returned. However, if you use non-negative coordinates outside of the scope
of the map, the map is subsequently extended to the new position, setting
the default key as entry where necessary.

Floating-point coordinates are always rounded to a grid position
(see @ref{Position Grid Rounding}).
@end table

@c ----------------- Map Transformation --------------------

@node Map Transformation
@subsection Map Transformation
@findex lib.map.transform

You may transform any libmap-map according to the eight map transformation
constants given in @ref{Rotating and Mirroring Maps}.

@table @asis
@item @b{Syntax:}
@i{newmap} = @i{mymap}@b{^}@i{maptransformation}

@i{newmap} = @b{lib.map.transform}(@i{mymap}, @i{maptransformation})

@table @asis
@item @i{mymap}, @i{newmap}
libmap-maps.

@item @i{maptransformation}
One of the following eight constants: @code{MAP_IDENT}, @code{MAP_ROT_CW},
@code{MAP_ROT_180}, @code{MAP_ROT_CCW}, @code{MAP_FLIP_HORIZONTAL},
@code{MAP_FLIP_VERTICAL}, @code{MAP_FLIP_SLASH}, @code{MAP_FLIP_BACKSLASH}.
@end table

@item @b{Syntax Samples:}
See @ref{Rotating and Mirroring Maps}.

@item @b{Details:}
As map transformations can be composed with @samp{^}, it is possible to combine
several transformations without brackets; it's only important to always have the
map on the left side of the @samp{^}-sign:
@example
newmap = mymap ^ MAP_ROT_CW ^ MAP_FLIP_HORIZONTAL
@end example
However, each such combination can equally well be expressed with a single constant.

After a transformation, height and width of a map might have swapped.
@end table

@c ----------------- Map Horizontal Concatenation --------------------

@node Map Horizontal Concatenation
@subsection Map Horizontal Concatenation
@findex lib.map.concat_horizontally

You may glue libmap-maps one after another in horizontal direction using
@samp{..}. Note the similarity to the meaning of @samp{..} in the context of
strings to remember its meaning in contrast to @samp{+} (see
@ref{Map Vertical Concatenation}).

@table @asis
@item @b{Syntax:}
@i{newmap} = @i{mymap1} @b{..} @i{mymap2}

@i{newmap} = @b{lib.map.concat_horizontally}(@i{mymap1}, @i{mymap2})

@table @asis
@item @i{mymap1}, @i{mymap2}, @i{newmap}
libmap-maps.
@end table

@item @b{Syntax Samples:}
See @ref{Connecting Two Maps}.

@item @b{Details:}
The upper-left corner of the second map is set beneath the upper-right corner
of the first, i.e. the bottom lines of the maps are aligned. If you want to
align them in another way, you may first vertically concat a map of suitable
height to the second (or first) map, like in this example:
@example
newmap = mymap1 .. (wo:newMap(" ", 1, 13) + mymap2)
@end example

The default key of the new map is the default key of the first map. Any missing
position to gain a rectangular map is subsequently set to this default key.
@end table

@c ----------------- Map Vertical Concatenation --------------------

@node Map Vertical Concatenation
@subsection Map Vertical Concatenation
@findex lib.map.concat_vertically

You may glue libmap-maps on top of each other in vertical direction using
@samp{+}. Compare with the meaning of @samp{..} (see
@ref{Map Horizontal Concatenation}).

@table @asis
@item @b{Syntax:}
@i{newmap} = @i{mymap1} @b{+} @i{mymap2}

@i{newmap} = @b{lib.map.concat_vertically}(@i{mymap1}, @i{mymap2})

@table @asis
@item @i{mymap1}, @i{mymap2}, @i{newmap}
libmap-maps.
@end table

@item @b{Syntax Samples:}
See @ref{Connecting Two Maps}.

@item @b{Details:}
The upper-left corner of the second map is set below the lower-left corner
of the first, i.e. the left borders of the maps are aligned. If you want to
align them in another way, you may first horizontally concat a map of suitable
width to the second (or first) map, like in this example:
@example
newmap = mymap1 + (wo:newMap(" ", 13, 1) .. mymap2)
@end example

The default key of the new map is the default key of the first map. Any missing
position to gain a rectangular map is subsequently set to this default key.
@end table

@c ----------------- Map Fusing --------------------

@node Map Fusing
@subsection Map Fusing
@findex lib.map.fuse

You may fuse libmap-maps in the way described in @ref{Connecting Two Maps}, by
interpreting the two keys of the two maps at a position as parts of a combined
(fused) key at this position.

@table @asis
@item @b{Syntax:}
@i{newmap} = @i{mymap1} @b{*} @i{mymap2}

@i{newmap} = @b{lib.map.fuse}(@i{mymap1}, @i{mymap2})

@table @asis
@item @i{mymap1}, @i{mymap2}, @i{newmap}
libmap-maps.
@end table

@item @b{Syntax Samples:}
See @ref{Connecting Two Maps}.

@item @b{Details:}
Missing keys in one map are replaced by the default key of this map.

The default key of the result is the concatenation of the default key of the
first map with the default key of the second map (as expected).

The inverse of the fusing operation is given by @ref{lib.map.defuse}.

One of the maps is allowed to be a string, which is then interpreted as a
1x1-map with the given string as default key. The result of the fusing process
then is that each tile key is concatenated with the given string.
@end table

@c ----------------- Map Default Keys --------------------

@node Map Default Keys
@subsection Map Default Keys
@findex lib.map.set_default_key

A libmap-map always includes a default key, which is used in various places
throughout the library. It is the placeholder whenever a key out of scope of
the map is requested, or when @ref{drawMap} or @code{wo} (see
@ref{World Creation}) are invoked without a default or ignore key. Hence, it is
sometimes necessary to retrieve or change the default key of a map.

@table @asis
@item @b{Syntax:}
@i{defaultkey} = @i{mymap}@b{.defaultkey}

@i{defaultkey} = @i{mymap}@b{["defaultkey"]}

@i{keylength} = @i{mymap}@b{.keylength}

@i{keylength} = @i{mymap}@b{["keylength"]}

@i{mymap}@b{.defaultkey} = @i{newkey}

@i{mymap}@b{["defaultkey"]} = @i{newkey}

@i{mymap}:@b{set_default_key}(@i{newkey})

@b{lib.map.set_default_key}(@i{mymap}, @i{newkey})

@table @asis
@item @i{defaultkey}, @i{newkey}
A non-empty string.

@item @i{mymap}
A libmap-map.

@item @i{keylength}
A positive integer, which equals the length of the default key.
@end table

@item @b{Syntax Samples:}
See @ref{Other Map Tasks}.

@item @b{Details:}
It typically makes sense to change the default key of a map, when two or more
keys can be equally well thought of as being "default". Such an example occurs
during the import of Sokoban levels: While the canonical default key would be
the key of the inner free tiles, it is temporarily set to the key of the outer
area to allow a simple matching and trimming. It is then set back again:
@example
local map = lib.import.level_to_map(level, "\n", " ")
map:replace("_")
map:replace("-")
map:replace_outside(" ", "-")
-- Remove redundant walls by outside:
-- A wall is redundant, if it is surrounded by "-" or "#".
-- In this case, it can be replaced by "-".
map.defaultkey = "-"
map[map:match(@{@{po(0,0), "#"@}, @{NEIGHBORS_8, "-", "#"@}@})] = "-"
map = map:trim()
map.defaultkey = " "
@end example
See @ref{lib.map.match} and @ref{lib.map.trim} for details on their use of
default keys.

The keylength of a map can be read, but not written. To change the keylength,
a new default key has to be assigned. On the other hand, it is possible to
change the default key to a key of different length; however, this rarely makes
sense, as each line will be reinterpreted, and the width of the map changes.
Still, the width has to fit to the new keylength, otherwise an error is
thrown.

If you want to change the keylength without reinterpreting each line, you
should instead fuse or defuse the map (see @ref{Map Fusing},
@ref{lib.map.defuse}). @ref{newMap} allows this quite easily:
@example
extendedmap = mymap * wo:newMap(" ")
restrictedmap = (mymap:defuse())[1] * (mymap:defuse())[3]
@end example
@end table

@c ----------------- Map Width and Height --------------------

@node Map Width and Height
@subsection Map Width and Height
@c @findex lib.map.width
@c @findex lib.map.height

A libmap-map always includes its width and height. These determine for example
the exact position of the second map during a concatenation (see
@ref{Connecting Two Maps}).

@table @asis
@item @b{Syntax:}
@i{width} = @i{mymap}@b{.width}

@i{width} = @i{mymap}@b{["width"]}

@i{height} = @i{mymap}@b{.height}

@i{height} = @i{mymap}@b{["height"]}

@table @asis
@item @i{width}, @i{height}
Positive integers.

@item @i{mymap}
A libmap-map.
@end table

@item @b{Details:}
See also @ref{Other Map Tasks}.

It is not possible (and rarely necessary) to directly change width and height
of a map. Instead, you might use @ref{lib.map.extend} to extend a map to a
given position, @ref{lib.map.sub} to retrieve a rectangular part of a map, or
@ref{lib.map.trim} to remove unused lines and columns from the map.

Note that width and height are not invariant. They change with many operations,
like transformations, concatenations or setting a key outside the former scope
of a map.

Also note that the upper-left corner of a map has coordinates @code{@{0, 0@}},
so the lower-right corner is @code{@{width - 1, height - 1@}}.
@end table

@c ----------------- lib.map.covers --------------------

@node lib.map.covers
@subsection lib.map.covers
@findex lib.map.covers

@code{covers} checks whether a position is within the scope of a map.

@table @asis
@item @b{Syntax:}
@i{result} = @i{mymap}:@b{covers}(@i{position})

@i{result} = @b{lib.map.covers}(@i{mymap}, @i{position})

@table @asis
@item @i{result}
A boolean value: @code{true}, if @i{position} is within the rectangle of grids
spanned by @code{(0,0)} and @code{(mymap.width - 1, mymap.height - 1)},
otherwise @code{false}.

@item @i{mymap}
A libmap-map.

@item @i{position}
A positional value (position or table with two entries).
@end table

@item @b{Syntax Samples:}
@example
if map1:covers(po(no["mycoin"]) - po(no["anchor1"])) then
    wo(no["mycoin"]) = ti["-"]
end
@end example

@item @b{Details:}
Floating-point positions are handled as expected, i.e. the position of a marble
which is on a grid corresponding to the map lets @code{cover} return
@code{true}.

Remember to subtract the anchor of an already drawn map to get the correct
information when you use positions of the level world.
@end table

@c ----------------- lib.map.defuse --------------------

@node lib.map.defuse
@subsection lib.map.defuse
@findex lib.map.defuse

@code{defuse} returns a table of maps of keylength one, which correspond to the
first, second, n-th character of each key at each position, respectively.

@table @asis
@item @b{Syntax:}
@i{result} = @i{mymap}:@b{defuse}()

@i{result} = @b{lib.map.defuse}(@i{mymap})

@table @asis
@item @i{result}
A non-empty table with maps as entries at integer positions. There are as many
maps as the keylength of @code{mymap}.

@item @i{mymap}
A libmap-map.
@end table

@item @b{Full Example:}
Given the following map,
@example
mymap = wo:newMap(" .", @{"#C# # # # # #C",
                         "# w1.1# .2.2# ",
                         "# .1.1D3.2.2# ",
                         "# .1.1# .2w2# ",
                         "#C# # # # # #C"@})
@end example
@code{mymap:defuse()} will return a table
@example
result = @{map1, map2@}
@end example
containing the following two maps:
@example
map1 = wo:newMap(".", @{"#######",
                       "#w.#..#",
                       "#..D..#",
                       "#..#.w#",
                       "#######"@})
map2  = wo:newMap(".", @{"C     C",
                        " 11 22 ",
                        " 11322 ",
                        " 11 22 ",
                        "C     C"@})
@end example

@item @b{Details:}
The default keys of the defused maps are the single characters of the default
key, in corresponding sequence.

The inverse of defusing is @ref{Map Fusing}.
@end table

@c ----------------- lib.map.extend --------------------

@node lib.map.extend
@subsection lib.map.extend
@findex lib.map.extend

@code{extend} changes a map in-place such that it covers a given position. If
the position already is within the scope of the map, nothing happens.

@table @asis
@item @b{Syntax:}
@i{mymap}:@b{extend}(@i{position})

@b{lib.map.extend}(@i{mymap}, @i{position})

@table @asis
@item @i{mymap}
A libmap-map.

@item @i{position}
A positional value (position, table with two entries, valid object, or string).
@end table

@item @b{Syntax Samples:}
@example
mymap:extend(po(no["mycoin1"]) - po(no["anchor1"]))
mymap:extend("secondanchor")
@end example

@item @b{Details:}
Negative coordinates are silently ignored. However, if the other coordinate
makes sense, the map might still get extended.

Floating-point coordinates are rounded to a grid position
(see @ref{Position Grid Rounding}).
@end table

@c ----------------- lib.map.match --------------------

@node lib.map.match
@subsection lib.map.match
@findex lib.map.match

You may use @code{match} to search for patterns or keys within a map.
@code{match} then returns a position list of grid positions.

@table @asis
@item @b{Syntax:}
@i{result} = @i{mymap}:@b{match}()

@i{result} = @i{mymap}:@b{match}(@i{tilekey})

@i{result} = @i{mymap}:@b{match}(@i{conditionlist})

@i{result} = @i{mymap}:@b{match}(@{conditionlist@})

@i{result} = @b{lib.map.match}(@i{mymap}, @i{conditionlist})

@table @asis
@item @i{result}
The position list of all matched positions.

@item @i{mymap}
A libmap-map.

@item @i{conditionlist} = condition, condition, ...
A list of conditions. A position is matched if and only if all conditions of the
@i{conditionlist} are matched.

@item @i{condition} = @{@i{positionlist}, @i{tilekey}, @i{tilekey}, ...@}
A position @code{pos} is matched by this condition if and only if for each position
@code{relativepos} in @code{positionlist} the tilekey
@code{mymap[pos + relativepos]} equals one of the tilekeys in the list. If
@code{pos + relativepos} is outside the scope of @i{mymap}, its tilekey is the
default key.

@item @i{tilekey}
Non-empty string of the same length as the default key of @code{mymap}
(no wildcards).

@item @i{positionlist}
A single relative position or a position list of relative positions.
@end table

@item @b{Full Example:}
Given the following map,
@example
mymap = wo:newMap(" ", @{"#####",
                        "#w# #",
                        "# D #",
                        "# #w#",
                        "#####"@})
@end example
@code{mymap:match("#")} will return a position list of all walls @code{"#"}, it
is identical to @code{mymap:match(@{po(0, 0), "#"@})} and
@code{mymap:match(@{@{po(0, 0), "#"@}@})}.

We may search for all positions @code{pos} which are between two walls with:
@example
result = mymap:match(@{po(-1, 0), "#"@}, @{po(1, 0), "#"@})
@end example
The two positions @code{po(-1, 0)} and @code{po(1, 0)} are relative to the
returned position. This returns a position list including positions like the
wall at @code{@{1,0@}} (which indeed is between two walls at @code{po(1, 0) +
po(-1, 0)} and @code{po(1, 0) + po(1, 0)}), but also @code{@{1,1@}}. If we want
to exclude walls at our position, we have to give all other keys instead:
@example
result = mymap:match(@{po(-1, 0), "#"@}, @{po(1, 0), "#"@}, @{po(0, 0), "w", " ", "D"@})
@end example

Finally, @code{mymap:match()} will return all positions of the map, i.e. a
position list with all positions between @code{@{0,0@}} and
@code{@{mymap.width - 1, mymap.height - 1@}}.

See also @ref{Requesting and Changing Single Map Entries}.

@item @b{Details:}
You can, but need not pack the condition list @code{match} into a single table.
This possibility exists to easily work with automatically generated condition
lists, but should be avoided in other cases due to readability.

The result of @code{match} is sorted primarily vertical, and secondarily
horizontal, i.e. a typical result would be:
@example
po(1, 1) .. po(1, 3) .. po(1, 4) .. po(2, 2) .. po(2, 3) .. po(5, 1)
@end example

If you feed the position list back into a replacing command, like in
@example
mymap = wo:newMap(" ", @{"####",
                        "#  #",
                        "####"@})
mymap[mymap:match(@{NEIGHBORS_8, "#"@})] = "#"
@end example
remember that the newly added changes could not be respected by the
@code{match}; so in the above example, the match returns an empty position list
and no tilekey is subsequently replaced.

Floating-point coordinates are rounded to a grid position
(see @ref{Position Grid Rounding}).
@end table

@c ----------------- lib.map.paste --------------------

@node lib.map.paste
@subsection lib.map.paste
@findex lib.map.paste

@code{paste} copies a map into another map at a given position. This command
works in-place, i.e. the receiving map is changed, instead of returning a new map.

@table @asis
@item @b{Syntax:}
@i{map1}:@b{paste}(@i{map2}, @i{position})

@b{lib.map.paste}(@i{map1}, @i{map2}, @i{position})

@table @asis
@item @i{map1}
The libmap-map to receive the copy.

@item @i{map2}
The libmap-map which is to be copied into @code{map1}.

@item @i{position}
A positional value (position, table with two entries, valid object, position
list, group, or string). The upper-left position @code{@{0, 0@}} of @code{map2}
is inserted at this position (or these positions) into @code{map1}.
@end table

@item @b{Full Example:}
@example
map1 = wo:newMap(" ", @{"#######",
                       "#w #  #",
                       "#  D  #",
                       "#  # w#",
                       "#######"@})
map2 = wo:newMap(".", @{"F.E",
                       "E.E"@})
@end example
In this situation, @code{map1:paste(map2, po(1, 1) .. po(5, 3))} will change
map1 into:
@example
@{"####### ",
 "#F E  # ",
 "#E E  # ",
 "#  # F#E",
 "#####E#E"@}
@end example

@item @b{Details:}
The receiving map will be extended with its default key as necessary.

Each tilekey of the copied map which equals its default key will be ignored
during the pasting process.

Floating-point coordinates are rounded to a grid position
(see @ref{Position Grid Rounding}).

If a part of a map is to be copied to a position with negative coordinates, an
error is thrown. However, if this part is to be ignored anyway (because it is
the default key), then the negative coordinate is silently ignored.
If for example we have
@example
map1 = wo:newMap(" ", @{"#######",
                       "#w #  #",
                       "#  D  #",
                       "#  # w#",
                       "#######"@})
map2 = wo:newMap(".", @{".FE",
                       ".EE"@})
@end example
then @code{map1:paste(map2, po(-1, 0))} will change
map1 into
@example
@{"FE#####",
 "EE #  #",
 "#  D  #",
 "#  #  #",
 "#######"@}
@end example
while @code{map1:paste(map2, po(0, -1))} throws an error.

A map can be pasted multiple times into another map by providing a position
list or object group. The sequence of pastings is then given by the sequence of
the list or group, so the pasting at the second entry might overwrite the
changes done by the first entry.
@end table

@c ----------------- lib.map.print --------------------

@node lib.map.print
@subsection lib.map.print
@findex lib.map.print

@code{print} prints a map to standard output. You may use this command for
debugging purposes, or to support development or translation of a level, but it
should not be used in the released form of a level.

@table @asis
@item @b{Syntax:}
@i{mymap}:@b{print}([@i{withXYCounts} [, @i{left_separator} [, @i{right_separator}]]])

@b{lib.map.print}(@i{mymap} [, @i{withXYCounts} [, @i{left_separator} [, @i{right_separator}]]])

@table @asis
@item @i{mymap}
A libmap-map.

@item @i{withXYCounts}
A boolean value, @code{false} by default.

@item @i{left_separator}, @i{right_separator}
Strings to be printed on the left and on the right side of the map, empty
strings by default.
@end table

@item @b{Full Example:}
@example
mymap = wo:newMap(" ", @{"#######",
                        "#w #  #",
                        "#  D  #",
                        "#  # w#",
                        "#######"@})
@end example
Then @code{mymap:print(true, " -> ", "|")} prints the following to standard output:
@example
  -> 0123456|
0 -> #######|
1 -> #w #  #|
2 -> #  D  #|
3 -> #  # w#|
4 -> #######|
@end example

@item @b{Details:}
If you use maps wider than ten times its keylength, the x-count will show
only the last digits of the x coordinate.

If you want to insert lines between the columns, you can fuse the map
with your desired character, like in @code{(mymap * "|"):print(...)}.

You can actually use @code{print} to generate a map for a level file if you
provide appropriate separators:
@example
mymap:print(false, "    \"", "\",")
@end example
@end table

@c ----------------- lib.map.replace --------------------

@node lib.map.replace
@subsection lib.map.replace
@findex lib.map.replace

@code{replace} replaces all occurrences of a single tile key in a map in-place
with another tile key.

@table @asis
@item @b{Syntax:}
@i{mymap}:@b{replace}(@i{oldkey} [, @i{newkey}])

@b{lib.map.replace}(@i{mymap}, @i{oldkey} [, @i{newkey}])

@table @asis
@item @i{mymap}
A libmap-map.

@item @i{oldkey}
A non-empty string of the same length as @code{mymap}'s default key.

@item @i{newkey}
A non-empty string of the same length as @code{mymap}'s default key, which is the
replacement for @code{oldkey}. The default replacement key is the default key itself.
@end table

@item @b{Syntax Samples:}
@example
mymap:replace("#", "-")
@end example
will change @code{mymap} in such a way that each @code{"#"} is replaced by
@code{"-"}. If @code{"-"} is omitted, each @code{"#"} is replaced by the
default key instead.

@item @b{Details:}
@samp{mymap:replace(tile1, tile2)} is equivalent to
@example
mymap[mymap:match(tile1)] = tile2 or mymap.defaultkey
@end example
but faster, because no position list is constructed in between (see
@ref{lib.map.match}).

See also @ref{lib.map.replace_outside} and
@ref{Requesting and Changing Single Map Entries}.
@end table

@c ----------------- lib.map.replace_outside --------------------

@node lib.map.replace_outside
@subsection lib.map.replace_outside
@findex lib.map.replace_outside

@code{replace_outside} is a very specialized command, which is used to replace
all occurrences of a tile key which are connected to the border of the map by a
path of this tile key with another tile key. The replacement is done in-place,
i.e. no new map is created or returned.

@table @asis
@item @b{Syntax:}
@i{mymap}:@b{replace_outside}(@i{oldkey} [, @i{newkey}])

@b{lib.map.replace_outside}(@i{mymap}, @i{oldkey} [, @i{newkey}])

@table @asis
@item @i{mymap}
A libmap-map.

@item @i{oldkey}
A non-empty string of the same length as @code{mymap}'s default key.

@item @i{newkey}
A non-empty string of the same length as @code{mymap}'s default key, which is the
replacement for @code{oldkey}. The default replacement key is the default key itself.
@end table

@item @b{Syntax Samples:}
See @ref{Other Map Tasks}.

@item @b{Details:}
@code{replace_outside} shows similarities with @ref{lib.map.replace} and
@ref{lib.map.trim}. It is the only universal way to handle the area near
the border of a map, and can be combined with @ref{lib.map.match} and
@ref{lib.map.trim} to show its full potential.

Because of its recursive nature, old and new tile key must be different; in
contrast to the situation of @ref{lib.map.replace} identical tile keys are not
silently ignored, but throw an error message.
@end table

@c ----------------- lib.map.sub --------------------

@node lib.map.sub
@subsection lib.map.sub
@findex lib.map.sub

@code{sub} returns a copy of a rectangular section of a map as a new map.

@table @asis
@item @b{Syntax:}
@i{submap} = @i{mymap}:@b{sub}(@i{upperleft}, @i{lowerright})

@i{submap} = @i{mymap}:@b{sub}(@i{upperleft}, @i{width}, @i{height})

@i{submap} = @b{lib.map.sub}(@i{mymap}, @i{upperleft}, @i{lowerright})

@i{submap} = @b{lib.map.sub}(@i{mymap}, @i{upperleft}, @i{width}, @i{height})

@table @asis
@item @i{submap}
A libmap-map, the rectangular section of @code{mymap}.

@item @i{mymap}
A libmap-map.

@item @i{upperleft}, @i{lowerright}
Positional values (position, valid object, table with two entries, or name of a
named position.

@item @i{width}, @i{height}
Positive integers.
@end table

@item @b{Syntax Samples:}
See @ref{Other Map Tasks}.

@item @b{Details:}
If the bottom right-hand corner overlaps the area of @code{mymap}, the resulting
@code{submap} will still be just the rectangular section of @code{mymap}, i.e.
width and height can be less than the arguments specified. Use
@code{submap:extend(width, height)} to ensure the full width and height.

Floating point positions are rounded to grid positions, and the lower-right
corner may not have coordinates less than those of the upper-left corner,
otherwise an error is thrown.

The default key of the submap is the default key of the original map.

The upper-left corner of the submap of course is @code{@{0,0@}}, i.e. the
coordinates are shifted accordingly.
@end table

@c ----------------- lib.map.trim --------------------

@node lib.map.trim
@subsection lib.map.trim
@findex lib.map.trim

@code{trim} returns the smallest rectangular section of a map as new map such
that its border consists of a given tile key only, i.e. it trims the original
map from the North, East, South, and West.

@table @asis
@item @b{Syntax:}
@i{trimmedmap} = @i{mymap}:@b{trim}([@i{tilekey}])

@i{trimmedmap} = @b{lib.map.trim}(@i{mymap} [, @i{tilekey}])

@table @asis
@item @i{trimmedmap}
A libmap-map, the trimmed copy of @code{mymap}.

@item @i{mymap}
A libmap-map.

@item @i{tilekey}
A non-empty string of the same length as the default key. If omitted, the
default key is used instead.
@end table

@item @b{Full Example:}
With the following map:
@example
mymap = wo:newMap(" ", @{"#######",
                        "#w #  #",
                        "#  D  #",
                        "#  # w#",
                        "#######"@})
@end example
Trimming with @samp{mymap:trim()} will return just a copy of the original map,
but @samp{mymap:trim("#")} returns a map as follows:
@example
@{"w #  ",
 "  D  ",
 "  # w"@})
@end example

@item @b{Details:}
The default key of the trimmed map is the default key of the original map.

If the original map consists of the trimmed key only, then @code{trim} returns
a 1x1-map with the trimmed key as only entry, and the default key of the
original map.
@end table

@c ----------------- Map Transformation Index and MAP_ALL --------------------

@node Map Transformation Index and MAP_ALL
@subsection Map Transformation Index and MAP_ALL

All eight transformation constants (see @ref{map read directions},
@ref{Rotating and Mirroring Maps}, @ref{Map Transformation}) are additionally
packed into the table @code{MAP_ALL}, so a simple call to
@code{ipairs(MAP_ALL)} can iterate over all of them. @code{MAP_ALL} is provided
without need to load libmap.

Each transformation offers the field @code{"index"}, which returns the number at
which the transformation appears in @code{MAP_ALL}. libmap is not needed to use
@code{"index"} either.

@table @asis
@item @b{Syntax:}
@b{MAP_ALL} = @{@b{MAP_IDENT}, @b{MAP_ROT_CW}, @b{MAP_ROT_180}, @b{MAP_ROT_CCW}, @b{MAP_FLIP_BACKSLASH},
           @b{MAP_FLIP_HORIZONTAL}, @b{MAP_FLIP_SLASH}, @b{MAP_FLIP_VERTICAL}@}

@b{transformation_index} = @i{maptransformation}.@b{index}

@table @asis
@item @i{transformation_index}
An integer between 1 and 8.

@item @i{maptransformation}
A map transformation.
@end table

@item @b{Syntax Samples:}
@example
MAP_ALL[MAP_ROT_CW.index] == MAP_ROT_CW
@end example

@item @b{Details:}
You may not safe map transformations as attributes of objects, for example the
following will throw an error:
@example
no["stone_a"]["_mytrafo"] = MAP_ROT_CCW
@end example
Instead, you have to use @code{index} and retrieve the correct transformation
from @code{MAP_ALL}:
@example
no["stone_a"]["_mytrafo"] = MAP_ROT_CCW.index
...
oldtrafo = MAP_ALL[no["stone_a"]["_mytrafo"]]
@end example
@end table

@c ----------------- Map Transformation Composition and Powers --------------------

@node Map Transformation Composition and Powers
@subsection Map Transformation Composition and Powers
@findex lib.map.transformation_compose
@findex lib.map.transformation_power

The transformation constants (see @ref{map read directions},
@ref{Rotating and Mirroring Maps}, @ref{Map Transformation}) can be composed
according to their true operation on a map, as soon as libmap is loaded. The
composition is returned by the operations @samp{*} and @samp{^}.

@table @asis
@item @b{Syntax:}
@i{composition} = @i{maptransformation1} @b{*} @i{maptransformation2}

@i{composition} = @i{maptransformation1} @b{^} @i{maptransformation2}

@i{composition} = @b{lib.map.transformation_compose}(@i{maptransformation1}, @i{maptransformation2})

@i{composition} = @b{lib.map.transformation_power}(@i{maptransformation1}, @i{maptransformation2})

@i{power} = @i{maptransformation} @b{^} @i{exponent}

@i{power} = @b{lib.map.transformation_power}(@i{maptransformation}, @i{exponent})

@table @asis
@item @i{composition}
The result of composing two map transformations.

@item @i{maptransformation1}, @i{maptransformation2}, @i{maptransformation}
Map transformations.

@item @i{power}
The @code{exponent}-th power of @code{maptransformation} (again a map
transformation).

@item @i{exponent}
An integer.
@end table

@item @b{Syntax Samples:}
@example
new_transformation = (MAP_ROT_CW * MAP_FLIP_HORIZONTAL) ^ 2
another_transformation = (new_transformation ^ MAP_ROT_180) ^ (-1)
@end example

@item @b{Details:}
The eight possible map transformations are the elements of a mathematical
group, the dihedral group of order 8. Composition of any two map
transformations therefore yields another one of the eight map transformations.
An @i{n}-th power of a map transformation is the composition of @i{n} such
transformations. In the case of the dihedral group, any 4-th power returns the
original element. This fact is applied during calculating a power, so it
doesn't make a difference to the performance when you use large numbers as
exponents.

Composing with @code{MAP_IDENT} doesn't change the value; it's like adding zero
to a number, or multiplying with one.

Keeping to group theoretic notions, the operation @samp{^} between map
transformations should denote conjugation instead of composition. Instead of
this, it is chosen to be synonymous to @samp{*} to allow for associativity of
expressions like:
@example
new_map = old_map ^ MAP_ROT_CCW ^ MAP_FLIP_VERTICAL
@end example
(Remember that Lua evaluates @samp{^} from the right.)

The inverse can be calculated with a power to @code{-1}, but also by @samp{-},
see @ref{Map Transformation Inverse}.
@end table

@c ----------------- Map Transformation Inverse --------------------

@node Map Transformation Inverse
@subsection Map Transformation Inverse

The transformation constants (see @ref{map read directions},
@ref{Rotating and Mirroring Maps}, @ref{Map Transformation}) have proper
inverses, i.e. map transformations that reverse their action. These inverse
transformations are returned by @samp{-}.

@table @asis
@item @b{Syntax:}
@i{inverse} = @b{-}@i{maptransformation}

@i{inverse} = @b{lib.map.transformation_inverse}(@i{maptransformation})

@table @asis
@item @i{inverse}
The inverse map transformation of @code{maptransformation}.

@item @i{maptransformation}
A map transformation.
@end table

@item @b{Syntax Samples:}
@example
reverse_transformation = -MAP_ROT_CW
@end example
In this case, @code{reverse_transformation} equals @code{MAP_ROT_CCW}, because
their composition @code{MAP_ROT_CW * MAP_ROT_CCW} equals the trivial
transformation (or identity) @code{MAP_IDENT}.

@item @b{Details:}
The eight possible map transformations are the elements of a mathematical
group, the dihedral group of order 8. The inverse of any map transformation
therefore yields another one of the eight map transformations. Composition of
any map transformation with its inverse results in @code{MAP_IDENT}. However,
within the dihedral group of order 8, only two elements have inverses that are
not their own inverses: the two rotations by 90 degrees.

Keeping to group theoretic notions, the inverse is denoted by @samp{^ (-1)},
which works just as well(see @ref{Map Transformation Composition and Powers}).
@end table

@c ----------------- Random Map Transformations --------------------

@node Random Map Transformations
@subsection Random Map Transformations
@findex lib.map.random_transformation

libmap provides the function @code{lib.map.random_transformation()} to pick one
of the eight transformations by random.

@table @asis
@item @b{Syntax:}
@i{randomtransformation} = @b{lib.map.random_transformation}()

@table @asis
@item @i{randomtransformation}
A map transformation, randomly chosen from @code{MAP_ALL}.
@end table

@item @b{Syntax Samples:}
@example
wo:drawMap(ti, po(5, 4), mymap, lib.map.random_transformation())
@end example

@item @b{Details:}
When you use random map transformations, remember that four out of the eight map
transformations switch height and width of the map they are applied to.
@end table


@c ----------------- libimport --------------------
@node libimport
@section libimport
@findex lib.import

libimport is dedicated to parse level files of other games or formats and
typically returns @ref{libmap}-maps. In this context, the word "level" refers to
a string, representing a level of the other game. A "monolevel" is a string
which holds a single level, but also additional information, like titles or
author names. A "multilevel" is a string composed of one or more monolevels.
A "map" is a map in the libmap-sense, i.e. an Enigma level.

Apart from the following functions, lib.import includes the minor routines
@samp{lib.import.string_replace}, which is a wrapper for @code{string.gsub},
and @samp{lib.import.string_remove_multiples}, which removes multiple
occurrences of a string in another string.

This library is described as of release 1.

You can load it by adding a @samp{dependency} element to the
@ref{<compatibility>} XML Metadata element as follows:

@example
  <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/libimport}" @i{el}:@b{id}="@var{lib/libimport}" @i{el}:@b{release}="@var{1}" @i{el}:@b{preload}="@var{true}"/>
@end example

It preloads automatically the libraries @ref{libmap} and @ref{liblua}.


@menu
* lib.import.unpack_multilevel::        Extract a level from a multilevel.
* lib.import.uncompress_rle::           Decode run-length encoding.
* lib.import.level_to_map::             Converts a level into a map.
* lib.import.map_sokoban::              Converts a Sokoban level into a map.
* lib.import.map_wanderer::             Converts a Wanderer level into a map.
@end menu

@c ----------------- unpack_multilevel --------------------

@node lib.import.unpack_multilevel
@subsection lib.import.unpack_multilevel
@findex lib.import.unpack_multilevel

@samp{unpack_multilevel} extracts a level from a multilevel string. For this,
it needs a regexp describing a single level line.

@table @asis
@item @b{Syntax:}
@b{lib.import.unpack_multilevel}(@i{multilevel}, @i{sublevel_number}, @i{format})

@table @asis
@item @i{multilevel}
A multilevel string.

@item @i{sublevel_number}
The number of the level in @code{multilevel} to be extracted. First level is
@samp{1}. If @code{nil}, @samp{1} is taken as default.

@item @i{format}
A string referencing an entry in @samp{lib.import.line_regexp}. Currently, only
@samp{sokoban} and @samp{wanderer} are supported. But you can add further
entries to @samp{lib.import.line_regexp} if necessary.
@end table

@item @b{Syntax Samples:}
@example
level_four = lib.import.unpack_multilevel(large_string, 4, "sokoban")
@end example

@item @b{Details:}
A level extracted with @code{unpack_multilevel} has still to be converted into
a format Enigma understands. A level is a string, and lines of the level are to
be determined by line endings, which can be quite different. In contrast to
this, an Enigma map is a table of strings, with each line in a separate entry
of the table. Hence, at least the line endings have to be dealt with.
@end table

@c ----------------- uncompress_rle --------------------

@node lib.import.uncompress_rle
@subsection lib.import.uncompress_rle
@findex lib.import.uncompress_rle

@samp{uncompress_rle} takes a string as argument and returns a decoded version
without run-length encoding.

@table @asis
@item @b{Syntax:}
@b{lib.import.uncompress_rle}(@i{level}, @i{attribs})

@table @asis
@item @i{level}
A level string.

@item @i{attribs}
A table containing further parameters. Currently, the only supported parameter
is @samp{error_on_multiple}.
@end table

@item @b{Syntax Samples:}
@example
uncompressed = lib.import.uncompress_rle(compressed, @{error_on_multiple = "\n"@})
@end example

@item @b{Details:}
Levels typically include long lines of repeating characters, like walls or
spaces. To save space, these are sometimes counted and replaced by the total
number and a single example of the character. This is called "run-length
encoding", or RLE.
@example
"############  A #####BB#" compresses to "12#2 A5#2B#"
@end example
However, some characters don't make sense to be repeated, like line endings.
To return an error when trying to repeat a line ending during decompression,
you can hand a string to the attribute @samp{error_on_multiple}. Any character
in this string is then forbidden to be repeated. Remember that the @samp{new
line}-character is represented by @samp{\n} in Lua.
@end table

@c ----------------- level_to_map --------------------

@node lib.import.level_to_map
@subsection lib.import.level_to_map
@findex lib.import.level_to_map

@samp{level_to_map} breaks a level string down into a table of strings, which
is then converted into a @ref{libmap}-map.

@table @asis
@item @b{Syntax:}
@b{lib.import.level_to_map}(@i{level}, @i{line_ending}, @i{default_key})

@table @asis
@item @i{level}
A level string.

@item @i{line_ending}
A string describing a single line ending. Default: @samp{\n}

@item @i{default_key}
The default key of the returned map. Default: @samp{ }
@end table

@item @b{Syntax Samples:}
@example
mymap = lib.import.level_to_map(level, "|", " ")
@end example

@item @b{Details:}
Multiple line endings are interpreted as multiple lines (of which the last
lines are filled with the default key).

Make sure that the last line of the level ends in a proper line ending, and only
one line ending. Otherwise, the returned map will be too short or too long.
@end table

@c ----------------- map_sokoban --------------------

@node lib.import.map_sokoban
@subsection lib.import.map_sokoban
@findex lib.import.map_sokoban

@samp{map_sokoban} takes a Sokoban multilevel as argument, and returns a
beautified @ref{libmap}-map.

@table @asis
@item @b{Syntax:}
@b{lib.import.map_sokoban}(@i{multilevel}, @i{sublevel_number}, @i{keylength_one})

@table @asis
@item @i{multilevel}
A multilevel string.

@item @i{sublevel_number}
The number of the level to be extracted. First level is @samp{1}. Default:
@samp{1}

@item @i{keylength_one}
A boolean value. If @code{false}, the returned map has keylength two. Otherwise,
it has keylength one. Default: @samp{false}
@end table

@item @b{Syntax Samples:}
@example
map_four = lib.import.map_sokoban(multilevel, 4, true)
@end example

@item @b{Details:}
Sokoban level files can be very different - they can use run-length encoding and
multilevel files. Sometimes, @samp{|} is used as line ending instead of or even
together with @samp{\n}. @samp{ }, @samp{_} and @samp{-} can all represent
space. Sometimes, the outside is filled with @samp{ }, then again with @samp{#}.
Finally, line width can vary. We use a slightly generalized version, to include
chessoban levels. Allowed characters are:
@example
   - _ space  space
   #          wall
   .          goal
   $ *        box, box with goal
   n N        st_chess, st_chess with goal
   @@ +        player, player with goal
@end example
The returned map will use @samp{ } for inside space, @samp{-} for
outside space, default key is @samp{ }.

If you chose @samp{keylength_one = true}, the returned map will use the
characters as described above. Otherwise, the returned map will have keylength
two, and the characters @samp{*}, @samp{N}, and @samp{+} are resolved into
@samp{$.}, @samp{n.}, and @samp{@@.} respectively, while the other keys become
@samp{  }, @samp{- }, @samp{# }, @samp{ .}, @samp{$ }, @samp{n }, and
@samp{@@ }. You can then use @ref{res.composer} to easily draw your map.

Remember that the returned map uses the inner space @samp{ } or @samp{  } as
default key. Hence, if you want to paste the map into another one
(@ref{Connecting Two Maps}), you will have to switch the default key to
@samp{-} or @samp{- } in beforehand to yield a good result.
@end table

@c ----------------- map_wanderer --------------------
@node lib.import.map_wanderer
@subsection lib.import.map_wanderer
@findex lib.import.map_wanderer

@samp{map_wanderer} takes a Wanderer monolevel as argument, and returns a
@ref{libmap}-map. Note that Enigma does not yet have the necessary game objects
to simulate Wanderer.

@table @asis
@item @b{Syntax:}
@b{lib.import.map_wanderer}(@i{monolevel})

@table @asis
@item @i{monolevel}
A monolevel string.
@end table

@item @b{Syntax Samples:}
@example
mymap = lib.import.map_wanderer(monolevel)
@end example

@item @b{Details:}
Wanderer is a game originally created by Steven Shipway in 1988.
Wanderer level files are uncompressed monolevels with fixed
width. The level itself is followed by a short description
(title/author/email) in a single line or a line of @samp{#}. Last
line optionally is a number. A Wanderer level knows the
following characters (taken from Wanderer's editor):
@example
   : _ #      earth, rock, indestructible rock
   * - space  treasure, alternative space, space
   O < > ^    falling boulder, arrow from right, arrow from left, balloon
   ! + B      landmine, cage, bomb
   / \        deflectors
   T A X @@    teleport, arrival, exit, start
   M S C ~    big monster, baby monster, time capsule, thingy
@end example
Due to its fixed width (40) and height (16), a Wanderer level is not always
surrounded by walls; you might have to add them.

Note that Enigma does not yet support the game elements of Wanderer, hence this
function currently is only of use to developers.
@end table

@c ----------------- libsoko --------------------
@node libsoko
@section libsoko
@findex lib.soko.create_sokoball

This library is described as of release 1.

You can load it by adding a @samp{dependency} element to the
@ref{<compatibility>} XML Metadata element as follows:

@example
  <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/libsoko}" @i{el}:@b{id}="@var{lib/libsoko}" @i{el}:@b{release}="@var{1}" @i{el}:@b{preload}="@var{true}"/>
@end example

It preloads automatically the libraries @ref{libimport}, @ref{libmap},
@ref{libmath}, and @ref{liblua}.

The only function which is meant to be used in levels is
@samp{lib.soko.create_sokoball}.

@table @asis
@item @b{Syntax:}
@b{lib.soko.create_sokoball}(@i{multilevel}, @i{sublevel_number}, @i{args})

@table @asis
@item @i{multilevel}
A multilevel string in the sense of @ref{libimport}.

@item @i{sublevel_number}
A number determining the number of the level in @code{multilevel}. Default is
@samp{1}.

@item @i{args}
A table holding optional information to construct the level,
default is @{@}. The following keywords are currently supported,
all other keywords will return an error:
@table @asis
@item @i{design}
A number or a design table, see below.

@item @i{maxdesign}
A number, see below.
@end table
@end table

@item @b{Syntax Samples:}
@example
lib.soko.create_sokoball(many_levels, 13, @{design = 48@})
lib.soko.create_sokoball(many_levels, 12, @{maxdesign = MAXDESIGN[1.1]@})
@end example

@item @b{Details:}
@samp{create_sokoball} creates a sokoball-level from the string
@code{multilevel}. This string can be a multilevel, in which case
@samp{sublevel_number} determines the number of the level, starting with 1
(default is 1).

The design can be chosen by @samp{design}. This is either a number, which refers
to the list of predefined designs in @code{libsoko_designlist.xml}, or a table
with the corresponding design entries. A missing entry will be interpreted as
the entry from lib.soko_designlist.default. If the @samp{design} variable is
omitted, a check-number is created from the level which uniquely* determines
a design from the design list, with @code{maxdesign} as highest possible
design number.

*Uniquely means: The design might change when the design list is enlarged.

The number of available designs is 150 in Enigma 1.1, which equals the constant
@code{MAXDESIGN[1.1]}. However, further versions of Enigma might support more
designs. If a multilevel is loaded with a (numerically given) maxdesign number
which is larger than the number of available designs, only those levels will be
available for play whose calculated design number is supported, all others will
show an error message. However, it is better to use the MAXDESIGN-constants.
These will always raise an error, when the requested designs are not available.
The MAXDESIGN-constants are read-only.

If both the design argument as well as the maxdesign-number are
omitted, the original 150 designs will be used as fallback, no matter which
version of Enigma is running.

To define own designs, please consult
@samp{data/levels/lib/libsoko_designlist.xml}
or use @ref{libimport} in the first place.

Returns width and height of new Enigma level.
@end table


@c ===================  Advanced Features  =======================

@node Advanced Features
@chapter Advanced Features

@menu
* Resolvers::               Standard tools for interpretation of tile maps
* General Features::        Special features like scrolling, flood, fire,...
* Tips and Tricks::         Simple patterns that are valuable like a feature
@end menu

@c ----------------- Resolvers --------------------
@node Resolvers
@section Resolvers

Every tile in the world is defined by a key that needs to be resolved to its
declaration. This can be done either by the @ref{Tiles Repository} @samp{ti}
alone, or by additionally chained resolvers. In the chapter @ref{Lua API} we
learned how to set up a @ref{World} by static @ref{Tile and Object Declaration}s.
Now it is time to explore the capabilities of resolvers. In the
@ref{World Creation} you had to supply a top resolver as an argument. Let us
look which types of resolvers are available and how you can chain these resolvers.

@menu
* Resolver Chaining::  Linking resolvers and the tiles repository
* Custom Resolver::    Writing simplified own resolvers
* res.autotile::       Generate tiles from given template declarations
* res.composer::       Compose tiles from given base tiles
* res.maze::           Generate arbitrarily shaped mazes
* res.puzzle::         Generate puzzle tiles and shuffle resulting puzzle clusters
* res.random::         Choosing random tiles in a given distribution
* res.train::          Set up floor chains that move on given railways
@end menu

@c ----------------- Resolver Chaining --------------------

@node Resolver Chaining
@subsection Resolver Chaining

There exist several useful resolvers that may simplify the task of level writing
or provide dynamic features like randomness, mazes, etc. Each of them handles
just some keys out of your world map. For the other keys the resolver has no
idea how to resolve them to object declarations. Thus each resolver has to be
linked to a so called @samp{subresolver}. The resolver just forwards all key
requests that it can not handle itself to its subresolver. Indeed it will in
most cases even forward modified key requests to its subresolver that are
required by the process of handling its own keys.

The last resolver in the chain will either use the @ref{Tiles Repository}
@samp{ti} as its subresolver or a @ref{Custom Resolver} function, which will be
@samp{ti} based, too.

A typical resolver chain will look like:


@table @asis
@item @b{Syntax Sample:}
@example
@var{subresolver} = @i{res}.@i{random}(@i{ti}, ...)
@var{topresolver} = @i{res}.@i{composer}(@var{subresolver})
width, height = @i{wo}(@var{topresolver}, ...)
@end example

@item @b{Details:}
The call of every resolver returns a context reference handle, that must be
supplied to the upward resolver in the chain. Thus you need to start with the
lowest resolver in your level code. The @ref{World Creation} takes the top most
resolver context handle.

There is no limit to the number of chained resolvers. But the order of resolvers
may sometimes be critical. Please read carefully the resolver notes for usage,
restrictions and caveats.

@item @b{Full Example:}
The level "Demo Resolver Chain" of levelpack "Demolevels":
@example
ti["~"] = @{"fl_water"@}
ti["s"] = @{"fl_sahara"@}
ti["t"] = @{"fl_tigris"@}
ti["1"] = @{"ac-blackball", 0, 0.5@}

ti["template_trigger"] = @{"it_trigger", target="myoxyd%%", action="open"@}
ti["template_oxyd"]    = ti["~"] .. @{"st_oxyd", "myoxyd%%"@}

myrandom = res.random(ti, " ", @{"s", "t"@})

myautotile = res.autotile(myrandom, @{"a", "h", "template_trigger"@},
                              @{"A", "H", "template_oxyd"@})

w, h = wo(myautotile, " ", @{
"A~                ~E",
"~~                ~~",
"~~   h        b   ~~",
"~~                ~~",
"B~     c    d     ~F",
"~~                ~~",
"~~        1       ~~",
"~~                ~~",
"C~     f    e     ~G",
"~~                ~~",
"~~   g        a   ~~",
"~~                ~~",
"D~                ~H"
@})

wo:shuffleOxyd()
@end example
@end table

@c ----------------- Custom Resolver --------------------

@node Custom Resolver
@subsection Custom Resolver
@findex custom resolver

A custom resolver is a function in the level that allows a dynamic remapping
of tiles. When this function is registered in the resolver chain it is called
once for every tile to be set. The tile that this function returns will be set.

Typical use cases are design patterns that are easy to calculate, but tedious
to draw in the map and dynamic generated levels that differ slightly on every
restart.

@table @asis
@item @b{Syntax:}
tile = @b{myresolver}(@i{key}, @i{x}, @i{y})

@table @asis
@item @i{key}
String that contains the tile key to be resolved.
@item @i{x}
The world x coordinate of the tile.
@item @i{y}
The world y coordinate of the tile.
@end table

@item @b{Details:}
A custom resolver function is the last resolver that is called in the chain.
It has to return the final tile that should be drawn at the given position.
This can be done by statement @samp{return ti["k"]}, which references the tile
already declared in the tile map.

If no suitable tile was declared you can alternatively return a new tile
like @samp{return ti(@{"st_switch", state=ON@})}.

If you decide not to draw any tile at all, you must return an empty tile
declaration: @samp{return @{"nil"@}} or @samp{return @{@}}.

@samp{return nil} indicates an error of usage of an unknown tile key.

@item @b{Example:}
The level "Demo User Resolver" of levelpack "Demolevels":
@example
ti["r"] = @{"fl_rough_red"@}
ti["b"] = @{"fl_rough_blue"@}
ti["1"] = @{"#ac-blackball"@}

ti["x"] = @{"it_cross"@}

function myresolver(key, x, y)
    if key == " " then
        local center = ((x%3) * (y%3))%2
        local checker = ((math.modf(x/3) %2) + (math.modf(y/3) %2))%2
        if center + checker == 1 then
            return ti["r"]
        else
            return ti["b"]
        end
    else
        return ti[key]
    end
end

w, h = wo(myresolver, " ", @{
"                    ",
"                    ",
"                    ",
"      x x           ",
"       x            ",
"      x x           ",
"                    ",
"          1         ",
"                    ",
"                    ",
"                    ",
"                    ",
"                    "
@})
@end example
@end table

@c ----------------- Autotile Resolver --------------------

@node res.autotile
@subsection res.autotile
@findex res.autotile

Autotiling reduces the number of required tile declarations by generating them
according to given simple rules. The most common application are a bunch of
identical switch like objects that all target the same type of object
like a door or a laser. As each of them has its individual target object it
would require to write a separate tile declaration with a unique tile key, e.g.

@example
ti["A"] = @{"st_floppy", target="laserA"@}
ti["B"] = @{"st_floppy", target="laserB"@}
ti["C"] = @{"st_floppy", target="laserC"@}
ti["a"] = @{"st_laser", name="laserA"@}
ti["b"] = @{"st_laser", name="laserB"@}
ti["c"] = @{"st_laser", name="laserC"@}
@end example

Autotiling requires just one template tile of each type and substitutes any
pattern @samp{%%} by a unique substitution.

@example
ti["template_switch"] = @{"st_floppy", target="laser%%"@}
ti["template_laser"]  = @{"st_laser", name="laser%%"@}
@end example

Independent on the number of required unique objects you have just one template.
You just declare the used range of tile keys by a rule and are free to use
them within your level map.

@table @asis
@item @b{Syntax:}

@b{res.autotile}(@i{subresolver}, @i{rules})

@table @asis
@item @i{subresolver}
Resolver to which unresolved requests should be forwarded. May be @samp{ti}
as the final resolver of the resolver chain.
@item @i{rules} = @i{rule}, @i{rule},...
One rule or as many as you like, all separated by a comma.
@item @i{rule} = @i{prefixrule} | @i{rangerule}
Each rule can be either a prefixrule or a rangerule in any mixture
@item @i{prefixrule} = @{@i{prefix}, @i{template}@}
A table with two entries. First a prefix string that is common to all tile
keys that should be handled followed by key string of the template tile.
@item @i{rangerule} = @{@i{first}, @i{last}, @i{template}@ [, @i{offset}]@}
A table with at least three entries. A string with the first key to be handled,
followed by a string with the last key to be handled. The third value is the key
string of the template tile. An optional fourth value, that defaults to @code{1},
defines the number of the first key on @samp{%%} pattern substitutions.
@end table

@item @b{Syntax Samples:}
@example
res.autotile(ti, @{"A", "template_switch"@}, @{"L", "template_laser@})
res.autotile(ti, @{"a", "e", "template_trigger@}, @{"A", "E", "template_door"@}
@end example

@item @b{Details:}
Prefix rules need a key length of at least 2. You can not use it with maps
of just one character per tile. The resolver will create a tile declaration for
any tile key in the map that matches the given prefix. A copy of the template
will be taken.

Within this copy of the template all occurrences of the two characters @samp{%%}
in explicit object declarations will be substituted by a single percent sign
followed by the suffix of the used tile key. Thus a key of @samp{AD} will target
the laser @samp{laser%D}. You need to use the key @samp{LD} in the map for the
matching laser.

Rangerules match any tile key in the given range. It can well be used in one
character key maps. But it can be used in multicharacter maps, too. In this case
the given first and last keys may just differ in the last character. Again a
copy of the template rule will be generated and the @samp{%%} patterns will be
substituted. But in this case the substitution is composed of a single percent
sign followed by an integer number, that counts the key position within the
given range, starting with the given offset or default @code{1}. Thus a key of
@samp{c} in the syntax sample above will target the door @samp{door%3}. You
would need to use the key @samp{C} in the map for the matching door.

The template tile definitions can well be composed of several concatenated
tiles even with references of base tiles. The pattern substitution takes place
on any attribute value containing string descriptions. A valid template would
be:
@example
ti["template"] = ti["~"] .. ti(@{"it_trigger", target=@{"door%%#*","laser%%"@}@}) .. @{"st_grate1"@}
@end example

A pattern substitution can even take place on a key of a referenced base tile.
Every occurrence of the two characters @samp{%%} in the key will be substituted
by the suffix of the used tile key without a preceeding percent sign. E.g. the
template:

@example
ti["template"] = ti["P%%"] .. @{"st_floppy", target="laser%%"@}
@end example

applied to a key with the suffix @samp{d} will result in a base tile key @samp{Pd}.
This feature is especially useful if the autotile resolver is chained to
another subresolver which generates the base tiles.

@item @b{Full Example:}
@example
ti[" "] = @{"fl_sahara"@}

ti["template_a"] = @{"st_floppy", target=@{"door%%#*","laser%%"@}@}
ti["template_A"] = @{"st_blocker", "door%%#"@}
ti["template_1"] = @{"st_laser_s", "laser%%"@}

ti["x"] = @{"#ac-marble_black"@} .. ti(@{"it_floppy"@})

local resolver = res.autotile(ti, @{"a", "e", "template_a"@},
    @{"A", "E", "template_A"@},  @{"1", "5", "template_1"@})

w, h = wo(resolver, " ", @{
"                    ",
"                    ",
"   a   DB  e    BC  ",
"                    ",
"   CD  b   AE   c   ",
"                    ",
"   d   EA           ",
"                    ",
"           x        ",
"                    ",
"                    ",
"   4  2  5  1  3    ",
"                    "
@})
@end example
A more elaborate example can be found in @ref{Orthogonal Autotiling}.

@item @b{Caveats:}@anchor{Caveats}
Do not use the hash sign @samp{#} as suffix character for key length 2 and
above autotiled keys. A key @code{"A#"} could result in an unexpected @samp{%%}
substitution in the name attribute. A name @code{"sample%%"} would be
substituted by @code{"sample%#"} which is a name that will be autonumbered
(@pxref{Object Naming}).
@end table


@c ----------------- Composer Resolver --------------------

@node res.composer
@subsection res.composer
@findex res.composer

The composer resolver reduces the number of required tile declarations by
generating them by composition of base tiles. Even small levels and nearly
every large level will use many different objects in numerous tile compositions.
As the usable one character tile key candidates will not suffice you will need
to use two or three character tile keys. But you will need numerous tile
declarations, one for every used object combination.

The composer frees you from declaring every used combination. You just declare
the base objects, e.g. the floors and all stones, items, actors and use
combinations of these base tiles keys. The composer constructs the required
tile declarations on the fly. E.g. with the following base tile declarations:

@example
ti[" ."] = @{"fl_space"@}
ti[" ~"] = @{"fl_water"@}
ti["X "] = @{"st_grate"@}
ti["h "] = @{"it_hammer"@}
@end example

You can freely use any of the additional combinations like @code{"X."} - a grate
on space, @code{"X~"} - a grate on water, @code{"h."} - a hammer on space,
@code{"h~"} - a hammer on water.

@table @asis
@item @b{Syntax:}

@b{res.composer}(@i{subresolver})

@b{res.composer}(@i{subresolver}, @i{sequence})

@table @asis
@item @i{subresolver}
Resolver to which unresolved requests should be forwarded. May be @samp{ti}
as the final resolver of the resolver chain.
@item @i{sequence}
Search sequence for basic tile declarations given as a string of priority
numbers. The sequence defaults to @code{"123456789"}.
@end table

@item @b{Syntax Samples:}
@example
res.composer(ti)
@end example

@item @b{Details:}
For every key in the map the subresolver will be first requested for a tile
declaration. Thus any given explicit declaration will precede the auto
composition.

Just in case that no declaration exists the search starts for existing subkey
tiles. Subkeys are keys with all but some characters replaced by a whitespace
@samp{ }.

The search sequence is given by the optional second argument and defaults to
@code{"123456789"}. In the first step all character positions marked by a
@samp{1} in the sequence string are maintained in the key string and all others
are replaced by whitespace. In the second step all character positions marked
by a @samp{2} in the sequence string are maintained in the key string and all
others are replaced by whitespace. This procedure continues until the number
equals the key length. All generated subkeys are resolved by the subresolver
and concatenated in the given sequence.

With the default sequence @code{"123456789"} a key request for @code{"~mX"} is
resolved to subkeys @code{"~  "}, @code{" m "} and @code{"  X"}. These subkeys
are resolved by the subresolver. If the subresolver is @samp{ti} the result is:

@example
ti["~  "] .. ti[" m "] .. ti["  X"]
@end example

With a key length of 3 or more characters it is sometimes useful to avoid a
total decomposition into single character based subkeys. E.g. you may want
to use a @ref{res.autotile} or @ref{res.puzzle} as subresolver. Both have the
need of essential 2 character subkeys. In this case you can simply define
the sequence as @code{"122"} for a key length of 3. A key request of
@code{"~Pa"} will be resolved to subkeys @code{"~  "}, @code{" Pa"}. In case
of a puzzle subresolver this would result in:

@example
ti["~  "] .. ti[" P"]
@end example

with second tile declaration being a @ref{st_puzzle} declaration with the
@samp{connections} attribute being set to @code{"w"} according to the last key
character @samp{a}.

With a @code{"231"} you stick to a total decomposition, but you redefine the
sequence of evaluation and composition. For the key @code{"~mX"} you would get
in contrast to the first example:

@example
ti["  X"] .. ti["~  "] .. ti[" m "]
@end example

In all cases, subkeys, that are strings of whitespace only, will simply be
ignored. With the default sequence the key @code{"~ X"} will result just in:

@example
ti["~  "] .. ti["  X"]
@end example

If you set your floors by usage of the composer you should use the all
whitespace key as your default floor as this key does not resolve via the
composer and needs the backup of the default mechanism.

@item @b{Full Example:}
@example
ti["  "] = @{"fl_sahara"@}
ti[" ="] = @{"fl_tigris"@}
ti[" ."] = @{"fl_abyss"@}
ti[" ~"] = @{"fl_water"@}
ti[" ;"] = @{"fl_lawn"@}

ti["# "] = @{"st_granite"@}
ti["W "] = @{"st_wood"@}
ti["X "] = @{"st_oxyd"@}
ti["G "] = @{"st_grate_cross"@}

ti["2 "] = @{"it_coin_s"@}
ti["s "] = @{"it_seed"@}
ti["c "] = @{"it_cherry"@}
ti["h "] = @{"it_hammer"@}

ti["k "] = @{"it_key"@} .. ti(@{"st_lightglass"@})

ti["xx"] = @{"#ac_marble_black"@}

local resolver = res.composer(ti)

w, h = wo(resolver, "  ", @{
--0001020304050607080910111213141516171819
 "                                        ",
 "  h= ;W;2;c G~ ~# #.2.X X~k=k;          ",
 "                                        ",
 "  2;s;    2.s.    2=s=                  ",
 "  c;h;    c.h.    c=h=    xx            ",
 "                                        "
@})
@end example

@end table


@c ----------------- Maze Resolver --------------------
@node res.maze
@subsection res.maze
@findex res.maze

The maze resolver supports you in the creation of quite arbitrary mazes. The
shape is no longer limited to boring rectangular areas of one grid thick walls
leaving the player just a one grid path uniquely connecting all parts of the maze.

This second generation maze generator lets you fill mazes in arbitrarily shaped
areas, mazes with thick walls or chasms, or thin walls of just a sheet of window
glass, mazes with cells of single grid, cells that are whole islands or mazes
based on @ref{it_strip} that have cells of no extent and consist of connections
only. The maze cells may be aligned strictly rectangular or shifted in one
direction, they may be just connected to its 4 neighbors or to 6 neighbors in
hexagonal mazes or three dimensional mazes. You can write and plug in your own
maze generation and rendering algorithms. And finally you can analyse,
postprocess and even modify your maze even after the initial creation.

From the mathematical point of view we provide the basic structures for
generation of quite arbitrary directed graphs. Our maze consists of cells, the
vertices of a graph. Every cell can be connected to a given number of neighbor
cells.  But these connections, that are the passages from one cell to another,
can even be direction dependent. This allows you to use window panes on either
side of a connection or to use oneways for your connections, too. These passages
from one cell to another are the edges of our graph and as they may be directed
we have a directed graph. But for most mazes the support of directions is
irrelevant and transparent, and you do not really need to know anything about
graphs at all. Thus we called the resolver just a maze resolver.

Of course such a versatile resolver needs some configuration. As the parameters
exceed the number of arguments, that you can reasonably supply to a function
just by enlisting them, we decided to group the parameters for specific
tasks and to use a table with named attributes for the configuration. This
sounds more complex than it is. But watch out carefully for the table curly
braces as they are necessary and can not be omitted.

In a big level you may want to generate two or even more completely independent
mazes. You can do this by using multiple instances of this resolver. The
resolver handle returned on the configuration is a unique reference pointer for
the maze for subsequent requests. Store it and link all the maze resolvers as
explained in @ref{Resolver Chaining}.

@table @asis
@item @b{Location:}
This resolver is part of the library @samp{libmaze} as of release 2. You can
use it by adding the following dependency to your level @ref{<compatibility>}
declaration:
@example
  <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/libmaze}" @i{el}:@b{id}="@var{lib/libmaze}" @i{el}:@b{release}="@var{2}" @i{el}:@b{preload}="@var{true}"/>
@end example

The library @ref{libmap} is automatically preloaded by this resolver.

@item @b{Syntax:}

@i{themaze} = @b{res.maze}(@i{subresolver}, @i{attributes})

@table @asis
@item @i{subresolver}
Resolver to which unresolved requests should be forwarded. May be @samp{ti}
as the final resolver of the resolver chain.
@item @i{attributes} = @{@i{keyvalue}, @i{keyvalue},...@}
An anonymous table with one or many attributes given as key value pairs,
separated by a comma.
@item @i{keyvalue} = <area=@i{area_value} | render = @i{render_value} | kernel = @i{kernel_value} | spacing = @i{spacing_value} | persistent=@i{persistence}>
Values for given keys that may occur in any sequence in the anonymous table.
@item @i{area_value} = @{<@i{rectangular_area} | @i{marked_area}>@}
The maze area specification, that is either defined as a rectangular area
or an area marked in the world's map.
@item @i{rectangular_area} = @i{anchor}, @i{width}, @i{height}
An rectangular area that is given by an anchor position within the world and
two numbers for the width and height measured in maze cells.
@item @i{anchor}
Anything that is convertible to a @ref{Position} that denotes the upper left
edge of the rectangular maze area. Besides a position value, an object reference
or a name string of an object or position are supported value types.
@item @i{marked_area}
One or multiple strings separated by a comma as simple entries in the anonymous
table. Every string does either specify a key match, a key prefix or an object
name. All these strings can be used at the same time for marking an area. The
strings can occur in any sequence and multiplicity.
@item @i{kernel_value} = @{kernel_width, kernel_height@}
The size of the kernel of a cell given by width and height in number of grids.
@item @i{spacing_value} = @{spacing_x, spacing_y@}
The distance of the kernel of one cell to its neighbor in x and y direction
measured in number of grids.
@item @i{render_value} = @{<@i{std_renderer_args} | @i{other_renderer}>@}
The specification for drawing the maze. In case of a missing specification
no drawing will be done at all. If the default standard renderer should be used
its parameters can be directly supplied, other renderers need a type
specification plus the necessary configuration information.
@item @i{std_renderer_args} = @i{passage_keys} [, <@i{wall_key} [, @i{kernel_key}] | @i{cell_map}>]]
The standard renderer takes info about tile keys to be used for the passages,
and either a cell map, or additional tile keys for the wall and optionally the
kernel of a cell.
@item @i{passage_keys} = <@i{passage_key} | @{@i{passage_open}, @i{passage_closed}@}>
Usually you just give a tile key for open maze passages. Closed passages appear
like walls and use the same tile key. But in case you want to use special tile
keys for open and for closed passages you can supply two strings in an
anonymous table. If you give no wall key you may need to include an
@samp{st_nil} in your open passage tile declaration to kill a wall stone drawn
by your world map.
@item @i{wall_key}
The tile key to be used for drawing walls. If it is omitted no wall is drawn
and the resolver relies on all possible wall tiles to be drawn by the world
map itself.
@item @i{kernel_key}
In most cases the cell kernel will be drawn by the world map. But if not you
can supply a tile key that will be drawn on every cell kernel grid.
@item @i{cell_map}
Instead of kernel and wall tile keys you can supply a @ref{libmap} map of a
complete cell. The map can provide arbitrary tiles for cell kernels larger than
a single grid. The walls can differ on the south and east side, too.
@item @i{other_renderer} = @i{renderer}  [, @i{other_renderer_args}]
Enlisting of a renderer function followed by its specific arguments.
@item @i{renderer}
The function that does the rendering. By default it is
@samp{lib.maze.renderer_standard} with the above given arguments. Other supplied
renderers are @samp{lib.maze.renderer_window} and
@samp{lib.maze.renderer_strip}
@findex lib.maze.renderer_standard
@findex lib.maze.renderer_window
@findex lib.maze.renderer_strip

@item @i{persistence}
A boolean flag that defaults to @samp{false}. You need to set it to @samp{true}
if you want to access the maze or any of its cells after the level
initialization. Otherwise the maze reference handle with all its data may get
invalid due to memory garbage collection. This is no problem for most mazes,
that will be directly rendered and have no need of further evaluation or changes
during runtime.
@end table

@item @b{Syntax Samples:}
@example
maze1 = res.maze(ti, @{area =@{"anchor1", 4, 5@}, render = @{" ", "-", " "@}@})
maze2 = res.maze(ti, @{area =@{"."@}, kernel=@{1,1@}, render = @{"!", "~", "-"@}@})
maze3 = res.maze(ti, @{area =@{"amaze#*"@}, render = @{@{".","+"@}, "~", "-"@}@})
maze4 = res.maze(ti, @{area =@{po(2, 12), 5, 5@}, kernel=@{3,2@},
                   render = @{".", wo:newMap(" ", @{"!!!~","--!~","~~~~"@})@}@})
@end example

@item @b{Details:}
To be written.


@item @b{Full Example:}
@example
@end example
@end table

@c ----------------- Puzzle Resolver --------------------

@node res.puzzle
@subsection res.puzzle
@findex res.puzzle

The puzzle resolver helps you to reduce the number of required tile declarations
for clusters of @ref{st_puzzle} stones. By usage of the @samp{cluster} attribute
of @ref{st_puzzle} you can easily set clusters of fully connected stones. But
for irregular, internally just partial connected puzzles you often need a bunch
of similar tile declarations that differ just in the @samp{connections} attribute
value.

@example
ti["B1"] = @{"st_puzzle_blue", cluster=1@}
ti["Ba"] = @{"st_puzzle_blue", connections="w"@}
ti["Bb"] = @{"st_puzzle_blue", connections="sw"@}
ti["Bd"] = @{"st_puzzle_blue", connections="ew"@}
ti["Bh"] = @{"st_puzzle_blue", connections="n"@}
@end example

Like @ref{res.autotile} this resolver offers autotiling. You just define one
template tile and can use all connections variations

@example
ti["B"] = @{"st_puzzle_blue"@}
@end example

Additionally this resolver registers every puzzle stone set and allows you to
shuffle the puzzle clusters. You can even select shuffle algorithms and define
accessible sides of a puzzle.

@table @asis
@item @b{Location:}
This resolver is part of the library @samp{libpuzzle} as of release 3. You can
use it by adding the following dependency to your level @ref{<compatibility>}
declaration:
@example
  <@i{el}:@b{dependency} @i{el}:@b{path}="@var{lib/libpuzzle}" @i{el}:@b{id}="@var{lib/libpuzzle}" @i{el}:@b{release}="@var{3}" @i{el}:@b{preload}="@var{true}"/>
@end example

@item @b{Syntax:}

@b{res.puzzle}(@i{subresolver}, @i{rules})

@table @asis
@item @i{subresolver}
Resolver to which unresolved requests should be forwarded. May be @samp{ti}
as the final resolver of the resolver chain.
@item @i{rules} = @i{rule}, @i{rule},...
One rule or as many as you like, all separated by a comma.
@item @i{rule}
The string of the template tile key that is the common tile key prefix for all
autogenerated tile declarations.
@end table

@item @b{Syntax Samples:}
@example
res.puzzle(ti, "B", "Y", "I", "M")
@end example

@item @b{Details:}
The puzzle resolver assumes a tile key length of two or more characters. The
given rules are prefix strings which need concat with a one character suffix
to a standard tile key. Given a rule with a proper template rule you can use
any of the following suffices without tile declaration:

@example
    Suffix   Cluster Connections
Solid Hollow
 '0'   '5'       0   autoconnect
 '1'   '6'       1   autoconnect
 '2'   '7'       2   autoconnect
 '3'   '8'       3   autoconnect
 '4'   '9'       4   autoconnect
 ' '   '+'      nil    ""
 'a'   'A'      nil    "w"
 'b'   'B'      nil    "s"
 'c'   'C'      nil    "sw"
 'd'   'D'      nil    "e"
 'e'   'E'      nil    "ew"
 'f'   'F'      nil    "es"
 'g'   'G'      nil    "esw"
 'h'   'H'      nil    "n"
 'i'   'I'      nil    "nw"
 'j'   'J'      nil    "ns"
 'k'   'K'      nil    "nsw"
 'l'   'L'      nil    "ne"
 'm'   'M'      nil    "new"
 'n'   'N'      nil    "nes"
 'o'   'O'      nil    "nesw"
 'p'   'P'      10   autoconnect
 'q'   'Q'      11   autoconnect
 'r'   'R'      12   autoconnect
 's'   'S'      13   autoconnect
 't'   'T'      14   autoconnect
 'u'   'U'      15   autoconnect
 'v'   'V'      16   autoconnect
 'w'   'W'      17   autoconnect
 'x'   'X'      18   autoconnect
 'y'   'Y'      19   autoconnect
 'z'   'Z'      20   autoconnect
@end example

All puzzle stones set by this resolver will be registered and shuffled by
default with the @samp{intensity} of 3. You can define other intensity attribute
values on any puzzle stone. The maximum intensity of all stones in a cluster
will be taken. The intensity multiplied by the number of stones in a cluster
describes the number of inverse pushes, called pulls, that will be performed
during shuffling. Thus an intensity of 3 on a cluster of 6 stones will perform
18 pulls. That means it is guaranteed that you can solve the puzzle with 18
pushes. But as some pull operations may neutralize the user may be able to
solve such a shuffled puzzle with less than 18 pushes.

If you define no shuffle @samp{algorithm} it is assumed that the user can
rotate the puzzle from any side and any @ref{st_puzzle}. The requested number
of shuffling pull operations will be performed from random puzzle stones in a
manner that guarantees that the user can solve the puzzle if he has free access
to all sides.

If you set the @samp{algorithm} on any of the puzzle stones to the value
@code{"marked"} the resolver registers that the user has no free access, but
just from positions that you did mark. You do mark a position by setting
the attribute @ref{push_directions} on a floor. All floors adjacent to puzzle
stones, including floors beneath another puzzle stone, will be checked for this
attribute. It is your responsibility to mark all floors and to ensure that
the player has continuous access to these floors for solving the puzzle by
push rotations. The attribute takes a string value, a substring of @code{"nesw"}.
If it contains the character of the required push direction this push event will
take part in the random reverse shuffling process.

Note that hollow stones and their restriction of not being able to initiate a
rotation if fully respected on shuffling.

@item @b{Full Example:}
@example
ti["  "] = @{"fl_sahara"@}
ti["##"] = @{"st_granite"@}

ti[".."] = @{"fl_sahara", push_directions="nesw"@}

ti["B"] = @{"st_puzzle_blue"@}
ti["Y"] = @{"st_puzzle_yellow"@}
ti["I"] = @{"st_puzzle_blue", intensity=2/6@}
ti["M"] = @{"st_puzzle_blue", algorithm="marked", intensity=10@}

ti["xx"] = @{"#ac_marble_black"@} ..ti(@{"it_magicwand"@})

local resolver = res.puzzle(ti, "B", "Y", "I", "M")

w, h = wo(resolver, "  ", @{
"                                        ",
"B1B1B1B1                                ",
"B2B1BjB1                      Y1Y6Y1    ",
"B2B2B2B2                      Y1Y1YC    ",
"                                Y6YnY1  ",
"                ##########      Y1Y1Y1  ",
"                ##M1M1M1##              ",
"  I1I1          ##M1McM1..              ",
"  I6Ia          ..M1M1M1..      xx      ",
"  I1I1            ....####              ",
"                                        ",
"                                        ",
"                                        "
@})
@end example
@end table


@c ----------------- Random Resolver --------------------

@node res.random
@subsection res.random
@findex res.random

With map based level description you have explicit control about the objects
being set on every single grid. But sometimes you may want to introduce some
randomness in the used objects. E.g. a floor may be made up of two types at
random to generate a different look on every level start. The randomness would
even make a level more difficult to play if one of the two floors would
invert the mouse forces. The random resolver allows you to set up such
cases.

@table @asis
@item @b{Syntax:}

@b{res.random}(@i{subresolver}, @i{hits}, @i{replacements})

@table @asis
@item @i{subresolver}
Resolver to which unresolved requests should be forwarded. May be @samp{ti}
as the final resolver of the resolver chain.
@item @i{hits} = @i{key} | @{@i{hit}, @i{hit}, ...@}
Either a single tile key string that defines the tiles to be randomized, or a
table of hit descriptors that should all be examined in parallel.
@item @i{hit} = @i{key} | @{@i{key}, @i{superkey}@}
Either a single tile key string or a pair of tile key string and a related
tile superkey string. The superkey tile will be set additionally to the random
replacement.
@item @i{replacements} = @i{key} | @{@i{replacement}, @i{replacement}, ...@}
Either a single tile key string that would be taken without randomness or as in
most cases a table of replacement descriptors from which the resulting tile
should be selected with randomness.
@item @i{replacement} = @i{key} | @{@i{key}, @i{frequency}@}
Either a single tile key string that should be taken with a frequency of @samp{1},
or a pair of a tile key string with a given frequency number. The frequency can
be an integer or non-integer number, but must be positive or zero.
@end table

@item @b{Syntax Samples:}
@example
res.random(ti, "x", @{"a", "b"@})
res.random(ti, @{@{"x", "y"@},@{"i","j"@}@}, @{@{"a", 2@}, @{"b", 1@}@})
@end example

@item @b{Details:}
Every key in the map is checked against the given hit key strings. If it fits
one of them a replacement will take place.

The replacement will be one of the replacement tile keys resolved via the
subresolver. The different keys will be chosen with a likelihood according to
the ratio of the given frequency numbers. If no frequency is supplied a default
of @samp{1} is taken. Thus in the first example both keys are taken in a ratio
1:1, whereas in the second the ratio will be 2:1.

When a superkey is given for a hit key this superkey will additionally be
resolved via the subresolver. This feature allows to use randomness on tiles
with more than one object on a grid position. E.g. an item or an actor on a
random floor. The other objects can be set via the superkey while the random
floor is set according to the replacement rules.

@item @b{Full Example:}
@example
ti["~"] = @{"fl_water"@}
ti["s"] = @{"fl_sahara"@}
ti["t"] = @{"fl_tigris"@}
ti["i"] = @{"fl_inverse_gray"@}
ti["b"] = @{"fl_yinyang_yin"@}
ti["w"] = @{"fl_yinyang_yang"@}

ti["c"] = @{"it_coin_s"@}
ti["p"] = @{"it_brush"@}

ti["1"] = @{"ac_marble_black", 0, 0.5@}

simple_random = res.random(ti, " ", @{"s", "t"@})

full_random = res.random(simple_random, @{".",@{"C","c"@},@{"p","p"@}@},
                                        @{@{"i",3@},@{"b",4@},@{"w",1@}@})

w, h = wo(full_random, "s", @{
"         ~~.........",
"         ~~.........",
"         ~~......C..",
"         ~~.........",
"         ~~.........",
"         ~~.........",
"         c1.........",
"         ~~.........",
"         ~~.........",
"         ~~.........",
"         ~~......p..",
"         ~~.........",
"         ~~........."
@})
@end example

Note that in this example we can use @samp{p} as key as well as superkey. This
is due to the fact that nowhere else this tile is directly set. Whereas the
tile key @samp{c} is used for another tile with the default floor. Thus we do
need to use another unique key @samp{C} for the coin on our random floor.

@end table

@c ----------------- Train Resolver --------------------
@node res.train
@subsection res.train
@findex res.train

The train resolver supports you in the set up of train like wandering floor
chains. Usually short passages of solid standard floors wander on a closed
path of otherwise unpassable floors like @ref{fl_abyss} or @ref{fl_water}.

The path itself is called railway, even though the name train does not really
fit the features of the wandering floor chains. But these names have been
chosen by Petr Machata in his first implementation of a simple wandering floor
feature.

In contrast to real world train, the wandering floors themselves do not move at
all. Thus they do neither carry items or stones, nor do they allow an actor to
rest on them and to be automatically transported along the path. The train
is more like a curb wheel of a trunk. New floors are added to the front while
trailing floors are removed.

Actually a chain of floors is composed of two train locos which move along the
railway path. One at the front that sets floor of the standard passable kind and
one at the end, or exactly one grid behind the end, that resets floor of the
unpassable floor kind.

Usually both train locos move at the same speed keeping the passable floor
chain length constant. But this resolver allows you to set up arbitrary
number of train locos moving in arbitrary direction at arbitrary speed on a
railway. But the resulting floor patterns will likely no longer behave like
trains. Nevertheless we keep the name.

Every railway path has to be described by a chained train resolver instance. The
paths of different resolvers may cross each other, but crossing trains may cause
unexpected results as the train locos just set floors without any respect to
other trains. In future it is planned to add track and train line attributes,
which will allow even more complex railways.

@table @asis
@item @b{Syntax:}

@b{res.train}(@i{subresolver}[, @i{suffix}][, @i{hits}])

@table @asis
@item @i{subresolver}
Resolver to which unresolved requests should be forwarded. May be @samp{ti}
as the final resolver of the resolver chain.
@item @i{suffix}
An optional key suffix string. Every grid position with a matching key is
registered as part of the railway path.
@item @i{hits} = @i{hit}, @i{hit}, ...
One or many resolver key hits that will identify positions of the railway path
with optional trains located on them.
@item @i{hit} = @i{key} | @{@i{key} [, @i{subkey}][, edge=@i{edgevalue}][, train=@i{trainvalue}]@}
Either a single tile key string or a table of a tile key string with an optional
related tile subkey string and optional further arguments.
@item @i{edgevalue}
A railway position that marks one of two edges spanning a rectangular railway
path.
@item @i{trainvalue} = @{@i{successorkey} [, @i{predecessorkey}] [, length=@i{trainlength}] [, orientation=@i{traveldirection}] [, interval=@i{speed}] [, name=@i{namevalue}]@}
A train loco that moves with the given speed interval, defaulting to 0.25
seconds per grid, and starting into the given travel direction. The loco sets
floors given by the successor key string that will be resolved via the subresolver.
If a trainlength is given, a second train loco is automatically created that
preceeds this one by the given length. This front train loco will set floors
defined by the predecessor key string. If the train loco has an assigned name
string, the front train loco will be named with an appended @code{"_front"}.
@end table

@item @b{Syntax Samples:}
@example
res.train(ti, ".", @{" ^", train=@{" ~", " w", orientation=NORTH, length=6, interval=0.3@}@})
res.train(ti, @{"e", edge=true@}, @{">", train=@{" w", orientation=EAST@}@}, @{"<", train=@{"~", orientation=WEST@}@})
@end example

@item @b{Details:}
Every key in the map is checked against the given hit key strings. If it fits
one of them the positition is added to the railway path and the subkey is used
to set remaining objects via the subresolver onto the grid. If no subkey is
given no additional objects are set.

If the key is no hit, but a suffix string is given and matches the key, the
position will be registered as part of the railway path, too. In this case
the suffix part of the key will be replaced by space characters and the
resulting key will be resolved via the subresolver.

There is no need of marking every grid position of a railway, what would be a
very annoying task if many stones and items are positioned on its path. By
default every train moves straight forward. You just need to provide hints for
positions where the train turns left or right. Marking the positions of the path
that follow every turn is sufficient.


@item @b{Full Example:}
@example
ti["  "] = @{"fl_sahara"@}
ti[" ~"] = @{"fl_water"@}
ti[" w"] = @{"fl_wood"@}
ti["# "] = @{"st_rawglass"@}
ti[" @@"] = @{"#ac_marble"@}

railway1 = res.train(ti, ".", @{"1^", train=@{" ~", " w", orientation=NORTH, length=6@}@})
railway2 = res.train(railway1, @{"2e", edge=true@}, @{"2^", train=@{" ~", " w", orientation=NORTH, length=5@}@})

wo(railway2, "  ", @{
    "             .        ",
    "   .                  ",
    "              1^      ",
    "                     @@",
    "              #       ",
    "          2e          ",
    "                      ",
    "                      ",
    "  # #.            2^  ",
    "       .              ",
    "                  2e  ",
    "               .      ",
    "         .            "
@})
@end example
The first railway has just marked the essential positions that define the
path.
@end table

@c ----------------- General Features --------------------

@node General Features
@section General Features

@menu
* Display Follow Strategy::    How the display view follows the active marble
* Flood Spreading::            How a water flood spreads over a given area
* Fire Spreading::             How to start, use, and stop fire.
* Heat-Transformation::        How some floors transform when a fire starts nearby.
* Freeze Checking::            How to turn frozen boxes in a Sokoban to st_death.
@end menu

@node Display Follow Strategy
@subsection Display Follow Strategy

As the world can be larger than a display screen the active marble can move
out of the area that is visible at level start. Somehow the display has to
follow the active marble.

Whereas prior Enigma versions did provide just a handful of fixed modes, future
versions will give you a much more detailed control of the display following
strategy. We decided to switch the configuration to the future parameters
already now. This allows us to give you some more follower control, even though
some attributes are still limited in their values.

The strategy is described by the following parameters.

@table @asis
@item @b{Attributes:}

@table @asis
@item @ref{FollowGrid}
@item @ref{FollowMethod}
@item @ref{FollowThreshold}
@item @ref{FollowAction}

@end table

@item @b{Syntax Samples:}
@example
wo["FollowGrid"] = true
wo["FollowMethod"] = FOLLOW_SCROLL
@end example

@item @b{Details:}
The attributes should always be set in the sequence as given above. This is due
to the fact that the first attributes may reset some of the later attributes
to matching defaults. This way you will have to set just a two attributes for
the most common cases.

You can set the display follow strategy at any point. You are even allowed to
switch the strategy during the running game.

@item @b{Valid Configurations as of Enigma 1.10:}

@table @asis
@item @b{Screen Flipping:}
@example
wo["FollowGrid"] = true
wo["FollowMethod"] = FOLLOW_FLIP
@end example
The default strategy. The screen flips as soon as the marble reaches the outer
half of the boundary grid tile. The screen moves by a full screen minus the
common tile row or column.

@item @b{Half Screen Scrolling:}
@example
wo["FollowGrid"] = true
wo["FollowMethod"] = FOLLOW_SCROLL
wo["FollowAction"] = FOLLOW_HALFSCREEN
@end example
As soon as the marble reaches the outer half of the boundary grid tile the
display scrolls pixel by pixel by half a screen. It realigns to the grid. As
on a standard sized screen the display would have to scroll 9.5 grids in
horizontal direction such scrolls will alternate in scrolls of 9 and 10 grids.
The follower will try to stabilize the reachable scroll positions.

@item @b{Permanent Smooth Scrolling:}
@example
wo["FollowGrid"] = false
wo["FollowMethod"] = FOLLOW_SCROLL
@end example
The active actor will always stay in the center of the screen. The display
compensates the actor's movement pixel by pixel by scrolling. The display
positions are not aligned to grid tiles.

@item @b{Full Screen Scrolling:}
@example
wo["FollowGrid"] = true
wo["FollowMethod"] = FOLLOW_SCROLL
wo["FollowAction"] = FOLLOW_FULLSCREEN
@end example
As soon as the marble reaches the outer half of the boundary grid tile the
display scrolls pixel by pixel by a full screen minus the common tile row or
column.

@item @b{No Screen Scrolling:}
@example
wo["FollowMethod"] = FOLLOW_NO
@end example
No scrolling at all. Even if the active actor moves out of sight the display
remains at its position.

@item @b{Screen Flipping at a given threshold:}
@example
wo["FollowGrid"] = true
wo["FollowMethod"] = FOLLOW_FLIP
wo["FollowThreshold"] = po(2.5, 1.5)
@end example
The screen flips as soon as the marble reaches the given distance to the screen
boundary. The screen moves by a full screen minus twice the threshold distance.
The final display realigns to the grid even on odd threshold distances.

@item @b{Full Screen Scrolling at a given threshold:}
@example
wo["FollowGrid"] = true
wo["FollowMethod"] = FOLLOW_SCROLL
wo["FollowThreshold"] = po(2.5, 1.5)
@end example
The screen scrolls as soon as the marble reaches the given distance to the screen
boundary. The screen moves by a full screen minus twice the threshold distance.
The final display realigns to the grid even on odd threshold distances.
@end table

@end table

@node Flood Spreading
@subsection Flood Spreading
@cindex flood

A flood is active @ref{fl_water} that, originating from a source, spreads over
@ref{floodable} areas. In contrast to a flood standard water is just static,
its @samp{state} is @samp{IDLE} and it will not spread to adjacent floors. But
a flood reaching a static water lake will cross it as a tsunami and continue
actively spreading on all riparian zones.

You set up the area by adding the attribute @ref{floodable} with value
@code{true} on all its floors. Just @ref{fl_water} and the framed variants of
@ref{fl_wood}, @ref{fl_hay} and @ref{fl_rock} do not require to be explicitly
marked floodable as they are floodable by default. The marked area is the
maximum area that may be flooded. But obstacles may block the flood temporarily
or permanently.

A flood starts at a source.  As soon as you add a @samp{fl_water_source} or set
the @samp{state} to @samp{FLOODING}, the @ref{fl_water} starts to spread to
floodable neighboring grids with a speed defined by the attribute
@samp{interval}. The speed will be inherited to floors flooded by the stream.

Floodable floors with solid stones, closed doors or @ref{st_window} with
blocking faces on top will keep the flood from spreading to their grid position
or if already flooded to spread to a neighboring grid. But as soon as the
obstacle vanishes, e.g. an @ref{st_door} opens, the flood continues to spread.
Hollow stones, especially @ref{st_oneway} do not block flood streams, totally
independent of actor blocking features on certain types or faces.

Of special interest are the @ref{st_box} variants and their successor floors,
the framed variants of @ref{fl_wood}, @ref{fl_hay} and @ref{fl_rock}. A flood
will flow beneath a box stone, if the floor beneath is floodable. In consequence
of the upcoming water, the box stone will fall and build a framed floor of the
given kind. These floors act like bridges over flooding water. They still let
the flood spread to further neighboring floodable floors. Thus a user can not
stop a flood by pushing an @ref{st_box} onto its path, but he can make the water
passable for his marbles. In fact this framed floors can even operate as a flood
source, but we do not recommend this usage.

In contrast to these floor building stones the @ref{st_puzzle} does neither
fall on static nor on flooding @ref{fl_water}. As a solid stone it will even
block a flood on neighboring grids to reach its position. But of course once
moved completely over @ref{fl_water} the puzzle will fall if its own conditions
are met. The successor @ref{fl_gray} will not build a bridge over water. It
fills up the ditch and replaces the water completely. Thus the user can use
puzzles to stop a flood.

When a flood stream spreads to a new floor items on these floors may be affected.
E.g. @ref{it_crack} get flooded and do vanish. All @ref{it_burnable} besides oil
get wiped out, too.

Further active components of the flood concept are @ref{it_vortex} and
@ref{it_wormhole}. Besides actors both do spread a flood. The @ref{it_wormhole}
spreads the flood to its @samp{destination} if the floor at this grid is marked
@samp{floodable}. An @ref{it_vortex} will flood all its @samp{destination}s,
but of course just if it is in state @samp{OPEN}. In case the destinations are
vortices, too, they must be open, too, for a successful flood spreading. When the
last closed vortex on either end opens again the hold flood continues to spread.
Note that in these cases the flood reaches the destination grid from beneath.
Thus no stone will block the emerging water. But nevertheless a stone on the
destination position may well block the water from spreading to the neighboring
grids.

Be aware that the Enigma flood has some extraordinary features. The most
important is the ability to spread unlimitedly from every grid that got flooded,
independently of a still existing connection to the flood source. Thus once a
door is opened and a bit of the flood passes the door, the flood will continue
to spread even if the door closes again. Same is true for toggling vortices or
puzzle stones being pushed into a flood building a complete bridge over the
water stream. But this feature is intentionally, as it avoids many shortcut
situations and thus makes the flood more usable for level authors.

@c ----------------------------------------------------------------------
@node Fire Spreading
@subsection Fire Spreading

The 1.0-version of Enigma introduced a new fire system, making use of
attributes and messages of the floor tiles. The default fire, once
ignited, spreads over the landscape and destroys items, marbles and
some stones. It spreads along those floor tiles that are marked ``burnable'' by
default (like @ref{fl_hay} or @ref{fl_wood}), by attribute (see attribute
@ref{burnable}), or by one of two items that indicate burnability: the invisible
@ref{it_burnable} and the visible @code{it_burnable_oil}. On a burning floor,
all items are destroyed. However, some items prevent the floor from burning,
like @ref{it_meditation} or @ref{it_dynamite} (which ignites instead).

Fire can be ignited in several standard ways:
@itemize @bullet
@item The @code{setfire}-message sets fire to a floor if it is
burnable and the item on it allows it to burn; non-burnable items like
@ref{it_dynamite} are not ignited by this.
@item The @code{heat}-message ignites burnable floors as does
@code{setfire}, but also initiates a @ref{Heat-Transformation} of the floor
and ignites items on it.
@item The @code{ignite} and @code{explosion}-messages that are used by
@ref{it_dynamite} and @ref{it_bomb} can initiate fire via
@ref{it_burnable}[_oil] or if the
@ref{ignitable}-attribute of the floor is set (off by default).
@item The floor already starts burning on initialization when the
@code{initfire}-attribute is set (off by default).
@item Fire in the neighborhood, see below.
@end itemize

If needed, the @code{forcefire}-message can be used to set fire to
non-burnable floors. Internally, it is equivalent to manually setting
@code{it_burnable_ignited}; however, setting @code{it_burnable_ignited}
manually is deprecated to allow a further development of the fire-system in
future.

Fire does the following:
@itemize @bullet
@item It kills @ref{st_box}_wood, @ref{st_box}_hay, and @ref{st_flat}_moveburnable
above it, and @ref{st_flat}_burnable beneath it.
@item It melts @ref{st_ice} to @ref{fl_water}.
@item It heats its neighboring tiles, which might result in a
@ref{Heat-Transformation} of the floor.
@item It might ignite or destroy items on its neighbor, this concerns
@ref{it_dynamite}, both @ref{it_bomb}, and @ref{it_crack}.
@item It might set fire to its neighbor.
@item It shatters marbles that are not protected with @ref{it_umbrella} or other
measures. Note that in future versions, jumping over fire with @ref{it_spring}
might get allowed.
@end itemize

Fire stops burning after a random amount of time, as long as the
@code{eternal}-attribute of the floor is not set. When it stops
burning, it might replace the floor by another kind
(``fire-transform''), this is: @ref{fl_wood} is replaced by
@ref{fl_abyss}, @ref{fl_lawn} by @ref{fl_dunes}. Finally, it
puts @ref{it_burnable}_ash on the floor, which prohibits a second
fire and which can be removed with @ref{it_brush}. However, ash is not
set if the @ref{noash}-attribute is set (default only for @ref{fl_abyss}).

Since the spreading of fire is a random event, in 0.92, a level author couldn't
be sure that a particular item was ignited or fire was set. Since 1.0, these can
be assured by setting the @ref{secure}-attribute: When a burnable floor with
@code{secure = true} is near fire, it will eventually catch fire, items on it
are ignited, etc. @code{secure} is @code{false} by default.

In 0.92, there were two speeds of fire: When using @ref{it_burnable},
fire spread much faster than without. This is still the same in
1.0 and above. However, you can set the @ref{fastfire}-attribute to hasten
the fire without setting the invisible @ref{it_burnable}, this should be the
preferred method.

Fire that burns under a stone is not allowed to spread; the only exceptions are
floating stones like @ref{st_grate}, and those stones that are destroyed by fire
anyway (@ref{st_box}_wood, @ref{st_box}_hay, @ref{st_flat}_burnable,
@ref{st_flat}_moveburnable). In contrast to this, fire might also spread to
under a movable stone, but not further.

You can stop fire with @code{it_extinguisher}, which creates the fireproof
@code{it_burnable_fireproof}. Another way to stop fire is to push the totally
inert @ref{st_box}_rock over it: This is the only movable stone that doesn't
allow fire under it. A final way to stop fire is to send the
@code{stopfire}-message to a floor.

@strong{Differences between 1.0 and 0.92}

The old fire system of Enigma versions up to 0.92, differs from
the 1.0 and above version mainly in the following points:

@itemize @bullet
@item no fire-transform except @ref{fl_wood} to @ref{fl_abyss}
@item no @ref{Heat-Transformation}s
@item ash on @ref{fl_abyss}
@item no difference between different floors
@item replication via same-floor-pattern instead of
burnable-floor-pattern: 0.92 didn't distinguish between burnable and
non-burnable floors. Instead, fire was allowed to spread to floors of
the same kind slowly.
@item burnable items always catch fire: In 1.0 and above, a burnable item
(except for @ref{it_burnable}[_oil]) on a non-burnable floor won't catch fire,
in 0.92 it did.
@end itemize

A good model of the 0.92-system can be attained via the
compatibility-modes: All non-Enigma-modes (@pxref{Engine Compatibility} and
@ref{<compatibility>}) feature a version which only marginally differs from
0.92-fire, yet allowing some of the new achievements, like secure- or
eternal-fire.

Note that in 0.92, fire-transformation happened at the beginning of
the fire, which manifested in the so called ``burning-abyss''-bug.
Besides other details, this is how the original 0.92 system differs from the
one in 1.0-non-Enigma-mode.

@strong{Burnable and Fireproof Floors}

All floors that look like plastic, fabrics, or organics are burnable by default:
@code{fl_adhesionless, fl_aquamarine, fl_bluegray, fl_bluegreen, fl_blueslab,
fl_fake_trigger, fl_hay, fl_ivory, fl_marble, fl_platinum, fl_red, fl_redslab,
fl_rough*, fl_tigris, fl_woven}.

All floors that look like wood are burnable and leave @ref{fl_abyss} behind:
@code{fl_bast, fl_plank, fl_samba*, fl_wood*}, and @ref{fl_bridge}_b*.

All floors that look like grass are burnable and leave @ref{fl_dunes} behind:
@ref{fl_lawn}.

All other floors are fireproof (they don't burn by default):
@code{fl_abyss*, fl_brick, fl_bright, fl_concrete, fl_dark, fl_darkgray,
fl_dummy, fl_dunes,  fl_gravel, fl_gray, fl_himalaya, fl_ice, fl_inverse*,
fl_metal*, fl_mortar, fl_pinkbumps, fl_rock, fl_sahara, fl_sand, fl_slope*,
fl_space, fl_stone, fl_swamp, fl_water, fl_white, fl_yinyang*}, and
@ref{fl_bridge}_g*.

An open @ref{fl_bridge} is never burnable, this overrides all items and
attributes. A closed @ref{fl_bridge} is burnable if and only if it is brown,
but this can be changed via attribute @code{burnable}. Note that changing the
flavor of @ref{fl_bridge} will change @code{burnable} according to the new
flavor as well.

@strong{Fireproof Items}

Most items are passively burnable, this is: An item is destroyed by
fire, if and only if the floor could burn all by itself.  However,
there are some items with individual reactions (@code{it_burnable,
it_burnable_oil, it_dynamite, it_bomb*, it_crack*})
and some items that are completely fireproof. These are: @code{it_burnable_ash,
it_burnable_fireproof, it_debris, it_dummy, it_explosion*, it_extinguisher,
it_extinguisher_medium, it_meditation*, it_trap, it_vortex*} and the fire
animations themselves: @code{it_burnable_ignited} and
@code{it_burnable_burning}.

Note that @code{it_extinguisher_empty, it_trigger} (visible and invisible),
@code{it_landmine}, and @code{it_death} are passively burnable.  In particular,
@code{it_landmine} does not explode or create @code{it_meditation} when burning.
The reaction of @ref{it_sensor} towards fire might be changed in future
versions.

If you need to save a passively burnable item from fire, simply set a fireproof
floor like @code{fl_sand} or @code{fl_rock} below it. This normally is the case
when using @ref{it_strip}. However, you can use the @code{burnable}-attribute in
these cases to force burnability of the floors.

@node Heat-Transformation
@subsection Heat-Transformation

When a fire starts to burn near @ref{fl_ice}, it melts to @ref{fl_water}. In the
same sense, @ref{fl_water} boils to @ref{fl_swamp}, and this again to
@ref{fl_dunes}. In contrast to most other fire-related actions, this is not
random, but always and only happens, when a nearby fire starts to burn, i.e.
once for each new fire.

Examples: Put an @ref{st_box}_rock on @ref{fl_ice}. A fire will melt
the ice, and @ref{st_box}_rock creates a fireproof and safe way to the
other side. If you use @ref{st_box}_wood instead, @ref{fl_wood}_framed is
created, which presumably catches fire and leaves @ref{fl_abyss}
behind. Finally, @ref{st_box}_hay will create @ref{fl_hay}_framed, which is
burnable, but won't burn down to @ref{fl_abyss}. A similar combination is
@code{fl_water} with @ref{st_chess}.

You can enforce a transformation by sending the @code{heat}-message to the
floor.

If you want to suppress this transformation, you can switch to
a non-Enigma-compatibility-mode.

@node Freeze Checking
@subsection Freeze Checking

With Enigma 1.1 and above, you can use a special feature to support Sokoban
levels and Sokoban parts of levels: Whenever a movable stone is pushed into
some unmovable position, this feature automatically transforms the stone into
@ref{st_death}, to demonstrate that the game is lost and provide a simple way
for the player to restart.

The feature is called ``Freeze Checking''. It applies to each stone with
attribute @code{freeze_check = true} which is pushed onto a floor with
attribute @code{freeze_check = true}. This way you can restrict the freeze
check to a bounded area. For a true Sokoban the goal tiles should not be marked
with @code{freeze_check = true}, as a frozen box on a goal is not considered
harmful. On the other hand, you can specify which boxes are freeze-checked. This
gives further freedom to use other stones inside your Sokoban area: Floor and
stone both need the @code{freeze_check}-attribute activated.

The freeze check recognizes three basic constellations of stones that lead to a
freeze of a standard movable stone. With @code{B} as box (movable or
persistent) and @code{#} as wall (persistent):
@example
BB   #B   #B
BB    #    B#
@end example
There are more freeze constellations which are not recognized, the simplest
would be:
@example
#B
 BB
  #
@end example
Don't rely on this fact, it might be changed in future versions.

Please bear in mind: The freeze check is not intelligent. It can't foresee that
one of your functions might remove a stone, it can't foresee that some door
will never open up again (doors are considered as non-existent), it doesn't
recognize when you put an @ref{it_puller}, @ref{it_cherry}, or @ref{st_swap} in
your level. It handles special stones in a way to minimize false-positive freeze
checks.

Floating stones (like @ref{st_grate}) create completely new frozen
constellations. From the following two examples, only the right example is
frozen (@code{G} is @code{st_grate_cross}):
@example
G    G
BB   BB
GB   GBG
@end example
At present, none of these are recognized as frozen by Enigma, floating stones
are considered as non-existing during a freeze check. To demonstrate the
difficulty, you may analyze yourself which of the following constellations is
frozen:
@example
G      G      GBG   GB#    G G#G
B#    BBB     BB    GB G   BBBBB
G    #B B#   #B      G     G#G G
      G G     G
@end example

In some cases, stones are even handled differently although they have similar
properties: @ref{st_box}_wood and @code{st_flat_moveburnable} (see
@ref{st_flat}) are both movable and both destroyed by fire (see @ref{Fire
Spreading}). There would never be frozen stones, as they can easily be burned
away. Yet, @code{st_box_wood} uses the default freeze checking, whereas
@code{st_flat_moveburnable} is considered as non-existing. This is because
@code{st_box_wood} is often used without fire, whereas
@code{st_flat_moveburnable} is primarily used in combination with fire.

Another example is @ref{st_shogun}_s, which is considered as a default
movable stone, in contrast to the remaining shogun stones. This way you can use
@code{st_shogun_s} with goal @ref{it_shogun}_s, but don't have to fear
false-positive freeze checks from the non-standard way in which shogun stones
move.

As a concluding remark, the freeze checking is to be used as a support for the
gamer only. It's not meant to be exploited as special feature to make movable
stones unmovable or to provide a way to jump back to the starting position. It
is subject to changes in future versions. And versions before 1.1 won't make a
freeze check at all - so you can't rely on it to happen. It should really be
used in Sokoban-kind parts of a level only, for which it is designed.

@c ----------------------------------------------------------------------
@node Tips and Tricks
@section Tips and Tricks

@menu
* Nearest Object Clustering::    When nearest object addresses wrong target
* Orthogonal Autotiling::        Autotiling with different sources and targets
@end menu

@node Nearest Object Clustering
@subsection Nearest Object Clustering

The nearest object as described in @ref{Object Naming} provides a major feature
for reducing the number of needed tile declarations. As the selection needs
to be unique a rule had to be defined in case of equal distances. South wins,
then east, stones are favored to items, floors and actors.

In most cases level authors can arrange their objects to fit these rules. But
sometimes the level design does not allow the straight forward usage of a
simple nearest object selection. E.g.

@example
ti["F"] = @{"st_floppy", target="@@door#*"@}
ti["B"] = @{"st_blocker", name="door#"@}
wo@{ti, " ", @{
"       B            ",
"       FB#####FB####",
"       # F    B     ",
"       # #    F#####",
@end example

In both cases the floppy switch that is located at the crossing of two blocker
doors will open the false one.

But you can use a cluster concept like the one we introduced for
@ref{Cluster Stones}. Just add one or in rare cases two or three additional
groups. Assign all standard cases to group A and the out of line cases in
group B:

@example
ti["F"] = @{"st_floppy", target="@@doorA#*"@}
ti["B"] = @{"st_blocker", name="doorA#"@}
ti["f"] = @{"st_floppy", target="@@doorB#*"@}
ti["b"] = @{"st_blocker", name="doorB#"@}
wo@{ti, " ", @{
"       b            ",
"       fB#####fb####",
"       # F    B     ",
"       # #    F#####",
@end example

By clustering the doors in two groups you just need two additional tile
declarations. But you will likely be able to handle a dozen of additional
switch/door combinations.

@node Orthogonal Autotiling
@subsection Orthogonal Autotiling

Autotiling is useful whenever you want to define lots of
target-action-pairings, even when source and target objects differ (i.e. use
different tile keys). In this case we speak of @samp{orthogonal autotiling}.
Let's take a look at the important parts of the API 2 version of the level
@samp{Laser Games}:

@example
...
ti["T*"] = @{"it_trigger", target = "mirror%%", action_1 = "turn", action_0 = "turnback"@}
ti["F*"] = @{"st_fourswitch", target = "mirror%%"@}
ti["1*"] = @{"st_mirror", name = "mirror%%", flavor = "triangle", orientation = NORTH@}
ti["2*"] = @{"st_mirror", name = "mirror%%", flavor = "triangle", orientation = SOUTH@}
ti["3*"] = @{"st_mirror", name = "mirror%%", orientation = NORTH@}
...

local resolver = res.autotile(ti, @{"T", "T*"@}, @{"F", "F*"@},
    @{"1", "1*"@}, @{"2", "2*"@}, @{"3", "3*"@}, @{"4", "4*"@}, @{"5", "5*"@},
    @{"6", "6*"@}, @{"7", "7*"@}, @{"8", "8*"@}, @{"9", "9*"@})

w, h = wo(resolver, "  ", @{
"# # # # # # # # # # # $ # $ # $ # $ # # ",
"#                 #                   # ",
"#     =   =       #   1a  9b  3c  2d  $ ",
"#             =   #                   # ",
"#     TaTbTcTd    #   3e  4f  5g  4h  $ ",
"#     TeFfFgTh    #                   # ",
"#     TiFjFkTl    #   6i  3j  4k  7l  $ ",
"#     TmFnFoTp    #                   # ",
"#     TqTrTsTt    #   8m  7n  6o  8p  $ ",
"#                 #                   # ",
"#       @@   =     #   1q  7r  3s  2t  $ ",
"#                 #                   # ",
"# # # # # # # # # # # $ # $ # $ # ^ # # "
@})
...
@end example

We have different kinds of sources for our actions (triggers @code{T} and
fourswitches @code{F}), and different kinds of targets (mirrors @code{1},
@code{2} etc.). However, as all mirrors are consistently named @code{mirror%%},
with @code{%%} being replaced by @code{%a} to @code{%t}, the connections
between the objects can be set easily without having to worry about different
object types: The trigger @code{Ta} will turn mirror @code{1a} (which is called
@code{mirror%a}), @code{Tb} will turn @code{9b} and so on. If we decide to
replace mirror @code{1a} by, say, mirror type @code{2}, we can simply replace
@code{1a} by @code{2a}, and still preserve the action-target-pairing.

In this very special situation, the attribute @code{counterclock} proves to
be useful: All mirrors in this level turn clockwise, except for @code{9b}.
Without @code{counterclock}, we'd have to use a callback-function to decide
about the target and manually choose between the actions @code{turn} and
@code{turnback}. However, by setting

@example
ti["9*"] = @{"st_mirror", name = "mirror%%", flavor = "triangle",
                         orientation = SOUTH, counterclock = true@}
@end example

it's possible to send the same messages to all mirrors that correspond to
triggers (i.e. @code{turn} when the trigger is pressed down and @code{turnback}
when it is released again), and still to have one or more mirrors behave in a
different way (i.e. rotating in another direction). The @code{inverse}
attribute is of a similar use.

@c ==================  Extension Development  =======================

@node Extension Development
@chapter Extension Development

@menu
* Resolver Development::
@end menu

@node Resolver Development
@section Resolver Development

Resolvers are designed to provide easy pluggable extensions for usage by level
authors. Further on resolvers should be as flexible as possible. To reach these
goals each resolver consists of three parts: the configurator, the implemention
and the finalizer.

@menu
* Resolver Configurator::
* Resolver Implementation::
* Resolver Finalizer::
@end menu


@node Resolver Configurator
@subsection Resolver Configurator
@findex res.resolvername

The configurator is the function that is being called, when the author
supplies the resolver specific parameters.

@table @asis
@item @b{Syntax:}
context = @b{res.resolvername}(@i{subresolver},...)

@table @asis
@item @i{subresolver}
Resolver to which unresolved requests should be forwarded. May be @samp{ti}
as the final resolver of the resolver chain.
@end table

@item @b{Details:}
This function has just one mandatory parameter, the subresolver. You are free
to specify arbitrary further parameters due to the needs of the resolvers task.

All official resolvers will be registered in the registry table @samp{res} under
their official name:

@example
function res.composer(subresolver)
    ...
end
@end example

This configurator function will be called just once per level start. It is
called after the tile declarations and before the first tile is set and the
implementation part may be called.

It is the task of the configurator function to check the user supplied
parameters thoroughly and to provide appropriate error messages on bad
parameters. Do this with a lua error message call at level 2 or the useful
helper functions @ref{assert_bool} and @ref{assert_type}:
@example
error("Resolver autotile rule " .. i.." is not a table", 2)
assert_bool(is_resolver(subresolver), "res.composer first argument (subresolver)", 2)
assert_type(args[1], "res.composer second argument (sequence)", 2, "non-empty string")
@end example

The configuration function has to return a table that contains the context
for subsequent calls of the implementation. This table has three predefined
entries:

@table @asis
@item @b{[1]} = @i{implementation function}
@item @b{[2]} = @i{finalizer function}
@item @b{[3]} = @i{subresolver}
@item @b{...} = resolver specific additional entries
@end table

All the checked and preprocessed parameters have to be stored in this context
table for later usage. The resolver implementation function is usually
registered as @samp{res.resolvername_implementation}. The finalizer can be
@samp{nil} if no finalization is necessary. The subresolver given as the
first parameter of the configurator call needs to be the third context
table entry.

The context needs to add a metatable with two entries. First @code{"_type"}
needs to identify the context as an enigma data type for the @ref{etype}
function. Most resolvers do simply store the string @code{"resolver"}, but
special ones might return special identification strings like @code{"maze"}.
The second required entry is @code{"_resolver"} that needs a boolean @samp{true}
value assigned for purpose of secure identification of resolver tables. A
default resolver metatable is stored at @samp{res.metatable} and can directly
be set by @samp{setmetatable}.

@item @b{Full Example:}
@example
function res.composer(subresolver)
    assert_bool(is_resolver(subresolver), "res.composer first argument (subresolver)", 2)
    local context = @{res.composer_implementation, nil, subresolver@}
    setmetatable(context, res.metatable)
    return context
end
@end example
@end table

@node Resolver Implementation
@subsection Resolver Implementation
@findex res.composer_implementation

When the map gets evaluated on the world creation the top resolver is asked
for every key to return the valid tile declaration. This is done with the
following call.

@table @asis
@item @b{Syntax:}
tile = @b{resolver_implementation}(@i{context}, @i{evaluator}, @i{key}, @i{x}, @i{y})

@table @asis
@item @i{context}
The context as provided as return value by the @ref{Resolver Configurator}.
@item @i{evaluator}
A system function that needs to be called whenever this resolver needs to
look up the key by its subresolver.
@item @i{key}
The key string that should be resolved
@item @i{x}, @i{y}
The position of the tile.
@end table

@item @b{Details:}
Based on the given parameters, the key, the position, the resolver parameters
stored in the context and the existing tiles that can be requested via the
evaluator function the implementation needs to decide if it takes influence on
the key. Note that it is not possible to access any world object via its
coordinates at this time. On every call you have to assume that it may be the
first tile that is set.

If the key is not resolved to a final tile by this resolver, the subresolver
must be called via the evaluator function:
@example
local tile = evaluator(context[3], key, x, y)
@end example

Remember that the subresolver is stored at position 3 of the context. As no
influence should be taken this tile is the one that should be returned.

But if you want to return another tile you are free to do it. You can decide
on another key and ask the subresolver for the appropriate tile. You can
even concatenate two tiles returned by subsequent subresolver calls. You are
allowed to return a new tile with a table declaration of an object. Some valid
return statements:
@example
return evaluator(context[3], "a", x, y)
return evaluator(context[3], "a", x, y) .. evaluator(context[3], "b", x, y)
return evaluator(context[3], "a", x, y) .. ti(@{"st_laser_n", state=ON@})
@end example

You are even allowed to add new tile declarations to the tiles repository to
speed up subsequent calls:
@example
ti["newkey"] = evaluator(context[3], "a", x, y) .. ti(@{"st_laser_n", state=ON@})
@end example

A resolver implementation can store and modify any of its private parameters
in the context table for subsequent calls. Especially it can enlist all
coordinates for postprocessing operations in the finalizer.

@item @b{Full Example:}
The implementation of the composer (without the special sequence treatment)
@example
function res.composer_implementation(context, evaluator, key, x, y)
    local tile = evaluator(context[3], key, x, y)
    if tile ~= nil then
        return tile
    end
    -- try to compose tile
    for i = 1, #key do
        local subkey = string.rep(" ", i-1) .. string.sub(key, i, i) .. string.rep(" ", #key - i)
        local subtile = evaluator(context[3], subkey, x, y)
        if subtile == nil then
            return nil
        end
        if tile == nil then
            tile = subtile
        else
            tile = tile .. subtile
        end
    end
    return tile
end
@end example
@end table

@node Resolver Finalizer
@subsection Resolver Finalizer
@findex res.resolver_finalization

If the @ref{Resolver Configurator} provides a finalizer function in its context
this function will be called once when all tiles from the map have been set.

@table @asis
@item @b{Syntax:}
@b{resolver_finalization}(@i{context})

@table @asis
@item @i{context}
The context as provided as return value by the @ref{Resolver Configurator}.
@end table

@item @b{Details:}
The finalization functions of chained resolvers are called from bottom to top.

Many resolvers have no need of a finalization. But some like a maze constructor
need to know all participating tiles until they can do their final work.

As all tiles from the map have been processed the objects can now be accessed.
Further information may be stored in the resolver's context.

The finalizer does neither call its subresolver nor does it return a value.
@end table

@c ==================  Guidelines and Hints  =======================

@node Guidelines and Hints
@chapter Guidelines and Hints

Up to now we described all features in their full extend. Of course you are
free to use them all without any restrictions for your private levels. We are
committed to maintain all features in future versions of Enigma.

But for inclusion of your levels into the Enigma project we would like to
recommend conformance to some common standards. These few points guarantee that
your levels can easily be processed by our administration tools, the players
can talk about your level and your level remains editable by the project
maintainers in case of urgent need.

Additionally we like to give you some hints how to write good levels by means
of proper strategy.

@menu
* Filename Recommendation::
* Title Recommendation::
* Tile Key Recommendation::
* Easy Mode Hints::
@end menu

@node Filename Recommendation
@section Filename Recommendation
No space for spaces

@node Title Recommendation
@section Title Recommendation
English titles preferred - use subtitle, too

@node Tile Key Recommendation
@section Tile Key Recommendation

The following guidelines are not compulsory, but we nevertheless encourage
them, as they ease the development of new and the maintenance of old levels.

@itemize @bullet
@item Stones use capital letters, items small letters, floors use punctuation marks.
@item The default floor is @code{" "}. The second most important floor typically is
@code{"_"} or @code{"."}. It's a good idea to use tile keys for floors, which are
small and don't obstruct the view on the more important objects, like
stones and items. Important floors (like bridges) may have letters or
numbers to emphasize their importance (a bridge could be @code{"b"}, or a
number to use autotiling).
@item Water typically is @code{"~"}, as the tilde is a small character which resembles
a wave. Similarly, an abyss can be well described by @code{"_"}, as the underscore
resembles a hole.
@item On a German keyboard, the four characters @code{"."}, @code{","}, @code{":"} and @code{";"} are
arranged in a square, so you can easily use them to arrange quadruples
of floors, like lawn pieces of different brightness.
On a US keyboard, you can use @code{","}, @code{"."}, @code{"<"} and @code{">"} to the same purpose.
Another quadruple of characters are the arithmetic operators @code{"+"}, @code{"-"},@code{"*"}, and @code{"/"}.
@item Slopes can be described using @code{"<"}, @code{">"}, @code{"v"} and @code{"^"}. As you see, we
encourage you to use the letter @code{"v"} for a floor at this point, as it
resembles an arrow pointing down. For slant slopes, it's a good idea to
use either numbers (following the number keypad on your keyboard), or
quadruple characters like @code{"."}, @code{","}, @code{":"}, @code{";"} or arithmetic operators.
@item Although it fits nicely to @code{"/"}, it's not a good idea to use the backslash
as a tile key, as it has to be masked to work correctly. Similarly, we
disencourage the use of brackets as tile keys.
@item The most important simple stone should be @code{"#"}, all other stones should
use their first letter, like ``laser'' -> @code{"L"}, ``switch'' -> @code{"S"}, ``box'' -> @code{"B"}.
If two stones have the same first letter, the more important one should
be given priority (@code{"L"} for laser instead of @code{"L"} for @code{"st_lightglass"},
@code{"G"} for @code{"st_lightglass"} instead of @code{"G"} for @code{"st_greenbrown"}).
@item Orientable stones like boulders or lasers should use @code{"N"}, @code{"E"}, @code{"S"}, @code{"W"}
if they appear in more than one orientation.
@item Stones of the same kind, which appear several times in different ways
(like switches with different actions) should use consecutive letter
(@code{"S"}, @code{"T"}, @code{"U"}, ...) or numbers.
@item Oxyd stones should use @code{"O"} or @code{"0"}. If you put several different oxyd
stones, e.g. of different colors, make use of consecutive letters (@code{"P"},
@code{"Q"}, @code{"R"} ...) or numbers.
@item If you want to put mirrors, it's a good idea to use characters resembling
the orientation of the mirror, i.e. @code{"|"}, @code{"-"}, and @code{"/"}. As the backslash
is no good tile key, you may use @code{"&"} or @code{"Q"} instead, as these characters
include a prominent slant line similar to the backslash. Triangular
mirrors are best written with @code{"<"}, @code{">"}, @code{"v"} and @code{"^"}.
@item For rotator stones, it's a good idea to use @code{"R"} and @code{"L"} for clockwise
(right) and counter-clockwise (left) rotating stones. As an alternative,
you might want to use characters which are written in either clockwise
or counter-clockwise manner, like @code{"p"} and @code{"q"}. Note that this might
depend on your handwriting.
@item Documents can use either @code{"d"}, or @code{"i"} (for @code{"information"}), as @code{"d"} is
used more often (e.g. for autotiling purposes). If several documents
appear in the level, you can use consecutive letters (@code{"i"}, @code{"j"}, @code{"k"} ...).
Remember that you can take advantage of autotiling if you have lots of
different documents in your level.
@item Coins can be written with @code{"c"}, with @code{"$"} or with numbers resembling their worth.
@item Marbles should be @code{"@@"}, all other actors should use small letters
(@code{"t"} for ac_top, @code{"p"} for ac_pearl, ...), or large punctuation marks.
@item For autotiling, it's a good idea to use @code{"X"}, @code{"Y"}, @code{"x"}, @code{"y"}, @code{"*"}, @code{"?"} and
similar characters which associate themselves with variables as template
keys. Another possibility is to use a full word like @code{"door"} or @code{"switch"}
as template tile key, which has the advantage of being easier
@end itemize

@node Easy Mode Hints
@section Easy Mode Hints
write easy first, floor friction,...

@c ==================  Compatibility  =======================

@node Compatibility
@chapter Compatibility


@menu
* Engine Compatibility::     Differences between Compatibility Modes
@end menu

@c ----------------------------------------------------------------------
@node Engine Compatibility
@section Engine Compatibility

Although Enigma was inspired by the Oxyd game series, there are
some differences between the native Enigma engine mode and the other modes as
well as between the other modes themselves. Using the compatibility element
of the xml-metadata (@pxref{<compatibility>}), it is possible to activate some
of these special features. Here is a list of the major differences

@strong{All non-Enigma modes @code{(oxyd1, per.oxyd, oxyd.magnum, oxyd.extra)}}

@itemize @bullet
@item Keep @ref{it_key} when using @ref{st_key}.
@item Oxyd stones (@ref{st_oxyd}) must blink before they can be
ultimately opened (pairs must be hit with some time delay).
@item The non-Enigma modes feature a model of the 0.92-Fire System
(see @ref{Fire Spreading}).
@item @ref{it_squashed} and @ref{it_cross} can't be removed with
@ref{it_brush}.
@item The only function of @ref{it_pencil} is to turn
@ref{st_flat} and its movable variant into the burnable variants.
@item @ref{it_bottle} doesn't break when a stone is pushed over it.
@item @ref{st_swap} and @ref{st_pull} may not swap/pull into the level
border.
@end itemize


@strong{@code{oxyd1}-compatibility}

@itemize @bullet
@item @ref{it_seed} grows to @ref{fl_wood}_framed under @ref{st_grate}_cross,
not to @ref{st_box}_wood.
@item Flying actors may pass @ref{st_grate}).
@item @ref{st_box}_wood only falls when moved.
@item The @code{ignite}-message (e.g. by @ref{it_dynamite}) doesn't
kill @ref{it_document}.
@item Bombs @ref{it_bomb} aren't ignited when @ref{st_box}_wood is pushed over
them (see @code{oxydmagnum}-compatibility).
@end itemize


@strong{@code{per.oxyd}-compatibility}

@itemize @bullet
@item When painted with @ref{it_brush}, @ref{st_ghost}_purplemarble becomes
an open @ref{st_fake}_oxydc instead of @code{st_purplemarble}.
@item @ref{it_hammer} doesn't laser-transform into @ref{it_sword}.
@item @ref{it_umbrella} doesn't explode in laser light.
@item @ref{it_cross} inverts signals it receives.
@end itemize


@strong{@code{oxyd.magnum}-compatibility}

@itemize @bullet
@item @ref{it_seed} grows to @ref{fl_wood}_framed under @ref{st_grate}_cross,
not to @ref{st_box}_wood.
@item Bombs@ref{it_bomb} aren't ignited when @ref{st_box}_wood is pushed over
them (see @code{oxyd1}-compatibility).
@end itemize



@c ......................................................................

@node Object Index
@unnumbered Object Index

@printindex ob

@node Attribute Index
@unnumbered Attribute Index

@printindex at

@node Message Index
@unnumbered Message Index

@printindex ms

@node Function Index
@unnumbered Function Index

@syncodeindex vr tp
@syncodeindex fn tp

@printindex tp

@node Concept Index
@unnumbered Concept Index

@printindex cp

@c ==================  Renaming Index  =======================
@node Renaming Index
@unnumbered Renaming Index

@table @asis
@item @b{ac-blackball} @expansion{} @code{ac_marble_black}, @pxref{ac_marble}
@item @b{ac-bug} @expansion{} @ref{ac_bug}
@item @b{ac-horse} @expansion{} @ref{ac_horse}
@item @b{ac-killerball} @expansion{} @ref{ac_killer}
@need 200
@item @b{ac-rotor} @expansion{} @ref{ac_rotor}
@item @b{ac-top} @expansion{} @ref{ac_top}
@item @b{ac-whiteball} @expansion{} @code{ac_marble_white}, @pxref{ac_marble}
@item @b{ac-whiteball-small} @expansion{} @code{ac_pearl_white, owner=DEFAULT}, @pxref{ac_pearl}
@need 200
@item @b{fl-abyss} @expansion{} @ref{fl_abyss}
@item @b{fl-abyss_fake} @expansion{} @code{fl_fake_abyss}, @pxref{fl_fake}
@item @b{fl-acblack} @expansion{} @code{fl_yinyang_yin}, @pxref{fl_yinyang}
@item @b{fl-acwhite} @expansion{} @code{fl_yinyang_yang}, @pxref{fl_yinyang}
@need 200
@item @b{fl-black} @expansion{} @ref{fl_dark}
@item @b{fl-bluegray} @expansion{} @ref{fl_bluegray}
@item @b{fl-bluegreen} @expansion{} @ref{fl_bluegreen}
@item @b{fl-bluegreenx} @expansion{} @ref{fl_aquamarine}
@need 200
@item @b{fl-brick} @expansion{} @ref{fl_brick}
@item @b{fl-bridge} @expansion{} @ref{fl_bridge}
@item @b{fl-bridge-closed} @expansion{} @code{fl_bridge, state=CLOSED}, @pxref{fl_bridge}
@item @b{fl-bridge-open} @expansion{} @ref{fl_bridge}
@need 200
@item @b{fl-bumps} @expansion{} @ref{fl_pinkbumps}
@item @b{fl-concrete} @expansion{} @ref{fl_concrete}
@item @b{fl-darkgray} @expansion{} @ref{fl_darkgray}
@item @b{fl-dunes} @expansion{} @ref{fl_dunes}
@need 200
@item @b{fl-floor_001} @expansion{} @ref{fl_bast}
@item @b{fl-gradient} @expansion{} @code{fl_slope_ps}, @pxref{fl_slope}
@item @b{fl-gradient1} @expansion{} @code{fl_slope_ps}, @pxref{fl_slope}
@item @b{fl-gradient2} @expansion{} @code{fl_slope_pn}, @pxref{fl_slope}
@need 200
@item @b{fl-gradient3} @expansion{} @code{fl_slope_pe}, @pxref{fl_slope}
@item @b{fl-gradient4} @expansion{} @code{fl_slope_pw}, @pxref{fl_slope}
@item @b{fl-gradient5} @expansion{} @code{fl_slope_ose}, @pxref{fl_slope}
@item @b{fl-gradient6} @expansion{} @code{fl_slope_osw}, @pxref{fl_slope}
@need 200
@item @b{fl-gradient7} @expansion{} @code{fl_slope_one}, @pxref{fl_slope}
@item @b{fl-gradient8} @expansion{} @code{fl_slope_onw}, @pxref{fl_slope}
@item @b{fl-gradient9} @expansion{} @code{fl_slope_ise}, @pxref{fl_slope}
@item @b{fl-gradient10} @expansion{} @code{fl_slope_ine}, @pxref{fl_slope}
@need 200
@item @b{fl-gradient11} @expansion{} @code{fl_slope_isw}, @pxref{fl_slope}
@item @b{fl-gradient12} @expansion{} @code{fl_slope_inw}, @pxref{fl_slope}
@item @b{fl-gradient13} @expansion{} @code{fl_slope_tn}, @pxref{fl_slope}
@item @b{fl-gradient14} @expansion{} @code{fl_slope_ts}, @pxref{fl_slope}
@need 200
@item @b{fl-gradient15} @expansion{} @code{fl_slope_tw}, @pxref{fl_slope}
@item @b{fl-gradient16} @expansion{} @code{fl_slope_te}, @pxref{fl_slope}
@item @b{fl-gravel} @expansion{} @ref{fl_gravel}
@item @b{fl-gray} @expansion{} @ref{fl_gray}
@need 200
@item @b{fl-hay} @expansion{} @ref{fl_hay}
@item @b{fl-himalaya} @expansion{} @ref{fl_himalaya}
@item @b{fl-ice} @expansion{} @ref{fl_ice}
@item @b{fl-inverse} @expansion{} @code{fl_inverse_white}, @pxref{fl_inverse}
@need 200
@item @b{fl-inverse2} @expansion{} @code{fl_inverse_gray}, @pxref{fl_inverse}
@item @b{fl-leaves} @expansion{} @code{fl_lawn_a}, @pxref{fl_lawn}
@item @b{fl-leavesb} @expansion{} @code{fl_lawn_b}, @pxref{fl_lawn}
@item @b{fl-leavesc1} @expansion{} @code{fl_lawn_c1}, @pxref{fl_lawn}
@need 200
@item @b{fl-leavesc2} @expansion{} @code{fl_lawn_c2}, @pxref{fl_lawn}
@item @b{fl-leavesc3} @expansion{} @code{fl_lawn_c3}, @pxref{fl_lawn}
@item @b{fl-leavesc4} @expansion{} @code{fl_lawn_c4}, @pxref{fl_lawn}
@item @b{fl-leavesd1} @expansion{} @code{fl_lawn_d1}, @pxref{fl_lawn}
@need 200
@item @b{fl-leavesd2} @expansion{} @code{fl_lawn_d2}, @pxref{fl_lawn}
@item @b{fl-leavesd3} @expansion{} @code{fl_lawn_d3}, @pxref{fl_lawn}
@item @b{fl-leavesd4} @expansion{} @code{fl_lawn_d4}, @pxref{fl_lawn}
@item @b{fl-leavese1} @expansion{} @code{fl_lawn_e1}, @pxref{fl_lawn}
@need 200
@item @b{fl-leavese2} @expansion{} @code{fl_lawn_e2}, @pxref{fl_lawn}
@item @b{fl-leavese3} @expansion{} @code{fl_lawn_e3}, @pxref{fl_lawn}
@item @b{fl-leavese4} @expansion{} @code{fl_lawn_e4}, @pxref{fl_lawn}
@item @b{fl-light} @expansion{} @ref{fl_ivory}
@need 200
@item @b{fl-lightgray} @expansion{} @ref{fl_platinum}
@item @b{fl-marble} @expansion{} @ref{fl_marble}
@item @b{fl-metal} @expansion{} @ref{fl_metal}
@item @b{fl-metal1} @expansion{} @code{fl_metal_1}, @pxref{fl_metal}
@need 200
@item @b{fl-metal2} @expansion{} @code{fl_metal_2}, @pxref{fl_metal}
@item @b{fl-metal3} @expansion{} @code{fl_metal_3}, @pxref{fl_metal}
@item @b{fl-metal4} @expansion{} @code{fl_metal_4}, @pxref{fl_metal}
@item @b{fl-metal5} @expansion{} @code{fl_metal_5}, @pxref{fl_metal}
@need 200
@item @b{fl-metal6} @expansion{} @code{fl_metal_6}, @pxref{fl_metal}
@item @b{fl-mortar} @expansion{} @ref{fl_mortar}
@item @b{fl-nomouse} @expansion{} @ref{fl_adhesionless}
@item @b{fl-normal_x} @expansion{} @code{fl_metal_7}, @pxref{fl_metal}
@need 200
@item @b{fl-normal} @expansion{} @code{fl_metal_7n}, @pxref{fl_metal}
@item @b{fl-plank} @expansion{} @ref{fl_plank}
@item @b{fl-red} @expansion{} @ref{fl_red}
@item @b{fl-rock} @expansion{} @ref{fl_rock}
@need 200
@item @b{fl-rough} @expansion{} @ref{fl_rough}
@item @b{fl-rough_medium} @expansion{} @code{fl_rough, friction=5.0, adhesion=1.2}, @pxref{fl_rough}
@item @b{fl-rough_slow} @expansion{} @code{fl_rough, friction=7.0, adhesion=0.5}, @pxref{fl_rough}
@item @b{fl-rough-blue} @expansion{} @ref{fl_blueslab}
@need 200
@item @b{fl-rough-red} @expansion{} @ref{fl_redslab}
@item @b{fl-sahara} @expansion{} @ref{fl_sahara}
@item @b{fl-samba} @expansion{} @ref{fl_samba}
@item @b{fl-samba1} @expansion{} @code{fl_samba_h}, @pxref{fl_samba}
@need 200
@item @b{fl-samba2} @expansion{} @code{fl_samba_v}, @pxref{fl_samba}
@item @b{fl-sand} @expansion{} @ref{fl_sand}
@item @b{fl-space} @expansion{} @ref{fl_space}
@item @b{fl-springboard} @expansion{} @ref{fl_white}
@need 200
@item @b{fl-stone} @expansion{} @ref{fl_stone}
@item @b{fl-stwood} @expansion{} @code{fl_wood_framed}, @pxref{fl_wood}
@item @b{fl-stwood1} @expansion{} @code{fl_wood_framed_h}, @pxref{fl_wood}
@item @b{fl-stwood2} @expansion{} @code{fl_wood_framed_v}, @pxref{fl_wood}
@need 200
@item @b{fl-swamp} @expansion{} @ref{fl_swamp}
@item @b{fl-thief} @expansion{} @ref{fl_thief}
@item @b{fl-tigris} @expansion{} @ref{fl_tigris}
@item @b{fl-trigger} @expansion{} @code{fl_fake_trigger}, @pxref{fl_fake}
@need 200
@item @b{fl-water} @expansion{} @ref{fl_water}
@item @b{fl-white} @expansion{} @ref{fl_bright}
@item @b{fl-wood} @expansion{} @ref{fl_wood}
@item @b{fl-wood1} @expansion{} @code{fl_wood_h}, @pxref{fl_wood}
@need 200
@item @b{fl-wood2} @expansion{} @code{fl_wood_v}, @pxref{fl_wood}
@item @b{fl-woven} @expansion{} @ref{fl_woven}
@item @b{it-abyss} @expansion{} @ref{it_trap}
@item @b{it-bag} @expansion{} @ref{it_bag}
@need 200
@item @b{it-banana} @expansion{} @ref{it_banana}
@item @b{it-blackbomb} @expansion{} @code{it_bomb_black}, @pxref{it_bomb}
@item @b{it-blocker} @expansion{} @ref{it_blocker}
@item @b{it-blocker-new} @expansion{} @code{it_blocker_new}, @pxref{it_blocker}
@need 200
@item @b{it-booze} @expansion{} @ref{it_bottle}
@item @b{it-booze-broken} @expansion{} @code{it_bottle_broken}, @pxref{it_bottle}
@item @b{it-brake} @expansion{} @ref{it_brake}
@item @b{it-brush} @expansion{} @ref{it_brush}
@need 200
@item @b{it-burnable} @expansion{} @ref{it_burnable}
@item @b{it-burnable_ash} @expansion{} @code{it_burnable_ash}, @pxref{it_burnable}
@item @b{it-burnable_burning} @expansion{} @code{it_burnable_burning}, @pxref{it_burnable}
@item @b{it-burnable_fireproof} @expansion{} @code{it_burnable_fireproof}, @pxref{it_burnable}
@need 200
@item @b{it-burnable_ignited} @expansion{} @code{it_burnable_ignited}, @pxref{it_burnable}
@item @b{it-burnable_oil} @expansion{} @code{it_burnable_oil}, @pxref{it_burnable}
@item @b{it-cherry} @expansion{} @ref{it_cherry}
@item @b{it-coffee} @expansion{} @ref{it_coffee}
@need 200
@item @b{it-coin1} @expansion{} @code{it_coin_s}, @pxref{it_coin}
@item @b{it-coin2} @expansion{} @code{it_coin_m}, @pxref{it_coin}
@item @b{it-coin4} @expansion{} @code{it_coin_l}, @pxref{it_coin}
@item @b{it-crack0} @expansion{} @code{it_crack_i}, @pxref{it_crack}
@need 200
@item @b{it-crack1} @expansion{} @code{it_crack_s}, @pxref{it_crack}
@item @b{it-crack2} @expansion{} @code{it_crack_m}, @pxref{it_crack}
@item @b{it-crack3} @expansion{} @code{it_crack_l}, @pxref{it_crack}
@item @b{it-cross} @expansion{} @ref{it_cross}
@need 200
@item @b{it-death} @expansion{} @ref{it_death}
@item @b{it-document} @expansion{} @ref{it_document}
@item @b{it-drop} @expansion{} @ref{it_drop}
@item @b{it-dynamite} @expansion{} @ref{it_dynamite}
@need 200
@item @b{it-explosion1} @expansion{} @code{it_explosion_nil}, @pxref{it_explosion}
@item @b{it-explosion2} @expansion{} @code{it_explosion_hollow}, @pxref{it_explosion}
@item @b{it-explosion3} @expansion{} @code{it_explosion_debris}, @pxref{it_explosion}
@item @b{it-extinguisher} @expansion{} @ref{it_extinguisher}
@need 200
@item @b{it-extinguisher_empty} @expansion{} @code{it_extinguisher_empty}, @pxref{it_extinguisher}
@item @b{it-extinguisher_medium} @expansion{} @code{it_extinguisher_medium}, @pxref{it_extinguisher}
@item @b{it-extralife} @expansion{} @ref{it_extralife}
@item @b{it-flagblack} @expansion{} @code{it_flag_black}, @pxref{it_flag}
@need 200
@item @b{it-flagwhite} @expansion{} @code{it_flag_white}, @pxref{it_flag}
@item @b{it-floppy} @expansion{} @ref{it_floppy}
@item @b{it-glasses} @expansion{} @ref{it_glasses}
@item @b{it-glasses-broken} @expansion{} @code{it_glasses_broken}, @pxref{it_glasses}
@need 200
@item @b{it-hammer} @expansion{} @ref{it_hammer}
@item @b{it-hollow} @expansion{} @code{it_meditation_hollow}, @pxref{it_meditation}
@item @b{it-hill} @expansion{} @code{it_meditation_hill}, @pxref{it_meditation}
@item @b{it-hstrip} @expansion{} @code{it_strip_ew}, @pxref{it_strip}
@need 200
@item @b{it-inversesensor} @expansion{} @code{it_sensor, invisible=true, inverse=true}, @pxref{it_sensor}
@item @b{it-key} @expansion{} @code{it_key, code=1}, @pxref{it_key}
@item @b{it-key_a} @expansion{} @code{it_key, code=1}, @pxref{it_key}
@item @b{it-key_b} @expansion{} @code{it_key, code=2}, @pxref{it_key}
@need 200
@item @b{it-key_c} @expansion{} @code{it_key, code=3}, @pxref{it_key}
@item @b{it-landmine} @expansion{} @ref{it_landmine}
@item @b{it-magicwand} @expansion{} @ref{it_magicwand}
@item @b{it-magnet} @expansion{} @ref{it_magnet}
@need 200
@item @b{it-magnet-on} @expansion{} @code{it_magnet_on}, @pxref{it_magnet}
@item @b{it-magnet-off} @expansion{} @code{it_magnet_off}, @pxref{it_magnet}
@item @b{it-pencil} @expansion{} @ref{it_pencil}
@item @b{it-pin} @expansion{} @ref{it_pin}
@need 200
@item @b{it-pipe-e} @expansion{} @code{it_pipe_e}, @pxref{it_pipe}
@item @b{it-pipe-es} @expansion{} @code{it_pipe_es}, @pxref{it_pipe}
@item @b{it-pipe-h} @expansion{} @code{it_pipe_ew}, @pxref{it_pipe}
@item @b{it-pipe-n} @expansion{} @code{it_pipe_n}, @pxref{it_pipe}
@need 200
@item @b{it-pipe-ne} @expansion{} @code{it_pipe_ne}, @pxref{it_pipe}
@item @b{it-pipe-s} @expansion{} @code{it_pipe_s}, @pxref{it_pipe}
@item @b{it-pipe-sw} @expansion{} @code{it_pipe_sw}, @pxref{it_pipe}
@item @b{it-pipe-v} @expansion{} @code{it_pipe_ns}, @pxref{it_pipe}
@need 200
@item @b{it-pipe-w} @expansion{} @code{it_pipe_w}, @pxref{it_pipe}
@item @b{it-pipe-wn} @expansion{} @code{it_pipe_nw}, @pxref{it_pipe}
@item @b{it-puller-e} @expansion{} @code{it_puller_e}, @pxref{it_puller}
@item @b{it-puller-n} @expansion{} @code{it_puller_n}, @pxref{it_puller}
@need 200
@item @b{it-puller-s} @expansion{} @code{it_puller_s}, @pxref{it_puller}
@item @b{it-puller-w} @expansion{} @code{it_puller_w}, @pxref{it_puller}
@item @b{it-ring} @expansion{} @ref{it_ring}
@item @b{it-rubberband} @expansion{} @ref{it_rubberband}
@need 200
@item @b{it-seed} @expansion{} @code{it_seed_wood}, @pxref{it_seed}
@item @b{it-seed_nowood} @expansion{} @code{it_seed_fake}, @pxref{it_seed}
@item @b{it-seed_volcano} @expansion{} @code{it_seed_volcano}, @pxref{it_seed}
@item @b{it-sensor} @expansion{} @code{it_sensor, invisible=true}, @pxref{it_sensor}
@need 200
@item @b{it-spade} @expansion{} @ref{it_spade}
@item @b{it-spoon} @expansion{} @ref{it_spoon}
@item @b{it-spring1} @expansion{} @code{it_spring_keep}, @pxref{it_spring}
@item @b{it-spring2} @expansion{} @code{it_spring_drop}, @pxref{it_spring}
@need 200
@item @b{it-springboard} @expansion{} @ref{it_springboard}
@item @b{it-squashed} @expansion{} @ref{it_squashed}
@item @b{it-shogun-s} @expansion{} @code{it_shogun_s}, @pxref{it_shogun}
@item @b{it-shogun-m} @expansion{} @code{it_shogun_m}, @pxref{it_shogun}
@need 200
@item @b{it-shogun-l} @expansion{} @code{it_shogun_l}, @pxref{it_shogun}
@item @b{it-surprise} @expansion{} @ref{it_surprise}
@item @b{it-sword} @expansion{} @ref{it_sword}
@item @b{it-tinyhollow} @expansion{} @code{it_meditation_dent}, @pxref{it_meditation}
@need 200
@item @b{it-tinyhill} @expansion{} @code{it_meditation_bump}, @pxref{it_meditation}
@item @b{it-trigger} @expansion{} @ref{it_trigger}
@item @b{it-umbrella} @expansion{} @ref{it_umbrella}
@item @b{it-vortex-open} @expansion{} @code{it_vortex_open, scissor=false}, @pxref{it_vortex}
@need 200
@item @b{it-vortex-closed} @expansion{} @code{it_vortex_closed, autoclose=true, scissor=false}, @pxref{it_vortex}
@item @b{it-vstrip} @expansion{} @code{it_strip_ns}, @pxref{it_strip}
@item @b{it-weight} @expansion{} @ref{it_weight}
@item @b{it-whitebomb} @expansion{} @code{it_bomb_white}, @pxref{it_bomb}
@need 200
@item @b{it-wormhole} @expansion{} @code{it_wormhole_on, scissor=false}, @pxref{it_wormhole}
@item @b{it-wormhole-off} @expansion{} @code{it_wormhole_off, scissor=false}, @pxref{it_wormhole}
@item @b{it-wrench} @expansion{} @ref{it_wrench}
@item @b{it-yinyang} @expansion{} @ref{it_yinyang}
@need 200
@item @b{st-actorimpulse} @expansion{} @ref{st_actorimpulse}
@item @b{st-actorimpulse_invisible} @expansion{} @code{st_actorimpulse_invisible}, @pxref{st_actorimpulse}
@item @b{st-beads} @expansion{} @ref{st_beads}
@item @b{st-bigbluesand-e} @expansion{} @code{st_bluesand_e}, @pxref{st_bluesand}
@need 200
@item @b{st-bigbluesand-es} @expansion{} @code{st_bluesand_es}, @pxref{st_bluesand}
@item @b{st-bigbluesand-esw} @expansion{} @code{st_bluesand_esw}, @pxref{st_bluesand}
@item @b{st-bigbluesand-ew} @expansion{} @code{st_bluesand_ew}, @pxref{st_bluesand}
@item @b{st-bigbluesand-n} @expansion{} @code{st_bluesand_n}, @pxref{st_bluesand}
@need 200
@item @b{st-bigbluesand-ne} @expansion{} @code{st_bluesand_ne}, @pxref{st_bluesand}
@item @b{st-bigbluesand-nes} @expansion{} @code{st_bluesand_nes}, @pxref{st_bluesand}
@item @b{st-bigbluesand-nesw} @expansion{} @code{st_bluesand_nesw}, @pxref{st_bluesand}
@item @b{st-bigbluesand-new} @expansion{} @code{st_bluesand_new}, @pxref{st_bluesand}
@need 200
@item @b{st-bigbluesand-ns} @expansion{} @code{st_bluesand_ns}, @pxref{st_bluesand}
@item @b{st-bigbluesand-nsw} @expansion{} @code{st_bluesand_nsw}, @pxref{st_bluesand}
@item @b{st-bigbluesand-nw} @expansion{} @code{st_bluesand_nw}, @pxref{st_bluesand}
@item @b{st-bigbluesand-s} @expansion{} @code{st_bluesand_s}, @pxref{st_bluesand}
@need 200
@item @b{st-bigbluesand-sw} @expansion{} @code{st_bluesand_sw}, @pxref{st_bluesand}
@item @b{st-bigbluesand-w} @expansion{} @code{st_bluesand_w}, @pxref{st_bluesand}
@item @b{st-bigbrick-e} @expansion{} @code{st_brick_e}, @pxref{st_brick}
@item @b{st-bigbrick-es} @expansion{} @code{st_brick_es}, @pxref{st_brick}
@need 200
@item @b{st-bigbrick-esw} @expansion{} @code{st_brick_esw}, @pxref{st_brick}
@item @b{st-bigbrick-ew} @expansion{} @code{st_brick_ew}, @pxref{st_brick}
@item @b{st-bigbrick-n} @expansion{} @code{st_brick_n}, @pxref{st_brick}
@item @b{st-bigbrick-ne} @expansion{} @code{st_brick_ne}, @pxref{st_brick}
@need 200
@item @b{st-bigbrick-nes} @expansion{} @code{st_brick_nes}, @pxref{st_brick}
@item @b{st-bigbrick-nesw} @expansion{} @code{st_brick_nesw}, @pxref{st_brick}
@item @b{st-bigbrick-new} @expansion{} @code{st_brick_new}, @pxref{st_brick}
@item @b{st-bigbrick-ns} @expansion{} @code{st_brick_ns}, @pxref{st_brick}
@need 200
@item @b{st-bigbrick-nsw} @expansion{} @code{st_brick_nsw}, @pxref{st_brick}
@item @b{st-bigbrick-nw} @expansion{} @code{st_brick_nw}, @pxref{st_brick}
@item @b{st-bigbrick-s} @expansion{} @code{st_brick_s}, @pxref{st_brick}
@item @b{st-bigbrick-sw} @expansion{} @code{st_brick_sw}, @pxref{st_brick}
@need 200
@item @b{st-bigbrick-w} @expansion{} @code{st_brick_w}, @pxref{st_brick}
@item @b{st-blackballs} @expansion{} @code{st_jamb_black}, @pxref{st_jamb}
@item @b{st-black1} @expansion{} @code{st_passage_black_square}, @pxref{st_passage}
@item @b{st-black2} @expansion{} @code{st_passage_black_slash}, @pxref{st_passage}
@need 200
@item @b{st-black3} @expansion{} @code{st_passage_black_cross}, @pxref{st_passage}
@item @b{st-black4} @expansion{} @code{st_passage_black_frame}, @pxref{st_passage}
@item @b{st-block} @expansion{} @ref{st_plop}
@item @b{st-blocker} @expansion{} @ref{st_blocker}
@need 200
@item @b{st-blocker-growing} @expansion{} @code{st_blocker_new}, @pxref{st_blocker}
@item @b{st-bluegray} @expansion{} @ref{st_bluegray}
@item @b{st-bluegray_hole} @expansion{} @code{st_bluegray_hollow}, @pxref{st_bluegray}
@item @b{st-blue-sand} @expansion{} @ref{st_bluesand}
@need 200
@item @b{st-bolder} @expansion{} @ref{st_boulder}
@item @b{st-bolder-e} @expansion{} @code{st_boulder_e}, @pxref{st_boulder}
@item @b{st-bolder-n} @expansion{} @code{st_boulder_n}, @pxref{st_boulder}
@item @b{st-bolder-s} @expansion{} @code{st_boulder_s}, @pxref{st_boulder}
@need 200
@item @b{st-bolder-w} @expansion{} @code{st_boulder_w}, @pxref{st_boulder}
@item @b{st-bombs} @expansion{} @code{st_dispenser_bombblack}, @pxref{st_dispenser}
@item @b{st-brake} @expansion{} @ref{st_brake}
@item @b{st-break_acblack} @expansion{} @code{st_break_black}, @pxref{st_break}
@need 200
@item @b{st-break_acwhite} @expansion{} @code{st_break_white}, @pxref{st_break}
@item @b{st-break_bolder} @expansion{} @code{st_break_boulder}, @pxref{st_break}
@item @b{st-break_gray} @expansion{} @code{st_break_plain}, @pxref{st_break}
@item @b{st-break_invisible} @expansion{} @code{st_ghost_break}, @pxref{st_ghost}
@need 200
@item @b{st-brick} @expansion{} @ref{st_brick}
@item @b{st-brick_magic} @expansion{} @code{st_magic_brick}, @pxref{st_magic}
@item @b{st-brownie} @expansion{} @ref{st_brownie}
@item @b{st-bug} @expansion{} @code{st_break_bug}, @pxref{st_break}
@need 200
@item @b{st-bumps} @expansion{} @ref{st_pinkbumps}
@item @b{st-camouflage} @expansion{} @ref{st_camouflage}
@item @b{st-camouflage_hole} @expansion{} @code{st_camouflage_hollow}, @pxref{st_camouflage}
@item @b{st-camouflage_move} @expansion{} @code{st_camouflage_movable}, @pxref{st_camouflage}
@need 200
@item @b{st-chameleon} @expansion{} @ref{st_chameleon}
@item @b{st-chargeminus} @expansion{} @code{st_charge_minus}, @pxref{st_charge}
@item @b{st-chargeplus} @expansion{} @code{st_charge_plus}, @pxref{st_charge}
@item @b{st-chargezero} @expansion{} @code{st_charge_zero}, @pxref{st_charge}
@need 200
@item @b{st-chess} @expansion{} @ref{st_chess}
@item @b{st-chess_black} @expansion{} @code{st_chess_black}, @pxref{st_chess}
@item @b{st-chess_white} @expansion{} @code{st_chess_white}, @pxref{st_chess}
@item @b{st-coffee} @expansion{} @code{st_magic_oxydc}, @pxref{st_magic}
@need 200
@item @b{st-coinslot} @expansion{} @ref{st_coinslot}
@item @b{st-death} @expansion{} @ref{st_death}
@item @b{st-death_invisible} @expansion{} @code{st_death_invisible}, @pxref{st_death}
@item @b{st-disco-dark} @expansion{} @code{st_disco_dark}, @pxref{st_disco}
@need 200
@item @b{st-disco-light} @expansion{} @code{st_disco_light}, @pxref{st_disco}
@item @b{st-disco-medium} @expansion{} @code{st_disco_medium}, @pxref{st_disco}
@item @b{st-door_a} @expansion{} @code{st_door_a}, @pxref{st_door}
@item @b{st-door_b} @expansion{} @code{st_door_b}, @pxref{st_door}
@need 200
@item @b{st-door_c} @expansion{} @code{st_door_c}, @pxref{st_door}
@item @b{st-door-h} @expansion{} @code{st_door_d, faces="ns"}, @pxref{st_door}
@item @b{st-door-h-open} @expansion{} @code{st_door_d, faces="ns", state=OPEN}, @pxref{st_door}
@item @b{st-door-v} @expansion{} @code{st_door_d, faces="ew"}, @pxref{st_door}
@need 200
@item @b{st-door-v-open} @expansion{} @code{st_door_d, faces="ew", state=OPEN}, @pxref{st_door}
@item @b{st-fakeoxyd} @expansion{} @code{st_fake_quake}, @pxref{st_fake}
@item @b{st-fakeoxyda} @expansion{} @code{st_magic_oxyda}, @pxref{st_magic}
@item @b{st-fart} @expansion{} @ref{st_quake}
@need 200
@item @b{st-firebreak} @expansion{} @code{st_flat_burnable}, @pxref{st_flat}
@item @b{st-firebreak_move} @expansion{} @code{st_flat_moveburnable}, @pxref{st_flat}
@item @b{st-flash} @expansion{} @ref{st_flash}
@item @b{st-flhay} @expansion{} @code{st_box_hay}, @pxref{st_box}
@need 200
@item @b{st-floppy} @expansion{} @ref{st_floppy}
@item @b{st-flrock} @expansion{} @code{st_box_rock}, @pxref{st_box}
@item @b{st-fourswitch} @expansion{} @ref{st_fourswitch}
@item @b{st-glass} @expansion{} @ref{st_rawglass}
@need 200
@item @b{st-glass_move} @expansion{} @code{st_rawglass_movable}, @pxref{st_rawglass}
@item @b{st-glass1} @expansion{} @ref{st_lightglass}
@item @b{st-glass1_hole} @expansion{} @code{st_lightglass_hollow}, @pxref{st_lightglass}
@item @b{st-glass1_move} @expansion{} @code{st_lightglass_movable}, @pxref{st_lightglass}
@need 200
@item @b{st-glass2} @expansion{} @ref{st_darkglass}
@item @b{st-glass2_hole} @expansion{} @code{st_darkglass_hollow}, @pxref{st_darkglass}
@item @b{st-glass2_move} @expansion{} @code{st_darkglass_movable}, @pxref{st_darkglass}
@item @b{st-glass3} @expansion{} @ref{st_redfiber}
@need 200
@item @b{st-grate1} @expansion{} @code{st_grate_cross}, @pxref{st_grate}
@item @b{st-grate2} @expansion{} @code{st_grate_framed}, @pxref{st_grate}
@item @b{st-grate3} @expansion{} @code{st_portal_horse}, @pxref{st_portal}
@item @b{st-greenbrown} @expansion{} @ref{st_greenbrown}
@need 200
@item @b{st-greenbrown_hole} @expansion{} @code{st_greenbrown_hollow}, @pxref{st_greenbrown}
@item @b{st-greenbrown_move} @expansion{} @code{st_greenbrown_movable}, @pxref{st_greenbrown}
@item @b{st-invisible} @expansion{} @ref{st_invisible}
@item @b{st-invisible_hole} @expansion{} @code{st_invisible_hollow}, @pxref{st_invisible}
@need 200
@item @b{st-invisible_magic} @expansion{} @code{st_ghost_greenbrown}, @pxref{st_ghost}
@item @b{st-invisible_move} @expansion{} @code{st_invisible_movable}, @pxref{st_invisible}
@item @b{st-key} @expansion{} @code{st_key, code=0}, @pxref{st_key}
@item @b{st-key_a} @expansion{} @code{st_key, code=1}, @pxref{st_key}
@need 200
@item @b{st-key_b} @expansion{} @code{st_key, code=2}, @pxref{st_key}
@item @b{st-key_c} @expansion{} @code{st_key, code=3}, @pxref{st_key}
@item @b{st-knight} @expansion{} @ref{st_knight}
@item @b{st-laserbreak} @expansion{} @code{st_break_laser}, @pxref{st_break}
@need 200
@item @b{st-laserswitch} @expansion{} @ref{st_laserswitch}
@item @b{st-lasertimeswitch} @expansion{} @ref{st_laserflop}
@item @b{st-laser} @expansion{} @code{st_laser_e}, @pxref{st_laser}
@item @b{st-laser-e} @expansion{} @code{st_laser_e}, @pxref{st_laser}
@need 200
@item @b{st-laser-n} @expansion{} @code{st_laser_n}, @pxref{st_laser}
@item @b{st-laser-s} @expansion{} @code{st_laser_s}, @pxref{st_laser}
@item @b{st-laser-w} @expansion{} @code{st_laser_w}, @pxref{st_laser}
@item @b{st-lightpassenger} @expansion{} @ref{st_lightpassenger}
@need 200
@item @b{st-lightpassenger_off} @expansion{} @code{st_lightpassenger_off}, @pxref{st_lightpassenger}
@item @b{st-likeoxyda} @expansion{} @code{st_fake_oxyda}, @pxref{st_fake}
@item @b{st-likeoxyda-open} @expansion{} @code{st_fake_oxyda, state=OPEN}, @pxref{st_fake}
@item @b{st-likeoxydb} @expansion{} @code{st_fake_oxydb}, @pxref{st_fake}
@need 200
@item @b{st-likeoxydb-open} @expansion{} @code{st_fake_oxydb, state=OPEN}, @pxref{st_fake}
@item @b{st-likeoxydc} @expansion{} @code{st_fake_oxydc}, @pxref{st_fake}
@item @b{st-likeoxydc-open} @expansion{} @code{st_fake_oxydc, state=OPEN}, @pxref{st_fake}
@item @b{st-likeoxydd} @expansion{} @code{st_fake_oxydd}, @pxref{st_fake}
@need 200
@item @b{st-likeoxydd-open} @expansion{} @code{st_fake_oxydd, state=OPEN}, @pxref{st_fake}
@item @b{st-mail-e} @expansion{} @code{st_mail_e}, @pxref{st_mail}
@item @b{st-mail-n} @expansion{} @code{st_mail_n}, @pxref{st_mail}
@item @b{st-mail-s} @expansion{} @code{st_mail_s}, @pxref{st_mail}
@need 200
@item @b{st-mail-w} @expansion{} @code{st_mail_w}, @pxref{st_mail}
@item @b{st-marble} @expansion{} @ref{st_redbrown}
@item @b{st-marble_hole} @expansion{} @code{st_redbrown_hollow}, @pxref{st_redbrown}
@item @b{st-marble_move} @expansion{} @code{st_redbrown_movable}, @pxref{st_redbrown}
@need 200
@item @b{st-metal} @expansion{} @ref{st_metal}
@item @b{st-metal_hole} @expansion{} @code{st_metal_hollow}, @pxref{st_metal}
@item @b{st-mirror-p|} @expansion{} @code{st_mirror_slab_n}, @pxref{st_mirror}
@item @b{st-mirror-p/} @expansion{} @code{st_mirror_slab_e}, @pxref{st_mirror}
@need 200
@item @b{st-mirror-p-} @expansion{} @code{st_mirror_slab_s}, @pxref{st_mirror}
@item @b{st-mirror-p\\} @expansion{} @code{st_mirror_slab_w}, @pxref{st_mirror}
@item @b{st-mirror-p|t} @expansion{} @code{st_mirror_slab_nt}, @pxref{st_mirror}
@item @b{st-mirror-p/t} @expansion{} @code{st_mirror_slab_et}, @pxref{st_mirror}
@need 200
@item @b{st-mirror-p-t} @expansion{} @code{st_mirror_slab_st}, @pxref{st_mirror}
@item @b{st-mirror-p\\t} @expansion{} @code{st_mirror_slab_wt}, @pxref{st_mirror}
@item @b{st-mirror-p|m} @expansion{} @code{st_mirror_slab_nm}, @pxref{st_mirror}
@item @b{st-mirror-p/m} @expansion{} @code{st_mirror_slab_em}, @pxref{st_mirror}
@need 200
@item @b{st-mirror-p-m} @expansion{} @code{st_mirror_slab_sm}, @pxref{st_mirror}
@item @b{st-mirror-p\\m} @expansion{} @code{st_mirror_slab_wm}, @pxref{st_mirror}
@item @b{st-mirror-p|tm} @expansion{} @code{st_mirror_slab_ntm}, @pxref{st_mirror}
@item @b{st-mirror-p/tm} @expansion{} @code{st_mirror_slab_etm}, @pxref{st_mirror}
@need 200
@item @b{st-mirror-p-tm} @expansion{} @code{st_mirror_slab_stm}, @pxref{st_mirror}
@item @b{st-mirror-p\\tm} @expansion{} @code{st_mirror_slab_wtm}, @pxref{st_mirror}
@item @b{st-mirror-3^} @expansion{} @code{st_mirror_triangle_n}, @pxref{st_mirror}
@item @b{st-mirror-3>} @expansion{} @code{st_mirror_triangle_e}, @pxref{st_mirror}
@need 200
@item @b{st-mirror-3v} @expansion{} @code{st_mirror_triangle_s}, @pxref{st_mirror}
@item @b{st-mirror-3<} @expansion{} @code{st_mirror_triangle_w}, @pxref{st_mirror}
@item @b{st-mirror-3^t} @expansion{} @code{st_mirror_triangle_nt}, @pxref{st_mirror}
@item @b{st-mirror-3>t} @expansion{} @code{st_mirror_triangle_et}, @pxref{st_mirror}
@need 200
@item @b{st-mirror-3vt} @expansion{} @code{st_mirror_triangle_st}, @pxref{st_mirror}
@item @b{st-mirror-3<t} @expansion{} @code{st_mirror_triangle_wt}, @pxref{st_mirror}
@item @b{st-mirror-3^m} @expansion{} @code{st_mirror_triangle_nm}, @pxref{st_mirror}
@item @b{st-mirror-3>m} @expansion{} @code{st_mirror_triangle_em}, @pxref{st_mirror}
@need 200
@item @b{st-mirror-3vm} @expansion{} @code{st_mirror_triangle_sm}, @pxref{st_mirror}
@item @b{st-mirror-3<m} @expansion{} @code{st_mirror_triangle_wm}, @pxref{st_mirror}
@item @b{st-mirror-3^tm} @expansion{} @code{st_mirror_triangle_ntm}, @pxref{st_mirror}
@item @b{st-mirror-3>tm} @expansion{} @code{st_mirror_triangle_etm}, @pxref{st_mirror}
@need 200
@item @b{st-mirror-3vtm} @expansion{} @code{st_mirror_triangle_stm}, @pxref{st_mirror}
@item @b{st-mirror-3<tm} @expansion{} @code{st_mirror_triangle_wtm}, @pxref{st_mirror}
@item @b{st-oneway} @expansion{} @ref{st_oneway}
@item @b{st-oneway_black"} @expansion{} @code{st_oneway_black}, @pxref{st_oneway}
@need 200
@item @b{st-oneway_black-e"} @expansion{} @code{st_oneway_black_e}, @pxref{st_oneway}
@item @b{st-oneway_black-n"} @expansion{} @code{st_oneway_black_n}, @pxref{st_oneway}
@item @b{st-oneway_black-s"} @expansion{} @code{st_oneway_black_s}, @pxref{st_oneway}
@item @b{st-oneway_black-w"} @expansion{} @code{st_oneway_black_w}, @pxref{st_oneway}
@need 200
@item @b{st-oneway-e"} @expansion{} @code{st_oneway_e}, @pxref{st_oneway}
@item @b{st-oneway-n"} @expansion{} @code{st_oneway_n}, @pxref{st_oneway}
@item @b{st-oneway-s"} @expansion{} @code{st_oneway_s}, @pxref{st_oneway}
@item @b{st-oneway-w"} @expansion{} @code{st_oneway_w}, @pxref{st_oneway}
@need 200
@item @b{st-oneway_white"} @expansion{} @code{st_oneway_white}, @pxref{st_oneway}
@item @b{st-oneway_white-e"} @expansion{} @code{st_oneway_white_e}, @pxref{st_oneway}
@item @b{st-oneway_white-n"} @expansion{} @code{st_oneway_white_n}, @pxref{st_oneway}
@item @b{st-oneway_white-s"} @expansion{} @code{st_oneway_white_s}, @pxref{st_oneway}
@need 200
@item @b{st-oneway_white-w"} @expansion{} @code{st_oneway_white_w}, @pxref{st_oneway}
@item @b{st-oxyd} @expansion{} @ref{st_oxyd}
@item @b{st-plain} @expansion{} @ref{st_flat}
@item @b{st-plain_break} @expansion{} @code{st_flat_breakable}, @pxref{st_flat}
@need 200
@item @b{st-plain_cracked} @expansion{} @code{st_flat_cracked}, @pxref{st_flat}
@item @b{st-plain_hole} @expansion{} @code{st_flat_hollow}, @pxref{st_flat}
@item @b{st-plain_move} @expansion{} @code{st_flat_movable}, @pxref{st_flat}
@item @b{st-pmirror} @expansion{} @code{st_mirror_slab_e}, @pxref{st_mirror}
@need 200
@item @b{st-polarswitch} @expansion{} @ref{st_polarswitch}
@item @b{st-pull} @expansion{} @ref{st_pull}
@item @b{st-puzzle} @expansion{} @ref{st_puzzle}
@item @b{st-puzzle-e} @expansion{} @code{st_puzzle_blue_e}, @pxref{st_puzzle}
@need 200
@item @b{st-puzzle-es} @expansion{} @code{st_puzzle_blue_es}, @pxref{st_puzzle}
@item @b{st-puzzle-esw} @expansion{} @code{st_puzzle_blue_esw}, @pxref{st_puzzle}
@item @b{st-puzzle-ew} @expansion{} @code{st_puzzle_blue_ew}, @pxref{st_puzzle}
@item @b{st-puzzle-hollow} @expansion{} @code{st_puzzle_blue_nesw_hollow}, @pxref{st_puzzle}
@need 200
@item @b{st-puzzle-n} @expansion{} @code{st_puzzle_blue_n}, @pxref{st_puzzle}
@item @b{st-puzzle-ne} @expansion{} @code{st_puzzle_blue_ne}, @pxref{st_puzzle}
@item @b{st-puzzle-nes} @expansion{} @code{st_puzzle_blue_nes}, @pxref{st_puzzle}
@item @b{st-puzzle-nesw} @expansion{} @code{st_puzzle_blue_nesw}, @pxref{st_puzzle}
@need 200
@item @b{st-puzzle-new} @expansion{} @code{st_puzzle_blue_new}, @pxref{st_puzzle}
@item @b{st-puzzle-ns} @expansion{} @code{st_puzzle_blue_ns}, @pxref{st_puzzle}
@item @b{st-puzzle-nsw} @expansion{} @code{st_puzzle_blue_nsw}, @pxref{st_puzzle}
@item @b{st-puzzle-nw} @expansion{} @code{st_puzzle_blue_nw}, @pxref{st_puzzle}
@need 200
@item @b{st-puzzle-s} @expansion{} @code{st_puzzle_blue_s}, @pxref{st_puzzle}
@item @b{st-puzzle-sw} @expansion{} @code{st_puzzle_blue_sw}, @pxref{st_puzzle}
@item @b{st-puzzle-w} @expansion{} @code{st_puzzle_blue_w}, @pxref{st_puzzle}
@item @b{st-puzzle2-e} @expansion{} @code{st_puzzle_yellow_e}, @pxref{st_puzzle}
@need 200
@item @b{st-puzzle2-es} @expansion{} @code{st_puzzle_yellow_es}, @pxref{st_puzzle}
@item @b{st-puzzle2-esw} @expansion{} @code{st_puzzle_yellow_esw}, @pxref{st_puzzle}
@item @b{st-puzzle2-ew} @expansion{} @code{st_puzzle_yellow_ew}, @pxref{st_puzzle}
@item @b{st-puzzle2-hollow} @expansion{} @code{st_puzzle_yellow_nesw_hollow}, @pxref{st_puzzle}
@need 200
@item @b{st-puzzle2-n} @expansion{} @code{st_puzzle_yellow_n}, @pxref{st_puzzle}
@item @b{st-puzzle2-ne} @expansion{} @code{st_puzzle_yellow_ne}, @pxref{st_puzzle}
@item @b{st-puzzle2-nes} @expansion{} @code{st_puzzle_yellow_nes}, @pxref{st_puzzle}
@item @b{st-puzzle2-nesw} @expansion{} @code{st_puzzle_yellow_nesw}, @pxref{st_puzzle}
@need 200
@item @b{st-puzzle2-new} @expansion{} @code{st_puzzle_yellow_new}, @pxref{st_puzzle}
@item @b{st-puzzle2-ns} @expansion{} @code{st_puzzle_yellow_ns}, @pxref{st_puzzle}
@item @b{st-puzzle2-nsw} @expansion{} @code{st_puzzle_yellow_nsw}, @pxref{st_puzzle}
@item @b{st-puzzle2-nw} @expansion{} @code{st_puzzle_yellow_nw}, @pxref{st_puzzle}
@need 200
@item @b{st-puzzle2-s} @expansion{} @code{st_puzzle_yellow_s}, @pxref{st_puzzle}
@item @b{st-puzzle2-sw} @expansion{} @code{st_puzzle_yellow_sw}, @pxref{st_puzzle}
@item @b{st-puzzle2-w} @expansion{} @code{st_puzzle_yellow_w}, @pxref{st_puzzle}
@item @b{st-redrock} @expansion{} @ref{st_redrock}
@need 200
@item @b{st-rock1} @expansion{} @ref{st_granite}
@item @b{st-rock1_hole} @expansion{} @code{st_granite_hollow}, @pxref{st_granite}
@item @b{st-rock1_move} @expansion{} @code{st_granite_movable}, @pxref{st_granite}
@item @b{st-rock2} @expansion{} @ref{st_darkgray}
@need 200
@item @b{st-rock2_hole} @expansion{} @code{st_darkgray_hollow}, @pxref{st_darkgray}
@item @b{st-rock3} @expansion{} @ref{st_plaster}
@item @b{st-rock3_break} @expansion{} @code{st_plaster_breakable}, @pxref{st_plaster}
@item @b{st-rock3_hole} @expansion{} @code{st_plaster_hollow}, @pxref{st_plaster}
@need 200
@item @b{st-rock3_move} @expansion{} @code{st_plaster_movable}, @pxref{st_plaster}
@item @b{st-rock3_movebreak} @expansion{} @code{st_plaster_movebreakable}, @pxref{st_plaster}
@item @b{st-rock4} @expansion{} @ref{st_purplemarble}
@item @b{st-rock5} @expansion{} @ref{st_tigris}
@need 200
@item @b{st-rock6} @expansion{} @ref{st_purplegray}
@item @b{st-rock7} @expansion{} @ref{st_greengray}
@item @b{st-rock8} @expansion{} @ref{st_concrete}
@item @b{st-rock9} @expansion{} @ref{st_ancient}
@need 200
@item @b{st-rock10} @expansion{} @ref{st_brownmarble}
@item @b{st-rotator-left} @expansion{} @code{st_rotator_ccw}, @pxref{st_rotator}
@item @b{st-rotator_move-left} @expansion{} @code{st_rotator_ccw_movable}, @pxref{st_rotator}
@item @b{st-rotator_move-right} @expansion{} @code{st_rotator_cw_movable}, @pxref{st_rotator}
@need 200
@item @b{st-rotator-right} @expansion{} @code{st_rotator_cw}, @pxref{st_rotator}
@item @b{st-rubberband} @expansion{} @ref{st_rubberband}
@item @b{st-scissors} @expansion{} @code{st_scissors, inverse=true}, @pxref{st_scissors}
@item @b{st-shogun} @expansion{} @ref{st_shogun}
@need 200
@item @b{st-shogun-l} @expansion{} @code{st_shogun_l}, @pxref{st_shogun}
@item @b{st-shogun-m} @expansion{} @code{st_shogun_m}, @pxref{st_shogun}
@item @b{st-shogun-ml} @expansion{} @code{st_shogun_ml}, @pxref{st_shogun}
@item @b{st-shogun-s} @expansion{} @code{st_shogun_s}, @pxref{st_shogun}
@need 200
@item @b{st-shogun-sl} @expansion{} @code{st_shogun_sl}, @pxref{st_shogun}
@item @b{st-shogun-sm} @expansion{} @code{st_shogun_sm}, @pxref{st_shogun}
@item @b{st-shogun-sml} @expansion{} @code{st_shogun_sml}, @pxref{st_shogun}
@item @b{st-spitter} @expansion{} @ref{st_spitter}
@need 200
@item @b{st-stonebrush} @expansion{} @code{st_ghost_purplemarble}, @pxref{st_ghost}
@item @b{st-stoneimpulse} @expansion{} @ref{st_stoneimpulse}
@item @b{st-stoneimpulse-hollow} @expansion{} @code{st_stoneimpulse_hollow}, @pxref{st_stoneimpulse}
@item @b{st-stoneimpulse_movable} @expansion{} @code{st_stoneimpulse_movable}, @pxref{st_stoneimpulse}
@need 200
@item @b{st-stone1} @expansion{} @ref{st_brownpyramid}
@item @b{st-stone2} @expansion{} @ref{st_redmarble}
@item @b{st-stone_break} @expansion{} @code{st_break_oxydc}, @pxref{st_break}
@item @b{st-surprise} @expansion{} @ref{st_surprise}
@need 200
@item @b{st-swap} @expansion{} @ref{st_swap}
@item @b{st-switch} @expansion{} @code{st_switch, instant=true}, @pxref{st_switch}
@item @b{st-switch_black} @expansion{} @code{st_switch_black, instant=true}, @pxref{st_switch}
@item @b{st-switch_white} @expansion{} @code{st_switch_white, instant=true}, @pxref{st_switch}
@need 200
@item @b{st-thief} @expansion{} @ref{st_thief}
@item @b{st-timer} @expansion{} @ref{st_timer}
@item @b{st-timeswitch} @expansion{} @ref{st_monoflop}
@item @b{st-turnstile} @expansion{} @code{st_turnstile_red}, @pxref{st_turnstile}
@need 200
@item @b{st-turnstile-green} @expansion{} @code{st_turnstile_green}, @pxref{st_turnstile}
@item @b{st-turnstile-e} @expansion{} @code{st_turnstilearm_e}, @pxref{st_turnstilearm}
@item @b{st-turnstile-n} @expansion{} @code{st_turnstilearm_n}, @pxref{st_turnstilearm}
@item @b{st-turnstile-s} @expansion{} @code{st_turnstilearm_s}, @pxref{st_turnstilearm}
@need 200
@item @b{st-turnstile-w} @expansion{} @code{st_turnstilearm_w}, @pxref{st_turnstilearm}
@item @b{st-volcano} @expansion{} @ref{st_volcano}
@item @b{st-volcano_active} @expansion{} @code{st_volcano_active}, @pxref{st_volcano}
@item @b{st-volcano-growing} @expansion{} @code{st_volcano_new}, @pxref{st_volcano}
@need 200
@item @b{st-volcano_inactive} @expansion{} @code{st_volcano_idle}, @pxref{st_volcano}
@item @b{st-whiteballs} @expansion{} @code{st_jamb_white}, @pxref{st_jamb}
@item @b{st-white1} @expansion{} @code{st_passage_white_square}, @pxref{st_passage}
@item @b{st-white2} @expansion{} @code{st_passage_white_slash}, @pxref{st_passage}
@need 200
@item @b{st-white3} @expansion{} @code{st_passage_white_cross}, @pxref{st_passage}
@item @b{st-white4} @expansion{} @code{st_passage_white_frame}, @pxref{st_passage}
@item @b{st-window} @expansion{} @ref{st_window}
@item @b{st-wood} @expansion{} @code{st_box_wood}, @pxref{st_box}
@need 200
@item @b{st-wood1} @expansion{} @code{st_box_wood_h}, @pxref{st_box}
@item @b{st-wood2} @expansion{} @code{st_box_wood_v}, @pxref{st_box}
@item @b{st-wood-growing} @expansion{} @code{st_box_wood_growing}, @pxref{st_box}
@item @b{st-wood_001} @expansion{} @ref{st_panel}
@need 200
@item @b{st-woven} @expansion{} @ref{st_woven}
@item @b{st-yellow} @expansion{} @ref{st_yellow}
@item @b{st-yinyang1} @expansion{} @code{st_blur_cross}, @pxref{st_blur}
@item @b{st-yinyang2} @expansion{} @code{st_blur_straight}, @pxref{st_blur}
@need 200
@item @b{st-yinyang3} @expansion{} @code{st_blur_magic}, @pxref{st_blur}
@item @b{st-3mirror} @expansion{} @code{st_mirror_triangle_s}, @pxref{st_mirror}
@end table
@bye

