FKISS Reference

04-Apr-2008

Introduction

This FKISS reference assumes that the reader is familiar with the KISS General Specification (KISS/GS), and understands the format of the configuration file (.CNF), and the basic concepts of cels, palettes and objects.


FKISS Overview

FKISS scripting instructions are embedded in the KiSS configuration file. All FKISS lines begin with the characters ";@" (the leading ";" means that non-FKISS programs will at least be able to load the doll and show something, as the FKISS script will be read as comments).

All FKISS scripts must begin with the line:

;@EventHandler

This enables the FKISS engine in the player program, and warns it to expect further script. It is required, and must precede any other FKISS code. Although some players treat this as case-insensitive (i.e. they will accept "@eventhandler"), strictly it is case-sensitive, and if the set is to be portable the line should be exactly as given. Note that unlike all other scripting commands, there are no brackets. However, some players allow the brackets to be present.

After the EventHandler line, FKISS scripts consist of events (or triggers) followed by a sequence of actions that must be executed when that event occurs. A further FKISS event automatically terminates the handler for the preceding event. For example:

;@alarm(1)
;@ unmap(#2)
;@ unmap(#3)
;@alarm(2)
;@ map(#2)
;@ map(#3)

This defines two event handlers. The first is triggered when timer number 1 expires, the second when timer number 2 expires.

The "@" character must immediately follow the ";", but other than this most whitespace is ignored. It is also legal to have multiple FKISS functions on the same line. Thus, the example above could be written as:

;@alarm(1) unmap(#2) unmap(#3)
;@alarm(2) map(#2) map(#3)

Ordering of FKISS scripting commands is often misunderstood by FKISS programmers. There are two rules here:

  1. The order that events occur in the script is (almost) completely irrelevant. The example above could equally well be written as:

    ;@alarm(2) map(#2) map(#3)
    ;@alarm(1) unmap(#2) unmap(#3)

    (ie with the events in reverse order), and the end result would be identical. If what you think you are doing contravenes this rule, then it will not work as you intend.

  2. Actions in the event handler will be executed in the order they appear in the script; note, however, that FKISS3 introduces actions that can override this rule in limited ways.

Rule 1 above include the word "almost"; this is because it is legal to have a script that includes two or more handlers for the same event. For example:

;@alarm(1) unmap(#2) unmap(#3)
;@alarm(2) map(#2) map(#3)
;@alarm(1) unmap(#4) unmap(#5)

includes two "alarm(1)" handlers. Different FKISS players can be expected to handle this in different ways. Some players will treat them as two separate events triggered one after the other (with the order in which they are processed being indeterminate); other players will combine the two handlers into one, with the order of the two sets of actions being different from player to player; still others process the first handler and completely ignore the second. !PlayKISS uses the second approach, and processes the actions lexically; internally, therefore, !PlayKISS will convert the example above to:

;@alarm(1) unmap(#2) unmap(#3) unmap(#4) unmap(#5)
;@alarm(2) map(#2) map(#3)

Because if this indeterminacy, it is strongly recommended that multiple handlers for the same event are avoided.


Transparency

The word "transparency" in KISS has two distinct meanings, depending on context:

In the descriptions for the various collision-detection events, it states that some take transparency into account (apart, collide), and some ignore transparency (in, out, stillin, stillout). In this context, transparency refers to pixel transparency. Where the event considers transparency, the two cels (objects, etc) are deemed to overlap if at least one non-colour-0 pixel of the first cel is over at least one non-colour-0 pixel of the second cel. Where the event ignores transparency, the two cels are deemed to overlap if the rectangles that delimit the cels intersect, whatever the colour of the pixels involved.

The transparent action modifies the cel transparency, and hence alters the way the cel is displayed. However, it has no affect on collision detection whatsoever. Even if one or both cels have a cel transparency of 255 (i.e. fully transparent), collisions are computed as if both had a cel transparency of 0 (i.e. fully opaque).


Cel ambiguity

The KISS specification allows an artist to use the same cel in more than one object, as in:

#1 tharg.cel
#2 tharg.cel

Although legal, this can cause problems in FKISS players if the duplicated cel is used in an FKISS event or action, as in:

;@press("tharg.cel")
;@ unmap("tharg.cel")

The ambiguity is obvious - which of the two "tharg.cel" is being referenced in the press and unmap? Different players handle this in different ways, and are often internally inconsistent: e.g. unmap("tharg.cel") unmaps all instances of tharg.cel, but press("tharg.cel") is only invoked for the first instance of tharg.cel.

The use of ambiguous cel names in FKISS functions will therefore behave differently in different players; it is therefore recommended that such ambiguity is avoided.


Cel groups

FKISS4 introduces a new concept to KISS, namely the cel group. Cel groups are a named assemblage of cels, optionally split into 1 or more frames. The format of a group name is an exclamation mark (!) followed by an alphabetic character, followed by up to 31 additional alphanumeric characters (e.g. !Group, !G173, !Body are all legal group names). Group names are case-insensitive.

Groups can be used in FKISS functions (event or action) anywhere that a single cel name can be used, in which case the FKISS function applies to all the cels in the group. For example @unmap(!Uniform) will unmap all the cels that are part of group !Uniform. Similarly, the event @press(!Body) will be invoked whenever any of the cels that make up !Body are clicked on with the mouse.

In addition, there are two FKISS actions that specifically relate to groups, @setframe and @letframe. These are described in the actions table below.

Cel membership of groups is controlled by extensions to the cel definition line described in KISS/GS. The original KISS/GS format is:

#<mark>[.<Fix>] <cel> [*<palnum>] [:<setnum>...]

while the extended format is:

#<mark>[.<Fix>] <cel> [*<palnum>] [:<setnum>...] [; [%t<transp>][%g][%u][%x<xoff>][%y<yoff>][<group> [:<frame>...]]]

Note that the extensions are preceded by a semi-colon (";"), which means that earlier KISS players will treat the text following as a comment. Considering each new entry in turn:

It is also possible to add further group membership details by following the cel definition line with additional lines of the form:

;<group> [:<frame>...]

A cel that uses all the possible features could look like this:

#5.10 bubble.cel *2 : 1 2 ;%t128 %g %u %x50 %y20 !Bubbles : 1 2 4
;!Bubbles 7 9
;!Balls

In addition to the features that are part of KISS/GS, "bubble.cel" starts off with a transparency of 128, a ghost and unmapped. It is offset (50,20) pixels from the object top left corner (overriding the offsets in the cel file).It appears in frames 1, 2, 4, 7 and 9 of group "!Bubbles". It also appears in group "!Balls", but is not a member of any frames in that group.


Variables and symbolic names

Variables (FKISS3 and later) consist of a single letter, or a letter followed by a single digit, and are case-insensitive (e.g. n3 and N3 are the same variable). There are therefore 286 possible variable names (a-z, a0-z0,...a9-z9). They are signed 32-bit values.

In FKISS4, variable names are extended to allow 32 alphanumeric characters (starting with an alphabetic).

FKISS4 also allows both alarms and labels to be given symbolic names, with the same format as variables. For example:
;@alarm(Blink)
:@ <something or other>
;@ randomtimer(Blink,5000,1000)

;@label(CheckCollision)
;@ gosub(CheckOverlap)

Note that although these symbolic names appear to be variables, they so not have a value and should not be used in any of the "let" functions. It is legal to use the same name for an alarm, a timer, and a variable, which leads to the following issues:
;@<some event>
;@ let(Count,3)
;@ timer(Count,1000)
;@ gosub(Count)

;@alarm(3)
; <something>

;@alarm(Count)
; <something>

;@label(3)
; <something>

;@label(Count)
; <something>

Which timer is set? Timer number 3, or the timer called "Count"? And which label is the target of the gosub, label number 3 or the label called "Count"? In such cases FKISS4 follows the rule that symbolic names for timers and alarms always have precedence over the value of variables; hence, timer(Count,1000) will set the timer associated with alarm(Count), and gosub(Count) will invoke the label(Count) handler.

Although the rules of FKISS4 mean that there is no confusion caused by overloading variables and labels or timers, doing so results in confusing and difficult-to-follow scripts, so it is disrecommended.


Stored values

With FKISS4 it is possible to store some or all variables between invocations of a doll, or even pass variables from one doll to another. There are four FKISS actions which support this: savevalue, loadvalue, deletevalue, and valuepool.

These four functions use the concept of a "pool" of values. One such pool is created automatically when a doll is loaded - this pool is anonymous, and private to that doll (i.e. no other doll can access it). By default, the various pool access functions refer in this pool. Dolls may use the valuepool function to access a named pool - such pools are not unique to the doll that created the pool, but can be accessed by any doll that knows the name of the pool. After a valuepool function has been executed, all accesses are to the named pool. Legal pool names are up to 64 characters long, are case-insensitive, and may include alphanumerics, underscores and hyphens. As named pools are effectively "public" it is strongly recommended that pool names should be chosen to make them as unique to the artist as possible; for example, rather than use "mypool" as the name of a pool, artists should include their name (and possibly the name of the doll as well); e.g. "Tigger-LanderGame-Scores". Access to the unique (doll-specific) pool can be reinstated by executing a valuepool function with a null string parameter (valuepool("")).

savevalue, loadvalue and deletevalue require an identifier by which the value is tagged. This identifier is up to 64 characters long, and may include alphanumerics, underscores and hyphens. It is case-insensitive.

If required, it is possible to include both the name of the pool and the identifier name, separated by a full stop ".". This allows access to a different pool to the currently-set valuepool, for the single function using the notation. It is illegal to include multiple full stops in an access, and illegal to specify a pool name without an identifier (i.e. to terminate an identifier with a full stop). If the identifier begins with a full stop, the doll-specific pool will be accessed.

To summarise:

valuepool("mypool-a") Sets the current pool to mypool-a.
loadvalue(v,"Fred") Set v to the value associated with the identifier Fred in the current pool.
savevalue("mypool.tharg",k) Store the current value of the variable k using the identifier tharg in the pool mypool.
deletevalue(".score") Delete the identifier score from the from the doll's unique pool.
loadvalue(v,"mypool.") Illegal
savevalue("a.b.c") Illegal


Hints

Hints allow the doll developer to have some limited control over the way the viewer software behaves. They are not part of FKISS, but the initial specification was developed at the same time as the later stages of FKISS4. It can therefore reasonably be assumed that an FKISS4-compatible viewer will support hints. It should be emphasized that these are not absolute instructions to the viewer software, but recommendations - the viewer may chose to ignore them. Normally, however, the viewer will respect them unless this will impose problems for viewer to handle the set; this may involve overriding some viewer configuration parameters set up by the end-user (e.g. see "Bounds").

A hint line may go anywhere in the cnf file, but will normally appear before any KISS definition lines (i.e. it will normally appear in a comment block at the start of the file). The format of a hint line is:

; HINT <name> <value>

The first character in the line must be a comment character ";" (so older viewers will ignore the line). After the semi-colon, the word "HINT" must be the first word on the line (i.e. can be preceded by nothing except the semi-colon and whitespace) and it must be in upper case. There must then be one or more spaces before <name>, and one or more spaces before the <value>. Hint names are case-insensitive.

Currently defined hint names are:

Hint Meaning
stack Set the depth of the FKISS event stack.
maxfix Defines the "Maximum Fix" value for the doll.
bounds Controls whether objects can be dragged beyond the bounds of the playfield.

Event Stack

FKISS viewers need to set a limit on the number of events that can be triggered by other FKISS events, to prevent a doll from "freezing" when an event triggers another event which triggers the first event, which... This limit is known as the stack depth. FKISS4 requires that all viewers support a minimum stack depth of 20, but other than this different viewers are allowed to have different stack depths.

Using the "stack" hint will request the player to allow a stack of at least the size given in the hint.

Example: ; HINT stack 50

Maximum Fix

Certain FKISS event (e.g. catch, drop) refer to a "maximum fix value". Objects with a maximum fix are never moveable (i.e. their fix value does not decrement as attempts are made to drag them); and the FKISS events are not triggered when an attempt is made to select them. However, different viewers (and hence different artists) have used different values to indicate that an object is maximally fixed; as a result, more recent viewers have had to make guesses as to the value used for any doll.

The "maxfix" hint allows the artist to specify the value that he or she is using to indicate that an object is completely immovable. Any object with a fix value equal to or greater than the specified value will be treated as maximally fixed.

Example: ; HINT maxfix 100

Bounds

Some players allow objects to dragged partly off the playfield. The "bounds" hint can be used to override this (and override any preferences set up by the user):

Bounds Keyword Meaning for
User drags FKISS Actions
All Full Full
FKISS Off Full
Visible Visible Visible
Limited Off Visible
None Off Off

In the table above, Full means that no part of the object can move outside the playfield; Visible means that the object is contrained so that mapped cels cannot move outside the playfield (i.e. no visible part of the object can be moved outside the playfield); and Off means that there are no limitations on object movement.

There is, in fact, an exception to the above rules - the movetorand FKISS action is always constrained to keep the top left of the object within the playfield.

Example: ; HINT bounds Visible


Parameter types

Parameters to FKISS events and action fall into a number of basic types, described in the table below. The "Usage" column is the code used in the event and action tables below to reference the parameter type.

These parameters should be strictly adhered to - if an fkiss function specifies an object reference (o), using an number (n) or a variable (v) will yield undefined results.

Usage Meaning Description Examples
c Cel reference The name of a cel. "eyes.cel"
o Object reference The mark of an object. #1
ov Object (inc variable) The mark of an object, or a variable containing the object number. #1
ObjectNumber
oc Cel or object reference Either the name of a cel or the mark of an object #1
ObjectNumber
ovc Cel or object (inc variable) Either the name of a cel or the mark of an object, or a variable containing the object number #4
"shirt.cel"
g Group The name of a cel group. !Body
ocg Cel, group or object reference The name of a cel or group, or the mark of an object "jacket.cel"
!Group2
#19
ovgc Cel, object (inc var) or group Any of cel name, group, object number, or variable "fred.cel"
#1
!MainGroup
ObjNum
n Number A numeric (integer) value 17
s String Any text "Hello there"
v Variable Variable name n6 (FKISS3)
Count (FKISS4)
i Identifier Numeric (integer) value, or a symbolic name for a label or an alarm. GetObj
23
d Number or Variable A literal number or a variable identifier. 75
k4
f Filename String containing a filename. "bang.wav"
k Keylist String containing the names or one or more keyboard keys.
In some cases only a single key name is allowed.
"abcd"
"updownleftright"
t Value tag The tag of a value in a value pool, or the name of a value pool.
For most uses, this can be the name of a pool plus the name of a tag, separated by a full stop.
"score-01"
"mypool.score"

In some case, these parameters may be followed by a number to allow the event or action description to refer to specific parameters [eg timer(d1,d2), movebyx(o1,o2,d)].

Legal key names in Keylist parameters (FKISS4 and later) are the alphanumeric keys ("a"-"z" and "0"-"9") plus the special keys "space", "up", "down", "left" and "right" only. Key names are case-insensitive (i.e. "a" & "A" are the same).


Events

The table below gives a complete list of all FKISS events currently defined, the version of FKISS in which they appear, and a brief description. In some cases, the format of the event is different for different versions of FKISS - in such cases, there are multiple entries. More detailed information can be obtained by following the links.

Event Version Example Description Related events Related actions
alarm(n) 1 alarm(3) A timer reaches zero. - timer
randomtimer
lettimer
alarm(i) 4 alarm(Blink)
apart(c,c) 2.1 apart("skirt.cel","body.cel") The two cels, groups or objects do not overlap, taking transparent pixels into account.
Triggers only if the cels did overlap before one of them was moved by the user.
collide
in
out
stillin
stillout
unfix
-
apart(ocg,ocg) 4 apart(!Furniture,#2)
begin() 1 begin() This event is triggered after the initialize event and before the version event. initialize
version
end
-
catch(oc) 1 catch(#2)
catch("body.cel")
The user clicks on the object or cel.
Applies to all cels & objects except those with a maximal fix value.
press
fixcatch
release
drop
fixdrop
unfix
-
catch(ocg) 4 catch(!Body)
col(n) 1 col(2) The user changes the palette to that specified - changecol
letpal
collide(c,c) 2.1 collide("shirt.cel","body.cel") The two cels, groups or objects touch, taking transparent pixels into account.
Triggers only if the cels did not overlap before one of them was moved by the user.
apart
in
out
stillin
stillout
unfix
-
collide(ocg,ocg) 4 collide(#2,!Uniform)
detached(o) 4 detached(#21) The object is no longer attached to its parent object. This may be triggered eitherby the FKISS action "detach" or if the object is detached from its parent by a user drag. - attach
detach
glue
letparent
letchild
letsibling
drop(oc) 1 drop("skirt.cel")
drop(#2)
The user releases the mouse on the object or cel.
Applies only to all cels & objects except those with a maximal fix value.
catch
press
fixcatch
release
fixdrop
unfix
-
drop(ocg) 4 drop(!Stuff)
end() 1 end() The user quits the player or closes the doll initialise
begin
version
-
fixcatch(oc) 1 fixcatch("skirt.cel")
fixcatch(#1)
The user clicks on the object or cel.
Applies only to fixed cels & objects
press
catch
release
drop
fixdrop
unfix
-
fixcatch(ocg) 4 fixcatch(!Clothes)
fixdrop(oc) 1 fixdrop("skirt.cel")
fixdrop(#2)
The user releases the mouse on the object or cel.
Applies only to fixed cels & objects
press
catch
release
drop
fixcatch
unfix
-
fixdrop(ocg) 4 fixdrop(!Group)
in(o,o) 2 in(#1,#2) The two objects, cels or groups overlap, ignoring transparency.
Triggers only if the objects did not overlap before one of them was moved by the user.
apart
collide
out
stillin
stillout
unfix
-
in(ocg,ocg) 4 in(!Body,"dress.cel")
initialize() 1 initialize() Before the doll is displayed after loading begin
version
end
-
keypress(k) 4 keypress("a")
keypress("up")
The user has pressed the specified key. This event is triggered once when the key is pressed - there is no autorepeat.
Only a single key name is allowed.
keyrelease letkey
letkeymap
keyrelease(k) 4 keyrelease("7")
keyrelease("left")
The user has released the specified key (i.e. is no longer pressing it).
Only a single key name is allowed.
keypress letkey
letkeymap
label(n) 3 label(3) Not really an event, but a way of sharing common actions.
The handler is triggered by a goto or gosub action from another handler
- goto
gosub
gotorandom
gosubrandom
label(i) 4 label(Count)
mousein(ocg) 4 mousein("body.cel")
mousein(#1)
mousein(!Body)
Triggered when the mouse pointer moves over the cel, object or group.
The event is only triggered if the cel, object or group is not occluded by other cels (i.e. if a mouse click would invoke a "press" event)
mouseout letmousex
letmousey
mouseout(ocg) 4 mouseout(!MyGroup)
mouseout(#21)
mouseout("cage.cel")
Triggered when the mouse pointer moves away from the cel, object or group. mousein letmousex
letmousey
never() 1b never() This event is never triggered.
Intended for debugging purposes during doll development.
- debug
out(o,o) 2 out(#2,#3) The two cels, groups or objects do not overlap, ignoring transparency.
Triggers only if the objects did overlap before one of them was moved by the user.
apart
collide
in
stillin
stillout
unfix
-
out(ocg,ocg) 4 out(!Body,"dress.cel")
overflow() 3 overflow() Triggered when an FKISS3 expression evaluation causes an error.
eg division by zero.
- let
etc
press(oc) 1 press("skirt.cel")
press(#1)
The user clicks on the object or cel.
Applies to all cels & objects.
catch
fixcatch
release
drop
fixdrop
unfix
-
press(ocg) 4 press(!Body)
release(oc) 1 release("skirt.cel")
press(#1)
The user releases the object or cel.
Applies to all cels & objects.
catch
fixcatch
press
drop
fixdrop
unfix
-
release(ocg) 4 release(!Uniform)
set(n) 1 set(3) The user changes the set to that specified - changeset
letset
stillin(o,o) 2 stillin(#2,#3) The two objects, cels or groups overlap, ignoring transparency.
Triggers irrespective of the state of the two objects before movement
apart
collide
in
out
stillout
unfix
-
stillin(ocg,ocg) 4 stillin(!Body,"dress.cel")
stillout(o,o) 2 stillout(#2,#3) The two objects, cels or groups do not overlap, ignoring transparency.
Triggers irrespective of the state of the two objects before movement
apart
collide
in
out
stillin
unfix
-
stillout(ocg,ocg) 4 stillout(!Body,"dress.cel")
unfix(oc) 1 unfix("skirt.cel")
unfix(#2)
A previously-fixed cel or object becomes free to move. apart
collide
in
out
stillin
stillout
setfix
unfix(ocg) 4 unfix(!StickyStuff)
version(n) 2 version(2) After begin, but only if the version code is supported by the current program.

Version codes are:
  • 0 : FKISS 1
  • 1 : FKISS 1b
  • 2 : FKISS 2
  • 3 : FKISS 2.1
  • 4 : FKISS 3
  • 5 : FKISS 4
initialize
begin
end
-


Actions

The table below gives a complete list of all FKISS actions currently defined, the version of FKISS in which they appear, and a brief description. In some cases, the format of the action is different for different versions of FKISS - in such cases, there are multiple entries. More detailed information can be obtained by following the links.
Action Version Example(s) Description Related events Related actions
add(v,d1,d2) 3 add(a1,a2,a3)
add(b,3,c1)
v := d1 + d2 - sub
div
mod
mul
let
etc
altmap(oc) 1 altmap(#1)
altmap("eyes1.cel")
If the object/cel is mapped (ie part of the image) unmap it; if it is unmapped (ie not map of the image) map it.
This applies in all sets.
- map
unmap
ifmapped
ifnotmapped
altmap(ovgc) 4 altmap(!MyGroup)
altmap(ObjNum)
attach(ov1,ov2) 4 attach(#9,#2) Attach object o1 to object o2. If o1 is already attached to another object, detach it first (triggering a "detached" event if appropriate). After this action, object o2 is the "parent" of object o1, and moving o2 will cause o1 to move so as to retain the same separation. Moving o1 (unless it is fixed)will cause the attachment to br broken. detached detach
glue
letparent
letchild
letsibling
changecol(d) 1 changecol(3)
changecol(a1)
Change the current palette group to that specified. col changeset
letpal
letkcf
setkcf
changeset(d) 1 changeset(0)
changeset(s)
Change the current set to that specified. set changecol
letset
debug(s) 1b debug("Hi there") Display the text to the user.
The exact form of the display (error box, message to terminal) is dependent on the platform.
never notify
deletevalue(t) 4 deletevalue("high-score")
deletevalue("mypool.speed")
Delete the value with tag t from the appropriate pool.
If no such tag exists, do nothing.
- loadvalue
savevalue
valuepool
detach(ov) 4 detach(#16)
detach(Child)
Detaches object o from whatever parent it may have had. detached attach
glue
letparent
letchild
letsibling
div(v,d1,d2) 3 div(a1,a2,10)
div(b,z5,z2)
v1 := d1 / d2
(Integer division)
- add
sub
mod
mul
let
etc
else() 3 else() Part of a structured if/else/endif - various ifs
endif
elseifequal(d1,d2) 4 elseifequal(Count,0) Part of a structured if/elseif/else/endif - various ifs
else
endif
elseifgreaterthan(d1,d2) 4 elseifgreaterthan(NumObj,0) Part of a structured if/elseif/else/endif - various ifs
else
endif
elseiflessthan(d1,d2) 4 elseiflessthan(X,6) Part of a structured if/elseif/else/endif - various ifs
else
endif
elseifnotequal(d1,d2) 4 elseifnotequal(Count,1) Part of a structured if/elseif/else/endif - various ifs
else
endif
endif() 3 endif() Terminator for structured if/else/endif - various ifs
else
exitevent() 3 exitevent() Aborts the current event handler. - -
exitloop() 4 exitloop() If the current (label) event has been called, directly or indirectly, by a "repeat" action, abort all event handlers down to that containing the repeat. Action processing will continue with the action after the repeat. If there is no repeat being processed, this action does nothing. - repeat
ghost(oc,d) 3 ghost("eyes.cel",1)
ghost(#1,a0)
If d is not zero, oc becomes a "ghost", otherwise it is unghosted.
A ghost object or cel cannot be dragged with the mouse - mouse clicks will be passed down to the next cel below.
- -
ghost(ovgc,d) 4 ghost(!Body,1)
ghost(ObjNum,1)
glue(ov1,ov2) 4 glue(#3,#7)
glue(Child,Parent)
This acts exactly as attach (q.v.), except that moving the child object does not detach it from its parent. detached attach
detach
letparent
letchild
letsibling
gosub(d) 3 gosub(100)
gosub(b2)
Triggers the event handler for label d.
When the label event finishes, processing of the current handler will continue.
label gosubrandom
goto
gotorandom
gosub(i) 4 gosub(CountObj)
gosubrandom(d1,d2,d3) 3 gosubrandom(50,1,2)
gosubrandom(b3,b1,5)
Performs a gosub to d2 or d3. d1 is the percentage chance that d2 is chosen rather than d3. label goto
gosub
gotorandom
gosubrandom(d,i1,i2) 4 gosubrandom(P,Map1,Map2)
goto(d) 3 goto(5)
goto(b2)
Triggers the event handler for label d.
When the label event finishes, processing of the current handler will also terminate.
label gosub
gosubrandom
gotorandom
goto(i) 4 goto(CountObj)
gotorandom(d1,d2,d3) 3 gotorandom(20,5,10)
gotorandom(m1,5,c2)
As gosubrandom, but performs a random goto rather than a random gosub. label gosub
gosubrandom
goto
gotorandom(d,i1,i2) 4 gotorandom(25,Map1,Map2)
ifequal(d1,d2) 3 ifequal(b,0)
ifequal(5,c)
Begins a structured if. The test is true if d1=d2. - other ifs
else
endif
iffixed(o,d1,d2) 2.1 iffixed(#1,10,15)
iffixed(#21,a3,a1)
If o is fixed (ie not freely movable), set timer d1 to trigger after time d2 alarm other ifs
timer
iffixed(ov,i,d2) 4 iffixed(ThisObj,Blink,500)
ifgreaterthan(d1,d2) 3 ifgreaterthan(a0,5)
ifgreaterthan(5,t1)
Begins a structured if. The test is true if d1 > d2 - other ifs
else
endif
iflessthan(d1,d2) 3 iflessthan(b1,0)
iflessthan(0,b1)
Begins a structured if. The test is true if d1 < d2 - other ifs
else
endif
ifmapped(c,d1,d2) 2.1 ifmapped("shoes.cel",10,15)
ifmapped("skirt.cel",a9,b1)
If c is mapped, set timer d1 to trigger after time d2 alarm other ifs
timer
ifmapped(ovcg,i,d) 4 ifmapped(!Uniform,Wave,500) Timer is only set if all cels in ovcg are mapped
ifmoved(o,d1,d2) 2.1 ifmoved(#1,1,1000)
ifmoved(#2,a1,a2)
If o has moved from its original position (in the current set), set timer d1 to trigger after time d2 alarm other ifs
timer
ifmoved(ov,i,d) 4 ifmoved(Jacket,Show,50)
ifnotequal(d1,d2) 3 ifnotequal(5,a)
ifnotequal(x1,x2)
Begins a structured if. The test is true if d1 <> d2. - other ifs
else
endif
ifnotfixed(o,d1,d2) 2.1 ifnotfixed(#10,a1,1000)
ifnotfixed(#11,1,a2)
If o is not fixed, set timer d1 to trigger after time d2 alarm other ifs
timer
ifnotfixed(ov,i,d) 4 ifnotfixed(This,Count,5000)
ifnotmapped(c,d1,d2) 2.1 ifnotmapped("C.cel",10,15)
ifnotmapped("D.cel",a,a1)
If c is not mapped, set timer d1 to trigger after time d2 alarm other ifs
timer
ifnotmapped(ovcg,i,d) 4 ifnotmapped(!Grp,Count,500) Timer is only set if no cels in ovcg are mapped
ifnotmoved(o,d1,d2) 2.1 ifnotmoved(#6,10,1200)
ifnotmoved(#5,a1,a2)
If o has not moved from its original location, set timer d1 to trigger after time d2 alarm other ifs
timer
ifnotmoved(ov,i,d) 4 ifnotmoved(Cover,1,Delay)
let(v,d) 3 let(a,10)
let(b1,b2)
v := d - add
sub
div
mod
mul
etc
letcatch(v) 3 letcatch(a1) Sets v to the object number currently being dragged.
If no object is being dragged, v is set to -1.
- let
etc
letchild(v,ov) 4 letchild(C1,#1) Sets v to the lowest numbered object currently attached to ov.
If no objects are attached,v is set to -1.
detached attach
detach
glue
letparent
letsibling
letcollide(v,c1,c2) 3 letcollide(d1,"A.cel","B.cel") If c1 and c2 overlap (taking account of transparency), v is set to 1. Otherwise, v is set to 0. collide
apart
in
out
stillin
stillout
letinside
etc
letcollide(v,ovcg1,ovcg2) 4 letcollide(x,!Unif,"a.cel") v is set to 1 if any cel in ovcg1 overlaps any cel in ovcg2
letfix(v,o) 3 letfix(a1,#1) Sets v to the current fix value of o - setfix
let
etc
letfix(v,ov) 4 letfix(fixval,Lever)
letframe(v,g) 4 letframe(framno,!Blink) Sets v to the current frame of g.
If no setframe has been executed for g, v is set to -1.
- setframe
let
etc
letheight(v,ov) 4 letheight(height,thisobj) Sets v to the current height of ov, excluding any unmapped cels - letwidth
let
etc
letinitx(v,ov) 4 letinitx(StartX,Obj)
letinitx(X,#1)
Sets v to the initial x ordinate of o (in the current set). - letinity
letobjectx
letobjecty
let
etc
letinity(v,ov) 4 letinity(StartY,Tiara)
letinity(Y,#7)
Sets v to the initial y ordinate of o (in the current set). - letinitx
letobjectx
letobjecty
let
etc
letinside(v,o1,o2) 3 letinside(t2,#2,#3) If o1 and o2 overlap (without taking account of transparency), v is set to 1, otherwise 0. collide
apart
in
out
stillin
stillout
letcollide
etc
letinside(v,ovcg1,ovcg2) 4 letinside(I,!Body,"shorts.cel")
letkcf(v,ovgc) 4 letkcf(palnum,"dress.cel")
letkcf(p,#2)
Sets v to the palette file number currently being used by ovgc. If ovgc refers to multiple cels that reference more than one palette file, or any cel in ovgc is Cherry KISS, v is set to -1. - setkcf
letpal
changecol
letkey(v,k) 4 letkey(k0,"updownleftright") Sets v to the index of the first key in k that is pressed. Indexing starts at 1 keypress
keyrelease
letkeymap
letkeymap(v,k) 4 letkeymap(k1,"updown") For each key in k that is pressed, the equivalent bit in v is set. keypress
keyrelease
letkey
letmapped(v,c) 3 letmapped(m1,"shoes.cel") Sets v to 1 if c is mapped, otherwise 0. - map
unmap
altmap
let
etc
letmapped(v,ovgc) 4 letmapped(nmap,!Uniform)
letmapped(n,#17)
Sets v to the number of cels in ovgc that are mapped
letmousex(v) 3 letmousex(x1) Sets v to the current mouse x position. If the mouse is outside the playfield, the result is still valid (i.e. the coordinate system extends beyond the playfield). mousein
mouseout
letmousey
let
etc
letmousey(v) 3 letmousey(x2) Sets v to the current mouse y position. As for letmousex, if the mouse is outside the playfield the result is still valid. mousein
mouseout
letmousex
let
etc
letobjectx(v,o) 3 letobjectx(x1,#2) Sets v to the x ordinate of o. - letobjecty
letinitx
letinity
let
etc
letobjectx(v,ov) 4 letobjectx(x1,ObjNum)
letobjecty(v,o) 3 letobjecty(x2,#2) Sets v to the y ordinate of o. - letobjectx
letinitx
letinity
let
etc
letobjecty(v,ov) 4 letobjecty(y,ObjNum)
letpal(v) 3 letpal(p1) Sets v to the currently selected palette group. col changecol
letkcf
setkcf
let
etc
letparent(v,o) 4 letparent(p,#32) Sets v to the number of the object to which o is currently attached.
If o is not attached, v is set to -1.
detached attach
detach
glue
letchild
letsibling
letparent(v,ov) 4 letparent(parent,child)
letset(v) 3 letset(s1) Sets v to the currently selected set. set changepal
let
etc
letsibling(v,o) 4 letsibling(s,#14) Sets v to the next lowest numbered object currently attached to the parent of o.
If o is not attached, or o is the highest-numbered object attached to its parent, v is set to -1.
detached attach
detach
glue
letchild
letparent
letsibling(v,ov) 4 letsibling(sib,sib)
lettimer(v,i) 4 lettimer(t0,6)
lettimer(TimeLeft,MainAlarm)
Sets v to the number of milliseconds left before the alarm referred to by 'i' times out.
If the alarm has timed out, but has not yet been processed, v is set to 0; if the specified alarm does not exist, v is set to -1.
alarm timer
randomtimer
lettransparent(v,c) 3 lettransparent(r1,"dress.cel")
lettransparent(v,ovcg) 4 lettransparent(t,!Blinds) If all cels in ovcg have the same transparency, v is set to this value.
If cels have different transparencies, v is set to -1.
   
letwidth(v,ov) 4 letwidth(w,thisobj)
letwidth(width,#2)
Sets v to the current width of ov, excluding any unmapped cels - letheight
let
etc
loadvalue(v,t) 4 loadvalue(s,"high-score")
loadvalue(speed,"mypool.speed")
Set v to the value tagged with t stored in the appropriate pool.
If tag t does not exist in the pool, v is unchanged.
- deletevalue
savevalue
valuepool
map(oc) 1 map(#2)
map("eyes1.cel")
Makes oc part of the current image. - unmap
altmap
ifmapped
ifnotmapped
map(ovgc) 4 map(!Uniform)
map(Objno)
mod(v,d1,d2) 3 mod(a1,b,c2)
mod(b2,10,b1)
v := d1 modulus d2 (remainder) - add
sub
div
mul
etc
move(o,d1,d2) 1 move(#1,10,202)
move(#10,a1,a2)
Moves o (d1,d2) pixels relative to its current position - movebyx
movebyy
moverandx
moverandy
moveto
movetorand
move(ov,d1,d2) 4 move(Jacket,dx,dy)
movebyx(o1,o2,d) 2 movebyx(#2,#3,10)
movebyx(#3,#10,a1)
Sets the x ordinate of o1 to the x ordinate of o2 plus d - move
movebyy
moverandx
moverandy
moveto
movetorand
movebyx(ov1,ov2,d) 4 movebyx(Obj,Obj,10)
movebyy(o1,o2,d) 2 movebyy(#4,#7,10)
movebyy(#11,#12,x2)
Sets the y ordinate of o1 to the y ordinate of o2 plus d - move
movebyx
moverandx
moverandy
moveto
movetorand
movebyy(ov1,ov2,d) 4 movebyy(Jacket,#15,0)
moverandx(o,d1,d2) 2.1 moverandx(#5,100,200)
movebyrandx(#10,a1,a2)
Moves object o horizontally by a random distance in the range d1 to d2 - move
movebyx
movebyy
moverandy
moveto
movetorand
moverandx(ov,d1,d2) 4 moverandx(obj,min,max)
moverandy(o,d1,d2) 2.1 moverandy(#6,0,500)
moverandy(#12,x1,x2)
Moves object o vertically by a random distance in the range d1 to d2 - move
movebyx
movebyy
moverandx
moveto
movetorand
moverandy(ov,d1,d2) 4 moverandy(Tiara,300,700)
moveto(o,d1,d2) 2 moveto(#10,100,200)
moveto(#12,x,y)
Moves o to (d1,d2) absolute position. - move
movebyx
movebyy
moverandx
moverandy
movetorand
moveto(ov,d1,d2) 4 moveto(Tharg,x,y)
movetorand(o) 2.1 movetorand(#12) Randomises the position of o - move
movebyx
movebyy
moverandx
moverandy
moveto
movetorand(ov) 4 movetorand(obj)
mul(v,d1,d2) 3 mul(a1,a1,a2)
mul(a2,m2,12)
v := d1 * d2 - add
div
mod
sub
let
etc
music(f) 2 music("song.mid") Plays the midi file f - sound
nop() 1 nop() Does nothing. never -
notify(s) 2 notify("Goodbye") Display the text to the user.
The exact form of the display (error box, message to terminal) is dependent on the platform.
- debug
quit() 1b quit() Exit the player.
Different players treat this in different ways - some simply close the doll, others quit the player.
- -
random(v,d1,d2) 3 random(r1,a1,a2)
random(r,1,1000)
v1 is set to a random number in the range d1 to d2 - let
etc
randomtimer(d1,d2,d3) 1 randomtimer(7,20,1200)
randomtimer(t,r1,r2)
Sets timer d1 to expire in a random time in the range d2 to (d2+d3) alarm timer
iffixed
ifnotfixed
ifmapped
ifnotmapped
ifmoved
ifnotmoved
randomtimer(i,d1,d2) 4 randomtimer(Blink,1000,100)
repeat(i,d,v) 4 repeat(UnmapObject,20,ObjNo) Performs a gosub(i) 'd' times. Before each gosub, 'v' is set to the index number of the call (i.e. 1 the first time, 2 the second time, etc). label gosub
exitloop
restrictx(ov,d1,d2) 4 restrictx(#1,x1,x2)
restrictx(rod,200,400)
Restricts all movement (user drags of FKISS "move" functions) such that (the left of) ov remains between d1 and d2.
If ov is outside the range when this function is executed, it is moved to the nearest point of the range.
If d1 is greater than d2 any previous restrictx values for the object are removed.
- restricty
move
etc
restricty(ov,d1,d2) 4 restricty(obj,ymin,ymax)
restricty(#3,0,50)
Restricts all movement (user drags of FKISS "move" functions) such that (the top of) ov remains between d1 and d2.
If ov is outside the range when this function is executed, it is moved to the nearest point of the range.
If d1 is greater than d2 any previous restricty values for the object are removed.
- restrictx
move
etc
savevalue(t,v) 4 savevalue("high-score",s)
savevalue("mypool.speed",score)
savevalue("rank",1)
Store v in the appropriate pool,using the tag t - deletevalue
loadvalue
valuepool
setfix(o,d) 2.1 setfix(#3,100)
setfix(#10,a1)
Set the fix attribute of o to d unfix letfix
iffixed
ifnotfixed
setfix(ov,d) 4 setfix(Skirt,10)
setframe(g,d) 4 setframe(!Clock,10)
setframe(!Group,fno)
All cels that are in frame d of group g are mapped, and all cels that are in group g but not in frame d are unmapped. - letframe
map
unmap
sound(f) 1 sound("bong.wav") Plays the wav or au file f - music
setkcf(ovgc,i) 4 setkcf(!dress,5)
setframe("skirt.cel",palno)
The palette file used for all cels in ovgc is changed to that with index 'i'. If i is less than zero or greater than the number of defined palette files, this function will have no effect. If the number of colours in the palette file is insufficient for any cel in ovgc, the result is indeterminate, but will typically result in parts of the cel being rendered in black. - letkcf
changecol
shell(s) 1 shell("mailto:tigger@orpheusinternet.co.uk") Send 's' to the local OS as a CLI command.
See notes.
- -
sound(f) 1 sound("bong.wav") Plays the wav or au file f - music
sub(v,d1,d2) 3 sub(x1,100,s2)
sub(x3,s2,t7)
v := d1 - d2 - add
div
mod
mul
let
etc
timer(d1,d2) 1 timer(10,1100)
timer(t0,n2)
Sets timer d1 to expire (i.e. trigger the associated alarm event) after d2 milliseconds, unless d2 is zero. If d2 is zero, the timer is cancelled without triggering the alarm. alarm randomtimer
lettimer
iffixed
ifnotfixed
ifmapped
ifnotmapped
ifmoved
ifnotmoved
timer(i,d) 4 timer(WaveArm,50)
transparent(co,d) 1b transparent("ban.cel",64)
transparent(#1,-50)
transparent(#3,b1)
Changes the transparency of co by d.
The transparency of a cel is between 0 (the cel is as rendered exactly as the cel file) and 255 (completely transparent).
- lettransparent
transparent(ovgc,d) 4 transparent(!Bubbles,128)
unmap(oc) 1 unmap(#5)
unmap("eyes2.cel")
Removes oc from the current image - map
altmap
ifmapped
ifnotmapped
unmap(ovgc) 4 unmap(!Jacket)
unmap(ObjNum)
valuepool(t) 4 valuepool("mypool")
valuepool("")
Sets the default pool for all future pool accesses to t.
If t is a null string (""), sets the pool to the unique doll-specific pool.
- deletevalue
loadvalue
savevalue
viewport(d1,d2) 1b viewport(100,80)
viewport(x0,y0)
Sets the top left of the visible area of the image to (d1,d2)
This function is not widely supported, and even less widely used.
- windowsize
windowsize(d1,d2) 1b windowsize(400,200)
windowsize(x1,y1)
Sets the visible size of the image to (d1,d2)
This function is not widely supported, and even less widely used.
- viewport

Use of the 'shell' action

It is fairly obvious that unfettered implementation of the shell action is a huge security problem - e.g. consider shell("rm -r *"). Furthermore, it is very non-portable - the command above will only work on Unix or Linux machines, and will be so much gobbledygook on Windows or RISC OS.

Therefore, most players either ignore shell completely, or provide an alternative interpretation where the command is an email or web URL. Hence:


Document last updated on 04 Apr 2008