Added part of docs
This commit is contained in:
280
docs/en/engine/scripts.md
Normal file
280
docs/en/engine/scripts.md
Normal 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.
|
||||
Reference in New Issue
Block a user