Added part of docs
Some checks failed
docs / deploy (push) Has been cancelled
docs / build (push) Has been cancelled

This commit is contained in:
Patryk Gensch
2026-05-19 20:51:59 +02:00
parent e91fd2e42a
commit df6cf2f3d3
66 changed files with 11821 additions and 0 deletions

View File

@@ -0,0 +1,180 @@
# Arithmetic
The Piklib/BlooMoo engine performs computations exclusively inside **arithmetic expressions** enclosed in square brackets. Round parentheses are reserved for method-call argument lists and do not act as grouping inside expressions. This chapter describes the available operators, the typing rules, and the conversions between primitive types.
## Syntax
An arithmetic expression is written between square brackets. It may appear anywhere a value is expected — including as a method argument or as the value assigned to a field:
```
VARIABLE_NAME^SET([VAL1+VAL2]);
*["ANIMO_"+_I_]^PLAY();
```
Expressions can be nested using additional pairs of square brackets:
```
[[VAL1+VAL2]*VAL3]
```
## Typing rule
All binary operations in expressions follow a single rule:
> **The result's type and the right operand's type are both determined by the type of the left operand.**
The right operand is cast to the left operand's type before the operation is performed, and the result also has that type. Examples:
```
"Value" + 2.5 → "Value2.50000" # DOUBLE cast to STRING
2 + "3" → 5 # STRING cast to INTEGER
```
A consequence: operand order matters not only for non-commutative operators, but also for the type of the result.
## Type conversions
Within the typing rule, the right operand is cast according to the rules below.
### From `STRING`
| Target | Rule |
|---|---|
| [`INTEGER`](../reference/INTEGER.md) | An integer is extracted from the start of the text (similar to `parseInt`). If the text does not start with a number, the result is `0`. |
| [`DOUBLE`](../reference/DOUBLE.md) | Same as `INTEGER`, but the fractional part is preserved. The decimal separator is a dot. |
| [`BOOL`](../reference/BOOL.md) | Text matching a truthful value (`TRUE` or a non-zero number) yields `TRUE`; otherwise `FALSE`. |
```
"5" → 5
"Test" → 0
```
### From `INTEGER`
| Target | Rule |
|---|---|
| [`STRING`](../reference/STRING.md) | The decimal representation of the number. |
| [`DOUBLE`](../reference/DOUBLE.md) | The number with a zero fractional part (five zeros after the dot). |
| [`BOOL`](../reference/BOOL.md) | A non-zero value yields `TRUE`; `0` yields `FALSE`. |
```
5 → "5"
3 → 3.00000
-2 → TRUE
0 → FALSE
```
### From `DOUBLE`
| Target | Rule |
|---|---|
| [`STRING`](../reference/STRING.md) | Decimal representation with a dot and five fractional digits. For `0.0` the fractional part is omitted. |
| [`INTEGER`](../reference/INTEGER.md) | Rounded to the nearest integer; ties round up for positive values and down for negative values. |
| [`BOOL`](../reference/BOOL.md) | Indirect: first cast to `INTEGER` (with the rounding above), then to `BOOL`. Values in the open interval `(-0.5, 0.5)` give `FALSE`, all others `TRUE`. |
```
3.5 → "3.50000", 4, TRUE
0.0 → "0", 0, FALSE
0.45362 → "0.45362", 0, FALSE
1.00001 → "1.00001", 1, TRUE
-0.5 → "-0.50000", -1, TRUE
```
### From `BOOL`
| Target | Rule |
|---|---|
| [`STRING`](../reference/STRING.md) | `TRUE``"TRUE"`, `FALSE``"FALSE"`. |
| [`INTEGER`](../reference/INTEGER.md) | `TRUE``1`, `FALSE``0`. |
| [`DOUBLE`](../reference/DOUBLE.md) | `TRUE``1.00000`, `FALSE``0.00000`. |
## Arithmetic operators
Expressions support the following binary operators:
| Operator | Meaning |
|---|---|
| `+` | addition / concatenation |
| `-` | subtraction |
| `*` | multiplication |
| `@` | division |
| `%` | remainder |
### Addition (`+`)
| Left operand type | Behaviour |
|---|---|
| [`STRING`](../reference/STRING.md) | Concatenation of the right operand (after casting) onto the left. |
| [`INTEGER`](../reference/INTEGER.md) | Numeric sum. |
| [`DOUBLE`](../reference/DOUBLE.md) | Numeric sum. |
| [`BOOL`](../reference/BOOL.md) | Logical conjunction (`AND`). `TRUE + FALSE` yields `FALSE`. |
### Subtraction (`-`)
| Left operand type | Behaviour |
|---|---|
| [`STRING`](../reference/STRING.md) | No effect; the result is the left operand. |
| [`INTEGER`](../reference/INTEGER.md) | Numeric difference. |
| [`DOUBLE`](../reference/DOUBLE.md) | Numeric difference. |
| [`BOOL`](../reference/BOOL.md) | No effect; the result is the left operand. |
### Multiplication (`*`)
| Left operand type | Behaviour |
|---|---|
| [`STRING`](../reference/STRING.md) | No effect; the result is the left operand. |
| [`INTEGER`](../reference/INTEGER.md) | Numeric product. |
| [`DOUBLE`](../reference/DOUBLE.md) | Numeric product. |
| [`BOOL`](../reference/BOOL.md) | Logical disjunction (`OR`). `FALSE * TRUE` yields `TRUE`. |
### Division (`@`)
| Left operand type | Behaviour |
|---|---|
| [`STRING`](../reference/STRING.md) | No effect; the result is the left operand. |
| [`INTEGER`](../reference/INTEGER.md) | Integer quotient. |
| [`DOUBLE`](../reference/DOUBLE.md) | Floating-point quotient. |
| [`BOOL`](../reference/BOOL.md) | No effect; the result is the left operand. |
Dividing a numeric type by `0` crashes the engine.
### Remainder (`%`)
| Left operand type | Behaviour |
|---|---|
| [`STRING`](../reference/STRING.md) | No effect; the result is the left operand. |
| [`INTEGER`](../reference/INTEGER.md) | Remainder. |
| [`DOUBLE`](../reference/DOUBLE.md) | Remainder truncated to an integer and then cast back to `DOUBLE`. The fractional part is lost — for example, `1.5 % 2` yields `1.00000`, not `1.50000`. |
| [`BOOL`](../reference/BOOL.md) | No effect; the result is the left operand. |
Taking a remainder with `0` as the right operand crashes the engine.
## Comparison operators
Expressions support the standard comparisons: `==`, `!=`, `<`, `<=`, `>`, `>=`. The right operand is first cast to the left operand's type (per the [typing rule](#typing-rule)), and the comparison is then performed.
### Equality and inequality
`==` returns `TRUE` if both operands (after casting) are equal; `!=` returns the opposite. For [`STRING`](../reference/STRING.md) the comparison is character-by-character; for numeric types, it is value-based.
### Less / greater
| Left operand type | `<` returns `TRUE` if |
|---|---|
| [`STRING`](../reference/STRING.md) | The left operand is lexicographically smaller than the right (character-by-character in CP1250 encoding). |
| [`INTEGER`](../reference/INTEGER.md) | The left operand's value is smaller. |
| [`DOUBLE`](../reference/DOUBLE.md) | The left operand's value is smaller. |
| [`BOOL`](../reference/BOOL.md) | The left operand is `FALSE` and the right is `TRUE` (`FALSE < TRUE`). |
`>` returns `TRUE` in the symmetric cases. `<=` and `>=` are equivalent to `<` or `==`, and `>` or `==`, respectively.
## Logical operators
`&&` (conjunction) and `||` (disjunction) accept only [`BOOL`](../reference/BOOL.md) operands. Passing an operand of another type (even one that could be cast) crashes the engine.
| Operator | Result |
|---|---|
| `&&` | `TRUE` only if both operands are `TRUE`. |
| `||` | `TRUE` if at least one operand is `TRUE`. |
Inside the [compound `@IF` condition](scripts.md#compound-condition), `&&` and `||` behave the same way, but they are part of the condition string rather than operators of an arithmetic expression.

90
docs/en/engine/events.md Normal file
View File

@@ -0,0 +1,90 @@
# Events and signals
The Piklib/BlooMoo engine drives game logic with a reactive, signal-based model. Every object can emit named signals, and scripts can attach procedures or code blocks to react to them. This chapter describes how the mechanism works and lists the most common signals.
## Attaching a signal handler
A signal is attached like any other property of an object — the value is either a procedure name or a code block:
```
OBJECT_NAME:ONCHANGED=PROCEDURE_NAME
OBJECT_NAME:ONCHANGED={OTHER_OBJECT^PLAY("TADA");}
```
Each signal name can have at most one handler attached to it on a given object.
## Parameterised signals
Some signals — notably [`ONCHANGED`](#onchanged) and [`ONBRUTALCHANGED`](#onbrutalchanged) — are emitted together with a value. That value can be used to filter the handler: the engine first looks up a handler matching the pair `signal + value`, and only falls back to a generic handler for the signal name if no specific one is registered.
The discriminator follows the signal name after a caret `^`:
```
OBJECT_NAME:ONBRUTALCHANGED^3=HANDLER_FOR_THREE
OBJECT_NAME:ONBRUTALCHANGED=GENERIC_HANDLER
```
In the example above, `OBJECT^SET(3)` runs `HANDLER_FOR_THREE`; any other value runs `GENERIC_HANDLER`.
## Handler execution
The signal system is synchronous and single-threaded. Emitting a signal immediately transfers control to its handler: the currently executing procedure is paused, the handler runs, and once it returns, control resumes where the signal was emitted. Signals are not queued.
A chain of nested signalproceduresignalprocedure invocations forms a call tree. The jump operators affect that tree as follows:
- [`@ONEBREAK`](scripts.md#jump-operators) — aborts only the current procedure and returns to its caller.
- [`@BREAK`](scripts.md#jump-operators) — aborts the entire call tree started by the original signal emission.
## Signal arguments
Some signals are emitted with extra arguments. Inside a handler, those arguments are available exactly like procedure arguments — through `$1`, `$2`, … (numbered from `1`). This lets a handler react to the specific value that triggered the signal.
## Universal signals
### ONINIT
Fired during the variable's initialisation as its file is loaded. The order in which `ONINIT` is fired across the variables of a single file is fixed and goes by type; the details are in [Variable initialisation](scripts.md#variable-initialisation).
Typical uses: filling in [arrays](../reference/index.md), setting up the initial state of animations, loading data from external files.
### ONSIGNAL
A general-purpose signal, emitted by calling the global `SEND` method on an object:
```
OBJECT_NAME^SEND("MY_SIGNAL");
```
The string passed in is available inside the handler as the first argument (`$1`). This mechanism allows custom events to be defined without relying on value changes or animation events.
## Value-change signals
Fired by [primitive types](../reference/index.md) (and any other type with a `VALUE` field) whenever the value is modified.
### ONCHANGED
Fired only when the new value differs from the previous one. The argument (`$1`) is the new value.
### ONBRUTALCHANGED
Fired on every modification, even if the new value is identical to the previous one. The argument (`$1`) is the new value.
In practice, `ONBRUTALCHANGED` is useful for detecting that a value-setting method (`SET`, `INC`, `SWITCH`, …) was called at all, regardless of whether it actually changed the value.
## Signals from graphical objects and sequences
### ONSTARTED
Fired when an animation or sequence starts playing.
- For a **sequence** — fired once, with the current event name from the `.SEQ` file as its argument.
- For an **animation** — fired with the event name from the `.ANN` file. If the animation is driven by a sequence, this signal can fire multiple times as the animation loops.
### ONFINISHED
Fired when playback finishes:
- for an **animation** — after the last frame is displayed and playback stops,
- for a **sequence** — after the last event finishes (or for each individual event played in turn, depending on configuration).
In both cases the signal is also fired in response to a manual `STOP` call (with no argument or with `TRUE`).

70
docs/en/engine/globals.md Normal file
View File

@@ -0,0 +1,70 @@
# Global and built-in variables
The engine exposes a handful of variables and names that can be referenced from anywhere in the scripts, regardless of context depth. This chapter covers the built-in objects, the implicit variables, the special procedures, and the variable-lookup hierarchy.
## Context hierarchy
Each loaded script creates its own variable context. Contexts are nested: a scene's context inherits from its episode's context, which inherits from the application's context, which in turn inherits from the engine's global context. Variable lookup walks from the lowest context upwards — a variable in a lower context shadows one with the same name in a higher context, but higher-context variables remain visible from lower ones.
## Built-in objects
The following objects are created lazily by the engine on first access and are available from any context under fixed names:
| Name | Type | Description |
|---|---|---|
| `MOUSE` | [`MOUSE`](../reference/index.md) | Mouse state (position, buttons). |
| `KEYBOARD` | [`KEYBOARD`](../reference/index.md) | Keyboard state. |
| `RAND` | [`RAND`](../reference/index.md) | Pseudo-random number generator. Also available under the alias `RANDOM`. |
| `SYSTEM` | [`SYSTEM`](../reference/index.md) | Interface to system functions (time, environment). |
All four objects are singletons in the engine's global context — every script reference resolves to the same instance.
## Objects from `Application.def`
Objects defined in `Application.def` — of type [`APPLICATION`](../reference/index.md), [`EPISODE`](../reference/index.md), and [`SCENE`](../reference/index.md) — are loaded into the engine's global context and remain visible to every script in the game. Other types in that file are ignored (see [Entry point](scripts.md#entry-point)).
## Implicit variables
The engine injects a few variables that are not declared explicitly in scripts.
### `_I_`
The loop counter set up by the [`@LOOP`](scripts.md#loop) statement. It is an [`INTEGER`](../reference/INTEGER.md) variable created locally in the current iteration's context. Its value updates automatically as the loop progresses.
Inside a `@LOOP`, `_I_` can be read in arithmetic expressions and passed as a method argument:
```
@LOOP({*["ANIMO_"+_I_]^PLAY();}, 0, 10, 1);
```
The [`@FOR`](scripts.md#for-bloomoo) loop allows a custom counter name to be supplied; in that case `_I_` is not set.
### `THIS`
A reference to the object that emitted the signal currently being handled. Only available inside a signal-handling block and procedures called from it. Its behaviour is detailed in [The THIS variable](scripts.md#the-this-variable).
### `$1`, `$2`, … `$N`
The arguments of a procedure or signal handler (numbered from `1`). Available only inside the body of a procedure or handler block:
```
PROCEDURE:CODE={VARIABLE_NAME^SET($1);}
```
This syntax is also covered in [Procedure arguments](scripts.md#procedure-arguments).
## Special procedures
Certain procedure names have conventional meaning — the engine invokes them automatically at fixed points in the lifecycle.
### `__ONINIT__`
Called once the initialisation of every variable in a loaded file has finished. See [Variable initialisation](scripts.md#variable-initialisation). A common use is to set the scene's initial state once all of its objects are available.
### `__INIT__`
Called after the scene has been loaded and variable initialisation has completed — just before control is handed off to the game's logic. Used to set scene-specific state that depends on the current episode or application.
## Naming convention
Names surrounded by double underscores (`__NAME__`) are reserved for the engine and for global conventional names (e.g. `__KEYB__`, `__INIT__`, `__ONINIT__`). AidemMedia scripts also use this format for their own globally significant variables to avoid being shadowed in local contexts.

38
docs/en/engine/index.md Normal file
View File

@@ -0,0 +1,38 @@
# Engine
**Piklib** (later **BlooMoo**) is a 32-bit graphical engine created by Aidem Media for a series of Polish adventure games released in the 2000s. This documentation describes the engine's internal logic and how it executes the games' scripts.
## Scope
This documentation focuses on the engine's **scripting language** and the **execution model** as seen from script-level code — that is, what a content programmer needs in order to read existing scripts or write new ones.
It is not a documentation of the engine's source code, nor a complete specification of every internal data structure; those areas are being filled in gradually.
## Structure
The engine documentation is divided into five chapters:
- [Scripts](scripts.md) — script syntax, the parser, loading order, and object initialisation.
- [Arithmetic](arithmetic.md) — computational expressions, operators, and conversion rules between primitive types.
- [Events and signals](events.md) — the engine's reactive model, attaching handlers, propagation through the call tree.
- [Global variables](globals.md) — built-in objects (`MOUSE`, `KEYBOARD`, `RAND`, `SYSTEM`), implicit variables (`_I_`, `THIS`, `$N`), and special procedures.
- [Engine quirks](quirks.md) — non-standard behaviours that are easy to miss.
The full list of available data types is in the [Type reference](../reference/index.md).
## Games using the engine
The list is incomplete and will be extended as more titles are identified.
| Game | Engine version |
|---|---|
| Reksio i Skarb Piratów | Piklib 8 |
| Reksio i Ufo | Piklib 7.1, Piklib 8 |
| Reksio i Czarodzieje | Piklib 8 |
| Reksio i Wehikuł Czasu | Piklib 8 |
| Reksio i Kapitan Nemo | BlooMoo |
| Reksio i Kretes w Akcji | BlooMoo |
| Poznaj Mity: Wyprawa po Złote Runo | Piklib 7.1 |
| Poznaj Mity: Wojna Trojańska | Piklib 7.2 |
| Poznaj Mity: Przygody Odyseusza | Piklib 8 |
| Poznaj Mity: Herkules | Piklib 8 |

118
docs/en/engine/quirks.md Normal file
View File

@@ -0,0 +1,118 @@
# Engine quirks
The Piklib/BlooMoo engine has a number of non-standard behaviours that often surprise programmers used to mainstream scripting languages. This chapter collects the most common ones in a single place.
## Expressions and operators
### Only square brackets group computations
Inside arithmetic expressions, grouping is done exclusively with `[ ]`. Round parentheses `( )` are reserved for method-call argument lists and have no grouping role (see [Arithmetic](arithmetic.md#syntax)).
### `@` instead of `/` for division
The division operator is the at-sign `@`, not `/`. Using `/` in an expression is not interpreted as division.
### The result type follows the left operand
All binary operations cast the right operand to the type of the left. The result also takes the left operand's type. The order of operands has non-trivial consequences (see [Typing rule](arithmetic.md#typing-rule)):
```
"Value" + 2.5 → "Value2.50000"
2 + "3" → 5
```
### Operators on `BOOL` have inverted logic
The `+` operator on [`BOOL`](../reference/BOOL.md) behaves as a logical conjunction (`AND`), and `*` as a disjunction (`OR`). The operators `-`, `@`, and `%` on `BOOL` have no effect (see [Arithmetic operators](arithmetic.md#arithmetic-operators)).
### `%` on `DOUBLE` loses the fractional part
The remainder operator on [`DOUBLE`](../reference/DOUBLE.md) first computes the result and then truncates it to an integer before casting it back to `DOUBLE`. As a result, `1.5 % 2` yields `1.00000`, not `1.50000`.
### `&&` and `||` accept only `BOOL`
The logical operators perform no implicit casting, even when the operand could be converted to `BOOL`. Passing an operand of any other type crashes the engine.
### Division by `0` in expressions crashes
Unlike the numeric-type methods (where `DIV` and `MOD` leave the value unchanged), the `@` and `%` operators in an arithmetic expression crash the engine when the right operand is `0`.
## Script syntax
### Code blocks must fit on one line
The entire block between `{` and `}` must fit on a single line of the script file. Multi-line blocks are not supported.
### Every statement must end with a semicolon
Including the last statement in a code block. Omitting the final semicolon can cause that statement to be skipped.
### Comments: `#` for lines, `!` for statements
A line starting with `#` is skipped entirely. A single statement preceded by `!` is commented out up to the next semicolon.
### The equality comparator changes in compound conditions
In a [simple `@IF` condition](scripts.md#simple-condition), equality is written as `_`. In a [compound `@IF` condition](scripts.md#compound-condition), the same comparator is written as an apostrophe `'`. The remaining comparators (`<`, `>`, `<_`/`<'`, `>_`/`>'`) follow the same pattern.
### Unquoted text is first looked up as a variable name
A value written without quotes is first interpreted as a variable name. If a variable with that name exists, its value is used; otherwise the text is treated as a [`STRING`](../reference/STRING.md) literal. This can lead to hard-to-spot collisions when a literal accidentally matches a variable name.
### Repeated object declarations merge properties
A repeated `OBJECT=NAME` line in the same file does not overwrite the previous definition — the engine merges the new properties into the existing object and overrides entries with the same keys.
### `Application.def` should end with an empty line
Missing a trailing empty line in `Application.def` can leave the last scene incorrectly parsed, which manifests as a black screen at startup.
## Numbers
### `DOUBLE` accepts `d` as the exponent marker
In scientific notation, both `e` and `d` are recognised as exponent separators: `1.23e4` and `1.23d4` are equivalent.
### `DOUBLE → INTEGER` rounds, it does not truncate
When casting [`DOUBLE`](../reference/DOUBLE.md) to [`INTEGER`](../reference/INTEGER.md), the value is rounded to the nearest integer rather than truncated. For positive values, `.5` rounds up; for negative values, it rounds down — so `-0.5 → -1` and `0.5 → 1`.
### `STRING → INTEGER` returns `0` instead of erroring
Casting a non-numeric string to [`INTEGER`](../reference/INTEGER.md) (or [`DOUBLE`](../reference/DOUBLE.md)) returns `0` (`0.00000`) silently. This can mask bugs in expressions mixing textual literals with numeric ones.
## Type methods
### `DOUBLE.MOD` drops the fractional part
Like the `%` operator, [`MOD`](../reference/DOUBLE.md#mod) on `DOUBLE` returns the integer part of the remainder.
### `DOUBLE.SGN` returns `INTEGER`, not `DOUBLE`
The [`SGN`](../reference/DOUBLE.md#sgn) method is the only `DOUBLE` method that does not modify the variable, and its return value is an [`INTEGER`](../reference/INTEGER.md).
### `INTEGER.RANDOM(min, max)` is inclusive on both ends
The two-argument form of [`RANDOM`](../reference/INTEGER.md#random) returns a value from `[min, max]`, including both endpoints. The one-argument form returns `[0, bound)`.
### `INTEGER.DIV` and `INTEGER.MOD` with `0` leave the value unchanged
Unlike division with the `@`/`%` operators in an expression, the [`DIV`](../reference/INTEGER.md#div) and [`MOD`](../reference/INTEGER.md#mod) methods on `INTEGER` return the unchanged current value when given a `0` divisor instead of crashing. The same applies to the `DOUBLE` variants.
### `STRING.COPYFILE` ignores its receiver
The [`COPYFILE`](../reference/STRING.md#copyfile) method on [`STRING`](../reference/STRING.md) does not use the value of the variable on which it is called — it operates purely on its two path arguments.
### `STRING.CHANGEAT` always replaces exactly one character
Regardless of the length of the replacement string, [`CHANGEAT`](../reference/STRING.md#changeat) removes a single character from the current value at the given position and inserts the entire replacement string in its place. The string length after the operation may differ from before.
## `THIS` in signal handlers
### `THIS.GETNAME` returns `"temp"`
Even though `THIS` references the object that emitted the signal, retrieving its name with `GETNAME` returns the string `"temp"`, hinting at an internal temporary-wrapper representation.
### Not every type-specific method works on `THIS`
Calling `GET`/`SET` (for primitive types) or `SHOW`/`HIDE`/`PLAY`/`PAUSE`/`STOP`/`RESUME` (for graphical objects) works reliably. Calling a type-specific method such as [`GETCFRAMEINEVENT`](../reference/index.md) on `ANIMO` typically crashes the engine. See [The THIS variable](scripts.md#the-this-variable) for details.

280
docs/en/engine/scripts.md Normal file
View File

@@ -0,0 +1,280 @@
# Scripts
The Piklib/BlooMoo engine drives game logic by interpreting text-based scripts. This chapter describes the syntax of those scripts, how the engine loads them, and the order in which objects are initialised.
## File formats
Scripts are stored in files with the `.CNV`, `.DEF`, `.CLASS`, and `.SEQ` extensions. They all share the same basic textual structure and differ only in their intended use.
The engine treats all script content as uppercase and is case-insensitive. By convention, scripts are written in uppercase.
### Encryption
Files shipped with the game are encrypted by default using a transposition cipher with a variable offset. An encrypted file begins with a header of the form:
```
{<X:N>}
```
where `X` is a letter indicating the direction of the offset (`D` means a negative offset) and `N` is the offset value. The engine detects this header automatically and decrypts the rest of the file before parsing. Files without this header are read as plain text.
## Object declaration
An object begins with a line containing the `OBJECT` keyword:
```
OBJECT=OBJECT_NAME
```
Lines between consecutive `OBJECT=` lines define properties of the current object. The definition lasts until the end of the file or the next `OBJECT=` line.
If the same object is declared more than once in a single file, its properties are merged — later entries override earlier ones.
## Object properties
Properties are written as `objectName:property=value`:
```
OBJECT_NAME:PROPERTY=VALUE
```
Signals can take an additional parameter after a caret (`^`):
```
OBJECT_NAME:ONBRUTALCHANGED^3=PROCEDURE_NAME
```
In both cases, the engine accepts both `KEY=VALUE` and `KEY = VALUE` (with spaces around the equals sign).
## Variable type
The type is essential — without it, the engine does not know how to handle the object, and the result is usually a hard crash. The type is declared with the `TYPE` property:
```
OBJECT_NAME:TYPE=STRING
```
The full list of available types is in the [Type reference](../reference/index.md).
## Literals and strings
How a literal is interpreted depends on its context:
- Text in double quotes (`"..."`) is always treated as a [`STRING`](../reference/STRING.md).
- Unquoted text is first checked against the names of existing variables — if a variable with that name exists, its value is used. Otherwise the text is taken literally.
Floating-point numbers accept both standard notation (`1.234`) and scientific notation with the letter `e` or `d` (`1.23e4`, `1.23d4`).
## Code blocks
Code blocks — used as the value of a signal or as the body of a procedure — are written inside curly braces. Statements are separated by semicolons; the final statement must also end with a semicolon, otherwise it may not be executed.
```
OBJECT_NAME:ONCHANGED={VARIABLE2^PLAY("TADA");}
```
The entire code block must fit on a single line — the engine does not support multi-line blocks directly inside a script file.
## Comments
The engine recognises two forms of comments:
- **Line comment** — a line starting with `#` is skipped entirely.
- **Statement comment** — a single statement preceded by `!` is treated as commented out, up to the next semicolon.
## Method calls
Methods are called using the caret (`^`):
```
OBJECT_NAME^METHOD(arg1, arg2);
```
## Arithmetic expressions
Computational expressions are written inside square brackets:
```
VARIABLE_NAME^SET([VARIABLE_NAME^GET()+"2"]);
```
Operators and typing rules are described in the [Arithmetic](arithmetic.md) chapter.
## String pointers
A `*` before a variable name or an expression means that the value is to be used as the name of another variable. This allows dynamic references built from text:
```
*VARIABLE_NAME^PLAY();
*["ANIMO_"+_I_]^PLAY();
```
In the first form, `VARIABLE_NAME` should be a [`STRING`](../reference/STRING.md) containing the actual object's name. In the second, the object name is constructed from an arithmetic expression.
## Procedure arguments
Inside the body of a procedure, arguments are accessed with a dollar sign followed by a number (numbered from `1`):
```
PROCEDURE:CODE={VARIABLE_NAME^SET($1);}
```
## The THIS variable
Inside a block that handles a signal, an implicit `THIS` variable is available, set to a reference to the object that fired the signal. `THIS` is also accessible from procedures called from within such a block.
`THIS` behaves unusually: calling `GETNAME` on it returns the string `"temp"`, suggesting that under the hood it is a temporary wrapper. The following work reliably on `THIS`:
- `GET` and `SET` for primitive types,
- `SHOW`, `HIDE`, `PLAY`, `PAUSE`, `STOP`, and `RESUME` for graphical objects ([`ANIMO`](../reference/index.md)).
Calling another type-specific method (e.g. `GETCFRAMEINEVENT` on [`ANIMO`](../reference/index.md)) usually crashes the engine. To work around this, AidemMedia scripts use the following pattern: store the object's name in a [`STRING`](../reference/STRING.md) variable first, then call `^RUN(string_variable, method_name)`, which internally resolves the string pointer to the actual object.
## Loops
### @LOOP
```
@LOOP(BEHAVIOUR code, INTEGER start, INTEGER delta, INTEGER increment)
```
Executes `code` for counter values `_I_` in the range `[start, start + delta)` with step `increment`. In pseudocode:
```
for (int _I_ = start; _I_ < start + delta; _I_ += increment) {
code;
}
```
### @FOR (BlooMoo)
```
@FOR(INTEGER counter, BEHAVIOUR code, INTEGER start, INTEGER delta, INTEGER increment)
```
Identical to `@LOOP`, except that the first argument selects a custom variable to act as the counter instead of the default `_I_`.
### @WHILE
```
@WHILE(mixed value1, STRING comparator, mixed value2, BEHAVIOUR code)
```
Executes `code` as long as the condition `value1 comparator value2` holds. The list of comparators is described below in [Conditional](#conditional).
## Conditional
The engine provides two forms of `@IF`.
### Simple condition
```
@IF(mixed value1, STRING comparator, mixed value2, BEHAVIOUR codeTrue, BEHAVIOUR codeFalse)
```
Available comparators:
| Comparator | Meaning |
|---|---|
| `_` | equal to |
| `!_` | not equal to |
| `<` | less than |
| `<_` | less than or equal |
| `>` | greater than |
| `>_` | greater than or equal |
### Compound condition
```
@IF(STRING condition, BEHAVIOUR codeTrue, BEHAVIOUR codeFalse)
```
Compound conditions add logical operators:
- `&&` — conjunction (and)
- `||` — disjunction (or)
In a compound condition, the equals sign is written as an apostrophe (`'`) rather than an underscore (`_`):
| Comparator | Meaning |
|---|---|
| `'` | equal to |
| `!'` | not equal to |
| `<` | less than |
| `<'` | less than or equal |
| `>` | greater than |
| `>'` | greater than or equal |
## Dynamic variable creation
Variables can be created on the fly inside a code block:
```
@INT(STRING name, INTEGER value)
@DOUBLE(STRING name, DOUBLE value)
@STRING(STRING name, STRING value)
@BOOL(STRING name, BOOL value)
```
Each statement creates a variable of the matching type with the given name and initial value.
## Jump operators
Inside loops and procedures, control flow can be redirected with:
- `@CONTINUE()` — skips the remaining statements in the current loop iteration and moves to the next one.
- `@BREAK()` — aborts the entire call tree started by the current signal or invocation.
- `@ONEBREAK()` — aborts the current procedure only.
- `@RETURN(mixed value)` — sets the value returned by the procedure but does not stop it from executing.
## Script loading order
Scripts in the engine are organised hierarchically: scripts at lower levels can see variables from their own scope and from all ancestors, but not the other way around.
### Entry point
The engine starts from `Application.def` in the `dane` subdirectory. This file defines objects of types [`APPLICATION`](../reference/index.md), [`EPISODE`](../reference/index.md), and [`SCENE`](../reference/index.md) — other types in this file are ignored.
Example contents:
```
OBJECT=GAME
GAME:TYPE=APPLICATION
GAME:PATH=GAME
GAME:EPISODES=PRZYGODA
GAME:STARTWITH=PRZYGODA
OBJECT=PRZYGODA
PRZYGODA:TYPE=EPISODE
PRZYGODA:PATH=GAME\PRZYGODA
PRZYGODA:SCENES=START,CREDITS,LEBIODKA
PRZYGODA:STARTWITH=START
OBJECT=START
START:TYPE=SCENE
START:PATH=GAME\PRZYGODA\START
```
### Loading subsequent files
After `Application.def` is read, the engine loads a `.CNV` file for each defined object. The file path is built from the object's `PATH` attribute (relative to the `dane` directory), the object's name, and the `.CNV` extension. If the file does not exist, loading is silently skipped.
The loading order is:
1. The file bound to the `APPLICATION` object.
2. The file of the first episode (`STARTWITH` attribute of `APPLICATION`).
3. The file of the first scene of that episode (`STARTWITH` attribute of `EPISODE`).
When locating files, the engine also takes the currently selected language into account (see [`APPLICATION.SETLANGUAGE`](../reference/APPLICATION.md#setlanguage)) — the chosen language identifier points to a subfolder of localised assets that is consulted while loading game files.
### Variable initialisation
Within each file, variables are created and initialised in a fixed order by type:
1. Procedures.
2. Primitive types ([`STRING`](../reference/STRING.md), [`DOUBLE`](../reference/DOUBLE.md), [`INTEGER`](../reference/INTEGER.md), [`BOOL`](../reference/BOOL.md)).
3. Arrays and conditions.
4. Animations, images, sounds, and fonts.
5. Buttons, text fields, sequences, mouse, keyboard, canvas observer.
For each variable in this phase the `ONINIT` signal is fired. Once all variables are initialised, the engine calls the `__ONINIT__` procedure if one is defined.