Files
dungeoncraft/docs/MISSION_SCRIPTING.md

117 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Mission scripting with blocks
Missions of editor campaigns are scripted with **blocks** (like Blockly): coloured puzzle pieces
put together in the block editor (see [CAMPAIGN_EDITOR.md](CAMPAIGN_EDITOR.md)). There is no code:
the game runs the blocks directly, inside its fixed simulation step, so a co-op match runs them
identically on every computer.
Code: `src/blocks.rs` (blocks, values, checking), `src/mscript.rs` (run time, triggers, zones),
`src/campaign_doc.rs` (`MissionScripts`, `TriggerDoc`, `TriggerKind`).
## Scripts of a mission
| Script | When it runs |
|---|---|
| Start | once, when the mission begins |
| Victory check | every second – use *If ... Win the mission* |
| Defeat check | every second – use *If ... Lose the mission* |
| Clock | every second |
| Triggers | whenever their condition is met (see below) |
The normal goals of the mission still apply; scripts are for anything more complicated. Any script
may call *Win* or *Lose*.
## Triggers
Each trigger has a **name**, a **kind** with its condition, **once** (fires only the first time;
switched on again by a *Switch trigger* block it may fire once more) and **active** (switched on at
the start). Conditions are checked ten times a second.
| Kind | Condition | The "trigger unit" |
|---|---|---|
| Zone entered | a unit of a side/kind comes into a zone | that unit |
| Zone left | a unit of a side/kind leaves a zone | that unit |
| Line crossed | a unit crosses a line zone (from one side to the other, within its ends) | that unit |
| Zone claimed | the player claims more tiles in a zone | – |
| Dug in the zone | fewer solid tiles in a zone (dug, caved in) | – |
| Units in the zone | the count of a side/kind in a zone becomes `< <= = != >= >` n | – |
| Timer | after n seconds, or every n seconds (*repeat*) | – |
| A unit falls | a unit of a side/kind dies (or the unit with this name, see *Spawn*) | the fallen unit (its place) |
| A tower falls | a tower of the dungeon / the knights / anyone is destroyed | – |
| A value is reached | gold, mana, creatures, heroes or a variable becomes `op n` | – |
| Room built | a room of a kind (or any) grows | – |
| Spell cast | a spell (or any) is cast | – |
| Creature slapped | the player slaps one of his creatures | – |
| Research done | the library finishes a discovery | – |
"Becomes" means the trigger fires when the condition turns true, not every check while it stays true.
Sides: player, heroes, Mossgrim, Lady Nightwell, rival 3, anyone. Kinds: any, or one of the 22
creatures and heroes.
## Blocks
| Category | Block | Fields |
|---|---|---|
| Speak | Message | text – `{name}` shows the value of variable `name` |
| | Objective | text (shown as the mission's objective) |
| | Crookfinger says | text (with a sound) |
| Units | Spawn | count, kind, level, side, where (the core, the trigger unit, a zone), optional name |
| | Hero wave | count (sent at once) |
| | Remove | side, zone (removes those units) |
| World | Change ground | zone → floor, earth, rock, water, lava, gold, mushroom grove (the core, portals, towers and the gate stay) |
| | Reveal | zone (lifts the fog of war) |
| | Show | zone (moves the camera there) |
| | Gold + / Mana + | amount (negative takes) |
| | Weather above ground | fair, rain, fog or storm, for seconds (0: until a block changes it); it fades in softly. Only maps with land above ground have weather |
| | Talent experience + | amount (experience for the player's master talents) |
| Logic | If / else | condition; blocks inside |
| | Repeat | times (0–100); blocks inside |
| | Repeat until | condition, checked **before** each run (already true: the inside never runs); blocks inside |
| | Repeat, then check: until | condition, checked **after** each run (the inside runs at least once); blocks inside |
| | Wait | seconds – the script pauses here and goes on with the next block later (also inside loops and "if") |
| | Switch trigger | trigger, on/off |
| Variables | Set | variable, value |
| | Change | variable, value to add |
| Mission | Win the mission / Lose the mission | – |
### Values
Every number field holds a **value**; the switch in front of it changes the value's kind:
- numbers: *Number*, *Variable*, *Gold*, *Mana*, *Seconds played*, *Count* (creatures of a
side/kind), *Count* in a zone, *Random* (whole number between a and b, deterministic),
*Calculation* (`+ - * /`, division by 0 gives 0),
- conditions (for *If*): *Comparison* (`< <= = != >= >`), *and*, *or*, *not*, *Yes/no*,
*Trigger unit is a* (kind), *Weather above ground is* (fair, rain, fog, storm).
Variables are numbers the mission remembers (saved with the game); a variable is known once some
script of the mission sets it.
### Checking
The editor checks while you build and marks problems red: empty texts, unknown zones, triggers or
creature kinds, variables never set, a condition where a number belongs (or the other way round).
A trigger whose zone is missing is marked in the trigger list. Problems are also listed in the
campaign file check (`CampaignDoc::validate`).
## At run time (`src/mscript.rs`)
- Every run of a script (the start, each second's checks, each fired trigger) is a **thread**: the
lists of blocks it is in and where. *Wait* parks a thread until its time; threads are saved with
the game, so a waiting script goes on after loading.
- The victory check, defeat check and clock start every second, but not while their previous run is
still waiting. A trigger that fires again while its last run waits starts a second run.
- Loops without a *Wait* run up to 2000 blocks per check (ten checks a second) and then go on at the
next check – a script can never hang the game.
- Blocks act at once, in order: a *Count* after a *Spawn* already sees the new units. Variables, the
random state, fired triggers, zone contents and waiting threads are part of `ScriptState`.
- Scripts always run from the first player's side; messages reach every player of a match.
- Test play shows the variables and the trigger log at the top right, and the zones on the map.
## The demo
*Open the demo* in the campaign editor: mission 1 ("The Trial of Triggers") uses all 14 trigger
kinds, all special scripts and every block (including both kinds of *until* loops and *Wait*) on a painted map with five zones (rectangle,
circle, line, tiles); mission 2 is a random map behind a branch. Play it with *Test play* and watch
the debug view.