[Top] | [Contents] | [Index] | [ ? ] |
This manual describes the internals of Enigma version 1.10, in particular how to build new levels using Lua and how to interact with the game engine.
1. Running Enigma | ||
2. Levelpack Basics | Addition and managing of levels in packs | |
3. Level Basics | Introduction to level description | |
4. Enigma Paradigm | Principles of world, objects and messages | |
5. Lua API | Describing a level with all its objects and interactions | |
6. Common Attributes and Messages | What all objects support | |
7. Floor Objects | ||
8. Item Objects | ||
9. Stone Objects | ||
10. Actor Objects | ||
11. Other Objects | Rubberbands, etc. | |
12. Advanced Features | Fire, ... | |
13. Extension Development | Resolver, Library Development | |
14. Old API - Objects | Description of all objects in Enigma | |
15. Old API - Variables | Lua variables that influence the game | |
16. Old API - Functions | Predefined functions | |
Object Index | ||
Attribute Index | ||
Message Index | ||
Function Index | ||
Concept Index |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
1.1 Locating Resources | ||
1.2 Startup Switches | ||
1.3 User Options | ||
1.4 Level Info | ||
1.5 Handicap and PAR | Background to score evaluation and HCP | |
1.6 User Sound Sets | How to create and install sound themes |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 by pressing <F2> within the main menu, or by starting Enigma with the switch ‘--log’ (see section Startup Switches) and looking at the console output.
This is the path to the file that stores your preferences concerning application
options. This file is usually located at your HOME
directory. For HOME
-less
Windows users, it is stored in the ‘Application Data\Enigma’ directory. Since it is the
third version in the history of Enigma, the file is named
‘.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 ‘--pref’ (see section 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 ‘.’ will hide the preferences filename.
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 ‘.enigma’ at your HOME
directory. For HOME
-less Windows users, it is the ‘Application Data\Enigma’
directory.
You can define your own path within the 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.
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 ‘User Path’.
Just in case you make many screenshots and have limited resources on the main ‘User Path’, you may want to store the images on another path. You can define your own path within the User Options.
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.
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.
This path shows the directory that contains the localization data.
Please note that some resources, like levels, may be zipped. In this case, a resource that you expect to find at ‘dirname/filename’ may be stored in a zipfile named ‘dirname.zip’. The path of the file within the zip can be either ‘dirname/filename’ or ‘./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 to be an update to the zip.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Besides starting Enigma by clicking on an installation-provided icon or start menu entry, you can start Enigma from a shell or commandline. With release 1.00, the Windows version supports this feature without restrictions. Although playing the distributed levels using this feature is not necessary, you may take advantage of this feature in special or advanced usage.
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, ‘--data path’ or ‘-d path’.
A switch for Enigma developers that forces all debugging assertions, even expensive ones, to be evaluated. The additionally evaluated checks look like ‘ASSERT(noAssert || long_lasting_check(), XLevelRuntime, "remark");’.
A switch for Enigma developers that allows you to add an additional path to the resource paths that precedes the system path (see section 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 ‘src/Enigma -d ./data’.
Just lists the available startup switches to the output and terminate.
A switch that allows you to override any other language preference. The language is given in the common 2-character sequence as ‘fr’ for French or ‘ru’ for Russian.
This switch turns on logging of internal information to the standard output. Windows users will find an file called ‘stdout.txt’ in the current working directory. The output will, for example, list the paths described in Locating Resources.
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.
Start Enigma without playing background music.
Start Enigma with sound being switched off.
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 Locating Resources.
The path of an alternative directory that contains the standard named preference file ‘.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.
Show the framerate (FPS) during the game.
Just print the version number to the output and terminate.
Start Enigma in window mode instead of screen mode.
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:
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):
C:\programs\Enigma-1.00\enigma.exe demo_simple.xml
You will find these levels in a levelpack called ‘Startup Levels’, which is only visible by default if you supplied levels on the commandline.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Please retain this option on the value ‘Never’ until release of Enigma 1.00.
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.
This textfield allows you to define an arbitrary directory for your Enigma user data as described in 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.
This textfield allows you to define an arbitrary directory for your Enigma user image data as described in 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
1.4.1 Public Ratings | ||
1.4.2 Scores | ||
1.4.3 Versions | ||
1.4.4 Private Annotations and Ratings | ||
1.4.5 Screenshots |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Most levels are rated within five different categories:
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.
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:
High values for intelligence are typically puzzles. int-ratings do not accumulate; the most difficult puzzle itself already determines the rating.
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.
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.
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.
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.
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):
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”.
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.
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.
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:
universal difficulty = 7*int + 6*dex + 4*pat + 3*kno + 4*spe - 23 |
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The version column shows detailed information about the level. Read the chapter Level Basics node see section <version> and see section <modes> for an explanation of the values.
For you as a player, the ‘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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘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 ‘-’ 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
While playing a level, you can make screenshots by pressing <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 <F1> to get a help screen. <ESC> returns to the level inspector. <Page Up> and <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 ‘user image path’ (see section Locating Resources).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As PAR (see section Scores) describes the difficulty of a level, the handicap ‘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 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 ‘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:
• | + 1.0 | for each unsolved level |
• | + log10(score/par) | for each solved level with existing par if score >= par |
• | + 0.7 | as upper limit for each solved level with existing par if score >= par |
• | + log2(score/par) | for each solved level with existing par if score < par |
• | - 3.0 | as lower limit and as value for levels without par |
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
(The following information accounts only for Enigma 1.01 and above.) Sound effects are triggered by so-called ‘sound events’. These sound events usually have a name (like ‘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 ‘sound set’.
You can use own sound files to create own sound sets for Enigma, and choose among them in the options menu (entry ‘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 ‘data/sound-defaults.lua’ file and in the empty sample file at ‘reference/soundset.lua’. Each entry in these tables is either a string like ‘enigma/st-coinslot’, which is interpreted as the file ‘soundsets/enigma/st-coinslot.wav’ with some default properties, or a list of sound attributes enclosed in curly braces. Sound events triggered with @ref{enigma.EmitSound} are converted the same way. Here is an example of such an entry:
dooropen = { file="my_soundset/open-door", volume=0.9, priority=4 }, |
The meaning of these attributes is as follows:
To design a new sound set, proceed as follows:
(user path)/soundsets/my_sounds/ /soundset.lua /high_pitch.wav /soundfile_13.wav ... |
... coinsloton = { file="enigma/st-coinslot" }, ... |
When using own sound files, remember to add the subfolder, like in
... coinsloton = { file="my_sounds/soundfile_13" }, ... |
No extension ".wav"! It's added automatically. Make sure that the extension is in lower case letters.
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 ‘soundset.lua’ file. You can install a downloaded zipped sound set simply by unpacking it and placing it into the ‘soundsets’-subdirectory of your user path. Make sure that the ‘soundset.lua’ is always exactly one subdirectory below ‘soundsets’. Deinstall a user sound set simply by deleting its directory. Renaming the directory does not suffice – you have to rename the ‘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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
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:
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:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘levels/auto’ on your ‘user path’ (see section Locating Resources). Just copy the level file to this folder and restart Enigma. The new level will be part of the ‘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 (see section 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 (see section 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 ‘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 ‘levels’ on your ‘user path’ (see section Locating Resources).
You must copy levelpacks distributed as zip archives to the subdirectory ‘levels’ on your ‘user path’. You do not need to unpack the zip, although it is possible, as described in the section Zip Levelpacks.
You must copy levelpacks that are distributed as a single XML index file to the subdirectory ‘levels/cross’ on your ‘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 Level Basics. The rest of this chapter explains how to arrange and sort existing levels in your own levelpacks.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘user path’ subdir ‘levels’ (see section Locating Resources). The ‘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 ‘user path’. If you registered your levelpacks on the system levels directory within the ‘index.lua’ file, you need to copy these registration lines to the ‘index_user.lua’ file, which you should store on your ‘user path’.
If you maintained several of your own levelpacks, Enigma 0.92 allowed you to keep them in several subdirectories of the ‘levels’ directory.However, since it also allowed you to keep all level files and different indices in the ‘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 ‘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 ‘levels’ that referenced level files in different subdirectories of ‘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 ‘index.xml’ exists, only this index is used. Thus, after a careful check, you may remove the old ‘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 ‘levels’ directory. Enigma stores the converted ‘index.xml’ within this directory. You may want to exchange the old ‘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 Level Basics.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Besides the classic levelpack format of a subdirectory of ‘levels’ with an ‘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 ‘.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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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:
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 ‘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: ‘[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 ‘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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
To create a new levelpack, you simply select the group to which you want to add the new pack. This is most likely the ‘User’ group. Right or ctrl click on the group and simply click on the ‘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 (see section 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 ‘Level types’ button, which uses symbols for references and carbon copies.
The ‘Default Location’ is a number that determines the sorting location within levelpack groups, if you have not resorted the levelpack manually (see section 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 clickling ‘OK’. Enigma will create the levelpack on your ‘userpath’ (see section Locating Resources).
If you decide not to create a new levelpack, just click ‘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 ‘Compose Pack’. Enigma will create the levelpack, and you can use the composer to fill it with levels.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘Edit Metadata’ button will appear only for your own levelpacks, which Enigma stores on your ‘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 ‘Default Location’ and the ‘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 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 ‘userpath’. For crossreference levelpacks, you simply need to delete the index XML file on the ‘levels/cross’ subdirectory of your ‘userpath’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘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 ‘Shift delete’. Then select any levelpack you want from within the composer levels. Add them by ‘Shift click’. 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 ‘F8’ to insert the levels of the clipboard as references. If you edit a levelpack that can take level copies, you may use ‘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 ‘OK’ button finalizes all changes. Leaving the composer via the‘Undo’ button reverts all changes.
Besides adding levels, you can delete levels by using the ‘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 ‘Undo’ button.
You can resort all levels with the ‘alt left arrow’ and ‘alt right arrow’. The new sorting appears immediately, and you can save it by using the ‘OK’ button.
You can use the ‘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 ‘auto’ folder, restart Enigma, add the levels from the ‘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 ‘auto’ folder.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 Lua 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:
Let us have a first view on complete simple ‘Hello World’ level in the new format:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <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"> <el:protected > <el:info el:type="level"> <el:identity el:title="Demo Simple" el:id="20060210ral001"/> <el:version el:score="1" el:release="1" el:revision="0" el:status="stable"/> <el:author el:name="Ronald Lamprecht"/> <el:copyright>Copyright © 2006 Ronald Lamprecht</el:copyright> <el:license el:type="GPL v2.0 or above" el:open="true"/> <el:compatibility el:enigma="0.92"/> <el:modes el:easy="false" el:single="true" el:network="false"/> <el:score el:easy="-" el:difficult="-"/> </el:info> <el: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) set_actor("ac-blackball", 4, 11) ]]></el:luamain> <el:i18n/> </el:protected> </el:level> |
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 ‘]]>’ for the end mark, and you would have to substitute it with ‘]] >’. 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 ‘Exp’ levelpack grouped in ‘Development’. The source code is located on the system path subdirectory ‘levels/enigma_experimental’ (see section Locating Resources).
If you make your first coding experiments on a copy of this level, either add your copy to the auto folder (see section Getting Started with Levelpacks), or use it as an argument on the command line (see section Startup Switches).
Of course we must look at the details of the format and explain the optional parts:
3.1 Getting Started with Levels | ||
3.2 XML Level structure | ||
3.3 Info metadata | ||
3.4 LUA code | ||
3.5 Internationalization (i18n) | ||
3.6 Usage | ||
3.7 Update and Upgrade | ||
3.8 Libraries |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A Simple 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 level in Enigma, so you can try it out right away.)
1 CreateWorld(20, 13) 2 draw_border("st-brownie") 3 fill_floor("fl-hay", 0,0, level_width,level_height) 4 5 set_stone("st-fart", level_width-1,0, {name="fart"}) 6 set_stone("st-timer", 0,0, {action="trigger", target="fart", 7 interval=10}) 8 9 oxyd(3,3) 10 oxyd(level_width-4,level_height-4) 11 oxyd(level_width-4, 3) 12 oxyd(3,level_height-4) 13 oxyd_shuffle() 14 15 set_actor("ac-blackball", 10,6.5) |
The resulting level looks like this inside the game:
Let's now turn to a line-by-line analysis of this program:
1 CreateWorld(20, 13) 2 draw_border("st-brownie") 3 fill_floor("fl-hay", 0,0, level_width,level_height) |
The level begins with a call to CreateWorld
, which creates a
new world that is 20 blocks wide and 13 blocks high. You can access every
block in the world with a pair of coordinates:
The upper left corner has coordinates (0,0); the lower right has
coordinates (19,12). Every block contains a floor tile, an (optional)
item, and an (optional) stone.
You draw a frame of stones around the newly created landscape with the
draw_border
command. Its argument, "st-brownie"
, is the
name of a stone. By convention, all stones have "st-"
prefixed
to their name; similarly all item names begin with "it-"
and
all floor names with "fl-"
.
The fill_floor
command in line 3 fills the complete floor with
tiles of type "fl-hay"
. The other arguments are the upper left
corner and the width and height of the rectangle to be filled.
5 set_stone("st-fart", level_width-1,0, {name="fart"}) 6 set_stone("st-timer", 0,0, {action="trigger", target="fart", 7 interval=10}) |
Lines 5 to 7 demonstrate how to create individual stones. The
set_stone
command takes a stone name, the desired
coordinates, and an (optional) list of attributes
as arguments. Note the use of curly braces {
,
}
to enclose the attribute list.
Attributes are the key to customizing the behavior of objects in a landscape. Here, we name the first stone we create. It's a fart stone that has the unpleasant habit of “blowing off” when triggered. The timer stone that we create in line 6-7 triggers this fart stone. This stone performs a predefined action at regular intervals. In this case, we want to send a “trigger” message every ten seconds to the object named “fart”.
9 oxyd(3,3) 10 oxyd(level_width-4,level_height-4) 11 oxyd(level_width-4, 3) 12 oxyd(3,level_height-4) 13 oxyd_shuffle() |
These commands place a couple of oxyd stones in the level. The
oxyd
command internally uses set_stone("st-oxyd", x,y,
…)
to create the stones, but additionally it assigns sensible
values to some of the oxyd stones' attributes (most notably the
color). The command on line 14 permutes the colors on the oxyd stones
currently in the landscape.
15 set_actor("ac-blackball", 10,6.5) |
This final line creates the black marble that the player controls. We call objects that can move around freely “actors” in Enigma. Unlike stones and items, actors are not restricted to integer coordinates, as you can see in this example.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <el:level xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://enigma-game.org/schema/level/1 level.xsd http://enigma-game.org/schema/editor editor.xsd" xmlns:el="http://enigma-game.org/schema/level/1" xmlns:ee="http://enigma-game.org/schema/editor"> <el:protected> <el:info el:type="level"> <!-- required elements omited --> </el:info> <el:elements/> <el:luamain><![CDATA[ ]]></el:luamain> <ee:editor/> <el:i18n/> </el:protected> <el:public> <el:i18n/> <el:upgrade/> </el:public> </el:level> |
The first line is the XML declaration. It is fixed besides the encoding specification. Enigma supports on all platforms, at least ‘US-ASCII’, ‘UTF-8’, ‘UTF-16’, ‘ISO-8859-1’, ‘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 ‘</element>’ for each start tag ‘<element>’. For elements that have only attributes and no content, you can and should use the alternative empty element notation ‘<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 ‘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, ‘&’ and ‘<’. 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 ‘&’ and ‘<’. Additionally, you must enclose attribute values with either ‘"’ or ‘'’. Of course, you must substitute the enclosing character used in attribute values, too. Use ‘"’ and ‘&apos’.
Elements:
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.
Attributes:
Namespace definition for the schema. The contents are fixed to “http://www.w3.org/2001/XMLSchema-instance”. The attribute tag ‘xsi’ must match the prefix of the next attribute tag, and is standard.
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.
Namespace definition for “Enigma level”. We use ‘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.
Only level editor programs use this last namespace definition. For example, we declared ‘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.
The protected node section contains all level data that derive from the author and should not be modified by anyone else.
The info node section contains all level metadata. It is mandatory and described in detail at section Info metadata.
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.
The luamain node section is the part to insert manually Lua level descriptions. It is described in detail at section LUA code.
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.
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 Internationalization (i18n).
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.
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 Internationalization (i18n).
This upgrade node is part of the Update and Upgrade system.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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:
<el:info el:type="level"> <el:identity el:title="Demo I18N" el:subtitle="Translate or let it be translated" el:id="20060211ral002"/> <el:version el:score="1" el:release="1" el:revision="0" el:status="experimental"/> <el:author el:name="Ronald Lamprecht" el:email="ral@users.berlios.de"/> <el:copyright>Copyright © 2006 Ronald Lamprecht</el:copyright> <el:license el:type="GPL v2.0 or above" el:open="true"/> <el:compatibility el:enigma="0.92"/> <el:modes el:easy="false" el:single="true" el:network="false"/> <el:comments/> <el:update el:url="http://…"/> <el:upgrade el:url="http://…" el:release="2"/> <el:score el:easy="-" el:difficult="-"/> </el:info> |
Attributes:
You may use the schema for single Enigma levels, libraries that contain level description parts for reuse, and descriptions for multiple levels at once.
‘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.
‘library’ are level description parts that may be included in levels. The library may consist simply of Lua code in the luamain node, or additional object descriptions in the elements node. Libraries may make use of nearly all nodes besides the ‘/level/protected/info/score’ and ‘/level/*/i18n’, which both must be provided, but will not be evaluated. Libraries are included in levels via the dependency node-element. See <compatibility>.
‘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.
The number of levels contained in a multilevel file.
Contents - Elements:
The title, subtitle and the main level identification string. See <identity>.
All aspects of the level <version>.
All information provided about the author him- or herself. See <author>.
The <copyright> message for the level.
Information about the <license> conditions.
All information about <compatibility> to Enigma releases, dependencies from libraries, external data and the editor program that generated the level.
The <modes> that the level supports, such as difficulty, network and control.
Optional comments, such as credits, dedication and code comments. See <comments>.
The author's own <score> of this level.
3.3.1 <identity> | ||
3.3.2 <version> | ||
3.3.3 <author> | ||
3.3.4 <copyright> | ||
3.3.5 <license> | ||
3.3.6 <compatibility> | ||
3.3.7 <modes> | ||
3.3.8 <comments> | ||
3.3.9 <score> |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The ‘identity’ element is required, since it provides the information for human and system identification of the level.
<el:identity el:title="Demo I18N" el:subtitle="Translate or let it be translated" el:id="20060211ral002"/> |
Attributes:
The English title of the level. 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 Internationalization (i18n) sections.
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 Internationalization (i18n) sections.
This is the central system identification string of the level that remains valid for all time, independent of upcoming release updates. Enigma's single demand on the id is that it is unique among all levels created by all authors around the world.
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:
YYYYMMDDuserNNN
Where ‘YYYY’,‘MM’,‘DD’ is the date of the creation of the first experimental version, ‘user’ stands for a user-specific name and ‘NNN’ for a random number. For example, my level called ‘Houdini’ has the id ‘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 no harm since the only requirement is the uniqueness.
Contents:
The element itself is empty - no content is allowed.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This element provides the versioning information for the system.
<el:version el:score="1" el:release="1" el:revision="0" el:status="experimental"/> |
Attributes:
The score version is given as a positive integer number. New levels start with score verison “1”. New level versions need to increase the score version number if the level modifications cause different solutions with uncomparable score values. Of course, level authors should be very restrictive with such modifications.
During the development of a level, you should use the attribute ‘status’ to mark a level as not released. When the author changes the ‘status’ to ‘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 ‘index.txt’ attribute ‘revision’.
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 AuthoridentifierLevelnumber_Releasenumber.Suffix, where the levelnumber is at least 2 digits; for example, ‘ral01_2.xml’
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 supercede 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 ‘$Revision$’. This Subversion format allows level authors to let their Subversion repository automatically insert the level revision number. They must simply set ‘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.
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 ‘released’.
As a level author, if you start to change a released level, you should first change the status back to ‘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.
Contents:
The element itself is empty - no content is allowed.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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:
<el:author el:name="Ronald Lamprecht" el:email="ral@users.berlios.de" el:homepage="http://myhomepage.domain"/> |
Attributes:
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 ‘anonymous’.
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.
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.
Contents:
The element itself is empty; no content is allowed.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The standardized location for the author's copyright message:
<el:copyright>Copyright © 2006 Ronald Lamprecht</el:copyright> |
Attributes:
none
Contents:
The author's copyright notice.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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:
<el:license el:type="GPL v2.0 or above" el:open="true"/> |
Attributes:
A short license identifier of the license type, with an optional link address to the license text or the string ‘special’, if the author supplies his/her own license as the content of this element.
A boolean statement, whether the chosen license fulfills the criteria of the Open Source Initiative (OSI). Please note that a value of ‘false’ may prevent your level from being distributed with Enigma.
Contents:
You may add a complete license text as the contents of this element. Please use the type attribute to identify the level.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
<el:compatibility el:enigma="0.92" el:engine="enigma"> <el:dependency el:path="lib/natmaze" el:id="lib/natmaze" el:release="1" el:preload="true" el:url="http://anywhere.xxx/mypage/natmaze.xml"/> <el:externaldata el:path="./extfile" el:url="http://anywhere.xxx/mypage/extdata.xml"/> <el:editor el:name="none" el:version=""/> </el:compatibility> |
Attributes:
The minimal Enigma release number required for compatibility.
The required engine compatibility mode that influences the behavior of various objects. This attribute is evaluated only for levels. Libraries ignore this attribute.
Contents - Elements:
The compatibility element itself contains only subelements as content.
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.
Attributes:
The resource path of the library without its suffix or any release extension. Enigma stores most libraries in the ‘lib’ subdirectory of its ‘levels’ directory, in most cases the resource path will be like the one in the example above: ‘lib/ant’. This is the valid path for the library file that may be either ‘levels/lib/ant.xml’ or ‘levels/lib/ant.lua’ or ‘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 ‘./mylib’ and store the library in the level pack directory itself.
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.
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.
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 checked them on conformance. You should always preload your libraries if you make use of the ‘elements’ section.
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 ‘library’ resource path attribute. The test levels will load the newest library version as published at the given url.
Contents:
none.
You can use this element to specify any external data file this level depends on. You can specify several files by multiple occurrence 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, including some data within a level may not be possible. However, distributing the data in the original unmodified format may be legal.
Attributes:
The resource path of the external data file with its suffix. Since the data are usually level- specific, you should store them with the level in the same levelpack directory. Thus, a relative resource path, such as ‘./datafile.ext’ is preferable.
This optional attribute allows you to specify an online address for the external data file. This method can access only well-formed xml data files.
You should use the online access method only as a backup address or due to very restrictive license conditions that make it impossible to distribute the data file with Enigma.
Contents:
none.
Special level editor programs use this element to store information about themselves.
Attributes:
The name of the level editor.
A version number of the editor, given as a string. .
Contents:
none
Contents:
none
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
<el:modes el:easy="false" el:single="true" el:network="false" el:control="force" el:scoreunit="duration" el:scoretarget="time"/> |
Attributes:
If a level provides a second easy-difficulty mode, set this attribute to ‘true’. If only a one difficulty mode is supported, set this attribute to ‘false’.
If a level provides a single player game as it is standard, set this attribute to ‘true’. Set this attribute to ‘false’ only if the level is a 2-player-network game.
If a level provides a 2-player-network game, set this attribute to ‘true’. If not, set this attribute to ‘false’.
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.
This attribute defines the evaluation and display mode of score values. By the default ‘duration’, the score is interpreted as level solution time and displayed in a MM:SS format. The ‘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.
The score target triggers the measuring of score values. ‘time’ will take the solution time, ‘pushes’ counts the pushes of stones, ‘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.
Contents:
none
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
<el:comments> <el:credits el:showinfo="true" el:showstart="false">Thanks to the author of my favorite libs</el:credits> <el:dedication el:showinfo="true" el:showstart="false">To a honorable or a beloved person</el:dedication> <el:code>some important general notes</el:code> </el:comments> |
Attributes: none
Contents - Elements:
The comments element itself contains only subelements as content.
The place to honor people who helped to make your level run.
Attributes:
A value of ‘true’ will display the message on the level info page
A value of ‘true’ will display the message on startup of the level. Please use this feature only in rare cases.
Contents:
The credits message itself. It may be broken into several lines. Whitespaces will be collapsed before display.
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.
Attributes:
A value of ‘true’ will display the message on the level info page
A value of ‘true’ will display the message on startup of the level. Please use this feature only in rare cases.
Contents:
The dedication message itself. It may be broken into several lines. Whitespaces will be collapsed before display.
Attributes:
none.
Contents:
The main code comment, which may be an explanation of the <version> status or a todo list. It may be broken into several lines. This comment will not be processed.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 <modes>.
<el:score el:easy="01:07" el:difficult="-"/> |
Attributes:
The solution time for the easy mode. The format is either MM:SS, where MM stands for the minutes, and SS for the seconds, or - if the author did not yet solve the level him/herself. For levels with a score unit mode ‘number’, the value would be the number of marble moves or pushes.
The solution time for the difficult mode. The format is either MM:SS, where MM stands for the minutes, and SS for the seconds, or - if the author did not yet solve the level him/herself. For levels with a score unit mode ‘number’, the value would be the number of marble moves or pushes.
Contents:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This element takes any Lua code as a single chunk with nearly no limitations:
<el: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) ]]></el:luamain> |
Attributes:
none
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 <compatibility>. Generally there is no more need to use Lua functions like ‘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 ‘el:preload="false"’. You should use the new function 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 ‘]]>’. Any occurrence must be substituted by ‘]] >’.
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The internationalization of levels is a driving force behind the level format changes. As you may have noticed, there are two ‘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 ‘demo_i18n.xml’ level:
<el:protected > <!-- elements ommited --> <el:i18n> <el:string el:key="title"> <el:english el:translate="false"/> </el:string> <el:string el:key="subtitle"> <el:english el:translate="true"/> <el:translation el:lang="de">Übersetzten oder übersetzten lassen</el:translation> </el:string> <el:string el:key="hint1"> <el:english el:comment="Let 'right' be ambiguous: correct and opposite of left - if not possible choose correct">Read the right document</el:english> <el:translation el:lang="de">Lies das rechte Dokument</el:translation> </el:string> <el:string el:key="hint2"> <el:english el:comment="the correct one and not the right positioned one">The right one, not the right one!</el:english> <el:translation el:lang="de">Das rechte, nicht das rechte</el:translation> </el:string> <el:string el:key="Heureka!"> <el:english el:translate="false">Heureka!</el:english> </el:string> </el:i18n> </el:protected> <el:public> <el:i18n> <el:string el:key="hint1"> <el:translation el:lang="fr">Lisez la document de droite</el:translation> </el:string> </el:i18n> </el:public> |
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, ‘title’ and ‘subtitle’.
For each string we like to translate or have translated, we define a ‘string’ subelement of the protected section and add a ‘english’ subelement to the ‘string’ element itself. The ‘string’ element just takes a single mandatory attribute, the key of the string. The ‘english’ element has a single mandatory attribute ‘translate’ that defaults to ‘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 ‘string’ element for this string at all. Thus, the elements for the strings with the keys ‘title’ and ‘Heureka!’ are optional and quite unusual.
‘title’ and ‘subtitle’ display the English text in the <identity> element. All other strings referenced by keys need to add the English text as the content of the ‘english’ element. ‘hint1’ and ‘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 ‘comment’ attribute to the ‘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 ‘translation’ subelement to the ‘string’ element. The ‘translation’ element has a single mandatory attribute ‘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 ‘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 ‘english’ element may be provided. The ‘key’ attribute in the ‘string’ element must match exactly the ‘key’ attribute in the corresponding ‘string’ element in the protected section. One subtle difference exists, due to technical and practical reasons. ‘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 ‘i18n’ section to avoid these troubles.
The ‘string’ element in protected section and in the public section must be unique concerning the attribute ‘key’ within the section. This means you should add translations for all known languages for a string in ‘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 ‘hint2’ for the German translator:
# level: "Demo Internationalization" # author: "Ronald Lamprecht" email "ral@users.berlios.de" # comment: "the correct one and not the right positioned one" # use: "Das rechte, nicht das rechte" #: po/level_i18n.cc:17 msgid "The right one, not the right one!" msgstr "" |
‘msgid’ is the English string. ‘msgstr’ takes the German translation. But the translator does not need to translate since the author provided the German translation in the ‘# use:’ line
As another example, ‘hint1’ for the French translator:
# level: "Demo Internationalization" # author: "Ronald Lamprecht" email "ral@users.berlios.de" # comment: "Let 'right' be ambiguous: correct and opposite of left - if not possible choose correct" # check: "Lisez la document de droite" #: po/level_i18n.cc:14 msgid "Read the right document" msgstr "Lisez le document de droite" |
Here the author gives the public translation in the ‘# check:’ line. Since it contains at least one mistake, the translator will correct it, as shown in the ‘msgstr’ string.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘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 ‘--xml-- ’. For 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 © 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 create_world( levelw, levelh) draw_border("st-wood") fill_floor("fl-leavesb", 0,0,levelw,levelh) oxyd( 4,4) oxyd( 14,4) set_actor("ac-blackball", 4, 11) --xml-- ]]></el:luamain> --xml-- <el:i18n/> --xml-- </el:protected> --xml-- </el:level> |
Please note that each XML metadata line must start exactly with ‘--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 ‘UTF-8’ or, of course ‘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 ‘.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: ‘xml2lua’ and ‘lua2xml’. Both are very simple Lua 5 scripts that you can execute as ‘lua xml2lua demo_simple.xml > demo_simple.lua’ with a properly installed Lua 5 version. On Unix systems, you can mark the scripts as executables and simply call ‘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 ‘--log’ and read the messages printed to the command line or written to the file ‘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 ‘level.xsd’ on the same directory as the level itself. Possible validation tools are the Xerces-C sample application ‘DOMPrint.exe -n -s -f -v=always level.xml’ or validating editors, such as Exchanger XML Lite. Such editors will provide you with selections of all possible elements and attributes at each position.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Enigma is able to load new level versions since we provide all necessary attributes in the <version> element.
If Enigma loads a new level version, which differs just in the ‘revision’, we speak of an ‘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:
<el:update el:url="http://myLevelServer.org/path/level_1.xml"/> |
Attributes:
A long-term valid, complete address for update downloads of this level in the same score and release version.
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 ‘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:
<el:upgrade el:url="http://myLevelServer.org/path/level_2.xml" el:release="2"/> |
Attributes:
A long-term valid, complete address for upgrade downloads of this level. A path to the new file.
The release version of the upgrade.
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Libraries are collections of Lua functions for reuse in many levels. To use a library, you must declare it as an dependency, as described in <compatibility>. Preloading the library is all you have to do to use the library. Otherwise, you can use the function enigma.LoadLib to load the library at a certain point of execution.
Enigma provides several very useful libraries. You will find them on the system path in the subdirectory ‘levels/lib’. Most of them are documented in-line. You will find a separate documentation file ‘doc/ant_lua.txt’ for ‘ant’.
In this section, we will concentrate on the aspects of writing and maintaining libraries:
3.8.1 Writing a Library | ||
3.8.2 Maintaining a Library |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Library files are nearly identical to level files. The main difference is the attribute ‘el:type’ in the ‘info’ element, which you should set to ‘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 ‘i18n’ elements.
The ‘el:luamain’ element takes the complete Lua code as it does for levels. Let's look at the essential XML parts of a library:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <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"> <el:protected > <el:info el:type="library"> <el:identity el:title="" el:id="lib/ant"/> <el:version el:score="1" el:release="1" el:revision="0" el:status="released"/> <el:author el:name="Petr Machata"/> <el:copyright>Copyright © 2002-2003 Petr Machata</el:copyright> <el:license el:type="GPL v2.0 or above" el:open="true"/> <el:compatibility el:enigma="0.92"> <el:dependency el:path="lib/natmaze" el:id="lib/natmaze" el:release="1" el:preload="false"> </el:compatibility> <el:modes el:easy="false" el:single="false" el:network="false"/> <el:score el:easy="-" el:difficult="-"/> </el:info> <el:luamain><![CDATA[ … ]]></el:luamain> <el:i18n/> </el:protected> </el:level> |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘lib/ant’. The filename of a given release is the basename with the addition of an underscore and the release number plus the suffix ‘xml’. Thus, you must store release ‘lib/ant’ as ‘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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
4.1 The World's Structure | ||
4.2 Object Description | ||
4.3 Methods of Interaction | ||
4.4 The Lifecycle of a Level |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
4.1.1 World's Shape and Coordinates | Grid Positions and Tiles | |
4.1.2 Object Layers | Floors, Items, Stones, Actors and Others | |
4.1.3 World as an Object | Global attributes and handle | |
4.1.4 Unpositioned Objects | Other objects like rubbers and gadgets | |
4.1.5 Owned Items | Players Inventories and other containers |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
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 lateron. A common size is 20x13 for a 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,...
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 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.
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 on the grid position {1, 2}. Thus we speak of a 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.
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 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 layers - the floor layer, the item layer and the stone layer.
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 default floor that gets automatically set on every grid where you set no other floor. Even if you 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 of 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 an 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 physically 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Friction, Brittleness, Modes and Co., Scrollmodes
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 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 add method to add them and you need to use Object Reference or Object Naming to access them lateron, as no position driven access does exist.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
4.2.1 Object Kind | ||
4.2.2 Object Reference | ||
4.2.3 Object Naming | ||
4.2.4 Object Attributes |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Up to now we have spoken about object kinds of floor ‘fl’, item ‘it’, stone ‘st’ and actor ‘ac’. All these kinds are called 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 ‘st_switch’. You will find all object kinds described in the chapters starting with Floor Objects. All these kind names with at least one underscore can be instantiated.
Most kinds provide subkinds like ‘st_switch_black’ and ‘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 ‘st_chess’ the super kind will result in a default ‘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 ‘st_chess’ returns the kind ‘st_chess_black’, whereas an ‘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 ‘_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 ‘st_switch’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Having set objects to the various layers a level author sometimes has the need of referencing them lateron. 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 ‘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 ceize to exist you have to be aware that the references are volatile, too. You can check every object reference for existance. 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 ceize 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. See section Object Naming.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
For addressing objects on a longterm valid basis every object can individually be tagged by a name. Assigning a name to an object is as simple as setting the attribute ‘name’ with a unique string on this object. Of course you can request an objects name by reading the attribute ‘name’.
The name is a string that should be made up of characters ‘a..z’, ‘A..Z’, numbers ‘0..9’ and the underscore ‘_’. Other special charcters are only allowed as far as they are explained in the following text.
It is up to you to ensure unique names. Reusage 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 ‘#’ as the last character to a name, e.g. ‘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. ‘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 named object repository. The API provides a variable ‘no’ that allows you to retrieve any named object, e.g. ‘no["mylaser_a"]’. You get an Object Reference or ‘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 ‘?’ and ‘*’. The question mark replaces a single arbitrary character, the asterix any number of arbitrary characters. E.g. ‘no["mydoor#*"]’ retrieves all auto named ‘mydoor’ objects in a single object group.
Many object attributes like ‘target’, ‘destination’ need object references to other objects. Besides a volatile Object Reference you always can provide a name string as a longterm 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 a object name with wildcards. Thus the string ‘"mydoor#*"’ is a valid target.
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 ‘@’ character.
ti["F"] = {"st_floppy", target="@door#*"} ti["D"] = {"st_blocker", name="door#"} |
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 preceed 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. 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 res.autotile and 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:
wo[{3,4}] = {"it_vortex", name="vortex1", destination="vortex2"} wo[{15,9}] = {"it_vortex", name="vortex2", destination="vortex1"} |
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 transfered even if the reference gets invalid. And like the user attributes the name is part of the object identity. Thus if you name an st_blocker and it it shrinks to an 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 completly 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 Messages. But what about the nearest object references? To avoid problems due to killed objects the standard nearest object reference with just one ‘@’ as prefix are finalized on 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 ‘@@’ the reference will not get finalized on initialization but remains dynamic.
ti["c"] = {it_coin_s", "magic#"} ti["v"] = {it_vortex", destination="@@magic#*"} |
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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. ‘obj["inverse"]=true’ sets a single object attribute to a boolean value and ‘{"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:
If we speak of a bool value we do it in the sense of Lua 5, that means with the possible values ‘true’ and ‘false’.
Many enumerated values like directions and colors are covered by the integer numbers.
Of special interest is the value ‘nil’. Just a few attributes make direct use of the value ‘nil’, e.g. "color" on some objects. If you set an attribute to value ‘nil’ you do actually reset its value to the default value. E.g. if you set the attribute "orientation" of st_boulder to ‘nil’ it will be set to its default, which is actually ‘NORTH’, an enumerated direction value. A subsequent read of the attribute will return this value. Just those attributes that allow a nil value will ever return ‘nil’ on a read access. As a direct consequence these attributes always default to ‘nil’.
The authors of Lua did decide to prohibit the usage of ‘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 ‘nil’. You would need to set such attributes explicitly. As a workaround we added a custom value ‘DEFAULT’ that can be used anywhere to set attributes - even within Lua tables.
mySwitch["color"] = nil mySwitch["color"] = DEFAULT wo[{3,6] = {"ac_marble_black", player=DEFAULT} |
Note that ‘DEFAULT’ is not equal to ‘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 ‘nil’. ‘DEFAULT’ will never be returned by the engine.
A group is an ordered set of Object References. As all contained objects must exist this value is seldomly used for attributes in object declarations. But is is very useful for postprocessing of objects and for usage within Callback Functions.
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 tokens 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 ‘target’:
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"} |
This versatility is useful to set tokens attributes independent of the given object reference types.
The chapter 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 ‘_’ 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 unaccessable attributes are named with a leading dollar sign ‘$’. 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 ‘{"st_door_h", state = OPEN}’ is opened from the very beginning. Whereas ‘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 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 hold 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Having looked at the description of the initial object composition of a level world we still need to undestand how to configure the dynamic behaviour of a level.
4.3.1 Messages | Asking objects to do something | |
4.3.2 Target - Action | Automatic reactions on an event | |
4.3.3 Callback Function | Lua hooks to react on events | |
4.3.4 Object State |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘open’ to the door. Another switch may send a message ‘on’ to a laser or ‘ignite’ to an @ref{it_dynamite}. On explosion the dynamite will in turn send automatically ‘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.
mydoor:message("open") myboulder:message("orientate", NORTH) mydoor:open() myboulder:orientate(NORTH) |
The last two examples are a common abbreviation of the first two ones.
Messages may return a value. But most messages just return ‘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 ‘ignite’ messages to its neighbours without knowing if the objects can be ignited at all. Furtheron 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 ‘open’ message to the door by Target - Action. Within a Lua Callback Function you may send messages during runtime to any object.
All messages are listed and described in Common Messages and the subsequent chapters.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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. Everytime the first object is triggered it will send the message to its target.
You configure such a target action by setting the attributes ‘target’ and ‘action’ on the first object. E.g. a for a switch stone that should open a door named ‘mydoor’ you can write:
{st_switch, target="mydoor", action="open"} |
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 ‘open’. The universal message for changing targets in their alternate states is ‘toggle’.
{st_switch, target="mydoor", action="toggle"} {st_switch, target="mydoor"} |
Now the door will toggle in sync with the switch between its open and closed state. The message 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 ‘true’ if it just switched on, and a value ‘false’ if it just switched off. The appropriate message for the door would be the universal message ‘signal’:
{st_switch, target="mydoor", action="signal"} |
Now the door will open when the switch is turned on and close if the switch is turned off.
The message signal takes an integer value of ‘0’ or ‘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 autoconverted 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. ‘target’ and ‘action’ are both able to take multiple values. ‘target’ is of type tokens, as described in Object Attributes, whereas ‘action’ can be a string or a table of strings.
{st_switch, target={grp(ojb1, obj2, obj3), "mydoor", myobject, "anotherdoor"}, action={"toggle", "open", "turn", "close"}} |
All objects described by a token receive the related message in the action table. If not enough messages are listed the default action ‘toggle’ will be sent.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘ON’,‘OFF’ or ‘OPEN’, ‘CLOSED’. These objects can be plugged together by just few common messages. Furtheron 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 usally named by appropriate uppercase names like above, the states are integer numbers starting with ‘0’ usually related to the default state. But some objects use another mapping due to historic reasons. E.g. states that are direction related use the state ‘3’ representing ‘NORTH’ usually as the default and number the directions clockwise down to ‘0’ representing ‘WEST’.
In most cases it is sufficient to perform a state independent common action like toggle. Even two stated objects can be easily sychronized by the standard action 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 st_fourswitch, that has four states, and two 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 ‘EAST’ state and the other should be off just while the fourswitch is in the ‘WEST’ state. This can be done by usage of state dependent target and actions:
{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"} |
Adding a number as suffix to ‘target_’ and ‘action_’ gives you special target and action attributes that will take precedence over the general ‘target’ and ‘action’ attributes if the state value equals the suffix number. An alternative declaration would be:
{st_fourswitch, target={"laser#1", "laser#2"}, action_3={"nop", "on"}, action_2={"off", "nop"}, action_1={"on", "nop"}, action_0={"nop", "off"}} |
Here we do address both lasers in all states. But one of them receives a 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 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:
{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"} |
The blocking of ‘action_0’ is essential and can not be omitted, as otherwise the default action would be performed. This would be a ‘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 nopaction attribute to true.
{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} |
When an objects leaves a trigger the state ‘0’ action will be performed. As neither ‘action_0’ nor ‘action’ is specified the default action will be performed, which is now ‘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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Snapshot Levelloading, Initialization, Runtime Callbacks, Ending Conditions - the mystery of Oxyds and Meditation
4.4.1 Library Preloading | ||
4.4.2 Snapshot Principle | ||
4.4.3 Level Initialization | ||
4.4.4 Object Transformation | Identity Transfer in case of Transformations | |
4.4.5 Runtime Ticks and Callbacks | ||
4.4.6 Ending Conditions |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Most levels contain objects that take influence on each other. A switch might toggle a door by 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 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:
{"st_switch", target="mydoor", state=ON} {"st_door_v", name="mydoor", state=OPEN} |
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 laserwitch 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.
{"st_laser", state=ON} {"st_laserswitch", target="mydoor"} |
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 immediatly 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 ‘_new’. These objects can be used in the initial level description to set objects in special initial states. E.g. 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 existance as a standard object.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
global variables tile declarations world init oxyd shuffle postinit()
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
During runtime some Enigma objects do transform into other successor objects, like an st_blocker/it_blocker, an @ref{st_brake}/@ref{it_brake}, an it_rubberband/ot_rubberband, an it_hammer/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 ‘_’, the user attributes, are transfered to the successor object. Thus you can rely on the successor to message the same target and you can it access it via its old name.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Read API Concept Draft
5.1 Lua Example | ||
5.2 Enigma Lua Types | ||
5.3 Object Definitions and Tiles | ||
5.4 Lua Positions | ||
5.5 World Creation and Resolver Chaining | ||
5.6 Custom Resolver | ||
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 two variations.
width, height = wo(topresolver, defaultkey, map)
width, height = wo(topresolver, defaultkey, width, height)
ti
| resolver | 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 tiles repository ‘ti’, or by given library Resolvers or by local Custom Resolver function. This argument takes the top resolver that is requested first.
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
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.
As an argument that is given instead of a map it describes the width of the desired world.
As an argument that is given instead of a map it describes the height of the desired world.
w, h = wo(ti, " ", 20, 13) w, h = wo(resolver, " ", { " ", ... " ") |
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 Width and 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 ‘ti’ the chain consists just of one element and the tile declaration stored in the tiles repository at the given key is taken. But there exist several useful Resolvers that may simplify the task of level writing or provide dynamic features like randomness, mazes, etc. If you like to use one or several of them you provide the instance of the resolver to be requested first in this constructor. The instance that should be requested next is set in the top resolver as first argument, and so on. The last library resolver takes usually ‘ti’ as its subresolver. For even more flexibility you can provide an own Custom Resolver function within the level to take influence on the key interpretation. This function has to be the last resolver in the chain.
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() |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A customer 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 return 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.
tile = myresolver(key, x, y)
String that contains the tile key to be resolved.
The world x coordinate of the tile.
The world y coordinate of the tile.
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 ‘return ti["k"]’, which references the tile already declared in the tiles map.
If no suited tile is already declared you can alternatively return a new tile like ‘return ti({"st_switch", state=ON})’.
If you decide not to draw any tile at all, you must return an empty tile declaration: ‘return ti({})’.
‘return nil’ indicates an error of usage of an unknown tile key.
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 ", " ", " ", " ", " ", " " }) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Some attributes and messages 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.
6.1 Common Attributes | ||
6.2 Common Messages | ||
6.3 Global Attributes |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The attribute of 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 ‘#’ sign (see section 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 is attribute is not listed in the individual object descriptions.
A sequence of characters of the given characters plus special characters as mentioned in the text above.
nil
Some objects will be autonamed if no name is defined.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The central attribute of any object that describes the current state of an object in its standard life cycle. This 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 toggle, signal, on, off, open, close.
Please use the given upper case constants.
0
While it is common to set the state attribute on object creation, it is preferable to change the object state later on by messages.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
All active objects react on being triggered by performing an action on their targets. This attribute is part of the Target - Action paradigm that guarantees pluggability of objects. You can either set a general ‘target’ attribute for an object, or you can set state dependent attributes ‘target_0’, ‘target_1’,... (see section Object State). They all have the same syntax:
Single targets may be declared by their object name or their reference. Multiple targets can be declared by usage of groups and tokens.
target = "myDoor" target = myObject target = {"myDoor", myObject} target = {grp(obj1, obj2), "myDoor", myObject} |
nil
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
All active objects react on being triggered by performing an action on their targets. This attribute is part of the Target - Action paradigm that guarantees pluggability of objects. You can either set a general ‘action’ attribute for an object, or you can set state dependent attributes ‘action_0’, ‘action_1’,... (see section Object State). They all have the same syntax:
A single action may be declared by its message string. Multiple actions that match multiple targets can be declared by tokens of strings.
action = "open" action = {"open", "turn", "toggle"} |
nil
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A very special addition to the Target - Action paradigm that allows in case of state specific actions to deny the sending of default messages (see section Object State).
true
, false
false
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An attribute that requests an invertion 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.
true
, false
false
All objects with boolean action values will support this attribute. Additionally some objects with other invertable action value types like directions will support the invertion of their attributes as stated in the individual object descriptions.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An attribute that describes one or several destinations. It is used by objects like it_vortex and it_wormhole to describe their teleporting destination.
Note that this attribute is only supported if it is listed in the individual description.
Just a single position for a first destination is allowed. Use tokens to define multiple destination.
destination = po(3.0, 4.7) destination = "myFloor" destination = myObject destination = {"vortex2","vortex3","vortex4"} |
Note that objects like ‘it_wormhole’ that have just a single destination do take the first token object.
nil
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 decelarating 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 it_strip, @ref{it_hollow} may provide friction values as well to deviate from the floor friction.
nil
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An attribute that describes the adhesion that allows an actor to accelarate 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 it_strip, @ref{it_hollow} may provide adhesion values as well to deviate from the floor adhesion.
nil
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An attribute that defines if a given object declaration should only be applied
on 'even' or 'uneven' grid positions. Setting this attribute to ‘0’ assures
that this object will only be set on grid positions with an even sum of
x + y
grid coordinates, where as a value of ‘1’ assures that the
sum must be uneven. This way you can easily provide two different object
declarations for a tile to generate an arbitrary chaped map of checkerboard
floors, items or stones.
0
, 1
nil
ti["c"] = ti({"fl_sahara", checkerboard=0}) .. {"fl_tigris", checkerboard=1} |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An attribute that gives you access to the ot_rubberbands 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 ‘add’ method.
ot_rubberband
objects
nil
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An attribute that gives you access to the ot_wires 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 ‘add’ method.
nil
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An attribute that gives you access to the group of all objects that are currently connected either by an ot_rubberband or an 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 ‘add’ method.
nil
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
true
, false
false
If a stone exists only in a movable variant this attribute will default to ‘true’.
This attribute is only writable for objects that exist in both variations.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A set of attributes that allow you to distort hit forces. Objects like @ref{st_flash}, @ref{st_spitter} and st_actorimpulse apply forces that are either based on the hit velocity or the position.
By usage of a simple ‘hit_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 ‘hit_distortion_xx’, ‘hit_distortion_xy’, ‘hit_distortion_yx’ and ‘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.
nil
, xx, yy - 1
, xy, yx - 0
By default no hit factor is applied. The hit matrix is the neutral one.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
6.2.1 toggle | ||
6.2.2 nop | ||
6.2.3 signal | ||
6.2.4 on | ||
6.2.5 off | ||
6.2.6 open | ||
6.2.7 close | ||
6.2.8 kill | ||
6.2.9 disconnect |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This is the default message that is always taken if no other message is provided. It toggles the Object State quite independent of the very nature of the state. Two-stated objects like switches will toggle their state form ‘ON’ to ‘OFF’ or from ‘OFF’ to ‘ON’. Door like objects will toggle their state from ‘OPEN’ to ‘CLOSED’ or from ‘CLOSED’ to ‘OPEN’. Other objects like st_fourswitch will turn into the next direction. Generally the object will toggle to its next state.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘toggle’ message (see section Object State).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A signal message tries to set the object to the state 0 (‘OFF’, ‘CLOSED’) or state 1 (‘ON’, ‘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 ‘true’, ‘false’ and direction values like ‘WEST’ to ‘NORTH’ are converted to 0 and 1. This allows you to use ‘signal’ as action message on most objects.
0
, 1
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This message is just supported by objects that can be switched on and off. Just objects in state ‘OFF’ will be switched on. An object in state ‘ON’ remains unchanged in its state.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This message is just supported by objects that can be switched on and off. Just objects in state ‘ON’ will be switched off. An object in state ‘OFF’ remains unchanged in its state.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This message is just supported by door like objects that can be opened and closed. Just objects in state ‘CLOSED’ will be opened. An object in state ‘OPEN’ remains unchanged in its state.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This message is just supported by door like objects that can be opened and closed. Just objects in state ‘OPEN’ will be closed. An object in state ‘CLOSED’ remains unchanged in its state.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This message causes the receipent 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This message causes the receipent to disconnect from all fellows by cutting all wires and rubbers that are connect to it.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A global scalar default factor for the actorimpulse stone bumping force. This global value is only used if no object specific value is set.
+200.0
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘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 Display Follow Strategy to permanent smooth scrolling:
if wo["CreatingPreview"] then wo["FollowGrid"] = false wo["FollowMethod"] = FOLLOW_SCROLL end |
true
, false
false
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A global variable that defines the it_glasses type that is generated on the laser light convertion of an it_extralife
A sum out of the constants ‘SPOT_DEATH’, ‘SPOT_HOLLOW’, ‘SPOT_ACTORIMPULSE’, ‘SPOT_SENSOR’, ‘SPOT_LIGHTPASSENGER’, ‘SPOT_TRAP’
SPOT_DEATH + SPOT_HOLLOW + SPOT_LIGHTPASSENGER
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 Display Follow Strategy.
0
, FOLLOW_FULLSCREEN
, HALFSCREEN
The distance of display readjustment. Positions are used to supply different values for x and y. The value ‘{19, 12}’ is a standard full screen move. The value ‘{9.5, 6}’ is a standard half screen move. A value ‘0’ is a minimal smooth move or the default value for grid based moves.
{19, 12}
Actually the default is mode based (see section Display Follow Strategy).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 (see section Display Follow Strategy).
true
, false
true
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 (see section Display Follow Strategy).
FOLLOW_NO
, FOLLOW_SCROLL
, FOLLOW_FLIP
FOLLOW_FLIP
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 (see section Display Follow Strategy).
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.
0.5
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A global read only variable reports the height of the world in grid units. This is set by the initial world constructor call (see section World Creation and Resolver Chaining).
?
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A global read only variable that defines the current diffculty 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 <modes>.
true
, false
true
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
10.0
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
30.0
Positve number are attracting, negative numbers are repelling.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A global variable that limits the number of colors assigned to autocolored st_oxyd. Be careful with increasing this value beyond its default.
OXYD_BLUE
, ... OXYD_BROWN
OXYD_BLACK
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A global variable that causes two it_extralifes to be added to both player inventories on start of a new level. Set it to ‘false’ if a gamer could misuse these items. It is important to set this attribute before the world is created (see section World Creation and Resolver Chaining).
true
, false
true
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
true
, false
false
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A global variable that defines if the essential actors have to survive the finish of the game (see section Ending Conditions). With this attribute set to ‘false’ a gamer can sacrify an essential actor to finish the level in the same step in some subtle cases.
true
, false
true
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A global read only variable reports the width of the world in grid units. This is set by the initial world constructor call (see section World Creation and Resolver Chaining).
?
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
10.0
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
30.0
Positive number are attracting, negative numbers are repelling.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
8.1 Standard Items |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
8.1.1 it_blocker | Shrinked Blocker Stone | |
8.1.2 it_brush | ||
8.1.3 it_coin | Enigma's currency | |
8.1.4 it_cross | Floor switch for patient Actors | |
8.1.5 it_death | Unpassable grid blocker | |
8.1.6 it_extralife | ||
8.1.7 it_floppy | ||
8.1.8 it_glasses | Glasses to spot certain objects | |
8.1.9 it_hammer | ||
8.1.10 it_key | ||
8.1.11 it_landmine | ||
8.1.12 it_magicwand | Wizards Tools | |
8.1.13 it_magnet | ||
8.1.14 it_rubberband | ||
8.1.15 it_sensor | Floor Switch for passing Actors | |
8.1.16 it_strip | Narrow Bridge | |
8.1.17 it_sword | ||
8.1.18 it_trap | ||
8.1.19 it_trigger | Floor Switch for Actors and Stones | |
8.1.20 it_umbrella | Death Protection Item | |
8.1.21 it_vortex | Teleport of Marbels | |
8.1.22 it_wormhole | Teleport of Actors | |
8.1.23 it_wrench |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A door like object that grows to st_blocker when an 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
(see section name) and address the blocker by this name. The complete identity
with all attributes including any user attributes will be transfered between
stone and item. E.g. {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.
0
, 1
; default: 1
See section 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.
true
, false
; default: false
A true value causes any actor passing this item to close and grow the blocker.
A signal of value 1 sends an open message, a signal of value 0 sends a close message.
A toggle causes a close message.
A close message take immediate effect if the item is not covered by a stone. The item transforms to a new growing 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.
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 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.
Sends an action at the moment the blocker reaches the open state. That means
an st_blocker did open and did generate this blocker item as its
successor. The value will be true
to express the open state.
A standard blocker item.
A blocker that just finished shrinking. Mainly used internally as the direct successor of an st_blocker. But it may be useful to generate an initial snapshot of a moving boulder over a blocker line, too. See example levels.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
TBD
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A coin activates an 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 ‘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 it_umbrella, a medium coin into an it_hammer and a large coin into an 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.
0
, 1
, 2
; access: read only
See section state
Represents the coin type with 0 being a small coin, 1 being a medium coin and 2 being a large coin.
A small coin.
A small coin.
A medium coin.
A large coin.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘interval’ without any other actor leaving or passing the cross grid the cross will perform its action. Similar, but instant sensors for actors are it_sensor and it_trigger
A cross can be drawn with an @ref{it_pencil} and it can be removed with an it_brush.
An st_lightpassenger moving onto a cross item will switch off.
0
, 1
; access: read only
See section state
The current state - ‘0’ for the last event being an actor leaving the cross, ‘1’ for the last event being an actor entering the cross.
10.0
Number of seconds that the actor must stay on the sensor to cause an action.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This item shatters any marble that tries to pass the grid. Even jumping marbles will be shattered. Just marbles protected by an activated it_umbrella can pass without taking harm. Apart from that an ‘it_death’ barrier can only be passed by walking around the complete barrier or by warping through an it_vortex, an it_wormhole or by means of an @ref{it_ring}.
The death item is the most secure barrier object. Comparable objects are @ref{it_booze_broken}, @ref{fl_abyss}, @ref{fl_water}, 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 unsecure.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An extralife transforms into it_glasses when hit by a laser beam and is itself a laser transformation result of an ‘it_coin_l’ (see section it_coin). The global variable 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.
A standard extralife item.
An extralife that is immune to light destruction for a short latency period.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A floppy activates an st_floppy when inserted by hitting the stone with the floppy as first item in the players inventory.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 players inventory. That means that the glasses must be shown in the inventory and not be burried 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 st_death visible, can uncover invisible passages by making hollow stones transparent, can make inactive st_lightpassenger be distinguishable from @ref{st_glass}, can make invisble it_sensor, it_trap and st_actorimpulse be visible.
All these features are configurable by the constants ‘SPOT_DEATH’, ‘SPOT_HOLLOW’, ‘SPOT_LIGHTPASSENGER’, ‘SPOT_SENSOR’, ‘SPOT_TRAP’ and ‘SPOT_ACTORIMPULSE’. You can set the ‘state’ attribute to a sum of these constants that should apply to given glasses. The default is for backward compatibility ‘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 it_extralife. The features of such new glasses are determined by the global variable ExtralifeGlasses.
SPOT_DEATH + SPOT_HOLLOW + SPOT_LIGHTPASSENGER
See section state
A sum of the constants ‘SPOT_DEATH’, ‘SPOT_HOLLOW’, ‘SPOT_LIGHTPASSENGER’, ‘SPOT_SENSOR’, ‘SPOT_ACTORIMPULSE’, ‘SPOT_TRAP’. ‘SPOT_NOTHING’ is the state of a broken glasses.
Active glasses item.
Broken glasses that spot nothing.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The hammer is used to destroy some stones, see Breakable Stones and st_lightpassenger.
It transforms into it_sword when hit by a laser beam and is itself a laser transformation result of an it_sword and an ‘it_coin_m’ (see section 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.
A standard hammer item.
A hammer that is immune to light transformations for a short latency period.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A key activates an st_key when inserted by hitting the stone with the key as first item in the players inventory.
1
The code of a key must match that of an st_key to unlock it.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
!!TBD - Work in progress !!
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 @ref{it_hollow} 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The wizard's tool, that allows to do all sort of magic things if it is the wielded item in the player's inventory:
st_brick_magic
transparent (@ref{st_brick_magic}).
st_invisible_magic
visible and non-transparent
(@ref{st_invisible}).
st_yinyang3
(@ref{st_yinyang}).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Attracts or repells actors in its ‘range’ with a force proportional to the ‘strength’ and the inverse of the squared distance. A magnet can be switched ‘ON’ and ‘OFF’.
Note that no forces are applied to actors at a distance smaller than 0.05 grids to avoid extraordinary large forces.
ON
, OFF
; default: OFF
See section state
The current magnet state - ‘ON’ for an active magnet, ‘OFF’ for an inactive magnet.
10.0
See section MagnetRange
The distance up to which the magnet applies forces to actors.
+30.0
See section MagnetStrength
A scalar factor for magnet forces. Positive numbers are attracting forces where as negative numbers are repelling forces.
A signal of value 1 switches the magnet on, a value of 0 switches the magnet off.
A toggle causes a change in the magnet activity state.
Switches the magnet on.
Switches the magnet off.
none
A magnet in state ‘OFF’.
A magnet in state ‘ON’.
A magnet in state ‘OFF’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A portable ot_rubberband that gets connected to the bearer on activation.
As the rubberbands ‘anchor1’ is given by the activator itself, just the ‘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 (see section Object Naming). A marble will be able to connect to the nearest object out of a given group.
If ‘anchor2’ does not exist, the ‘it_rubberband’ will be dropped.
The other attributes describe the force and length parameters of the ot_rubberband, that will be created on application of the item. In fact the items identity will be transfered to its successor (see section Object Transformation). After creation of the life rubberband the action message will be send to the target. Note that it is actually the ot_rubberband as the successor that sends the message.
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.
10.0
The force strength.
1.0
The natural length above which forces are applied.
0.0
The length smaller than the natural length below which inverted forces are applied.
0.0
The minimum length at which actors bounce.
0.0
The maximum length at which actors bounce.
On succesfull activation of this item the action message is send with a value of ‘true’. Note that the parameter ‘sender’ will report the new ot_rubberband.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The sensor item is a switch on top of a floor that reacts on actors passing it. It just performs actions on actors entering the sensors grid. It will send an action value of ‘true’ but of course the inverse attribute can be used to send an action value of ‘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 it_glasses by addition of ‘SPOT_SENSOR’ to show invisible sensor items. An actor with such an it_glasses in its inventory will be able to spot invisible sensor items. With the global attribute ExtralifeGlasses even glasses generated by laser lighting an it_extralife can be configured not to show invisible sensor items.
Alternative objects that react on actors are it_trigger and it_cross.
true
, false
; default: false
An invisible sensor is totally transparent. But the user may notice it, as actors cannot drop items onto the same grid position.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 neigboring 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.
nil
Describes the connections to the neighbor grids. The string is a substring of
"nesw"
listing the existing connections. The sequence of the sides, north,
east, south, west, is guaranteed on read access but arbitrary on write access.
nil
See section friction
Deviating friction that defaults to floor friction.
nil
See section adhesion
Deviating adhesion that defaults to floor adhesion.
""
"w"
"s"
"sw"
"e"
"ew"
"es"
"esw"
"n"
"nw"
"ns"
"nsw"
"ne"
"new"
"nes"
"nesw"
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The sword is used to neutralize st_knight.
It transforms into it_hammer when hit by a laser beam and is itself a laser transformation result of an 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.
A standard sword item.
A sword that is immune to light transformations for a short latency period.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 it_glasses by addition of ‘SPOT_TRAP’ to show invisible traps. An actor with such an it_glasses in its inventory will be able to spot invisible traps. With the global attribute ExtralifeGlasses even glasses generated by laser lighting an it_extralife can be configured to show invisible traps.
CLOSED
, OPEN
; default: CLOSED
See section state
A ‘CLOSED’ trap is intact and invisible, an ‘OPEN’ trap is broken and visible.
Opens the trap on value ‘1’
Opens the trap.
Opens the trap.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘ON’ and will send an action value of ‘true’, a released trigger is in state ‘OFF’ and will send an action value of ‘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 ‘ON’ without sending actions due to the 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 objects that react just on actors are it_sensor and it_cross.
ON
, OFF
; access: read only
See section state
The current switch state - ‘ON’ for a pressed trigger, ‘OFF’ for a released trigger.
true
, false
; default: false
An invisible trigger is totally transparent. But the user may notice it, as actors cannot drop items onto the same grid position.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An activated umbrella temporarily protects a marble from st_death, st_knight, @ref{st_thief}, @ref{fl_abyss}, @ref{fl_water}, @ref{fl_swamp}, @ref{fl_thief}, it_death, @ref{it_abyss}, @ref{it_booze_broken}, explosions, moving stones and the ‘shatter’ and ‘fall’ messages; in other words, from all lethal situations and thieves.
An umbrella gets destroyed when hit by a laser beam and is itself a laser transformation result of an ‘it_coin_s’(see section 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.
A standard umbrella item.
An umbrella that is immune to light destruction for a short latency period.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Teleports marbles to a given ‘destination’. Unlike it_wormhole it does not teleport other 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 marble will be teleported to the destination.
If there multiple destination addresses are given, the marble will be teleported to the single destinations in sequence. Blocked destinations are indicated by sparkles. Finally the marble exists on the first unblocked destination. If no unblocked destination exists the marble exists on 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 open or closed. Of course a marble 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 ‘autoclose’ you can configure a vortex to close after a marble has been emitted.
Marbles are emitted by vortices in a jumping fashion. The user can accelerate the marble for a short period and the marble may jump out of a vortex into a desired direction.
Vortex teleportation take 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 ‘scissor’ allows you to control the cutting behaviour.
OPEN
, CLOSED
; default: OPEN
See section state
The visual state of a vortex. An ‘OPEN’ vortex may still be busy due to ongoing teleportations and may not accept a marble.
nil
See section destination
The destination of the teleport given by an object or a position.
true
, false
; default: false
Flag that indicates whether the vortex should be closed after a teleport.
true
, false
; default: true
Rubberband cutting behaviour on teleporting.
Opens the vortex on value ‘1’, and closes the vortex on value ‘0’.
Opens a closed vortex and closes an open vortex if possible.
Tries to open the vortex.
Tries to close the vortex.
none
A vortex in state ‘OPEN’.
A vortex in state ‘OPEN’.
A vortex in state ‘CLOSED’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Teleports actors of any kind to a given ‘destination’. Unlike 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 repell actors in its ‘range’ with a force proportional to the ‘strength’ and the inverse of the squared distance. The force can be switched ‘ON’ and ‘OFF’ and is represented by its external ‘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 ‘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 ‘interval’. A latency separates actors travelling through a wormhole and avoids overlapping actors at the destination.
ON
, OFF
; default: OFF
See section state
The current force state - ‘ON’ for a force applying wormholes, ‘OFF’ for force neutral wormholes.
nil
See section destination
The destination of the teleport given by an object or a position.
10.0
See section WormholeRange
The distance up to which the wormhole applies forces to actors.
+30.0
See section WormholeStrength
A scalar factor for the wormhole force. Positive numbers are attracting forces where as negative numbers are repelling forces.
true
, false
; default: true
Rubberband cutting behaviour on teleporting.
0.0
The latency time after a teleport during which no further teleports take place.
A signal of value 1 switches the wormhole force on, a value of 0 switches the wormhole force off.
A toggle causes a change in the wormhle force activity state.
Switches the wormhole on.
Switches the wormhole off.
none
A wormhole in state ‘OFF’.
A wormhole in state ‘ON’.
A wormhole in state ‘OFF’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A wrench wielded as first item in the players inventory causes some objects to react on actor hits. An st_rotator changes its turning direction. An green st_turnstile rotates backwards when hit. An st_window face pushed with an wrench will swap to the opposite side of the stone if possible.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
9.1 Simple Stones | ||
9.2 Cluster Stones | ||
9.3 Transparent Stones | ||
9.4 Breakable Stones | ||
9.5 Special Stones |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
9.2.1 Cluster Features | Common Attributes and Features | |
9.2.2 st_bluesand | big sand stone look | |
9.2.3 st_brick | brick wall look | |
9.2.4 st_panel | wooden panel look |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘connections’, those sides that should be adjacent to other stones of the same cluster. Or you can give the outer faces, the ‘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 automatical clustering feature. Just set the ‘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 ‘cluster’ attribute and using the ‘faces’ attribute where necessary. ‘connections’ attribute and explicit naming of variations by a suffix are deprecated, but will continue to be supported.
nil
Describes the inner faces of stone. The string is a substring of "nesw"
listing the inner faces. The sequence of the sides, north, east, south, west,
is guaranteed on read access but arbitrary on write access.
nil
Describes the outer faces of stone. The string is a substring of "nesw"
listing the outer faces. The sequence of the sides, north, east, south, west,
is guaranteed on read access but arbitrary on write access.
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 superceds any explicitly given face description.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A standard cluster stone with the Cluster Features. It is recommended to use ‘st_bluesand’ with the attributes ‘cluster’ and ‘faces’.
""
"w"
"s"
"sw"
"e"
"ew"
"es"
"esw"
"n"
"nw"
"ns"
"nsw"
"ne"
"new"
"nes"
"nesw"
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A standard cluster stone with the Cluster Features. It is recommended to use ‘st_brick’ with the attributes ‘cluster’ and ‘faces’.
""
"w"
"s"
"sw"
"e"
"ew"
"es"
"esw"
"n"
"nw"
"ns"
"nsw"
"ne"
"new"
"nes"
"nesw"
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A standard cluster stone with the Cluster Features. It is recommended to use ‘st_panel’ with the attributes ‘cluster’ and ‘faces’.
""
"w"
"s"
"sw"
"e"
"ew"
"es"
"esw"
"n"
"nw"
"ns"
"nsw"
"ne"
"new"
"nes"
"nesw"
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
9.5.1 st_actorimpulse | Bumper Stone | |
9.5.2 st_blocker | Shrinkable Blocker | |
9.5.3 st_boulder | Moving Arrow Boulder | |
9.5.4 st_chess | Movable Chess Knight Stone | |
9.5.5 st_coinslot | Coin Driven Switch | |
9.5.6 st_death | Skull Stone | |
9.5.7 st_floppy | Floppy Driven Switch | |
9.5.8 st_fourswitch | Four Direction Switch | |
9.5.9 st_key | Key Driven Switch | |
9.5.10 st_knight | Sword Bearing Knight Stone | |
9.5.11 st_laser | Lightemitting Laser | |
9.5.12 st_laserflop | Lightsensitive Monoflop | |
9.5.13 st_laserswitch | Lightsensitive Switch | |
9.5.14 st_lightpassenger | Stone pushed by Light | |
9.5.15 st_mirror | Mirrors of all flavors | |
9.5.16 st_monoflop | Monoflop Switch | |
9.5.17 st_oxyd | Game Target Stone | |
9.5.18 st_polarswitch | Transparency Switch for Light Beams | |
9.5.19 st_rotator | Rotating Stone Impulser | |
9.5.20 st_rubberband | Rubberband generator | |
9.5.21 st_scissors | Scissors cutting rubberbands | |
9.5.22 st_switch | Classical on/off Switch | |
9.5.23 st_timer | Animated Timer | |
9.5.24 st_turnstile | Turnstile Pivot | |
9.5.25 st_turnstilearm | Turnstile Arm | |
9.5.26 st_window | Faced Window |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An active bumper for actors and some stones like 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 ActorimpulseStrength gives a default force that can be overridden by the stone attribute ‘strength’.
For sophisticated usage you can distort this force by usage of the hit_* attributes. Note that the ‘hit_factor’ overrides a ‘strength’ attribute.
An actorimpulse stone can be configured by the ‘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 it_brush in the player's inventory. The level author can configure it_glasses by addition of ‘SPOT_ACTORIMPULSE’ to show otherwise invisible actorimpulse stones. With the global attribute ExtralifeGlasses even glasses generated by laser lighting an it_extralife can be configured to show invisible actorimpulse stones.
An st_boulder hitting an actorimpulse stone will revert its direction and return in the incoming direction.
true
, false
; default: false
An invisible actorimpulse stone is totally transparent. But the user will notice it, as actors will bounce with additional impulses.
+200.0
See section ActorimpulseStrength
A scalar factor for the impulse force. Positive numbers are attracting forces where as negative numbers are repelling forces.
nil
See section hit_*
A ‘hit_factor’ overrides a given ‘strength’ attribute.
+1.0
See section hit_*
0.0
See section hit_*
0.0
See section hit_*
+1.0
See section hit_*
false
true
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A door like object that shrinks to it_blocker when hit by an 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 (see section name) and address the blocker by this name. The complete identity with all attributes including any user attributes will be transfered between stone and item. E.g. ‘{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 it_blocker.
OPEN
, CLOSED
; default: CLOSED
See section state
The stone represents the closed state and will always return state ‘CLOSED’. But you can set its state what is equivalent to sending an open message in case of value ‘OPEN’ and a close message in case of value ‘CLOSED’.
true
, false
; default: false
This attribute is irrelevant to the blocker stone itself. But it is transferred to the it_blocker when the blocker opens.
A signal of value 1 sends an open message, a signal of value 0 sends a close message.
A toggle causes an open unless the blocker stone is in the shrinking process. In this case it causes a close message.
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.
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.
Sends an action at the moment the blocker reaches the closing state. That means an it_blocker did close and did generate this blocker stone as its successor. The value will be ‘false’ to express the closing state.
A standard blocker stone.
A blocker that just starts growing. Mainly used internally as the direct successor of an it_blocker. But it may be useful to generate an initial snapshot of a moving boulder over a blocker line, too. See example levels.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 st_blocker, others change their state like st_oxyd, @ref{st_stoneimpulse}, @ref{st_fart}, st_mirror, 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_[black/white]}, @ref{st_plain}, st_lightpassenger.
Items getting beneath a moving boulder may react like on any other stone move on top of them. Additionally 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.
it_magicwand and lasers reverse its direction. An st_actorimpulse reverts the direction if the boulder hits it frontally. An st_rotator changes its direction according to the rotator's direction. An @ref{st_stoneimpulse} pushes a boulder away.
NORTH
, EAST
, SOUTH
, WEST
; default: 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.
true
, false
; default: false
The standard turning direction is clockwise. Use this attribute to revert the direction.
Change the orientation to the given direction value. The st_fourswitch provides a compatible action which allows you to set a boulder as target and this message as action.
Turn orientation in turning direction as defined by attribute ‘counterclock’.
Turn orientation in opposite turning direction as defined by attribute ‘counterclock’.
none
NORTH
EAST
SOUTH
WEST
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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_wand}, 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 The 1.0-Fire System). 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}.
BLACK
, WHITE
; default: BLACK
The color of the chess stone
true
; default: true
See section movable
Read only attribute that states the movability of a chess stone.
Flip the color of the stone.
NNE
, NEE
, SEE
, SSE
, SSW
, SWW
, NWW
, NNW
Jump into the given direction.
BLACK
BLACK
WHITE
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that is activated by insertion of an 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 ‘ON’ for a given ‘interval’ before switching back to state ‘OFF’. Multiple inserted coins do prolong the activity interval.
Standard not ‘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 temporaryly switching back to ‘OFF’ state. If the first interval runs off while the next coin did not yet finish its insertion the coinslot will first switch ‘OFF’ and switch ‘ON’ when the next coin is completly inserted.
Coinslots configured as ‘instant’ do activate immediatly when the actor hits the stone. On every actor hit a coin is inserted independent of the last insertion.
The ‘state’ of a coinslot can be requested but it can not be set, neither by attribute nor by messages.
ON
, OFF
; default: OFF
; access: read only
See section state
Current activity state of the coinslot.
true
, false
; default: false
A default coinslot switches to active state after insertion of a coin and allows the insertion of just one coin at a time.
3.0
Number of additional active seconds on insertion of a small it_coin.
6.0
Number of additional active seconds on insertion of a medium it_coin.
12.0
Number of additional active seconds on insertion of a large it_coin.
false
true
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Shatters any marble that hits or even just touches it. Just marbles protected by an activated it_umbrella will bounce unharmed as other actors do which will not die anyway.
Death stones can be configured by the ‘invisible’ attribute to be hidden while being idle. When hit by an actor any death stone becomes temporary visible. An actor with unbroken standard it_glasses in its inventory will be able to spot invisible death stones.
The level author can configure it_glasses by elimination of ‘SPOT_DEATH’ not to show invisible death stones. With the global attribute ExtralifeGlasses even glasses generated by laser lighting an it_extralife can be configured not to show invisible actorimpulse stones.
ON
, OFF
; default: OFF
; access: read only
See section state
Current activity state of the death stone. A stone is usually activated by a hitting actor.
true
, false
; default: false
Invisible death stones show only when hit by an actor or been toggled by a message.
Temporarily activate the stone to show its animation and to get visible for this period.
false
true
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that is activated by insertion of an 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 players inventory.
ON
, OFF
; default: OFF
: See section state
Current activity state of the floppy stone.
Switches on at value ‘1’, and off at values ‘0’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that points to one of the four directions turning on every switching event. The most common event is an actor hitting this stone. But 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 ‘action/target’-pair. This can be either a common pair or a state/direction dependent pair allowing you to issue different messages dependent on the pointing direction.
NORTH
, EAST
, SOUTH
, WEST
; default: NORTH
See section state
true
, false
; default: false
The standard turning direction is clockwise. Use this attribute to revert the direction.
Note that the action value is inverted in its boolean interpretation. This means that an inverted action value is not the reverse direction and should not be used as a direction value at all.
Note that the fourswitch reacts just on value 1
. Values of 0
are
simply ignored. Use message toggle if you need turns on any message value.
Note that a toggle turns the fourswitch independent of a message value.
Performs an action on each turn. If just a pair of global ‘target/action’ attributes are given, the action message is sent to the target with a direction value of the new orientation. This value suits any message of the target that expects a direction value, and the signal message, that translates the direction to a 1 for ‘NORTH’, ‘SOUTH’ and a 0 for ‘EAST’, ‘WEST’.
If state dependent target/action pairs are given instead, namely ‘target_0/action_0’ for the state ‘WEST’,... , ‘target_3/action_3’ for the state ‘NORTH’, two actions will be perfomed: 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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that is activated by insertion of an 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 ‘code’ are accepted.
On a second hit the switch is deactivated and the inserted key is returned to the player's inventory.
ON
, OFF
; default: OFF
; See section state
Current activity state of the key stone.
1
:
The code that is required to activate this switch.
Switches on at value ‘1’, and off at values ‘0’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A sword bearing knight stone that shatters all marbles that hit it, as long as they are not protected by an activated it_umbrella or wield an it_sword.
By hitting ‘st_knight’ with an 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.
0
to 4
; default: 0
; access: read only
See section state
Current hit count of the knight stone. Starting uninjured at state ‘0’ the knight is beaten after 4 hits.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The laser stone is the only object that is capable of emitting light beams. Per default laser stones are switched off. The ‘state’ attribute represents the activity of the laser and can be set initially to ‘ON’. A laser is orientated to one direction in 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 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 are revoke each other.
An initially switched on laser will not cause actions with its light beam due to the Snapshot Principle. If you have need of the actions you may switch on the laser by a message in the ‘postinit’ function (See section Level Initialization). E.g. a flickering laser caused by a laser that illuminates a st_laserswitch which toggles the laser needs to be switched on by a message.
ON
, OFF
; default: OFF
See section state
NORTH
, EAST
, SOUTH
, WEST
; default: NORTH
The orientation of the laser. It determines the direction that the laser will emit light if it is switched on.
true
, false
; default: false
The standard turning direction is clockwise. Use this attribute to revert the direction.
Switch the laser on at value ‘1’ and off at value ‘0’.
Turn orientation in turning direction as defined by attribute ‘counterclock’.
Turn orientation in opposite turning direction as defined by attribute ‘counterclock’.
WEST
SOUTH
EAST
NORTH
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that is triggered by actor hits and laser light. It switches instantly to state ‘ON’ and when it is no longer illuminated it switches back to state ‘OFF’ after a given ‘interval’. Repeatitive actor hits and continuing laser light will prolong the ‘ON’ state untill a trailing ‘interval’ after the last hit has been expired. A similar object without light sensitiveness is the st_monoflop.
The single state cycle, called monoflop, can be initiated by ‘on’ and ‘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 ‘ON’ without sending actions due to the 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.
ON
, OFF
; default: OFF
; See section state
Represents the activity state. The state of a new object can be set, but an active laserflop cannot be set to state ‘OFF’.
1.8
Number of seconds to return to state ‘OFF’ after the last hit.
Switches on at value ‘1’. A value of ‘0’ is ignored.
Switches the laserflop on like on an actor hit.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that is exclusively triggered by laser light. It switches instantly to state ‘ON’ when a laser beam hits the stone from any direction. It switches instantly back to state ‘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 ‘ON’ without sending actions due to the 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.
ON
, OFF
; default: OFF
; access: read only
See section state
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 ‘interval’-attribute (default 50 ms, which is quite fast) and may include the floor friction and local gradient via ‘friction’ and ‘gradient’. The resulting interval results as
interval = base * (1 + stone_friction * floor_friction) / (1 + stone_gradient * floor_gradient) |
with ‘base’ the value of the ‘interval’-attribute,
‘floor_friction’ the friction of the floor below the light passenger,
and ‘floor_gradient’ the parallel part of the force of the floor,
i.e., the sum of gradient-force and force_x/y
-attributes.
The light passenger can be switched on and off by messages (see below), and appears as ‘st_glass2’ when inactive. A player with an it_glasses in his inventory that includes the ‘SPOT_LIGHTPASSENGER’ feature is able to distinguish the switched off lightpassenger from an ‘st_glass2’. The variant ‘st_lightpassenger_off’ is deactivated from the beginning. A lightpassenger that moves onto an it_cross switches off immediatly. A switchted off lightpassenger can be switched on by an actor hit with a revealed it_brush in the inventory. Such a touch with a brush does wipe out a cross beneath the lightpassenger, too.
An st_boulder hitting a lightpassenger toggles the lightpassenger's state for a short period.
When an active ‘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 it_hammer.
ON
, OFF
; default: ON
; See section state
Represents the activity state.
0.05
The base interval for movements.
0.0
Stone friction of the speed of the light passenger.
0.0
Stone gradient of the speed of the light passenger.
Switches on at value ‘1’. A values of ‘0’ is ignored.
Switch the lightpassenger on.
Switch the lightpassenger off.
ON
ON
OFF
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Mirror stones redirect and fork laser beams. They exist in different shapes. You can set the shape by the attribute ‘flavor’ or by using the appropriate subkind. There are two planar versions called ‘slab’ and ‘sheets’, and a ‘triangle’ version.
The mirror panes can either be non-transparent or semi-transparent. Even though you set this feature with the attribute ‘transparent’ you should be aware that even with a value of ‘true’ the mirror is not fully transparent. E.g. a ‘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 ‘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 ‘movable’ is set to true. Mirrors that are not movable will differ slightly in a darker color.
Mirros 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 ‘counterclock’. An 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 ‘turnback’ or by an actor with a revealed it_wrench in its inventory.
Mirrors moved by stone pushing impulses issued by @ref{it_puller}, @ref{st_stoneimpulse},... or send by ot_wire will move without being turned.
"slab"
, "sheets"
, "triangle"
; default: "slab"
Mirror panes either set up as a triangle or as a side intransparent slab or as a mandatory semi-transparent pair of sheets.
NORTH
, EAST
, SOUTH
, WEST
; default: NORTH
; See section 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.
NORTH
, EAST
, SOUTH
, WEST
; default: 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.
true
, false
; default: false
Semitransparency of the mirror panes.
true
, false
; default: false
See section movable
Movability on actor hits and stone impulses.
true
, false
; default: false
The standard turning direction is clockwise. Use this attribute to revert the direction.
Change the orientation to the given direction value. The st_fourswitch provides a compatible action which allows you to set a mirror as target and this message as action.
Turn the orientation in turning direction as defined by attribute ‘counterclock’.
Turn the orientation in opposite turning direction as defined by attribute ‘counterclock’.
Turn the orientation in turning direction as defined by attribute ‘counterclock’ on value ‘1’. A value of ‘0’ is ignored.
slab
, state = NORTH
slab
, state = NORTH
sheets
, state = NORTH
triangle
, state = NORTH
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that is triggered by actor hits. It switches instantly to state ‘ON’ and after a given ‘interval’ back to state ‘OFF’. Repetitive actor hits will prolong the ‘ON’ state until a trailing ‘interval’ after the last hit has been expired. A switch similar to the monoflop is the st_laserflop, which is additionally light sensitive.
The single state cycle, called monoflop, can be initiated by ‘on’ and ‘signal’ messages. But an activated monoflop cannot be stopped by messages or state setting.
ON
, OFF
; default: OFF
; See section state
Represents the activity state. The state of a new object can be set, but an active monoflop cannot be set to state ‘OFF’.
1.8
Number of seconds to return to state ‘OFF’ after the last hit.
Switches on at value ‘1’. A values of ‘0’ is ignored.
Switch the monoflop on like on an actor hit.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The main target stones of the game. Opening all regular oxyd stones is the standard goal of the existing 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 ‘oxydcolor’ attributes to the oxyds.
For standard levels the ‘oxydcolor’ can be set to its default ‘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 ‘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 MaxOxydColor you can lower or increase this limit. By setting this attribute to ‘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. Uneven number of regular colored oxyds are not allowed.
Usually oxyds are shuffled by a ‘wo:shuffleOxyd()’ statement after setting of all oxyds. All ‘CLOSED’ oxyds that are not explicitly excluded by the ‘noshuffle’ attribute take place in shuffling. But you can define arbitrary rules to limit and influence the shuffling process to guarantee solvabitlity and fairness (see section shuffleOxyd).
Oxyds are opened either by an actor hit, an additional laser beam, an st_boulder triggering or a message call. A single opened oxyd is in the state ‘OPEN’. If a matching second oxyd is opened both switch to the state ‘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 ‘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 ‘closeall’ messages that is issued by @ref{st_fart} and oxyds colored ‘OXYD_FART’ on actor hits.
Closed oxyds can have different looks. Their visual representation is defined by their ‘flavor’. For each flavor exists an identical looking simple stone: @ref{st_likeoxyd_a}, @ref{st_likeoxyd_b}, @ref{st_likeoxyd_c}, @ref{st_likeoxyd_d}. If you like an identical looking pseudo stone that takes part in the oxyd shuffling you can use an oxyd of color ‘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 guranteed for these partial in game reshuffles. It can be initiated either by a ‘shuffle’ message that is send to any of the oxyd objects, or by usage of an oxyd of color ‘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 ‘CLOSED’. As it is the gaming target it is a certain exception to the Snapshot Principle.
An oxyd that is swapped in or out of a laser beam will act on the light change with proper actions.
CLOSED
, OPEN
, OXYDPAIR
; default: CLOSED
See section state
"a"
, "b"
, "c"
, "d"
; default: "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:
"a"
bronze, pyramid like stone that opens like a flower
"b"
black, flat stone that opens by a fade animation
"c"
blue, flat stone that opens by a concentric animation
"d"
dark blue, pyramid like stone that opens like a flower
OXYD_AUTO
, OXYD_FAKE
, OXYD_FART
, OXYD_BOLD
, OXYD_BLUE
, OXYD_RED
, OXYD_GREEN
, OXYD_YELLOW
, OXYD_CYAN
, OXYD_PURPLE
, OXYD_WHITE
, OXYD_BLACK
, OXYD_GREY
, OXYD_ORANGE
, OXYD_PINE
, OXYD_BROWN
; default: OXYD_AUTO
true
, false
; default: false
true
, false
; default: false
Static oxyds are neither swappable nor pullable.
Try open at value ‘1’, and close at values ‘0’.
Closes all opened oxyds if send to any object instance.
Reshuffles all closed oxyds if send to any object instance.
Values 0, 1.
"b"
"a"
"b"
"c"
"d"
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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_glass2} in its intransparent off state and like an @ref{st_glass1} in its transparent on state. Like other @ref{Glasstones} it is passable for invisible actors.
ON
, OFF
; default: OFF
See section state
An ‘OFF’ state is not transparent, an ‘ON’ state is transparent.
Switches on at value ‘1’, and off at values ‘0’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Rotators send impulses to neighboring stones, thus pushing them in the direction given by the rotation. st_boulder additionally change their direction 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 it_wrench and by laser beams. Every additional laser beam causes a change in the rotation direction.
CW
, CCW
; default: CW
See section state
The rotation direction - ‘CW’ for clockwise as default, or ‘CCW’ for counter clockwise.
true
, false
; default: false
The standard rotation direction is clockwise. Use this attribute to revert the direction.
true
, false
; default: false
See section movable
Switches the rotation direction.
CW
CW
CCW
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A rubberband stone attaches a new 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 ‘scissor’ is ‘true’, all rubberbands connected to the hitting actor are removed prior attaching the direct new connection.
The rubberband stone is static by default. But an actor with a revealed @ref{it_wand} can move it by hitting it. As the actor will get connected by an ot_rubberband at the same time you will usually place an st_scissors near the target place as an opportunity for the marble to free itself again from the rubberband stone.
10.0
The force strength.
1.0
The natural length above which forces are applied.
0.0
The length smaller than the natural length below which inverted forces are applied.
0.0
The minimum length at which actors bounce.
0.0
The maximum length at which actors bounce.
true
, false
; default: true
Rubberband cutting behaviour on connection.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone cuts all ot_rubberbands 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.
Send an action message with value ‘true’ on freeing an actor from its rubberbands.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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, gray colored one that reacts on any actor hits, and a black and a white colored switch. These last switches will react only if hit by marbles of matching color.
If a switch turns on or off there will be a short delay until it reaches the new state and performs it actions. If you need a switch without delay you need to set the ‘instant’ attribute.
ON
, OFF
; default: OFF
See section state
nil
, BLACK
, WHITE
; default: nil
The color of the switch that needs to match the hitting actor to cause a toggle. The default ‘nil’ color is a grey switch that matches all actors, marbles of any color as well as all other actors.
true
, false
; default: 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.
Switches on at value ‘1’, and off at values ‘0’.
BLACK
WHITE
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
Note that this is an exceptional object as its default state is ‘ON’ to support the most common case of immediatly runnning timers.
A single shot, not looping timer will send an action value of ‘true’. A looping timer will alternate the boolean action values starting with value ‘true’. You can use inverse to start with a value of ‘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.
ON
, OFF
; default: ON
See section state
An ‘ON’ state timer is running. A timer in state ‘OFF’ is reset and waiting for reactivation.
true
, false
; default: 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.
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.
true
, false
; default: true
A looping timer will send periodic events.
Switches on at value ‘1’, and off at values ‘0’.
The action value starts with ‘true’ and alternates on every event between ‘false’ and ‘true’. A timer that is reset starts again with value ‘true’
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A turnstile is a stone cluster that consists of a central pivot, this ‘st_turnstile’, and up to four neighboring st_turnstilearms of connecting orientations. When one the arms is hit by an actor or receives a stone pushing impulse by another object (e.g. ‘st_rotator’, ‘ot_wire’, ‘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 ‘flavor’s of turnstiles. The common ‘red’ version pulls only the actor, that did hit the arm. It keeps it behind the ‘st_turnstilearm’ and shatters all others in its surrounding. Whereas the ‘green’ version pushes all actors with its attached ‘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 levelborder 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 inbetween. Thus actors can pass abyss or water floors, but they will not grab any items located on the grid positions inbetween. 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 guranteed that any moved actors will fall even into a tiny @ref{it_hollow} 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 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 turnstile as it can be seen in the level ‘ZigZag’.
There are two other ways of coupling turnstiles. You can simply set another ‘st_turnstile’ as the target of a first one and perform a ‘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 st_turnstilearms via an ot_wire. A turnstile will propagate its rotation impulses via an wire that is connected at one of its arms. Two turnstiles connected by wired arms will resync 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 ‘orientation’ up to date for easy read evaluation of the current turnstile orientation.
true
, false
; default: false
The standard turning direction is clockwise. Use this attribute to revert the direction.
NORTH
, EAST
, SOUTH
, WEST
; default: 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 direction would not be defined. But every rotation does update this attribute relative to its previous value.
Rotate the turnstile counterclockwise on ‘1’, and clockwise at values ‘0’.
Turn in turning direction as defined by attribute ‘counterclock’.
Turn in opposite turning direction as defined by attribute ‘counterclock’.
At the end of each turn the action is performed with a value of ‘true’ on counterclock turns and ‘false’ on clockwise turns.
"red"
"red"
"green"
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An arm that usually connects to an 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 ‘NORTH’ arm has
a single standard connection of "s"
, the reverse direction.
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 free movable. All its impulses will turn the st_turnstile cluster instead.
A special move of an arm is due to actors being moved by another green 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.
NORTH
, EAST
, SOUTH
, WEST
; default: NORTH
See section state
NORTH
, EAST
, SOUTH
, WEST
; default: NORTH
The position of an arm in a turnstile cluster.
"s"
Describes the @ref{st_puzzle} like connection that is the opposite of the turnstile position. The string is a string of a single character describing the sole connection.
Change the orientation to the given direction value. The st_fourswitch provides a compatible action which allows you to set an arm as target and this message as action.
NORTH
NORTH
EAST
SOUTH
WEST
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 undistructable. Safety glass is seleted by setting the attribute ‘secure’ to ‘true’. Every glass face can be weakened by ‘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 it_hammer, or by weakening the window faces by prior scratching it with an @ref{it_ring}. Green safty glass windows will never break on actor attacks.
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 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 ‘inner_pull’.
"s"
Describes the window faces of the stone. The string is a substring of
"nesw"
listing the faces. The sequence of the sides, north, east, south,
west, is guaranteed on read access but arbitrary on write access.
true
, false
; default: false
Green safety glass is secure, whereas normal blue is not.
""
Describes the scratched window faces of the stone. The string is a substring of
"nesw"
listing the affected faces. The sequence of the sides, north, east,
south, west, is guaranteed on read access but arbitrary on write access.
Tries to tear the opposite window face into the given direction.
"s"
"w"
"s"
"sw"
"e"
"ew"
"es"
"esw"
"n"
"nw"
"ns"
"nsw"
"ne"
"new"
"nes"
"nesw"
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
10.1 Actor Attributes | Common attributes | |
10.2 Actors | All actors |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
11.1 Visible Others | Special gaming objects | |
11.2 Gadgets | Tools for plug and play construction of levels |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
11.1.1 ot_rubberband | Rubberband with forces | |
11.1.2 ot_wire | Stone connection that transfers impulses |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An orange link between two objects that can apply attracting or repelling forces to them.
The two connected objects are called anchors. The attribute ‘anchor1’ holds the first objects reference that must be an actor. The ‘anchor2’ references the second object that can either be another actor or a stone. Both objects must exist to add an 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 rubbers and 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 ‘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 ‘strength’. A positive strength is a natural attracting force, whereas a negative strength would repell the actors.
A rubberband that is shorter than its natural ‘length’ would normally not apply any force. But this special rubber allows you to set a ‘threshold’ where the rubberband starts to apply the opposite directed forces onto the actors, like a spring would do. Thus a positve ‘strength’ would lead to a repelling force, a negative one to an attracting force. A rubberband with a length inbetween ‘threshold’ and ‘length’ will apply no forces.
In some cases you do want to limit the length of rubberband. You can do this by setting ‘min’ and ‘max’ attributes. Actors will bounce on these limits. Do not try to use artificial large ‘strength’ values to ensure length limits, as this could lead to extreme forces causing unexpected and unstable actor movements.
Rubberbands can be cut by st_scissors, by receiving a kill message, by one of the anchors receiving a disconnect message or a stone anchor that ceases to exist.
Rubberbands can be dynamically generated by it_rubberband and st_rubberband.
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.
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.
10.0
The force strength.
1.0
The natural length above which forces are applied.
0.0
The length smaller than the natural length below which inverted forces are applied.
0.0
The minimum length at which actors bounce.
0.0
The maximum length at which actors bounce.
An action will be performed on behalf of it_rubberband after application and creation of this rubberband. The action value is ‘1’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 origin from an actor hitting a stone, an @ref{it_puller}, an st_rotator, an @ref{st_stoneimpulse}.
A single stone can be wired to many other stones. All these fellows will move on an impulse. But the impulses will not be propagated to further stones that are wired themsselves to any of the fellows. Just the direct wired stones will move.
You can request the wires connected to a stone by the stones wires attribute. As it is tedious to evaluate both anchors, every stone supports an attribute fellows that reports the connected objects.
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.
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
12.1 World Advanced Methods | Additional features provided by the world | |
12.2 Resolvers | Standard tools for interpretation of tile maps | |
12.3 General Features | Special features by various objects | |
12.4 Tips and Tricks | Simple patterns that are valuable like a feature |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
12.1.1 add | Add Other Objects to the world | |
12.1.2 drawBorder | ||
12.1.3 drawMap | ||
12.1.4 drawRect | ||
12.1.5 shuffleOxyd | Oxyd Shuffling Rules |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Add Other Objects to the world.
wo:add(tile_declarations)
One or many other object declarations given as tiles or anonymous tables.
wo:add({"ot_rubberband", anchor1="a1", anchor2="w", length=2, strength=80, threshold=0}) wo:add(ti["r"] .. {"ot_wire", anchor1="w1", anchor2="w2"}) |
Just Other Objects can be added by this method.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Draw a border around a rectangle out of given tiles.
wo:drawBorder(upperleft_edge, lowerright_edge, tile)
wo:drawBorder(upperleft_edge, width, height, tile)
Upper left anchor position of the rectangle.
Lower right end position of the rectangle.
Width of the rectangle.
Height of the rectangle.
wo:drawBorder(po(0, 0), wo["Width"], wo["Height"], ti["#"]) wo:drawBorder(no["myRectUL"], no["myRectLR"], {"st_grate1"}) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Even if the world is initialized by a map on creation of the world (see section World Creation and Resolver Chaining), it is sometime useful to be able to draw smaller submaps either as part of the initialization or as dynamic level changes within Callback Function. Of course the main purpose of ‘drawMap’ is the drawing of repeating patterns.
wo:drawMap(resolver, anchor, ignore, map)
Resolver to which unresolved requests should be forwarded. May be ‘ti’ as the final resolver of the resolver chain.
The anchor position where the upper left tile of the map should be drawn.
A tile key string that should be ignored. This key string is mandatory, even if it not used within the map.
A table of strings. Each string describes a row of tiles by its tile keys.
wo:drawMap(ti, po(5, 7), "-", {"abcabc"}) wo:drawMap(ti, anchor_object, "--", {"--##--##","##--##"}) |
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.
ti[" "] = {"fl-plank"} ti["X"] = {"st_oxyd"} ti["B"] = {"st-black3"} ti["W"] = {"st-white3"} ti["y"] = {"it-yinyang"} ti["1"] = ti["y"] .. {"#ac-blackball"} ti["2"] = ti["y"] .. {"#ac-whiteball"} function myresolver(key, x, y) if key == "w" then wo:drawMap(ti, po(x-1, y-1), "-", {"-W-", "WXW", "-W-"}) return ti({}) elseif key == "b" then wo:drawMap(ti, po(x-1, y-1), "-", {"-B", "BXB", "-B"}) return ti({}) else return ti[key] end end w, h = wo(myresolver, " ", { " ", " b b ", " w w ", " ", " ", " w ", " 12 b ", " w ", " w ", " b ", " w b ", " b ", " " }) wo:shuffleOxyd() |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
wo:drawRect(upperleft_edge, lowerright_edge, tile)
wo:drawRect(upperleft_edge, width, height, tile)
Upper left anchor position of the rectangle.
Lower right end position of the rectangle.
Width of the rectangle.
Height of the rectangle.
wo:drawRect(po(0, 0), wo["Width"], wo["Height"], ti[" "]) wo:drawRect(no["myRectUL"], no["myRectLR"], {"fl_water"}) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Shuffling the color distribution of the 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 st_oxyd that are not excluded by a ‘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 st_oxyds 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.
wo:shuffleOxyd(rules)
No rule or as many as you like, all seperated by a comma.
Each rule is a table with a subset of the listed entries. The group1 entry is mandatory. All other entries are optional and can be added in any combination.
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.
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.
max =
number
The maximum number of oxyd pairs.
min =
number
The minimum number of oxyd pairs.
circular = true
Avoid any pair of neighboring oxyds in group1. Avoid an oxyd pair of first and last oxyd in group1, too.
linear = true
Avoid any pair of neighboring oxyds in group1.
log =
"solution"
|"count"
|"all"
Log additional information to the log stream for debugging purposes and security checks by the level author.
wo:shuffleOxyd() wo:shuffleOxyd({"borderoxyds#*", circular=true}) wo:shuffleOxyd({"leftoxyds#*","rightoxyds#*", min=3}, {"islandoxyds#*", max=0}) |
Any call of ‘wo:shuffleOxyd()’ must occur after all st_oxyd have been set. That means that it must follow the standard world initialization (see section World Creation and Resolver Chaining). As a side effect shuffleOxyd will assign colors to all ‘OXYD_AUTO’ colored st_oxyd.
Once called the given shuffling rules remain valid. Any further reshuffling must be done by messages ‘closeall’ and ‘shuffle’ to one arbitrary st_oxyd instance. No addition of an st_oxyd or subsequent ‘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, fart 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. ‘{"islandoxyds#*", max=0}’ requests that there is no pair within this group of oxyds. Whereas ‘{"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 ‘n-1’ res. ‘n’ rules with all possible neighboring oxyd pairs as two groups and a rule of ‘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 ‘solution’ the pair distribution will be printed to the log stream.
In case of ‘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 ‘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.
wo["ConserveLevel"] = false ti["~"] = {"fl_water"} ti[" "] = {"fl_plank"} ti["c"] = {"it_crack3", brittleness=0} ti["^"] = {"st_oneway_n"} ti["1"] = {"ac_marble_black", 0, 0.5} ti["x"] = {"st_oxyd", "island#"} ti["y"] = {"st_oxyd", "left#"} ti["z"] = {"st_oxyd", "right#"} w, h = wo(ti, " ", { "~~x x x x x x~~", "~~ ~~", "~~~~^~~~~~~~~~~^~~~~", "y ~~~~ z", "~ cccc ~", "y ~~~~ z", "~ cccc ~", "y ~~~~ z", "~ cccc ~", "y ~~~~ z", "~~~~c~~~~~~~~~~c~~~~", "~~ ~~", "~~ 1 ~~" }) wo:shuffleOxyd({"island#*", min=3, linear=true}, {"left#*","right#*", max=2, min=2}) |
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
12.2.1 res.autotile | Generate tiles from given template declarations | |
12.2.2 res.composer | Compose tiles from given base tiles | |
12.2.3 res.maze | Generate arbitrarly chaped mazes | |
12.2.4 res.random | Choosing random tiles in a given distribution |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
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"} |
Autotiling requires just one template tile of each type and substitutes any pattern ‘%%’ by a unique substitution.
ti["template_switch"] = {"st_floppy", target="laser%%"} ti["template_laser"] = {"st_laser", name="laser%%"} |
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.
res.autotile(subresolver, rules)
Resolver to which unresolved requests should be forwarded. May be ‘ti’ as the final resolver of the resolver chain.
One rule or as many as you like, all seperated by a comma.
Each rule can be either a prefixrule or a rangerule in any mixture
A table with two entries. First a prefix string that is common to all tile keys that should be handeled followed by key string of the template tile.
A table with 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.
res.autotile(ti, {"A", "template_switch"}, {"L", "template_laser}) res.autotile(ti, {"a", "e", "template_trigger}, {"A", "E", "template_door"} |
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 and all occurences of the two characters ‘%%’ will be substituted by a single percent sign followed by the suffix of the used tile key. Thus a key of ‘AD’ will target the laser ‘laser%D’. You need to use the key ‘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 ‘%%’ 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. Thus a key of ‘c’ will target the door ‘door%3’. You need to use the key ‘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:
ti["template"] = ti["~"] .. ti({"it_trigger", target={"door%%#*","laser%%"}}) .. {"st_grate1"} |
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-blackball"} .. 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 ", " " }) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The composer resolver reduces the number of required tile declarations by generating them by composition of base tiles. Small motley 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:
ti[" ."] = {"fl_space"} ti[" ~"] = {"fl_water"} ti["X "] = {"st_grate"} ti["h "] = {"it_hammer"} |
You can freely use any of the additional combination like "X."
- a grate
on space, "X~"
- a grate on water, "h."
- a hammer on space,
"h~"
- a hammer on water.
res.composer(subresolver)
Resolver to which unresolved requests should be forwarded. May be ‘ti’ as the final resolver of the resolver chain.
res.composer(ti) |
For every key in the map the subresolver will be first requested for a tile declaration. Thus any given declaration will preceede the auto composition.
Just in case that no declaration exists the search starts for existing subkey tiles. Subkeys are keys with some characters replaced by a whitespace ‘ ’. For all key lengths the basic subkeys with just one character different from a whitespace will be examined. Additionally just for three character key length the three keys with just one whitespace replacement and two remaining original characters will be examined and these compositions will preced the composition of three one character tiles.
Thus for the key "h~"
the composer will look for "h "
and
" ~"
. For the three character key "#h~"
The composer will look for
"#h "
plus " ~"
, "# ~"
plus " h "
, " h~"
plus "# "
and finally "# "
plus " h "
plus " ~"
.
For the 4 character key "A#h~"
the composer will just look for
"A "
plus " # "
plus " h "
plus " ~"
. The
same holds for any larger key length.
It is recommended to add the composer resolver behind most other library resolvers in the resolver chain.
ti[" "] = {"fl_sahara"} ti[" ="] = {"fl_tigris"} ti[" ."] = {"fl_abyss"} ti[" ~"] = {"fl_water"} ti[" ;"] = {"fl_leaves"} ti["# "] = {"st_rock1"} ti["W "] = {"st_wood"} ti["X "] = {"st_oxyd"} ti["G "] = {"st_grate1"} ti["2 "] = {"it_coin_s"} ti["s "] = {"it_seed"} ti["c "] = {"it_cherry"} ti["h "] = {"it_hammer"} ti["k "] = {"it_key"} .. ti({"st_glass1"}) ti["xx"] = {"#ac-blackball"} local resolver = res.composer(ti) w, h = wo(resolver, " ", { " ", " h= ;W;2;c G~ ~# #.2.X X~k=k; ", " ", " 2;s; 2.s. 2=s= ", " c;h; c.h. c=h= xx ", " " }) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
res.random(subresolver, hits, replacements)
Resolver to which unresolved requests should be forwarded. May be ‘ti’ as the final resolver of the resolver chain.
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.
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.
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.
Either a single tile key string that should be taken with a frequency of ‘1’, or a pair of a tile key string with a given frequency number.
res.random(ti, "x", {"a", "b"}) res.random(ti, {{"x", "y"},{"i","j"}}, {{"a", 2}, {"b", 1}}) |
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 likelyhood according to the ratio of the given frequency numbers. If no frequency is supplied a default of ‘1’ is taken. Thus in the first example both keys are taken in an 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.
ti["~"] = {"fl-water"} ti["s"] = {"fl-sahara"} ti["t"] = {"fl-tigris"} ti["i"] = {"fl-inverse2"} ti["b"] = {"fl-acblack"} ti["w"] = {"fl-acwhite"} ti["c"] = {"it_coin_s"} ti["p"] = {"it_brush"} ti["1"] = {"ac-blackball", 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..", " ~~.........", " ~~........." }) |
Note that in this example we can use ‘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 ‘c’ is used for another tile with the default floor. Thus we do need to use another unique key ‘C’ for the coin on our random floor.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
12.3.1 Display Follow Strategy | How the display view follows the active marble | |
12.3.2 Fire Spreading | ||
12.3.3 Freeze Checking |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
wo["FollowGrid"] = true wo["FollowMethod"] = FOLLOW_SCROLL |
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.
wo["FollowGrid"] = true wo["FollowMethod"] = FOLLOW_FLIP |
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.
wo["FollowGrid"] = true wo["FollowMethod"] = FOLLOW_SCROLL wo["FollowAction"] = FOLLOW_HALFSCREEN |
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.
wo["FollowGrid"] = false wo["FollowMethod"] = FOLLOW_SCROLL |
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.
wo["FollowGrid"] = true wo["FollowMethod"] = FOLLOW_SCROLL wo["FollowAction"] = FOLLOW_FULLSCREEN |
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.
wo["FollowMethod"] = FOLLOW_NO |
No scrolling at all. Even if the active actor moves out of sight the display remains at its position.
wo["FollowGrid"] = true wo["FollowMethod"] = FOLLOW_FLIP wo["FollowThreshold"] = po(2.5, 1.5) |
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.
wo["FollowGrid"] = true wo["FollowMethod"] = FOLLOW_SCROLL wo["FollowThreshold"] = po(2.5, 1.5) |
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
12.4.1 Nearest Object Clustering | When nearest object address wrong target |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The nearest object as described in 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, Stone 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.
ti["F"] = {"st_floppy", target="@door#*"} ti["B"] = {"st_blocker", name="door#"} wo{ti, " ", { " B ", " FB#####FB####", " # F B ", " # # F#####", |
In both cases the floppy switch that is located at the crossing of to blocker doors will open the false one.
But you can use a cluster concept like the one we introduced for 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:
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#####", |
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
13.1 Resolver Development |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Resolvers are designed to provide easy pluggable extensions for usage by level authors. Furtheron resolvers should be as flexible as possible. To reach these goals each resolver consists of three parts: the configurator, the implemention and the finalizer.
13.1.1 Resolver Configurator | ||
13.1.2 Resolver Implementation | ||
13.1.3 Resolver Finalizer |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The configurator is the function that is being called, when the author supplies the resolver specific parameters.
context = res.resolvername(subresolver,...)
Resolver to which unresolved requests should be forwarded. May be ‘ti’ as the final resolver of the resolver chain.
This function has just one mandatory paramenter, 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 ‘res’ under their official name:
function res.composer(subresolver) ... end |
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 an lua error message call at level 2:
error("Resolver autotile rule " .. i.." is not a table", 2) |
The configuration function has to return a table that contains the context for subsequent calls of the implementation. This table has three predefined entries:
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 ‘res.resolvername_implementation’. The finalizer can be ‘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.
function res.composer(subresolver) local context = {res.composer_implementation, nil, subresolver} return context end |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
tile = resolver_implementation(context, evaluator, key, x, y)
The context as provided as return value by the Resolver Configurator.
A system function that needs to be called whenever this resolver needs to look up the key by its subresolver.
The key string that should be resolved
The position of the tile.
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 coordinate 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:
local tile = evaluator(context[3], key, x, y) |
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:
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) |
You are even allowed to add new tile declartions to the tiles repository to speed up subsequent calls:
ti["newkey"] = evaluator(context[3], "a", x, y) .. ti({"st_laser_n", state=ON) |
A resolver implementation can store and modifiy any of its private parameters in the context table for subsequent calls. Especially it can enlist all coordinates for postprocessing operations in the finalizer.
The implementation of the composer (without the special 3 character key treatment)
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 |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If the Resolver Configurator provides a finalizer function in its context this function will be called once when all tiles from the map have been set.
resolver_finalization(context)
The context as provided as return value by the Resolver Configurator.
The finalization functions of chained resolvers are called from top to bottom.
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 resolvers context.
The finalizer does neither call its subresolver nor does it return a value.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
14.1 Floors | ||
14.2 Items | ||
14.3 Stones | ||
10.2 Actors | ||
14.5 General object attributes | ||
14.6 The 1.0-Fire System | ||
12.3.3 Freeze Checking | ||
14.8 Differences between Compatibility Modes |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
14.1.1 Common Floor Attributes | Common attributes for single floor tiles | |
14.1.2 Special floor tiles | List of special floors | |
14.1.3 Regular floor tiles | List of regular floors | |
14.1.4 fl-abyss | Abyss | |
14.1.5 fl-ac[black/white] | Blackmarble and Whitemarble Floor | |
14.1.6 fl-bridge | Bridge | |
14.1.7 fl-dummy | Dummy floor | |
14.1.8 fl-gradient | Gradient | |
14.1.9 fl-ice | Ice | |
14.1.10 fl-inverse | Inverse Floor | |
14.1.11 fl-nomouse | No-mouse-floor | |
14.1.12 fl-space | Space Floor | |
14.1.13 fl-space-force | Space Floor with Vertical Force | |
14.1.14 fl-swamp | Swamp | |
14.1.15 fl-thief | Thief Floor | |
14.1.16 fl-water | Water |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Standard attributes:
friction
Overrides the default friction for this floor tile.
mousefactor
Overrides the default mousefactor.
force_x, force_y
Define horizontal and vertical flat forces on the floor. On
fl-gradient, force_x
and force_y
are additive to
the gradient's standard force.
freeze_check
See Freeze Checking.
Attributes connected to The 1.0-Fire System (all boolean):
burnable
Sets if the floor may burn.
ignitable
Sets if the floor gets ignited by explosions.
secure
Sets if the floor gets securely ignited and/or heated by neighbors.
eternal
Sets if the floor doesn't stop burning after awhile.
noash
Sets if the floor doesn't leave it-burnable_ash
behind.
fastfire
Sets if the fire spreads fast.
initfire
Sets if the floor starts burning on initialization.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
fl-abyss fl-acblack fl-acwhite fl-bridge( type ) fl-bridge-closed( type ) fl-bridge-open( type ) fl-dummy fl-gradient( type force ) fl-gradient{1..16}( force ) fl-ice fl-inverse fl-inverse2 fl-nomouse fl-swamp fl-thief fl-water |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
fl-abyss_fake fl-black fl-bluegray fl-bluegreen fl-bluegreenx fl-brick fl-bumps fl-concrete fl-darkgray fl-dunes fl-floor_001 fl-gravel fl-gray fl-hay fl-himalaya fl-leaves fl-leavesb fl-leavesc{1..4} fl-leavesd{1..4} fl-leavese{1..4} fl-light fl-lightgray fl-marble fl-metal fl-metal{1..6} fl-mortar fl-normal fl-normal_x fl-plank fl-red fl-rock fl-rough fl-rough-blue fl-rough-red fl-rough_medium fl-rough_slow fl-sahara fl-samba fl-samba1 fl-samba2 fl-sand fl-space fl-space-force fl-springboard fl-stone fl-stwood fl-stwood1 fl-stwood2 fl-tigris fl-trigger fl-white fl-wood fl-woven |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Kills marbles that roll onto it, unless they're protected by an
it-umbrella. st-wood: Wooden Stone transforms this floor into
fl-stwood
. Marbles may jump over an fl-abyss with an
it-spring[1/2/board]. Compare with it-abyss,
fl-water and fl-swamp.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Marbles on this floor are controlled by player 0 only (who has ac-blackball by default), respectively player 1 only (ac-whiteball by default). See it-changefloor for an item interacting with these floors.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
fl-bridge
can be open (marbles fall into it) or closed (marbles
may pass). The state can be changed via messages.
fl-bridge
closes and re-opens automatically when a stone is
pushed onto it. Thus st-wood: Wooden Stone and other stones don't fall into
it, as they do on fl-abyss.
Attributes
type
a
, x
or y
Messages
open, close, openclose
as they say
signal
change state, like openclose
Variants
fl-bridge
open by default
fl-bridge-open
fl-bridge-closed
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Prints its Oxyd code when entered. Used for maintenance purposes.
Compare it with st-dummy
(Oxyd Compatibility Stones) and
it-dummy
(System and Debug Items).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Adds a horizontal, vertical or diagonal force to actors on it. The
strength of the force is determined by enigma.SlopeForce
(see
Old API - Variables) or the attribute force
. It is additive to the
force determined by the force_[x/y]
-attributes (see Common Floor Attributes).
Attributes
force
overrides enigma.SlopeForce
type
between 1 and 24, determines the direction of the gradient and its design.
Direction of the forces to certain types: 1 and 21: south, 2 and 22: north, 3 and 23: east, 4 and 24: west, 5 and 9: south-east, 6 and 11: south-west, 7 and 10: north-east, 8 and 12: north-west.
Variants
fl-gradient
type 1 by default
fl-gradient1 .. fl-gradient12
type is 1..12
fl-gradient13 .. fl-gradient16
types are 22, 21, 24 and 23
The latter four gradients don't show an outline like the first twelve:
They all look identical, and similar to fl-gray
. The remaining
types show outlines that don't correspond to their forces (use them
for tubes etc.).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Ice has very low friction and mousefactor, such that it's difficult to
move on it. You can use it-pin and enigma.IceFriction
(see Old API - Variables) to ease the friction.
Variants
fl-ice
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Inverses the mouse movements (negative mouseforce
).
Variants
fl-inverse
fl-inverse2
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This floor prevents a player from controlling the marble
(mouseforce = 0
).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This floor prevents a player from controlling the marble
(mouseforce = 0
), but in contrast to fl-nomouse, there
also is no friction, so that marbles seldom get stuck on space.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This floor has (like fl-space) no friction and no mouseforce,
but adds a vertical force of the amount given in
enigma.FlatForce
. This is obsolete since you can use
fl-space
with force_y
-attribute (see Common Floor Attributes). Note however, that the enigma.FlatForce
overrides the
force_y
-attribute of fl-space-force
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Kills marbles that roll onto it, unless they're protected by an
it-umbrella. st-wood: Wooden Stone transforms this floor into
fl-stwood
.
Once in the swamp, marbles constantly sink with the speed
given by enigma.SwampSinkSpeed
(see Old API - Variables),
and may rise again when moving fast enough (compare with
fl-water and fl-abyss).
Marbles may jump over the swamp with an it-spring[1/2/board].
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This floor steals one item from the player's inventory. It looks like
the simple floor fl-bluegray
. Compare with st-thief: Thief Stone for
details.
Like st-thief
, st-chess_[black/white]: Chess (Knight) Stone can deactivate fl-thief
, leaving an
it-bag behind, filled
with the items the thief stole from the actors (plus possibly the item
that already lay on the floor, if it could be picked up; if it is a
static item, no it-bag
is produced).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Kills marbles that roll onto it, unless they're protected by an
it-umbrella. st-wood: Wooden Stone transforms this floor into
fl-stwood
.
Once in the water, marbles constantly sink with the speed
given by enigma.WaterSinkSpeed
(see Old API - Variables).
In contrast to fl-swamp, they can't rise again, as
long as they're in the water.
Marbles may jump over fl-water with an it-spring[1/2/board].
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
it-1pkillstone it-2pkillstone it-abyss it-bag it-banana it-blackbomb it-blackbomb_burning it-blocker it-blocker-new it-booze it-booze-broken it-brake it-bridge-oxyd it-bridge-oxyd_active it-brush it-burnable it-burnable_ash it-burnable_burning it-burnable_fireproof it-burnable_ignited it-changefloor it-cherry it-coffee it-coin1( value ) it-coin2( value ) it-coin4( value ) it-crack{0..3} ( type fixed brittleness ) it-cross( action target ) it-debris it-document( text ) it-drop it-dummy it-dynamite it-easykeepstone it-easykillstone it-explosion1 it-explosion2 it-explosion3 it-extinguisher( load ) it-extinguisher_empty( load ) it-extinguisher_medium( load ) it-extralife it-flagblack it-flagwhite it-floppy it-glasses it-glasses-broken it-hammer it-hill it-hollow( essential ) it-hstrip it-inversesensor( action target ) it-key( keycode ) it-key_a it-key_b it-key_c it-landmine it-magicwand it-magnet( on strength range ) it-magnet-off( on strength range ) it-magnet-on( on strength range ) it-odometer it-oxyd5f( action target ) it-pencil it-pin it-pipe-e it-pipe-es it-pipe-h it-pipe-n it-pipe-ne it-pipe-s it-pipe-sw it-pipe-v it-pipe-w it-pipe-wn it-puller-e it-puller-n it-puller-s it-puller-w it-ring it-rubberband( target length strength minlength scissor) it-seed it-seed_nowood it-seed_volcano it-sensor( action target ) it-shogun-l( action target ) it-shogun-m( action target ) it-shogun-s( action target ) it-signalfilter0( action target ) it-signalfilter1( action target ) it-spade it-spoon it-spring1 it-spring2 it-springboard it-squashed it-surprise it-sword it-tinyhill it-tinyhollow( essential ) it-trigger( action target invisible ) it-umbrella it-vortex-closed( autoclose targetx targety ) it-vortex-open( autoclose targetx targety ) it-vstrip it-weight it-whitebomb it-wormhole( on targetx targety strength range interval ) it-wormhole-off( on targetx targety strength range interval ) it-wrench it-yinyang |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Enigma includes several items that are not meant as items in the usual way:
it-1pkillstone, it-2pkillstone
Kills the stone on the same tile in single-player mode (correspondingly in multi-player mode). Unused, due to Enigma's missing networking capability.
it-bridge-oxyd, it-bridge-oxyd_active
Used for Oxyd compatibility to animate bridges. Use fl-bridge instead.
it-debris
Animation of a breaking floor. Creates fl-abyss, then kills itself.
it-dummy
Prints its own Oxyd code when picked up or used. Compare
fl-dummy and st-dummy
(Oxyd Compatibility Stones).
it-easykillstone
Kills the stone on the same tile in easy mode; if it is one of st-death: Skull Stones, st-flash: Flash Stone or st-thief: Thief Stone, it is transformed to st-plain: Plain Stones instead.
it-easykeepstone
Kills the stone on the same tile in normal mode; no exceptions.
it-explosion[1,2,3]
Sets a visual explosion effect of strength 1 (no remainder), 2
(it-hollow
remains, see Hills and Hollows) or 3
(it-debris
remains, shattering the floor).
it-oxyd5f
When a message is sent to this item, it performs its
action/target
-pair. Used for Oxyd compatibility only.
it-signalfilter[0/1]
Transforms signal 1 to signal 0 or 1, forgets signal 0. Used for Oxyd compatibility only.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
it-hill
and it-hollow
create small hills and hollows in
the floor, it-tinyhill
and it-tinyhollow
are smaller
versions. The strength of the slope is given by
enigma.HoleForce
(see Old API - Variables).
When a stone is pushed over them or an it-spade is used on them,
they decrease their size: it-hill
and it-hollow
become
it-tinyhill
and it-tinyhollow
; the latter two disappear
completely.
Messages
trigger
Converts a hill to a hollow and vice versa.
shovel
Hills and hollows are replaced by their tiny versions; tiny ones are removed.
signal
0: become it-hollow
or it-tinyhollow
, 1: become
it-hill
or it-tinyhill
Attributes
essential
only it-tinyhollow
and it-hollow
, see below
In Meditation Levels
If all existing ac-whiteball-small are inside hollows
(it-hollow
or it-tinyhollow
), the level succeeds.
Use the essential
-attribute if there are more holes than small
whiteballs in a level, and you want to determine which of the holes are
needed to finish the level (1 means this hollow must be filled with a
whiteball to end the level).
For example: If you have many holes and 3 whiteballs, then set
essential=1
in 3 holes. The game will end when the 3
whiteballs are inside the 3 marked holes.
Note that hollows might appear or disappear during the game; they are handled the same way as described above.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Compare The 1.0-Fire System.
Six items are particular to the fire system:
it-burnable
to allow a floor tile to catch fire, and
it ignites from explosions, like from it-dynamite,
it-blackbomb and it-whitebomb.
it-burnable_oil
is the visible variant of the invisible
it-burnable
.
it-burnable_ignited
carries the starting-animation of
fire. Use the setfire
-message to a floor instead.
it-burnable_burning
carries the animation of burning
fire. Use setfire
instead.
it-burnable_ash
is the unburnable remnant of a fire.
it-burnable_fireproof
saves a floor from fire.
Use it-extinguisher
to set it-burnable_fireproof
. After
using it once, it becomes it-extinguisher_medium
, which guards
less floor, and itself becomes it-extinguisher_empty
, which can
be laid down again.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Use this to set an invisible alternative to fl-abyss. Note
however, that st-wood: Wooden Stone doesn't fill it-abyss
as it does
with fl-abyss
. Marbles may jump over it-abyss
with an
it-spring[1/2/board]
, in contrast to it-death. Also,
compare to it-booze-broken.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As long as 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 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 in detail:
it-bag
is created by st-thief: Thief Stone and fl-thief when
they're captured by st-chess_[black/white]: Chess (Knight) Stone.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
it-banana
transforms into it-cherry when hit by a laser
beam, and into it-squashed when a stone is pushed over it.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This item can't be picked up, but received from st-bombs: Bombstones. It
can be ignited by lasers, fire and other explosions (other
it-blackbomb
, it-whitebomb, it-dynamite, exploding
st-bombs
above them), messages “ignite”, “expl” and
“explosion” and by pushing stones over them (except for
st-shogun-<sml>: Shogun Stones and, in Oxyd compatibility mode,
st-wood: Wooden Stone).
When exploding, it-blackbomb
ignites or destroys neighboring
items, and destroys its own floor tile by replacing it against
fl-abyss
. See also it-whitebomb for a stronger version.
Messages
ignite, expl
ignite, then explode
explode
explode instantly
Variants
it-blackbomb
it-blackbomb_burning
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This item is the shrunken form of st-blocker: Shrinkable Blocker Stone. When it is hit by
st-bolder: Bolder (or Arrow) Stone, it becomes st-blocker
again. It can be
destroyed with it-brake.
Messages
trigger, openclose
If shrunken, grow. Otherwise, change internal state; only sensible
while a stone is on top of it-blocker
.
open, close
These are complicated, but in most cases close
makes the item
grow. Consult the source code for details.
signal
1: open, 0: close
Variants
it-blocker
it-blocker-new
doesn't grow at once when st-bolder
just arrives (acts as if
recently shrank)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When used, the actor becomes slower for a short period of time. Note
that it-booze
is still under development; its behavior might be
changed.
When hit by a stone, it-booze
transforms into
it-booze-broken.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The remnants of it-booze after pushing a stone over it. Kills a marble that touches it, but not when it is jumping with it-spring[1/2/board] or protected by it-umbrella, compare it-abyss and it-death. Can be removed with it-brush while jumping over it, or otherwise protected.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When used, this item creates an st-brake: Brake, which itself can be
picked up as it-brake
again. It can be used to destroy
it-blocker.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This item can be used to make some invisible stones visible
(st-actorimpulse_invisible
(see st-actorimpulse: Bumper Stones),
st-break_invisible
(see Breakable-Stones),
st-stonebrush
(see st-invisible: Invisible Stones), and to remove debris
from the level: (it-cross, it-squashed,
it-booze-broken, it-glasses-broken
(see
it-glasses), it-burnable_ash
,
it-burnable_fireproof
(see Fire and Extinguisher)).
In addition, this item can be used to transform st-firebreak
into st-plain
and st-firebreak_move
into
st-plain_move
(see st-firebreak[_move]: Firebreakable Stones and
st-plain: Plain Stones).
The Per.Oxyd-compatibility stone st-yinyang3
(see
st-yinyang: Yin-Yang Stones) must be touched with an it-brush
or
it-magicwand in order to activate it.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When in multi-player mode, this item exchanges fl-acblack
and
fl-acwhite
below it after an actor has left it (see
fl-ac[black/white]). This way the marble can't roll back
as easily as before. Try the original Per.Oxyd Link Level 69 to see
this scarcely-used item in action.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When used, the marble becomes invisible for a short time.
Some benefits of this are that rotors and tops can't find it and
it can walk through glass. There are some different glassstones, and not all
may be passed when invisible. For details, see Glassstones.
When a stone is pushed over it-cherry
, it becomes
it-squashed.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
it-coffee
is supposed to pause the game; not implemented yet.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Activates st-coinslot.
When hit by a stone, it-coin2
transforms into it-coin4
,
and it-coin1
into it-coin2
. A laser beam transforms
it-coin1
, it-coin2
, and it-coin4
into
it-umbrella, it-hammer, and it-extralife.
Attributes
value
Determines how long st-coinslot keeps activated. Defaults:
it-coin1
3.0, it-coin2
6.0, it-coin4
12.0.
Variants
it-coin1
it-coin2
it-coin4
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Represents cracks in the floor. it-crack0
is invisible and
grows to it-crack1
, it-crack2
, it-crack3
, after
which the floor desintegrates to fl-abyss.
The brittleness
-attribute and
enigma.Brittleness
-variable determine the probability that a
crack grows when an actor enters. When the crack grows, it spreads to
neighboring unoccupied tiles. If you want to suppress this, set
enigma.Brittleness
to 0.0 and the brittleness
-attribute
of the cracks to 0.5 (or whatever you like, also see Old API - Variables).
Attributes
type
0, 1, 2, or 3
fixed
0: crack can grow, 1: crack doesn't grow
brittleness
overrides enigma.Brittleness
Messages
crack
grow by one step
Variants
it-crack0
it-crack1
it-crack2
it-crack3
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Marks an interesting spot, can be created with an it-pencil and removed with it-brush.
When a marble remains on the cross for at least 10 seconds,
it-cross
performs its action/target
(only once, not
every 10 seconds). it-trigger and
it-sensor have similar functions.
Attributes
action, target
as usual
Messages
brush
remove it-cross
signal
performs action/target
with inverted signal-data; works only in
Per.Oxyd-compatibility mode
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Kills a marble that touches it, even when it is jumping with it-spring[1/2/board], compare it-abyss and it-booze-broken. it-umbrella protects the marble.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 (like from it-blackbomb, it-whitebomb, st-bombs: Bombstones and also it-dynamite).
Attributes
text
The message to be displayed.
Messages
expl, bombstone
destroy
ignite
destroy if not in Oxyd compatibility mode
Example
set_item("it-document", 1,1, {text="Hello World!"}) Document(1,1, "Hello World") |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Transforms the marble into an ac-rotor for a short time. Can be used multiple times.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
it-dynamite
can be ignited by dropping it, by lasers, fire,
other explosions (it-blackbomb, it-whitebomb, other
it-dynamite
and st-bombs: Bombstones). While burning, it can't be
picked up. During explosion (it-explosion2
, see
System and Debug Items), it ignites neighboring items and
leaves an it-hollow
behind (see Hills and Hollows). On
fl-ice, it creates it-crack2
instead (see it-crack).
On fl-space, dynamite is supposed to result in shards. This is
not implemented yet: It creates it-hollow
without explosion.
Note that this and the exact implementation of explosions might change
in future versions.
Messages
ignite, expl, bombstone
ignite, then explode
explode
explode instantly
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Adds a life to the player's inventory.
A laser beam transforms this into it-glasses, and
it-extralife
itself results from it-coin4
(see
it-coin).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Marks the place, where ac-blackball respectively ac-whiteball respawn when killed. For this purpose, they have to be used at least once.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The floppy disk is needed to activate the floppy switch (see st-floppy: Floppy Switch).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
While it-glasses
is in the inventory, hollow stones become
invisible and st-death_invisible
becomes visible (see
st-death: Skull Stones).
it-glasses
breaks when a stone is pushed over it, and becomes
the inactive version it-glasses-broken
. it-glasses
results from the laser transformation of it-extralife.
Variants
it-glasses
it-glasses-broken
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The hammer is used to destroy some stones, see Breakable Stones and st-lightpassenger: Light Passenger. It also transforms into
it-sword when hit with a laser beam and is itself a
laser transformation result of it-sword and it-coin2
(see
it-coin).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
These items cover a small strip of the ground below them and provide a narrow bridge for the marble to safely pass fl-abyss, fl-swamp, fl-water, or any other floor.
Variants
it-hstrip
horizontal
it-vstrip
vertical
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Used to activate st-key: Key (or Lock) Stone.
Attributes
keycode
Variants
it-key
keycode
is 1
it-key_a
keycode
is 1
it-key_b
keycode
is 2
it-key_c
keycode
is 3
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Explodes when hit by a marble or by a stone, shatters the marble, and
leaves an it-hollow
behind (see Hills and Hollows).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
st-brick_magic
transparent (st-brick_magic: Magic Brick Stone).
st-invisible_magic
visible and non-transparent
(st-invisible: Invisible Stones).
st-yinyang3
(st-yinyang: Yin-Yang Stones).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Attracts actors in its range
with a force proportional to
strength
and the inverse of the distance. The magnet can be on
or off.
Attributes
on
TRUE
or FALSE
, see variants below
strength
default: 30
range
default: 1000 (quasi infinite)
Messages
on, off, onoff
as usual
signal
0: off, 1: on
Variants
it-magnet
by default off
it-magnet-on
it-magnet-off
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Supposed to measure the route the marble has rolled since picking up
it-odometer
. Not implemented yet.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Try to scratch an it-cross into the floor; the pencil is lost after this. Scratching onto ice results in a crack, scratching while flying or on certain floors results in dropping the pencil.
In addition, this item can be used to transform st-plain
into
st-firebreak
and st-plain_move
into
st-firebreak_move
(see st-plain: Plain Stones and
st-firebreak[_move]: Firebreakable Stones).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
While in inventory, it-pin
increases the friction of the
floor. Used in conjunction with fl-ice.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Pipes are used by st-mail: Mail Stones to transport items over large distances or onto unreachable grounds. Pipes can be destroyed by explosions (such as from it-blackbomb or it-whitebomb).
Variants
it-pipe-e
it-pipe-w
it-pipe-s
it-pipe-n
it-pipe-es
it-pipe-ne
it-pipe-sw
it-pipe-wn
it-pipe-h
horizontal
it-pipe-v
vertical
The first four variants depict endpoints of the pipe, they're of no use to st-mail: Mail Stones other than blocking the endpoint.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When dropped, these items pull a stone from the direction they point to, to their own position. They explode during this, shattering marbles near them.
Variants
it-puller-e
it-puller-w
it-puller-s
it-puller-n
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When a player drops this item, the marble is teleported. The destination depends on the game mode:
The marble is transported to its starting position or to the position of the last dropped it-flag[black/white].
Both marbles exchange their positions. In contrast to it-yinyang, the positions are exchanged, not the players.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Connects the actor using it with a target. This target can be an other actor or a stone. The target is determined by its name-attribute. If the target doesn't exist, the it-rubberband will be dropped.
Attributes
target
The target to connect with. It must be the name of an other actor or a stone.
length
The natural length of the rubberband (default: 1)
strength
The strength of the rubberband (default: 10)
minlength
The minimal length of the rubberband (default: 0)
scissor
Boolean value defining if already-existing rubberbands to the actor should be cut off. (Default: false)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
set_stones("st-glass", 5, 5, {name="MyRubberTarget1"}) … -- When used, this it-rubberband will connect the actor with the glassstone. set_item("it-rubberband", 3, 5, {target="MyRubberTarget1"}) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Stones can grow from three different seeds:
it-seed
creates st-wood: Wooden Stone, it-seed_nowood
creates
st-greenbrown-growing
, which produces the unmovable simple
stone st-greenbrown
, and it-seed_volcano
that creates
an st-volcano: Volcano. The new
stone inherits the name of the seed.
In Oxyd-Magnum-compatibility mode, it-seed
under
st-grate1
(see st-grate: Grates) grows to the simple floor
fl-stwood
instead of destroying the grate. In all other cases,
stones at the position of the seed are replaced by the new stone.
Seeds start growing on dropping them, on laser beams, stone hits and
the grow
and signal
-messages.
Messages
grow, signal
start growing
Variants
it-seed
it-seed_nowood
it-seed_volcano
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This is an invisible, quiet and less extensive version of
it-trigger. Whenever an actor enters it, it performs its
action/target
-pair, with second data TRUE
for
it-sensor
and FALSE
for it-inversesensor
.
Also compare it-cross.
Attributes
action, target
as usual
Variants
it-sensor
it-inversesensor
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Performs its action/target
-pair when an st-shogun-<sml>: Shogun Stones
of fitting size covers it.
Attributes
target, action
as usual
Messages
noshogun
deactivate
shogun ....
used to activate or deactivate it-shogun
Variants
it-shogun-s
it-shogun-m
it-shogun-l
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Decreases the size of an it-hill
or it-hollow
and
removes it-tinyhill
and it-tinyhollow
, see Hills and Hollows.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Shatters the marble. Note that in contrast to F3, it-spoon
only shatters the marble using it, not all of them.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Springs let marbles jump, e.g., over fl-water, fl-swamp, fl-abyss, it-abyss, and laser beams. Note that you can't jump over any kind of stone, or pass st-grate: Grates during the jump, even if you could on the ground. The interplay of jumping and fire (The 1.0-Fire System) will be target of future changes; don't use them together yet.
You can pick up and use it-spring1
and it-spring2
. You
keep the former in the inventory, but in general, drop
it-spring2
when using. it-springboard
is fixed to the
ground; you can only use it where it is.
When you're already sinking in fl-swamp
or fl-water
, you
can use springs to jump out of them, sinking then starts anew.
Variants
it-spring1
it-spring2
it-springboard
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The remnants of it-cherry or it-banana after pushing a stone over them. Can be removed with it-brush.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This item turns randomly into it-umbrella, it-spring1
(see
it-spring[1/2/board]), it-dynamite, it-coffee, or
it-hammer when dropped. The corresponding stone is st-surprise: Surprise Stone.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Used to neutralize st-knight: Knight Stone. The laser transforms it into it-hammer and vice versa.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When pushed down by an actor or a stone, this trigger performs its
action/target
-pair, and a second time when it is released
again. As second data it uses TRUE
when pressed, and
FALSE
if not.
Floating stones do not hold down a trigger, except of the tunnel puzzle-stone (see st-puzzle: Puzzle Stones).
it-trigger
can be initialized as invisible with attribute
invisible = TRUE
. Note that it still produces its
click-sounds. For a simpler version, see it-sensor. Also
compare it-cross.
Attributes
invisible
0.0 (visible) or 1.0 (invisible), by default 0.0
action, target
as usual
Messages
signal
perform action/target
according to second data
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
it-umbrella
temporarily protects a marble from st-death: Skull Stones,
st-knight: Knight Stone, st-thief: Thief Stone, fl-abyss, fl-water,
fl-swamp, fl-thief, it-death, it-abyss,
it-booze-broken, explosions, moving stones and the “shatter”
and “fall”-messages; in other words, from all lethal situations and
thieves.
it-umbrella
can be destroyed by laserlight and is the result of
laser-transforming an it-coin1
(see it-coin).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Vortices, like it-wormhole, can be used to teleport marbles. In the simplest case, every vortex is connected to exactly one other vortex. If there are multiple target vortices, the marble will be teleported to the first unblocked target site. Many levels in the original Oxyd games required the player to selectively block vortices to gain access to new parts of the level.
In a further contrast to wormholes, vortices can be open or closed,
and when marbles exit, they jump out of them. Furthermore, connecting
vortices in a cycle works as expected and is standard (though not
necessary), whereas connecting wormholes cyclic results in an
error-message (as long as their interval
-message isn't used).
Attributes
targetx, targety
destination of teleport
autoclose
not implemented yet, see variants below
Messages
open, close, openclose
as they say
trigger
identical to openclose
signal
0: close, 1: open
arrival
used by the teleport-system, don't use in levels
Variants
it-vortex-open
This vortex starts open and doesn't close when an actor jumps out of it. Default teleportation target is the own position, thus an actor keeps jumping in and out of it until moved away.
it-vortex-closed
This vortex starts closed and closes again when an actor jumps out of
it. If you want to create an open vortex that closes after an actor,
send a trigger
-message to it-vortex-closed
on
initialization.
Note that it-vortex-open
and it-vortex-closed
do
behave differently, in contrast to their names.
Example
This example creates three vortices. If the second vortex is blocked, a marble falling into the first one is transported to (20,1).
set_item ("it-vortex-open", 1, 1) set_item ("it-vortex-open", 10,1) set_item ("it-vortex-open", 20,1) Signal ("it(1 1)", "it(10 1)") Signal ("it(1 1)", "it(20 1)") Signal ("it(10 1)", "it(1 1)") Signal ("it(20 1)", "it(1 1)") |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Heightens the mass of the marble (making it more difficult to accelerate and guide) and it can't be dropped. Note that it can still be stolen by st-thief: Thief Stone or fl-thief and mailed away with st-mail: Mail Stones.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This item is the stronger version of it-blackbomb, and can't be
picked up also. It can be ignited by lasers, fire and other
explosions (it-blackbomb, other it-whitebomb
,
it-dynamite), messages “ignite”, “expl” and “explosion”
and by pushing stones over them (except for st-shogun-<sml>: Shogun Stones and,
in Oxyd compatibility mode, st-wood: Wooden Stone).
When exploding, it-whitebomb
ignites or destroys neighboring
items and destroys all nine neighboring floor tiles by replacing them
with fl-abyss
.
Messages
ignite, expl
ignite, then explode
explode
explode instantly
Note that, in contrast to it-blackbomb, white bombs are not removed from st-bombs: Bombstones-explosions.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Teleports actors to the coordinates given by the targetx
- and
targety
-attributes (compare it-vortex). In addition,
wormholes have a variable force field, which can be switched on and
off.
After teleporting an actor, the wormhole's teleporting ability is
switched off for a time period given by the interval
-attribute,
which is by default 0.0.
Attributes
targetx, targety
exit of the wormhole
strength, range
strength and range of the force field
on
whether force field is on
interval
minimal delay between two teleports
Messages
on, off, onoff
as usual
signal
0: off, 1: on
Variants
it-wormhole
it-wormhole-off
wormhole without force field
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Changes direction of st-rotator: Rotator Stone.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Toggles between players. Compare it-ring in multiplayer mode.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
For the common stone attribute freeze_check
, see Freeze Checking.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Simple stones
The following stone types are commonly used for “decoration”. They
generally do not have special properties or abilities. We use three types of
abbreviations in the tables: [abc]
stands for any of the
characters in square brackets, <abc>
stands for any subsequence
of the characters between the angle brackets (in this case abc, ab, bc,
a, b, c), and {1..9}
indicates a sequence of numbers.
st-beads st-blue-sand st-bluegray st-bluegray_hole st-brick st-brownie st-bumps st-camouflage st-camouflage_hole st-camouflage_move st-dummy st-fakeoxyd( blinking ) st-glass st-glass_move st-glass[123] st-glass[12]_hole st-glass[12]_move st-greenbrown st-greenbrown_hole st-greenbrown_move st-likeoxyd[abcd] st-likeoxyd[abcd]-open st-marble st-marble_hole st-marble_move st-metal st-metal_hole st-redrock st-rock{1..10} st-rock[123]_hole st-rock[13]_move st-stone[12] st-wood[12] st-wood_001 st-woven st-yellow |
Special stones
The following stones types are special in the sense that they perform some action, either when hit by an actor, or all by themselves.
st-3mirror( transparent movable orientation ) st-actorimpulse( force hit_factor hit_distortion_[xx/xy/yx/yy] ) st-actorimpulse_invisible( force hit_factor hit_distortion_[xx/xy/yx/yy] ) st-bigbluesand-<nesw> st-bigbrick-<nesw> st-black{1..4} st-blackballs st-block st-blocker st-blocker-growing st-bolder( direction ) st-bolder-[ensw]( direction ) st-bombs st-brake st-break_acblack st-break_acwhite st-break_bolder st-break_gray st-break_invisible st-breaking st-brick_magic st-bug st-chameleon st-chargeminus( charge ) st-chargeplus( charge ) st-chargezero( charge ) st-chess_black( color direction1 direction2 ) st-chess_white( color direction1 direction2 ) st-coffee st-coinslot( on action target ) st-death st-death_invisible st-disco-dark st-disco-light st-disco-medium st-door( type ) st-door-h( type ) st-door-h-open( type ) st-door-v( type ) st-door-v-open( type ) st-door_[abc] st-easymode st-explosion st-fakeoxyda st-fart st-firebreak st-firebreak_move st-flash( hit_factor hit_distortion_[xx,xy,yx,yy] ) st-flhay st-floppy( action target on ) st-flrock st-fourswitch( action target on ) st-grate[123] st-greenbrown-growing st-invisible st-invisible_magic st-key( action target on keycode ) st-key_[abc]( action target on keycode ) st-knight st-laser( dir on ) st-laser-[ensw]( dir on ) st-laserbreak st-laserswitch( action target inverse ) st-lasertimeswitch( action target inverse delay ) st-lightpassenger( interval friction_factor gradient_factor ) st-magic st-mail-[ensw] st-mirror*( movable transparent orientation ) st-mirror-3< st-mirror-3<m st-mirror-3<t st-mirror-3<tm st-mirror-3> st-mirror-3>m st-mirror-3>t st-mirror-3>tm st-mirror-3^ st-mirror-3^m st-mirror-3^t st-mirror-3^tm st-mirror-3v st-mirror-3vm st-mirror-3vt st-mirror-3vtm st-mirror-p- st-mirror-p-m st-mirror-p-t st-mirror-p-tm st-mirror-p/ st-mirror-p/m st-mirror-p/t st-mirror-p/tm st-mirror-p\ st-mirror-p\m st-mirror-p\t st-mirror-p\tm st-mirror-p| st-mirror-p|m st-mirror-p|t st-mirror-p|tm st-oneway( orientation ) st-oneway-[nesw]( orientation ) st-oneway_black( orientation ) st-oneway_black-[nesw]( orientation ) st-oneway_white( orientation ) st-oneway_white-[nesw]( orientation ) st-oxyd( flavor color static ) st-oxyd-0x18 st-peroxyd-0xb8 st-peroxyd-0xb9 st-plain st-plain_break st-plain_breaking st-plain_cracked st-plain_falling st-plain_hole st-plain_move st-pmirror( transparent movable orientation ) st-polarswitch( on ) st-pull st-puzzle-hollow( oxyd ) st-puzzle-<nesw>( oxyd ) st-puzzle2-hollow( oxyd ) st-puzzle2-<nesw>( oxyd ) st-rock3_break st-rock3_movebreak st-rotator-left st-rotator-right st-rotator_move-left st-rotator_move-right st-rubberband( length strength minlength scissor) st-scissors( action target ) st-shogun-<sml>( holes ) st-spitter( hit_factor hit_distortion_[xx/xy/yx/yy] ) st-stone_break st-stonebrush st-stoneimpulse st-stoneimpulse-hollow st-stoneimpulse_movable st-surprise st-swap st-switch( action target on ) st-switch_black( action target on ) st-switch_white( action target on ) st-thief st-timer( action target on interval loop invisible ) st-timeswitch( action target delay inverse ) st-turnstile st-turnstile-green st-turnstile-[ensw] st-volcano st-volcano-growing st-volcano_active st-volcano_inactive st-white{1..4} st-whiteballs st-window st-wood st-wood-growing st-yinyang{1..3} |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There are a few kinds of glassstones, all similar, but with different details. Some of them may be passed after the use of an it-cherry, others will be just pushed. Some are transparent for lasers, but not all! This table shows their exact properties.
stone: | actor is visible: | actor is invisible: | lasertransparent: |
---|---|---|---|
st-glass | - | pass | yes |
st-glass_move | push | pass | yes |
st-glass1 | - | pass | yes |
st-glass1_move | push | push | yes |
st-glass1_hole | pass | pass | yes |
st-glass2 | - | pass | no |
st-glass2_move | push | push | no |
st-glass2_hole | pass | pass | yes |
st-glass3 | - | - | yes |
st-polarswitch (on) | toggle | pass | yes |
st-polarswitch (off) | toggle | pass | no |
st-beads | - | pass | no |
These entries can be visualized as follows: A glassstone is transparent for
laser light, if it is not dark, or if it is hollow. Exception is
st-beads
, whose irregular sides would scatter the beam. A glassstone
can always be passed by invisible actors, with three exceptions:
st-glass3
, whose inside is filled with red stripes, and the two movables
st-glass1_move
and st-glass2_move
which have a non-glass frame
which the actor can use to move the stone. st-glass_move
does not have
such a frame and cannot be moved by an invisible actor.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A list of all breakable stones and what may break them. Messages are given in quotation marks. “pyro” is short for dynamite, bombs, bombstones, “ignite”, “expl” and “bombstone”.
st-stone_break, st-rock3_break, st-break_gray
hammer, laser, pyro
st-break_acblack
ac-blackball with hammer, laser, pyro
st-break_acwhite
ac-whiteball with hammer, laser, pyro
st-break_bolder
hammer, laser, bolder, “trigger”, (pyro?)
st-break_invisible
hammer after using a brush
st-laserbreak
laser, pyro
st-rock3_movebreak
hammer, pyro; this stone is movable by impulses (not actors)
st-plain_break
hammer, laser, pyro; falls into fl-abyss
st-plain_cracked
hammer, pyro
st-plain_move
pyro; this stone is movable; falls into fl-abyss, fl-water and fl-swamp; see also st-plain: Plain Stones
st-bug
st-breaking, st-plain_breaking
breaks instantly, looks like st-rock3
st-fart
hammer, laser; see also st-fart: Fart Stone
st-bombs
bombs, bombstones, “expl”, “bombstone”; see also st-bombs: Bombstones
st-brake
laser, bombs, “expl”; see st-brake: Brake
st-puzzle
st-volcano_active
hammer; see st-volcano: Volcano
st-lightpassenger
hammer when active and trapped; see st-lightpassenger: Light Passenger
st-firebreak
fire near the stone; see also st-firebreak[_move]: Firebreakable Stones
st-firebreak_move
fire under the stone; movable; falls into fl-abyss, fl-water and fl-swamp; see also st-firebreak[_move]: Firebreakable Stones
For the mentioned objects, see it-hammer, it-dynamite,
it-blackbomb, st-bombs: Bombstones, st-bolder: Bolder (or Arrow) Stone, it-brush.
Also compare st-plain: Plain Stones, since st-plain_cracked
results from
st-plain
when hit by a laser beam, and st-plain[_move]
can be transformed into and out of st-firebreak[_move]
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
st-magic
disappears when hit hard enough.
st-dummy
prints its own Oxyd code when hit. Compare
it-dummy
(System and Debug Items) and fl-dummy.
st-peroxyd-0xb8
, st-peroxyd-0xb9
and st-oxyd-0x18
just seem to destroy themselves on creation, the former two creating
fl-normal
beneath them. Their purpose in the original games is
unknown.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
These stones apply an impulse to actors that touch them. The amount
of force applied can be controlled by setting
enigma.BumperForce
(see Old API - Variables) accordingly (the
default is 200). Alternatively, the force
attribute can be used
to set this factor for individual bumper stones.
Attributes
force
factor of the transmitted force (overrides enigma.BumperForce
)
hit_factor
factor of the transmitted force (overrides enigma.BumperForce
and force
)
hit_distortion_xx, hit_distortion_xy, hit_distortion_yx, hit_distortion_yy
define a matrix to be applied to the force (default ((1,0),(0,1))
)
Variants
The invisible variant, st-actorimpulse_invisible
can be
“painted” with an it-brush.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
These stones are used to construct big clusters of stones that
visually seem like one big stone. Though mainly decorative, they also
have a small special ability, since they are the only stones that can't
be swapped with st-swap: Swap Stone or st-pull: Pull Stone (besides st-oxyd: Oxyd Stones
with true static
-attribute).
Attributes
connections
A number between 1 and 16. Each bit in (connections-1) corresponds to
an open face of the stone. You will normally simply use one of the
Lua constants PUZ_0001
to PUZ_1111
.
Variants
Two families of big stones differ in design:
st-bigbrick-<nesw>
(similar to st-brick
) and
st-bigbluesand-<nesw>
(similar to st-blue-sand
).
The term <nesw>
denotes all non-empty substrings of
nesw
, describing the directions to which the single parts are
open. Examples: st-bigbluesand-nw
is a blue stone with a border
on the south and east side, st-bigbrick-esw
is a brick-type
stone which connects to the east, south and west, and has a border on
the north side.
st-bigbrick
and st-bigbluesand
, without suffix, are not
defined. Use st-brick
and st-blue-sand
to set single
stones of these designs. Note, however, that both these stones are
swappable and pullable like normal stones.
See st-puzzle: Puzzle Stones for another kind of cluster-building stones.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
These stones only let black, or respectively, white marbles, pass.
Variants
st-black
and st-white
come in four flavors each:
st-black1
and st-white1
are not transparent at all,
…2
has a diagonal bar, …3
a cross and …4
only consists of a black or white frame.
See st-grate: Grates for other stones that only special actors may pass.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Mainly used as decorative, this stone also has a special function: When it receives a message from a stone, which is just hit by a black (or white, respectively) marble, it sends signal 1 to the neighboring stones west and east of it and 0 to north and south; or vice versa, depending on the position of the message-sending stone.
A typical construction for this is an st-blackballs
surrounded
by st-door: Doors and it-sensor, with st-blackballs
as
target of the action of it-sensor
. When in this situation a
black marble hits one of the closed doors, the door lets
it-sensor
perform its action, sending a message to
st-blackballs
. This then opens the knocked door and the door in
the opposite direction, while closing the doors in the perpendicular
directions. However, when it-sensor
triggers because of the
marble entering it, st-blackballs
won't trigger since there is no
collision causing this event.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone is movable and sinks on fl-abyss, fl-water and fl-swamp.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone shrinks to it-blocker when hit by an st-bolder: Bolder (or Arrow) Stone and vice versa.
Messages
trigger, openclose, open, close
shrink (open) / grow (close)
signal
1: shrink, 0: grow
Note that st-blocker
becomes a new object when shrinking, so
that the messages close
and signal (0)
only make sense
during transformation.
Variants
st-blocker
st-blocker-growing
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone runs in the direction given by the arrow on its picture. When a stone blocks its way, it triggers it (e.g. st-oxyd: Oxyd Stones, st-stoneimpulse: Impulse Stones), marbles are shattered.
Bolder stones fall into fl-abyss, but cross fl-water unchanged. it-magicwand and lasers reverse its direction. st-rotator: Rotator Stone changes its direction according to the rotators direction.
Attributes
direction
EAST
, NORTH
, SOUTH
or WEST
Messages
direction
Change direction to the direction in the second argument,
e.g. SendMessage(mystone, "direction", WEST)
.
Variants
st-bolder
default direction is NORTH
st-bolder-w
st-bolder-s
st-bolder-e
st-bolder-n
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When hit, st-bombs
adds an it-blackbomb to the
inventory. It can be destroyed with explosions from
it-blackbomb, it-whitebomb and other bombstones (see
Breakable-Stones). When exploding, it ignites items below it. It
also ignites it-dynamite beneath it, but not it-blackbomb
or it-whitebomb
.
Messages
expl, bombstone
destroy stone
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone can be picked up as item it-brake. It can be used to block st-bolder: Bolder (or Arrow) Stone. It destroys it-blocker and can itself be destroyed by lasers and explosions from bombs (it-blackbomb, it-whitebomb).
Messages
expl
destroy stone
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
At first sight identical with st-brick
, this stone becomes
transparent when hit with an it-magicwand.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone takes on the look of the floor beneath it. Actors can move through it, so these stones are perfect for hiding stuff under them. For solid, yet invisible stone-types see st-invisible: Invisible Stones.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When hit, the marble is provided with a constant electrostatic charge,
given by the charge
-attribute of st-charge
. The charge
is confined to be between -1.0 and +1.0. Actors with charges are
drawn together or pushed apart respectively, by a force given by
multiplication of their charges and the factor
enigma.ElectricForce
(see Old API - Variables) and divided by their
relative distance.
Attributes
charge
Variants
st-chargeplus
charge +1.0
st-chargeminus
charge -1.0
st-chargezero
charge 0.0
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When hit, a chess stone makes a knight move: two steps in direction of
the hit plus one step in direction of the vertical velocity
component. st-chess_black
can be moved only with the black
marble, st-chess_white
only with the white. When there is a
chess stone of opposite color or a thief stone (st-thief: Thief Stone) at
the target position of a knight move, this stone is destroyed.
When hit with a magic wand (it-magicwand), a chess stone changes color. Chess stones fall into fl-abyss and sink in fl-swamp, but cross fl-water undamaged. They inactivate fl-thief.
Chess stones can't jump over or into fire (see The 1.0-Fire System). 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 an st-chess_[black/white]
, in this context it
acts like an immovable stone. In the same sense, they don't act on
impulses of st-stoneimpulse: Impulse Stones or similar stones.
Attributes
color
0 for black, 1 for white
direction1, direction2
Used by the move
-message
Messages
capture
Destroy stone with capture-animation.
flip
Change color.
move_[nne, nnw, wwn, wws, ssw, sse, ees, een]
Make a knight move.
move
Make a knight move defined by the attributes direction1
(two
steps) and direction2
(one step). You can use the NORTH
,
SOUTH
, EAST
and WEST
constants for this.
Variants
st-chess_black
st-chess_white
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone is non-transparent at first and becomes transparent and
movable when hit (st-glass_move
). See st-fakeoxyda: Movable Fake Oxyd Stone for a
similar stone.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that can be activated with coins (see it-coin). The more coins you put in, the longer the switch will stay activated.
Attributes
on
as usual
target, action
as usual
Messages
on, off, onoff
as usual
signal
0: off, 1: on
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Simply kills all marbles that touch it (except when protected by an it-umbrella).
The invisible variant st-death_invisible
becomes visible while
using it-glasses.
Variants
st-death
st-death_invisible
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A passable stone, which darkens everything that is underneath the stone (much like tinted glass). Can be switched on and off (hence the name).
When lightened or darkened, this stone also lightens and darkens
neighboring st-disco
, such that the light on a passage can be
switched on and off just by sending a single message.
Messages
signal
With parameter 1, lighten the stone and (recursively) all neighboring disco stones; with parameter smaller than 1, darken them.
lighten
darken
Variants
st-disco-light
st-disco-medium
st-disco-dark
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Doors are designed to let actors pass or not, depending on their
internal state, which can be changed by triggers and other objects in
the game. There is a family of “standard doors” (referred to as
st-door
-variants) and three single variants
(st-door_a
, st-door_b
, st-door_c
), which differ
in design and behavior.
st-door
-variants let actors and laser beams pass in all
directions when they are opened, and block those perpendicular to the
doors when st-door
is closed. The other three have no
distinguished directions, they let actors and laser beams pass if, and
only if, they're open.
When an st-door
-variant is hit, the item at the door's position
performs its action/target
-pair (you can use all items for
this). There is nothing similar for the other variants.
st-door
-variants do not hold it-trigger down.
Attributes
type
h
(horizontal) or v
(vertical): only
st-door
-variants.
Messages
open, close, openclose
as they say
signal
0: close, 1: open
Variants
st-door
equals st-door-h
st-door-h
st-door-v
st-door-h-open
st-door-v-open
st-door_a
st-door_b
st-door_c
The first five all have the same design, the last three differ:
st-door_a
looks like st-oxyd: Oxyd Stones of flavor a
when
closed and like st-grate
when open, st-door_b
like
st-plain
and shrinks when opened, st-door_c
also like
st-plain
, but st-grate3
when opened. Note that this is
just design; they don't behave the same way.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In easy game mode, this stone converts the floor at its position to
fl-normal
. In normal game mode, the stone removes any item at
its position. The stone itself never appears in either game mode; it
removes itself immediately after performing its job.
This stone is commonly used to hide danger areas (water holes, abyss) or to insert helper items (umbrellas, seeds, etc.) that make the level easier in easy game mode.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone mimics an explosion when set, and destroys itself afterwards. Actors that contact it are shattered.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone looks like an st-oxyd: Oxyd Stones of flavor a
, yet it
transforms into the movable and transparent st-glass1_move
when
hit. See st-coffee for a similar stone.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The fart stone has the unpleasant habit of “blowing off” when triggered (by actor hit or signal) and will close all Oxyd stones. It can be destroyed with lasers and it-hammer, see also Breakable-Stones.
Messages
trigger
blow off
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
st-firebreak
gets destroyed when there is fire near it (see
The 1.0-Fire System). st-firebreak_move
is movable and
gets destroyed when there is fire below it, just like
st-wood: Wooden Stone. It falls into fl-water, fl-abyss and
fl-swamp (if you need it not to fall, use fl-bridge
instead).
st-firebreak
and st-firebreak_move
are the results of
st-plain
and st-plain_move
when using it-pencil on
them (see st-plain: Plain Stones), and can be reverted again by using
it-brush.
Messages
fire
st-firebreak[_move]
breaks
heat
st-firebreak
breaks
Variants
st-firebreak
st-firebreak_move
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When the flash stone is hit by the black marble, an impulse will be given to the white marble as if it had been hit itself – and vice versa, when the white marble hits the flash stone.
Attributes
hit_factor
factor of the transmitted force (default 20)
hit_distortion_xx, hit_distortion_xy, hit_distortion_yx, hit_distortion_yy
define a matrix to be applied to the force (default ((1,0),(0,1))
)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A switch that is activated by inserting a floppy disk (see it-floppy).
Attributes
on
1 or 0
target
action
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When hit, this stone visually turns its pointer and performs the
action given by the action/target
-pair.
Attributes
on
1: EAST
or WEST
, 0: NORTH
or SOUTH
action, target
as usual
Messages
trigger, signal
turn as if hit with a marble
Note that no direction
-attribute nor -message is implemented
yet. When using the direction in a level, you have to count the hits
yourself: The stone always starts with direction NORTH
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Floating grates, mainly decorative. st-grate1
and
st-grate2
block jumping marbles; all other actors may pass. In
Oxyd compatibility mode, all actors may pass.
st-grate3
lets only small marbles (ac-killerball and
ac-whiteball-small) and ac-horse pass. See
st-[black/white]: Black and white stones for other stones that let only some actors
pass.
Variants
st-grate1
st-grate2
st-grate3
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
st-invisible
is invisible and non-transparent for lasers, and
is solid, in contrast to st-chameleon: Chameleon Stone.
st-stonebrush
initially equals st-invisible
, but
turns into st-rock4
when hit with an it-brush,
respectively into st-likeoxydc-open
in Per.Oxyd compatibility
mode.
st-invisible_magic
is invisible and transparent for lasers, and
turns into st-greenbrown
when touched with it-magicwand.
Variants
st-invisible
st-invisible_magic
st-stonebrush
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When the right it-key is used on this stone, it performs the
action given by the action/target
-pair. For this, the key must
have the same keycode
-attribute as the stone.
In Enigma compatibility mode, the key remains in the stone and can't be used until removed from it. In all other modes, you keep the key.
Attributes
keycode
a numerical code determining the correct key
on
1: key used, 0: no key
action, target
as usual
Variants
st-key
keycode
is 0
st-key_a
keycode
is 1
st-key_b
keycode
is 2
st-key_c
keycode
is 3
Note that it-key
and st-key
do not match by defaults,
since the default keycodes are different. Use st-key_a
instead.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Also called “black knight stone”, this stone destroys all marbles
that hit it, as long as they are not protected by it-umbrella
or wield an it-sword. By hitting st-knight
with an
it-sword
four times, the knight stone spits out a cheeky remark
and can be passed thereafter, even without a sword.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
st-laser
emits a laser beam in a specified direction while
activated. Note that a laser stone starts deactivated, but you can
attach an on=TRUE
-attribute to it to initialize it in an
activated state.
Attributes
on
dir
direction of the laser beam (use SOUTH, EAST, NORTH, WEST
; read-only)
Messages
on, off, onoff
as usual
Variants
st-laser
standard direction is EAST
st-laser-w
st-laser-s
st-laser-e
st-laser-n
For redirecting and forking laser beams, see st-mirror: Mirror Stones.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This switch is on
while hit by a laserbeam
and off
when not hit by a laserbeam.
See also st-lasertimeswitch: Laser Time Switch.
Attributes
inverse=1
Inverts the on/off state of the switch
(i.e on
at startup and switch off
with laserbeam)
target,action
as usual
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This switch is a mix between st-laserswitch: Laser Switch and st-timeswitch: Time Switch.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 st-stoneimpulse: Impulse Stones.
The speed of the light passenger can be changed with the
interval
-attribute (default 50 ms, which is quite fast) and may
include the floor friction and local gradient via
friction_factor
(ff) and gradient_factor
(gf).
The resulting interval results as
interval = base * (1 + ff * friction) / (1 + gf * gradient) |
with base
the value of the interval
-attribute,
friction
the friction of the floor below the light passenger,
and gradient
the parallel part of the force of the floor,
i.e., the sum of gradient-force and force_x/y
-attributes.
The light passenger can be switched on and off by messages (see
below), and appears as st-glass2
when inactive. The variant
st-lightpassenger_off
is deactivated from the beginning.
When an active 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
it-hammer.
Attributes
interval
overrides the standard speed of the light passenger
friction_factor
involves friction into the speed of the light passenger (sensible: 1.0, default 0.0)
gradient_factor
involves gradients into the speed of the light passenger (sensible: 0.02, default 0.0)
Messages
onoff, on, off, trigger
trigger between activated and deactivated (= no skating)
signal
with parameter 0: deactivating, else activating
Variants
st-lightpassenger
st-lightpassenger_off
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When hit, these stones take the first item out of the player's inventory and drop it at their exit, or the exit of the appending it-pipe-structure. If this position is blocked (e.g., by another item), no item is taken from inventory.
Variants
st-mail-w
st-mail-e
st-mail-s
st-mail-n
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
These stones redirect and fork laser beams. They can be movable or non-movable, semi-transparent or non-transparent, plane or triangular, and have one of four orientations. When hit, the mirror turns 90 degrees clockwise.
Attributes
movable
transparent
orientation
Messages
trigger, turn
rotate clockwise
signal
0: do nothing, else: rotate clockwise
mirror-north, mirror-east, mirror-south, mirror-west
set orientation
Variants
There is a total of 32 mirrors, the names are constructed in the
following way: Start with st-mirror
. For a plane mirror, add
p
and one of the orientations |,/,-,\\
(the last one is
the backslash and has to be masked by doubling). For a triangular
mirror, instead add 3
and one of v,<,>,^
. For a
semi-transparent mirror, add a t
. Finally, for a movable
version, add an m
.
Or, use st-pmirror
and st-3mirror
and set the attributes
accordingly, with defaults /
or v
, non-transparent and
non-movable.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The marble can be pass this stone in only one direction. (Or to be more exact, the arrow on the stone points to the one side of the stone through which it can't be entered. Hard to explain, try it yourself :-)
There are three different variants of the one-way stone: the standard
one, st-oneway
, which both the black and the white marble can
pass, and two colored ones, st-oneway_black
and
st-oneway_white
, which completely block marbles of the other
color.
When hit with an it-magicwand, the standard st-oneway
flips its direction, the variants st-oneway_black
and
st-oneway_white
do not.
Attributes
orientation
One of NORTH
, EAST
, SOUTH
, or WEST
. This
determines the orientation of the stone when the level is loaded. You
need to use the direction
message for changing the orientation
during the game. Note that it is usually easier to use one of the
alternative names, like st-oneway-north
instead of explicitly
setting this attribute.
Messages
direction
Set the direction of the arrow during the game. Simply setting the
attribute orientation
is not enough, since this does not update
the stone's model on the screen.
signal, flip
Both these messages flip the direction of the arrow.
Variants
st-oneway
st-oneway-[nesw]
st-oneway_black
st-oneway_black-[nesw]
st-oneway_white
st-oneway_white-[nesw]
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Oxyd stones are characterized by two attributes: Their flavor and
their color. The flavor
only affects the visual representation
of the stone; it can be either `a' (opening like a flower), `b'
(displaying a fade-in animation), `c', or `d'. The color
attribute determines the color on the oxyd stone. The static
attribute declares the oxyd stone to be unswappable/unpullable (see
st-swap: Swap Stone and st-pull: Pull Stone).
Note: You should rarely need to create oxyd stones manually with set_stone. Use the predefined @ref{oxyd} function instead. It will automatically take care of creating two oxyd stones of every color.
Attributes
flavor
`a', `b', `c', or `d'
color
a number between 0 and 7
static
true
, false
(default) - static oxyds may not be swapped
or pulled
Messages
closeall
Close all oxyd stones.
shuffle
Interchange the colors of the oxyd stones in the current landscape. Better use the @ref{oxyd_shuffle} function.
trigger
Open the stone (useful for opening oxyd stones using switches)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
st-plain
and st-plain_hole
trigger between solid and
hollow when they receive a trigger
- or signal
-message.
The solid version additionally becomes st-plain_cracked
when hit
by a laser beam and can then be destroyed with an it-hammer or
explosions (see Breakable-Stones). The hollow version is
transparent to lasers. Note that st-plain_cracked
doesn't
become transparent or hollow by messages.
st-plain_move
is a movable and breakable stone (see
Breakable-Stones) that looks identical to st-plain
. It
falls into fl-abyss, fl-water and fl-swamp, but only
when moved. st-plain_move
and st-plain
can be
transformed into st-firebreak[_move]: Firebreakable Stones with it-pencil, and
get reverted by it-brush.
As st-plain
is a frequent design scheme, you might want to use
a version that doesn't transform under laser light. For this purpose,
use st-rock3
or one of the closed doors st-door_b
or
st-door_c
(see st-door: Doors). Other stones with the typical
st-plain
-design are st-chess_[black/white]: Chess (Knight) Stone and the
already mentioned st-firebreak[_move]
.
Messages
trigger, signal
switch between solid and hollow
Variants
st-plain
st-plain_hole
Note that there are more stones starting with “st-plain”, but none
of them has the ability to trigger between solid and hollow:
st-plain_move
, st-plain_breaking
,
st-plain_falling
, st-plain_break
and
st-plain-cracked
. See Breakable-Stones for them, and
st-door: Doors for stones with similar functions like st-plain
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When hit, this stone changes transparency for laser
beams. It uses the same graphics as st-glass1
and
st-glass2
. By default, it is non-transparent.
Attributes and messages are equivalent to those of switches:
Attributes
on
1 (transparent) or 0 (non-transparent)
Messages
signal
1 (lighten) or 0 (darken)
on, off, onoff
on = lighten, off = darken, onoff = toggle
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When pushed, this stone acts like pulled, regardless of the source of
the impulse. Actors on the destination field are pulled through it,
not caged under them. Hollow stones on the
position of the actor exchange their position with the pull-stone.
Note however, that the special combination of st-brake: Brake and
st-pull
is lethal for the marble.
The only stones that cannot be pulled, are
st-big[brick/bluesand]: Big Stones. Use them to make sure that an
st-pull
can't get out of a restricted area when you use, e.g.,
st-rotator: Rotator Stone or other objects that st-pull
reacts on.
In addition, you can declare st-oxyd: Oxyd Stones to be unswappable by
attribute static
.
Note that, in non-Enigma-modes, st-pull
may not get pulled into
the border of the level. This behavior might change in future
versions.
For a stone with similar function and restrictions, see st-swap: Swap Stone.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Puzzle stones can construct large clusters of stones, that move together and can be destroyed together. There are two families, blue and yellow puzzle stones, which behave different (the yellow ones are compatible to the puzzle stones in the original Oxyd-game). Each of these families again consists of several variants that differ in the location of sockets to which neighboring puzzle stones can be attached. A cluster is complete as soon as all sockets are connected to sockets of other puzzle stones of the same color.
Laser beams make all complete puzzle clusters explode. Besides this, yellow, incomplete puzzle cluster rotate on a laser beam (means: the lightened row or column rotates by one stone position). Incomplete blue clusters don't react on lasers.
If a complete cluster is moved fully onto a combination of
fl-water and fl-abyss, it becomes a bridge of
fl-gray
, similar to st-wood: Wooden Stone. An incomplete cluster
forms a bridge only on fl-water, and only if the wielded item
is not it-magicwand. Note that in contrast to st-wood
,
puzzle stones become bridges only after they are moved' they don't
react on changing the floor.
There also is a single hollow variant for each of the two colors,
st-puzzle-hollow
and st-puzzle2-hollow
. It acts as if
it had sockets to all four directions, but is still hollow. However,
these stones are the only hollow ones that press down
it-trigger.
When an actor hits:
it-magicwand
, it explodes;
it-magicwand
, it moves;
it-magicwand
, it rotates.
Note that an exploding cluster can shatter the marble.
In the current implementation, moving a puzzle stone over an item
doesn't change it. This affects, e.g., it-coin (that don't
transform), Hills and Hollows (that don't diminish),
it-blackbomb and it-whitebomb (that don't explode). Be
aware when using these items with it-puzzle
that
future implementations of Enigma might change this behavior.
Messages
scramble
Internal message used to scramble a puzzle using secondary
information; use @ref{AddScramble} and @ref{SetScrambleIntensity} to
scramble a puzzle in a level instead or make use of one of the
libraries (ant
and libpuzzle
both offer this
possibility)
Attributes
connections
A number between 1 and 16. Each bit in (connections-1) corresponds to
a socket on one of the four faces. Normally, you will simply use
one of the Lua constants PUZ_0000
to PUZ_1111
.
oxyd
0, if the puzzle stone is blue; 1, if it is yellow
(st-puzzle2-*
)
Variants
st-puzzle-hollow
blue hollow puzzle stone
st-puzzle-<nesw>
blue solid puzzle stone
st-puzzle2-hollow
yellow hollow puzzle stone
st-puzzle2-<nesw>
yellow solid puzzle stone
The term <nesw>
denotes all non-empty substrings of
nesw
, describing the directions to which there are sockets on
the stone. Examples: st-puzzle-nw
is a blue puzzle stone with
connections going north and west, st-puzzle2-esw
is a yellow
puzzle stone with connections to the east, south and west.
See st-big[brick/bluesand]: Big Stones for other kinds of cluster-building stones.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Rotator stones come in four flavors: Clockwise or counterclockwise
rotation, and movable or not movable. They send impulses to
neighboring stones, thus pushing them in the direction given by the
rotation. st-bolder: Bolder (or Arrow) Stone additionally change their direction to the
one they are pushed to. st-rotator
changes direction when hit
with an it-wrench or by a laser beam.
Variants
st-rotator-right
st-rotator-left
st-rotator_move-right
st-rotator_move-left
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If hit by a marble, this stone first removes existing connections with other stones, then attaches a new elastic between the marble and itself. Nothing happens if the marble was already attached to this particular stone.
This stone can be moved if hit with a magic wand.
Attributes
length
The natural length of the rubberband (default: 1)
strength
The strength of the rubberband (default: 10)
minlength
The minimal length of the rubberband (default: 0)
scissor
Boolean value defining if already existing rubberbands to other Stones should be cut off. (Default: true)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone cuts all rubber bands 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.
Attributes
target, action
as usual
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
These stones come in three basic variants: small (s
), medium
(m
) and large (l
). The smaller ones can be pushed into
bigger ones, forming combined forms denoted by combinations of s
,
m
and l
. When hit, these combined stones split again
into the smaller ones.
The shogun stones trigger shogun items (see it-shogun): A
single st-shogun-s
triggers it-shogun-s
, a combined
st-shogun-sm
triggers it-shogun-m
, and the triplet
st-shogun-sml
triggers it-shogun-l
.
Shogun stones don't ignite bombs when pushed over them.
st-shogun-s
is handled differently in a Freeze Checking than
the other shogun stones. This allows to use st-shogun-s
to use in a
Sokoban and avoids false freeze checks when used together with other shogun
stones (which are handled as non-existent during a freeze check).
Attributes
holes
between 1 and 7 (the three lower bits), used internally, thus read-only
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When hit, an it-extralife from the inventory of the hitting
marble is transformed into a cannonball (ac-cannonball) which
can open st-oxyd: Oxyd Stones, destroy items and floor tiles (replacing them
by fl-abyss). You can vary the initial velocity of the cannonball
by using the hit_factor
- and
hit_distortion_*
-attributes.
Attributes
hit_factor
factor of the transmitted force (default 1.0)
hit_distortion_xx, hit_distortion_xy, hit_distortion_yx, hit_distortion_yy
define a matrix to be applied to the force (default ((1,0),(0,1))
)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
These stones send impulses to their neighbors when they receive such themselves, or when hit by a laser beam (only when the laser beam is turned on or changed, not the entire time).
Messages
trigger
Pulse as if pulse arrived from direction given in the second argument to
SendMessage (like in SendMessage(mystone, "trigger",
NORTH
). Use NODIR
if no direction shall be assumed.
signal
0: do nothing, else: start pulsing
Variants
st-stoneimpulse
st-stoneimpulse-hollow
not activated by lasers; blocks laser and may shatter actors while pulsing
st-stoneimpulse_movable
movable version; pulses after move
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When hit, this stone randomly transforms into one of st-grate1
,
st-death
, st-glass1_hole
, st-magic
,
st-knight
, st-thief
, st-plain_break
,
st-plain_breaking
, or another st-surprise
(see st-grate: Grates, st-death: Skull Stones, Oxyd Compatibility Stones,
st-knight: Knight Stone, st-thief: Thief Stone, and Breakable-Stones). The corresponding
item is it-surprise.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone can exchange its position with other neighboring stones if it is hit hard enough. In a way, this makes swap stones a kind of “movable stone”, except that they can be exchanged only with other stones and may not be moved on empty fields.
The only stones that cannot be swapped, are
st-big[brick/bluesand]: Big Stones. Use them to make sure that an
st-swap
can't get out of a restricted area. In addition, you
can declare st-oxyd: Oxyd Stones to be unswappable by attribute
static
.
Note that, in non-Enigma-modes, st-swap
may not swap into the
border of the level. This behavior might change in future versions.
For a stone with similar function and restrictions, see st-pull: Pull Stone.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A simple switch.
Attributes
on
1 (activate) or 0 (inactive)
target, action
as usual
Variants
st-switch
All kinds of objects can activate this switch.
st-switch_black
Only black marbles can activate this switch.
st-switch_white
Only white marbles can activate this switch.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Takes one item from inventory shortly after hit by a player's marble. it-umbrella protects against thievery.
Thief stones can be destroyed with chess stones (st-chess_[black/white]: Chess (Knight) Stone). They then leave an it-bag behind, filled with the stolen items. If the tile is already occupied by an item that could be picked up, it is added to the bag, if the item couldn't be picked up, no bag is produced (you can use this to suppress bag generation).
Compare with fl-thief
(fl-thief).
Messages
capture
Destroy the thief stone with capture-animation (as if captured by a chess stone).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone can be used to trigger periodic events or to trigger one
single event after a certain amount of time. When triggering, it
performs its action/target
-pair, the second data is 1 for every
odd activation, and 0 for every even one.
Attributes
on
1 if the timer is running (default: 1)
interval
number of seconds before action
is performed (default: 1.0)
loop
If true
, restart the timer after performing action
, stop
on false
. Note: This argument doesn't work in Enigma 1.01 or
older. (default: true
)
action, target
as usual
invisible
if 1, stone is invisible (default: 0)
Messages
on, off, onoff
as usual
signal
0: off, 1: on
Example
-- activate a laser after 5 seconds set_stone("st-laser", 10,11, {name="laser"}) set_stone("st-timer", 10,10, {loop=0, action="onoff", target="laser", interval=5}) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When this switch is touched by an actor, it switches on
for 1.8 seconds and then switches off
again.
See also st-lasertimeswitch: Laser Time Switch.
Attributes
delay
The delay in seconds after which the switch goes off
.
inverse=1
Inverts the on/off state of the switch.
action, target
as usual
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A turnstile consists of the pivot (st-turnstile
or
st-turnstile-green
) and up to four arms
(st-turnstile-[w/e/s/n]
). When hit by an actor or by another
impulse (e.g., st-lightpassenger: Light Passenger or st-stoneimpulse: Impulse Stones), the
whole complex turns 90 degrees. The red standard version takes only
the actor hitting the turnstile, with it to the other side and shatters all
others in its surrounding; the green version takes all actors to the other
side, for which there is an arm behind them, and ignores the rest. Imagine the
red turnstile as pulling, the green one as pushing.
The turnstile may be blocked by other stones (even movable ones). Items are handled during rotation as if a stone is pushed over them.
When a turnstile-pivot rotates, it subsequently performs its
action/target
-pair, with secondary data 0 if it rotates
clockwise, 1 if counterclockwise. If you send a signal to a pivot (or
otherwise try to rotate it) that is already rotating, the signal
will be discarded. This way you can concatenate several turnstiles to
a complex, which simultaneously rotates (or only in certain parts),
without constructing an endless loop.
When two green turnstiles are intertwined, one of them is hit and an actor would be transported between them, then the second turnstile will be hit, too.
When an actor is to be warped outside of the level by a turnstile (which only happens with a green one directly at the levelborder), the actor is shattered instead of warped. This is the only case in which a green turnstile is able to shatter a marble.
Messages to the pivot
signal
0: rotate clockwise, 1: rotate counterclockwise
Variants
st-turnstile
st-turnstile-green
st-turnstile-e
st-turnstile-s
st-turnstile-n
st-turnstile-w
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone duplicates itself and spreads out very fast. During one
“life-cycle”, it starts as it-seed_volcano
(see
it-seed), grows as st-volcano-growing
(during which it
shatters nearby marbles), becomes st-volcano_active
when
mature, spreads new it-seed_volcano
on neighboring tiles and
becomes inactive after some random time period.
Seeds are spread to randomly chosen neighboring tiles on which are no other stones. Other items are destroyed by this.
While active (not while growing or while inactive), a volcano stone can be broken with it-hammer (see Breakable-Stones).
Messages
trigger
Makes an inactive stone active again.
Variants
st-volcano
starts inactive
st-volcano-growing
st-volcano_active
st-volcano_inactive
See also it-seed.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Hit this window hard with your marble to blast it into smithereens.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This stone is movable. If moved into fl-abyss, fl-water or
fl-swamp, it builds a wooden plank (fl-stwood1
or
fl-stwood2
). In Oxyd 1 compatibility mode st-wood
only
checks for floor when it is moved or when it receives the message
“fall”.
Note: There are two flavors of st-wood
that you may specify
by using st-wood1
or st-wood2
.
st-wood-growing
is a growing version of st-wood
, it
results from using a particular it-seed.
st-flhay
and st-flrock
are movable, too, and create
fl-hay
, respectively fl-rock
, when moved into
fl-abyss
, fl-water
or fl-swamp
. The difference
to st-wood
is that fl-hay
doesn't become fl-abyss
when burning and fl-rock
doesn't burn at all.
When there is fire under st-wood
or st-flhay
, they burn
away. In contrast to this, st-flrock
extinguishes fire as it
is pushed over it (see The 1.0-Fire System). This distinguishes
it from all other movable stones. Fire that is extinguished in this
way might leave it-burnable_ash
behind, but the floor does not
fire-transform.
Variants
st-wood
st-wood1
st-wood2
st-wood-growing
st-flrock
st-flhay
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Yin-Yang stones change into st-white1
or st-black1
if you touch them (see st-[black/white]: Black and white stones).
Actors get stuck inside the Yin-Yang Stone if they are starting there or when they warp there. They can be freed by changing the color of the Yin-Yang Stone to their color.
Variants
There are several flavors of this stone:
st-yinyang1
If touched, it changes it's color to the opposite color of your marble.
st-yinyang2
If touched, it changes it's color to the same color as your marble.
st-yinyang3
The Per.Oxyd compatible: You must hold it-magicwand or it-brush to change the color to the color opposite of your marble.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
10.1 Actor Attributes | Common attributes of actors | |
14.4.2 ac-blackball | Black Marble | |
14.4.3 ac-bug | Bug | |
14.4.4 ac-cannonball | Cannonball | |
14.4.5 ac-horse | Horse | |
14.4.6 ac-killerball | Small killer marble | |
14.4.7 ac-rotor | Rotor | |
14.4.8 ac-top | Spinning Top | |
14.4.9 ac-whiteball | White Marble | |
14.4.10 ac-whiteball-small | Meditation Marble |
Movable objects are called “actors” in Enigma. The most common actor is, of course, the black marble, but there are others, including the white marble, the killerball and a few more:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
All actors share a set of common attributes that determine their general behavior:
player values: 0, 1, nil; default: nil
The player “owning” this actor. This is either 0 or 1 for the first
or second player respectively. Actors attached to a player can pick
up items and can be respawned when they are killed (same player means
same inventory). Note: The controllers of the marble are given by the
controllers
-attribute
mouseforce values: float; default: 1.0
A factor that determines how much the actor accelerates when the mouse is moved. Default is 1, use higher values for fast moving actors. If set to 0, the actor cannot be moved with the mouse (but external forces can still exert a force on it).
controllers values: 0, 1, 2, 3
Determines which players may move this actor: 1=Player 0, 2=Player 1,
3=both, 0=none. By default, ac-blackball
, ac-whiteball
and
ac-whiteball-small
have their controllers
attribute set
to 1, 2, and 3 respectively. Use value 0 if you want a passive actor.
essential values: 0, 1, -1
Describes the necessity of an actor to be alive in case of multiple actors being attached to a player. A value 0 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 -1 marks an actor as totally necessary. If such an actor cannot be resurrected after a death, the player is essentially dead. A value of 1 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 1. For example, marking 3 out of 5 small whiteballs with 1 means that the player is dead if 3 small whiteballs are no longer alive. See Old API - Variables ‘enigma.ConserveLevel’ for more details about restart of levels.
essential_id values: string; default: model name of actor
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.
whiteball, blackball deprecated
TRUE
or FALSE
. Used by color-sensitive stones
(black/white switches for example) to determine whether the actor is
the black or the white marble. These attributes may disappear in
future versions, please do not use them.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This is the most common actor.
Attributes
mouseforce (default 1.0)
color (default 0.0)
blackball (default 1)
player (default 0)
controllers (default 1)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A small, passive marble. It can be used to break st-bug
(see
Breakable-Stones), to pass st-grate3
(see st-grate: Grates)
to open oxyds, etc. It can't shatter or die.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Used by st-spitter: Spitter Stone as a cannon ball. Don't use in levels.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A slightly larger actor that shuttles between the targets given in
its target1
- to target4
- attributes with a given
force
. In future versions, it's planned that marbles can ride
ac-horse
to surpass fl-abyss, fl-water etc.
ac-horse
can pass st-grate3
(see st-grate: Grates), open
oxyds and much more, without shattering or dying.
Attributes
force (default 10.0)
target1
target2
target3
target4
Example
The syntax of the target
-attributes is a little bit
uncommon. Here is an example from the meditation ral04_1
:
set_actor("ac-horse",16.5, 6.5, {force=6, target1="16 3", target2="3 3", target3="3 9", target4="16 9" }) |
The attribute consists of a string, holding the x- and y-coordinates,
separated by a blank. The ac-horse
in the example shuttles
between the coordinates (16,3), (3,3), (3,9) and (16,9) on a
rectangular route. Note that only four targets are allowed at
the moment.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A small marble, mostly controlled by the player, which shatters other marbles.
Attributes
mouseforce (default 2.0)
color (default 1.0)
whiteball (default 1)
controllers (default 3)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An actor that is actively attracted by marbles and shatters them. Compare ac-top.
Attributes
range (default 5.0)
force (default 10.0)
gohome (default 1)
attacknearest (default FALSE)
in case of multiple balls, the default behavior for rotors is to attack the center of all balls. If this flag is set to ‘TRUE’, the nearest ball will be attacked.
prefercurrent (default 0.0)
with values from 0.0 to 1.0 the likelihood is expressed that the rotor hunts the current controlled ball instead of the otherwise attacked aim. You will usually use this attribute in combination with ‘attacknearest=TRUE’. The Level ‘Toreador’ is an example of the behavior of rotors.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An actor that is actively attracted by marbles and shatters them. Compare ac-rotor.
Attributes
range (default 5.0)
force (default 10.0)
gohome (default 1)
attacknearest (default FALSE)
in case of multiple balls, the default behavior for rotors is to attack the center of all balls. If this flag is set to ‘TRUE’, the nearest ball will be attacked.
prefercurrent (default 0.0)
with values from 0.0 to 1.0 the likelihood is expressed that the rotor hunts the current controlled ball instead of the otherwise attacked aim. You will usually use this attribute in combination with ‘attacknearest=TRUE’. The Level ‘Toreador’ is an example of the behavior of rotors.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This marble is mostly played by another player or via it-yinyang.
Attributes
mouseforce (default 1.0)
color (default 1.0)
whiteball (default 1)
player (default 1)
controllers (default 2)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This is the meditation marble. In meditation levels, you must place
them in it-hollow
or it-tinyhollow
to win the level,
see Hills and Hollows.
Attributes
mouseforce (default 1.0)
color (default 1.0)
whiteball (default 1)
controllers (default 3)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
name
All objects may be given a name
attribute. Such named objects can
be searched using enigma.GetNamedObject.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The 1.0-version of Enigma introduces 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 fl-hay
or fl-wood1
), by
attribute (setting enigma.SetAttrib(myfloor, "burnable", TRUE)
),
or by one of two items that indicate burnability: the invisible
it-burnable
and the visible it-burnable_oil
. On a
burning floor, all items are destroyed. However, some items prevent the
floor from burning, like it-hollow
(see Hills and Hollows) or
it-dynamite (which is ignited instead).
Fire can be ignited in several standard ways:
setfire
-message sets fire to a floor if it is
burnable and the item on it allows it to burn; non-burnable items like
it-dynamite
are not ignited by this!
heat
-message ignites burnable floors as does
setfire
, but also initiates a heat-transformation of the floor
(see below) and ignites items on it.
ignite
and expl
-messages that are used by
it-dynamite
, it-blackbomb and it-whitebomb can
initiate fire via it-burnable[_oil]
or if the
ignitable
-attribute of the floor is set (off by default).
initfire
-attribute is set (off by default).
If needed, the forcefire
-message can be used to set fire to
non-burnable floors. Internally, it is equivalent to manually setting
it-burnable_ignited
, the last method (which was quite famous in
0.92) should be avoided in future, to allow a further development of
the fire-system.
Fire does the following:
st-firebreak
: beneath it).
it-dynamite
, it-blackbomb
, it-whitebomb
and
it-crack.
Fire stops burning after a random amount of time, as long as the
eternal
-attribute of the floor is not set. When it stops
burning, it might replace the floor by another kind
(“fire-transform”), this is: Wooden floors are replaced by
fl-abyss, leaves are replaced by fl-dunes
. Finally, it
puts it-burnable_ash
on the floor, which prohibits a second
fire and which can be removed with it-brush. However, ash is not
set if the floor is fl-abyss
or the noash
-attribute is
set.
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. In 1.0, these can be assured by setting the
secure
-attribute: When a burnable floor with
secure
-attribute is near fire, it will eventually catch fire,
items on it are ignited, etc.
In 0.92, there were two speeds of fire: When using it-burnable
,
fire spread much faster than without. This is still the same in
1.0. However, you can set the fastfire
-attribute to hasten
the fire without setting the invisible it-burnable
.
Fire that burns under a stone is not allowed to spread; the only exceptions are floating stones (as st-grate: Grates), and those stones that are destroyed by fire anyway (see st-wood: Wooden Stone-variants and st-firebreak[_move]: Firebreakable Stones). In contrast to this, fire might also spread to under a movable stone, but not further.
You can stop fire with it-extinguisher
, which creates the
fireproof it-burnable_fireproof
. Another way to stop fire is to
push the totally inert st-flrock
(see st-wood: Wooden Stone) 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 stopfire
-message to a
floor, which works the same way as st-flrock
.
Compare with Fire and Extinguisher.
Heat-Transformations
When a fire starts to burn near fl-ice, it melts to
fl-water. In the same sense, fl-water
boils to
fl-swamp, and this again to 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.
Examples: Put an st-flrock
on fl-ice
. A fire will melt
the ice, and st-flrock
creates a fireproof and safe way to the
other side. If you use st-wood: Wooden Stone instead, fl-stwood
is
created, which presumably catches fire and leaves fl-abyss
behind. A similar combination is fl-water
with
st-chess_[black/white]: Chess (Knight) Stone.
If you want to suppress this transformation, you can switch to a non-Enigma-compatibility-mode, see the following section.
Differences between 1.0 and 0.92
The old fire system of Enigma versions up to 0.92, differs from the 1.0 version mainly in the following points:
fl-[st]wood
to fl-abyss
it-burnable
and it-burnable_oil
themselves) on an
non-burnable floor won't catch fire, in 0.92 it did.
A good model of the 0.92-system can be attained via the compatibility-modes: All non-Enigma-modes (see Differences between Compatibility Modes and <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.
Burnable and Fireproof Floors
The following floors are fireproof (they don't burn by default):
fl-abyss*, fl-ac*, fl-black, fl-brick, fl-bridge*, fl-bumps,
fl-concrete, fl-dummy, fl-dunes, fl-gradient*, fl-gravel, fl-gray,
fl-himalaya, fl-ice*, fl-inverse, fl-inverse2, fl-darkgray, fl-metal*,
fl-mortar, fl-normal*, fl-rock, fl-sahara, fl-sand, fl-space*,
fl-springboard, fl-stone, fl-swamp, fl-water, fl-white
The following floors are burnable: fl-bluegray, fl-bluegreen*,
fl-hay, fl-light, fl-lightgray, fl-marble, fl-red, fl-rough*,
fl-tigris, fl-woven*, fl-trigger
The following floors are burnable and leave fl-dunes
behind:
fl-leaves*
The following floors are burnable and leave fl-abyss
behind:
fl-floor_001, fl-plank, fl-samba*, fl-stwood*, fl-wood*
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 (it-burnable,
it-burnable_oil, it-dynamite, it-blackbomb, it-whitebomb, it-crack*
)
and some items that are completely fireproof. These are:
it-hollow, it-tinyhollow, it-hill, it-tinyhill, it-vortex*,
it-burnable_fireproof, it-burnable_ash, it-extinguisher,
it-extinguisher_medium, it-abyss
, all items of section System and Debug Items (it-[1/2]pkillstone, it-bridge-oxyd*,
it-debris, it-dummy, it-easy[kill/keep]stone, it-explosion*,
it-oxyd5f, it-signalfilter[0/1]
) and the fire animations themselves:
it-burnable_ignited
and it-burnable_burning
.
Note that it-extinguisher_empty, it-trigger
(visible and
invisible), it-landmine
, it-changefloor
and
it-death
are passively burnable. In particular,
it-landmine
does not explode or create
it-hollow
when burning. The reaction of it-sensor and
it-inversesensor
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 fl-sand
or fl-rock
below it. This
normally is the case when using it-[h/v]strip and
it-changefloor. However, you can use the
burnable
-attribute in these cases to force burnability of the
floors.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 st-death: Skull Stones, 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 freeze_check = true
which is pushed onto a floor with
attribute 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 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 freeze_check
-attribute activated.
The freeze check recognizes three basic constellations of stones that lead to a
freeze of a standard movable stone. With B
as box (movable or
persistent) and #
as wall (persistent):
BB #B #B BB # B# |
There are more freeze constellations which are not recognized, the simplest would be:
#B BB # |
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 not existent), it doesn't recognize when you put an it-puller, it-cherry, or st-swap: Swap Stone in your level. It handles special stones in a way to minimize false-positive freeze checks.
Floating stones (like st-grate: Grates) create completely new frozen
constellations. From the following two examples, only the right example is
frozen (G
is st-grate1
):
G G BB BB GB GBG |
At present, none of these are recognized as frozen by Enigma, floating stones are considered as not existing during a freeze check. To demonstrate the difficulty, you may analyze yourself which of the following constellations is frozen:
G G GBG GB# G G#G B# BBB BB GB G BBBBB G #B B# #B G G#G G G G G |
In some cases, stones are even handled differently although they have similar
properties: st-wood: Wooden Stone and st-firebreak_move
(see
st-firebreak[_move]: Firebreakable Stones) are both movable and both destroyed by fire (see
The 1.0-Fire System). There would never be frozen stones, as they can
easily be burned away. Yet, st-wood
uses the default freeze checking,
whereas st-firebreak_move
is considered as not existing. This is because
st-wood
is often used without fire, whereas st-firebreak_move
is
primarily used in combination with fire.
Another example is st-shogun-s
, which is considered as a default
movable stone, in contrast to the remaining shogun stones (see
st-shogun-<sml>: Shogun Stones). This way you can use st-shogun-s
with goal
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.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Although Enigma was inspired by the original Oxyd-series, there are some differences between the current Enigma engine and the Oxyds as well as between the Oxyds themselves. Using the compatibility-section of the xml-metadata (see <compatibility>) or the enigma.SetCompatibility-function, it's possible to activate some of these behaviors. Here's a list of the currently implemented differences, not all of them are mentioned at the corresponding sections above:
All non-Enigma modes (oxyd1, per.oxyd, oxyd.magnum, oxyd.extra)
st-plain[_move]
into st-firebreak[_move]
.
oxyd1
-compatibility
fl-stwood
under st-grate1
(st-grate: Grates), not to st-wood: Wooden Stone.
st-grate1
and st-grate2
(see st-grate: Grates).
ignite
-message (e.g. by it-dynamite) doesn't
kill it-document.
oxydmagnum
-compatibility).
per.oxyd
-compatibility
st-stonebrush
(see
st-invisible: Invisible Stones) becomes st-likeoxydc-open
instead of
st-rock4
.
oxyd.magnum
-compatibility
fl-stwood
under st-grate1
(st-grate: Grates), not to st-wood: Wooden Stone.
oxyd1
-compatibility).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This chapter describes a few variables that you can change from level descriptions to alter the behavior of the game engine or set default attributes for some particular objects, or that carry interesting information about the context of the level. In the second case, you can usually achieve the same effect by setting the corresponding object attributes directly, but being able to specify a global default value often is more convenient. You can always override these default attribute values for specific objects by setting the appropriate object attributes.
TRUE
, FALSE
; default: TRUE
The conserve mode determines if a dead actor will be resurrected in case of extralives in the gamer's inventory.
If TRUE
, dead actors attached to a
player will be resurrected as long as extralives are available. If a player has
no living actor to control or is missing the actor's essential constraints
(see section Actor Attributes), the
player is dead. The level may still continue if a second player is alive. If
the gamer has a 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 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 extralives, and the level is restarted without
finishing the level game.
Use FALSE
if the level cannot be solved in case of resurrected actors.
In all other cases, mode TRUE
with proper usage of actors essential
constraints will be preferable (see section Actor Attributes).
TRUE
or FALSE
, read-only. Use this in a
level to determine whether it is just loaded to build a thumbnail. If so, you can,
e.g., change the start-position of ac-blackball 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 follow-mode to smooth (display.SetFollowMode):
if enigma.CreatingPreview then display.SetFollowMode(display.FOLLOW_SMOOTH) else display.SetFollowMode(…) end |
A value between 0 and 1, denoting the probability that a brittle floor plate disintegrates further when an actor enters or leaves it. 1 means that the floor will always crack, 0 that it is indestructible (see it-crack). Default: 0.5.
The amount of force applied to an actor that hits an st-actorimpulse: Bumper Stones stone. Default: 200.0.
A force multiplier for all electric forces between actors, see st-charge: Charge Stones. Default: 15.0.
All friction forces are multiplied by this value. Default: 1.0.
A global downward force. This is currently only applied on floors of
type fl-space-force, and obsolete since introduction of the
force_[x/y]
-attributes. Default: 0.
Friction of fl-ice is multiplied with this constant. Default: 1.0.
A force factor that affects the steepness of hollows and hills (see Hills and Hollows). Default: 1.0.
A force multiplier for magnetic fields (see it-magnet). Default: 30.0.
The range of magnetic fields (see it-magnet). Default: 10.0.
TRUE
or FALSE
. This is preferably used in Sokoban
levels to display a move counter in the inventory.
Default: FALSE
.
A force multiplier for sloped floor tiles (see fl-gradient). Default: 25.0.
How quickly balls sink in fl-water. Default: 1000.0.
How quickly balls sink in fl-swamp. Default: 4.0.
A force multiplier for it-wormhole. Default: 30.0.
The range of it-wormhole. Default: 10.0.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
16.1 AddRubberBand | Creating rubber bands | |
16.2 CreateWorld | Create the Level | |
16.3 display.SetFollowMode | Sets the follow mode | |
16.4 draw_border | Drawing a border of stones | |
16.5 draw_checkerboard_floor | Draws a checkerboard | |
16.6 draw_floor | Draws a line of floortiles | |
16.7 draw_items | Draws a line of items | |
16.8 draw_stones | Draws a line of stones | |
16.9 enigma.AddConstantForce | Add a constant force | |
16.10 enigma.GetAttrib | Get an objects attribute | |
16.11 enigma.GetNamedObject | Get an objects name | |
16.12 enigma.GetKind | Get an objects kind | |
16.13 enigma.KillFloor | Kills a floortile | |
16.14 enigma.KillItem | Kills an item | |
16.15 enigma.KillStone | Kills a stone | |
16.16 enigma.LoadLib | Loading a not preloaded library | |
16.17 enigma.NameObject | Set the name of an object | |
16.18 enigma.SetAttrib | Set an attribute of an object | |
16.19 enigma.SetAttribs | Set multiple attributes of an object | |
16.20 enigma.SetDefaultAttribs | Set default attributes | |
16.21 enigma.SetCompatibility | Compability of a level | |
16.22 fill_floor | Fills a rectangle with a floortile | |
16.23 fill_items | Fills a rectangle with an item | |
16.24 fill_stones | Fills a rectangle with a stone | |
16.25 MakeObject | Creates an object | |
16.26 SendMessage | Sending messages to objects | |
16.27 set_floor | Set a single floortile | |
16.28 set_item | Set a single item | |
16.29 set_stone | Set a single stone | |
16.30 set_stones | Set a list of stones | |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function connects two objects with a rubber band: The first object is always an actor, the second object can be either another actor or a stone.
The first argument actor is always a reference to an actor
created earlier with the set_actor
function. The second
parameter object may be either an actor or a stone created
earlier. The last two parameters define the properties of the rubber
band: strength denotes the force factor of the elastic, and
length denotes its natural length. No force is exerted on the actor if
the rubber band is shorter than its natural length.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
local ac=set_actor("ac-blackball", 1.5,7.5) local st=set_stone("st-brownie", 10,6) AddRubberBand(ac, st, 50, 10) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function creates a new level. Because objects can be added
to the level only after CreateWorld
has been called,
you should usually do so near the beginning of your level
description.
The width and height denote the size of the new level. All levels with only one screen have the minimum size of 20x13 blocks.
Note that level fields are indexed from zero, i.e., the field indices for a 20x13 level are in the range (0..19)x(0..12). Also note that the screens in Enigma overlap by one line or column: A level that fits on a single screen has size of 20x13, but two a level that is two screens wide 39x13 or 20x25, three screens 58x13 or 20x37.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function sets the followmode of a level. The followmode defines the behavior of the landscape if a level is bigger than one screen.
Possible values are:
Don't follow any sprite.
Scroll the screen.
Flip the screen region.
Scroll to the next screen.
Follow pixel by pixel.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function adds a border of stones to your level. If invoked with only one argument, this border encloses the whole level.
The name of the border stone.
(optional) Coordinates of upper-left corner. (0,0) if omitted.
(optional) Width and height of border.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
draw_border("st-marble") draw_border("st-greenbrown", 0,5,3,3) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function draws checkerboard composed of two selected floor types. name1 and name2 are names of floor objects. See set_floor for further details.
Names of floor objects
Location of left top corner of checkerboard area. Note that upper left map corner is [0,0].
Size of generated checkerboard.
Table of attribute names and corresponding values:
{attrib1=value1, attrib2=value2, …}
. These attributes,
together with default attributes, are passed to each tile of the
generated checkerboard.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
draw_checkerboard_floor("fl-abyss", "fl-rough", 2, 2, 23, 11) draw_checkerboard_floor("fl-normal", "fl-inverse", 0, 0, levelw, levelh) -- racetrack |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: Use this function to add several floor objects to your level at periodic distances. How does it work? At first it places the floor to location. Then it moves by increment, and again places the given floor. And again and again – as many times as defined by count.
Name of floor object.
This is Lua table with two elements: {x,y}. They represent the location of first floor object
{dx,dy}. dx is the increment per step in x-axis, dy is increment per step in y-axis. Often this function is used to add a row of floors in one direction, then Increment looks like this: {1,0} or {0,1}.
Number of steps to proceed.
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}. It represents the attributes to be passed to each created floor. You can omit this argument.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
draw_floor("fl-abyss", {3,0}, {0,1}, level_height) draw_floor("fl-gradient", {15, 5}, {1,0}, 4, {type=1}) draw_floor("fl-water", {level_width-4,3}, {0,1}, level_height-6) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function adds several item objects to your level at periodic distances. It works much like draw_floor, except that it adds items instead of floors.
Name of item object.
This is Lua table with two elements: {x,y}. They represent the location of first item that you want to add to map.
{dx,dy}. dx is the increment per step in x-axis, dy is increment per step in y-axis.
Number of steps to proceed.
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}. It represents the attributes to be passed to each created item. You may omit this argument.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
draw_items("it-trigger", {3,3}, {2,0}, 8) draw_items("it-tinyhill", {5,3}, {2,0}, 7) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function adds several stones to your level at periodic distances. It works much like draw_floor, except that it adds stones instead of floors.
Name of stone object.
This is Lua table with two elements: {x,y}. They represent the location of first stone to be placed to map.
Another Lua table with two elements: {dx,dy}. dx is the increment per step in x-axis, dy is increment per step in y-axis.
Total number of stones to add.
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}. It represents the attributes to be passed to each created stone. You may omit this argument.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
draw_stones("st-grate1", {9,1},{0,1}, 5) draw_stones("st-stone_break", {21,1}, {1,0}, 10) function draw_border(stonename, x0, y0, w, h) draw_stones(stonename, {x0,y0}, {1,0}, w) draw_stones(stonename, {x0,y0+h-1},{1,0}, w) draw_stones(stonename, {x0,y0}, {0,1}, h) draw_stones(stonename, {x0+w-1,y0},{0,1}, h) end |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Adds global gravity to the current level.
adds gravity in horizontal direction (positive means rightwards).
adds gravity in vertical direction (positive means downwards).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: The function is similar to SetAttrib, except that it doesn't set the attribute, but returns current attribute value. Function arguments have the same meaning as in SetAttrib, see its description. Also note GetKind.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
local bolder_dir = GetAttrib(bolder1, "direction") |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function searches for an object that has a name
attribute
with value objname. It returns a reference to the object or
nil
if none could be found.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
set_stone("st-wood", 7, 11, {name="woodie"}) … local Woodie = enigma.GetNamedObject("woodie") |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function returns the kind of an object.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
set_stone("st-wood", 7, 11) … local mystone=enigma.GetStone(7,11) local mystonetype = enigma.GetKind(mystone) mystonekind will be "st-wood" |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Kills the floor tile at position (x,y).
Coordinates of the floortile to kill.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Kills the item at position (x,y).
Coordinates of the item to kill.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Kills the stone tile at position (x,y).
Coordinates of the stone to kill.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function loads a Lua level library that has previously been declared in <compatibility> at a given point of code execution. If the library is declared with ‘el:preload="true"’, no Lua function call is necessary. The libraryId is the same as in the declaration.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: Gives the name value to object.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: The function sets the given attribute of a given object to a given value. If you try to pass an unknown attribute to an object, Enigma will ignore it (i.e., the value is assigned, but nothing special happens).
The variable that holds the object. Every function that creates an object returns the variable representing the freshly added object. That's right, what should be passed to SetAttrib. (See example.)
Name of the attribute. See the description of objects to learn which object knows what attributes.
New value of attribute.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
local ls = set_stone("st-laser", 1, 4, {on=FALSE, dir=NORTH}) set_attrib(ls, "name", "laser") -- (also "on" and "dir" are attributes in this example) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function sets several attributes at a time. The only thing it does is to call SetAttrib as many times as needed to set values of all desired attributes.
Value that holds the object, whose attributes are about to change.
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
local ls = set_stone("st-laser", 1, 4, {on=FALSE, dir=NORTH}) … (some lua code) … set_attribs(ls, {on=TRUE, dir=WEST}) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: Use this function if there are several objects of same kind, which have attributes (all or just some) with the same value. For example, if there are twenty wormholes with strength of 10, you can set the strength of 10 as a default value for all wormholes.
Notes: Default attributes can be overridden or several extra attributes can be assigned to an object. The attributes specified at creation time (using set_floor, set_item, set_stone functions) override the default attributes specified by SetDefaultAttribs.
item. In most cases, this is a wormhole, because it's usual to have several wormholes with the same strength and range, while it's not very common to have, for example, all doors vertical or all bolders facing west.
Table of keys and corresponding values: {attrib1=value1, attrib2=value2, …}
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
SetDefaultAttribs("it-wormhole", {range=1.0, strength=10}) set_item("it-wormhole", 11, 6, {targetx="48.5",targety="56.5"}) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function sets the compatibility of a level. Because certain objects may have a different behavior in the original Oxyd games, a compatibility mode exists for each game. Enigma itself has also a compatibility mode, it's the default.
Note: This function is deprecated. Set the compatibility information in the xml-node <compatibility> instead.
Possible values for compatibility are:
Oxyd1-mode
Per.Oxyd-mode
OxydMagnum-mode
Oxydextra-mode
Enigma-mode
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
fill_floor (floorname, x, y, w, h)
Description: This function fills an area of map with a selected floor type.
Name of the floor object. If this is the only argument to the function, the whole map area is filled with this kind of floor.
Coordinates of upper left corner of filled area. Note that the upper left square of map is at coordinates [0,0]. If those arguments are omitted, zero is passed instead.
Size of the filled area. If any of these arguments is omitted, level width or height respectively is passed by default.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
fill_floor("fl-space", 0,0, level_width,level_height) -- these two lines fill_floor("fl-space") -- do the same fill_floor("fl-gray", 1, 1, level_width-2, level_height-2) fill_floor("fl-water", 24,47, 11,1) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function fills an area of the map with items of a selected kind.
Note: Please note that in contrast to function fill_floor, this function doesn't have any default attributes, and no parameter may be omitted.
(strange, no one ever used this function in their map ....)
Name of item object.
Coordinates of the upper left corner of the filled area. Note that the upper left square of the map is at coordinates [0,0].
Size of the filled area - w is width and h is height.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
fill_items("it-wormhole", 1, 1, 3, 3) -- field of 3x3 wormholes |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function fills an area of the map with stones of a selected kind.
Note: Please note that in contrast to function fill_floor, this function doesn't have any default attributes, and no parameter may be omitted.
Name of stone object.
Coordinates of the upper left corner of the filled area. Note that the upper left square of the map is at coordinates [0,0].
Size of filled area - w is width and h is height.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
fill_stones("st-chameleon", 1, 1, 18, 11) fill_stones("st-grate1", 1, 5, 5, 7) fill_stones("st-death", 9, 5, 2, 2) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: The function MakeObject is used internally by other functions, like set_floor, set_item or set_stone. It takes care of creating the object and sets up all desired attributes, including default ones
Name of an internal Enigma object. It can be the name of any floor, stone or item.
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Example: To my best knowledge, no one uses this function in their levels. You should instead use set_floor/stone/item functions for creating particular Enigma objects. If you need this function, you are probably a guru and you don't need this manual either. |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This function sends a message to an object.
The recipient of the message. Can be either the name of an object or a reference as returned by enigma.GetNamedObject.
The message itself (e.g. “signal”) You can see which messages are understood in the documentation of the particular Old API - Objects.
Some specific messages expect some additional data (e.g., message “direction” expects a direction like SOUTH or WEST).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
set_stone("st-laser-s", 2, 2, {name="laser3", on=FALSE}) … SendMessage("laser3", "onoff") |
set_stone("st-bolder", 7, 11, {name="bolder1", direction=SOUTH}) … SendMessage("bolder1", "direction", WEST) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: As you would expect, this function creates a floor at a given [x,y] position in Enigma level, and passes all necessary default attributes and attributes passed in the attribs argument.
Enigma internal object name. The name should be the name of the floor (they typically start with “fl-” prefix). Enigma won't let you create a floor from another object, just from real floors.
Location where you want the floor to be placed. Note that level coordinates begin with zero (see CreateWorld).
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
function setup_gradient_rose(x,y) set_floor("fl-gradient", x, y+1, {type=1}) set_floor("fl-gradient", x, y-1, {type=2}) set_floor("fl-gradient", x+1, y, {type=3}) set_floor("fl-gradient", x-1, y, {type=4}) end |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function is very similar to the one named set_floor, described earlier. It creates an item at a given position. Items in Enigma are all those magic wands, brushes, coins, triggers, bombs and also, for example, the laser ray or crackles. Only one single item can be on each position.
Note: The rule of single-item-per-field also means that a laser cannot “overshoot” a magic wand or trigger, or that you cannot drop an item to cracked floor, etc. It may look like a disadvantage, but on the other hand, it can be used as an advantage (see, for example, the level named “Follow the Light” in “Oxyd Clones” package).
Enigma internal object name. The name must be the name of an item (they typically start with “it-” prefix). Enigma won't let you create an item from another object, just from real items.
Location where you want the item to be placed. Note that level coordinates begin with zero (see CreateWorld).
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
set_item("it-trigger", 34, 3, {action="openclose", target="bridge1"}) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function is very similar to the one named set_floor, describer earlier. It places the stone to the desired location. Stones in Enigma are all walls, glass blocks, death's heads, and also doors, switches, lasers, bolders and lots of other special Enigma objects.
Enigma internal stone name. The name must be the name of a stone (they typically start with “st-” prefix). Enigma won't let you create a stone from another object, just from real stones.
Location where you want the stone to be placed. Note that level coordinates begin with zero (see CreateWorld).
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
set_stone("st-door", 18, 6, {name="door01", type="h"}) set_stone("st-bolder", 2, 11, {name="bolder01", direction=NORTH}) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Description: This function is somehow similar to draw_stones. It can place several stones in locations all over the map. The locations to which the stones will be placed are listed in argument positions.
Enigma internal stone name.
Table of stone locations. Its format is like this: {loc1, loc2, …}, where each location is {x,y}. Together it looks like this: {{x1,y1}, {x2,y2}, …}.
Table of attribute names and corresponding values: {attrib1=value1, attrib2=value2, …}. Those attributes will be passed to created stones together with default attributes. You may omit this attribute.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
set_stones("st-glass", {{1,6},{1,12},{34,1},{34,2},{35,2},{36,1},{36,2}}) set_stones(bordertile, {{34, 1}, {34, 5}, {34, 7}, {34, 11}}) … set_stones("st-invisible", {{7,9}}) -- these two lines set_stone("st-invisible", 7, 9) -- do the same |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Jump to: | I O S |
---|
Jump to: | I O S |
---|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Jump to: | A O S |
---|
Index Entry | Section | |
---|---|---|
| ||
A | ||
autoclose | 8.1.1 it_blocker | |
autoclose | 9.5.2 st_blocker | |
| ||
O | ||
orientation | 9.5.3 st_boulder | |
orientation | 9.5.24 st_turnstile | |
orientation | 9.5.25 st_turnstilearm | |
| ||
S | ||
state | 9.5.8 st_fourswitch | |
|
Jump to: | A O S |
---|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Jump to: | O |
---|
Index Entry | Section | |
---|---|---|
| ||
O | ||
orientate | 9.5.3 st_boulder | |
orientate | 9.5.15 st_mirror | |
orientate | 9.5.25 st_turnstilearm | |
|
Jump to: | O |
---|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Jump to: | A C D E F G M S |
---|
Jump to: | A C D E F G M S |
---|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Jump to: | A C D G I L N O P R S T U |
---|
Jump to: | A C D G I L N O P R S T U |
---|
[Top] | [Contents] | [Index] | [ ? ] |
[Top] | [Contents] | [Index] | [ ? ] |
This document was generated on July, 21 2008 using texi2html 1.78.
The buttons in the navigation panels have the following meaning:
Button | Name | Go to | From 1.2.3 go to |
---|---|---|---|
[ < ] | Back | Previous section in reading order | 1.2.2 |
[ > ] | Forward | Next section in reading order | 1.2.4 |
[ << ] | FastBack | Beginning of this chapter or previous chapter | 1 |
[ Up ] | Up | Up section | 1.2 |
[ >> ] | FastForward | Next chapter | 2 |
[Top] | Top | Cover (top) of document | |
[Contents] | Contents | Table of contents | |
[Index] | Index | Index | |
[ ? ] | About | About (help) |
where the Example assumes that the current position is at Subsubsection One-Two-Three of a document of the following structure:
This document was generated on July, 21 2008 using texi2html 1.78.