Map Editor Documentation

Trigger reference

Every trigger event, expression and action: its JSON kind, editor sentence, fields and a minimal valid example.

Reference (generated) · Page 10 of 46

This page lists every node in the trigger language. It is generated from the same catalog the validator uses, so it cannot fall out of step with the game. The JSON Schema for whole scripts is at /schemas/v1/trigger-script.json.

Every node is a JSON object with a k naming its kind. Unknown properties are errors. Wherever a field takes an expression, you can write a bare number, string or boolean instead: 5 means {"k":"int","v":5}, 1.5 means {"k":"real","v":1.5}, "hi" means {"k":"str","v":"hi"}. A string is always text; to read a variable, use {"k":"var","name":"score"}. Wherever a field takes text, a bare string is shorthand for a one-part template.

Every example below passes validateTriggerScript when placed into this script (events go in events, expressions in conditions, actions in actions):

{
  "version": 1,
  "vars": [
    {
      "name": "score",
      "type": "int"
    },
    {
      "name": "squad",
      "type": "unitGroup"
    },
    {
      "name": "code",
      "type": "string"
    }
  ],
  "regions": [
    {
      "id": "arena",
      "x": 0,
      "y": 0,
      "w": 8,
      "h": 8
    }
  ],
  "functions": [
    {
      "name": "double",
      "params": [
        {
          "name": "n",
          "type": "int"
        }
      ],
      "returns": "int",
      "actions": [
        {
          "k": "return",
          "value": {
            "k": "mul",
            "a": {
              "k": "var",
              "name": "n"
            },
            "b": {
              "k": "int",
              "v": 2
            }
          }
        }
      ]
    }
  ],
  "hashtables": [
    {
      "name": "scores",
      "valueType": "int"
    }
  ],
  "triggers": [
    {
      "id": "main",
      "events": [
        {
          "k": "mapInit"
        }
      ],
      "actions": []
    }
  ]
}

Events

What makes a trigger fire. A trigger fires when any one of its events happens.

Map events

mapInit

Map initialisation. Fires once on the first tick, after every global initialiser.

Editor: the map starts

No fields.

{"k":"mapInit"}

Time events

periodic

Every N ticks. Fires when (tick − offset) is a multiple of everyTicks, from tick offsetTicks on.

Editor: every ‹Interval (ticks)› ticks, phase-shifted by ‹Phase offset›

FieldTypeRequiredDescription
everyTicksint (≥ 1)yesPeriod in ticks (20 = 1 second).
offsetTicksintnoPhase offset in ticks.
{"k":"periodic","everyTicks":1}

atTick

At tick. Fires once on an exact tick.

Editor: at tick ‹Tick›

FieldTypeRequiredDescription
tickint (≥ 0)yesTick number.
{"k":"atTick","tick":1}

timerExpires

Timer expires. Fires when a named timer reaches zero.

Editor: timer ‹Timer› expires

FieldTypeRequiredDescription
timertimerIdyesTimer name.
{"k":"timerExpires","timer":"wave_timer"}

Region events

unitEntersRegion

Unit enters region. Fires for each unit whose tile moved into the region this tick. Units that start inside do not count.

Editor: a unit enters ‹Region› matching ‹Filter›

FieldTypeRequiredDescription
regionregionIdyesRegion id.
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitEntersRegion","region":"arena"}

unitLeavesRegion

Unit leaves region. Fires for each unit that left the region this tick — including by dying or being removed (matched against its last snapshot).

Editor: a unit leaves ‹Region› matching ‹Filter›

FieldTypeRequiredDescription
regionregionIdyesRegion id.
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitLeavesRegion","region":"arena"}

Unit events

unitDies

Unit dies. Fires when a unit or building dies. The filter is matched against the unit as it was at death (aliveOnly is ignored); event unit = the dead unit, other unit = killer.

Editor: a unit dies matching ‹Filter›

FieldTypeRequiredDescription
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitDies"}

unitTrained

Unit trained. Fires when production completes a unit.

Editor: a unit finishes training matching ‹Filter›

FieldTypeRequiredDescription
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitTrained"}

buildingComplete

Building completes. Fires when construction finishes.

Editor: a building completes matching ‹Filter›

FieldTypeRequiredDescription
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"buildingComplete"}

unitAttacked

Unit attacked. Fires when a unit takes an attack; event value = damage, other unit = attacker.

Editor: a unit is attacked matching ‹Filter›

FieldTypeRequiredDescription
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitAttacked"}

heroLevels

Hero levels up. Fires when a hero gains a level; event value = new level.

Editor: a hero gains a level matching ‹Filter›

FieldTypeRequiredDescription
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"heroLevels"}

unitDamaging

Unit is about to take damage. Fires between armour and the hp write, for EVERY source of damage in the game — melee, projectiles, spells, burns, thorns, lava, a collapsing bridge. Unit = the victim, other unit = the dealer (0 for the environment), event damage = the amount about to land. This is the one event whose amount you can change: use "set event damage" for a custom armour system, a shield that absorbs part of a hit, or a damage-type table. Triggers fire in authored order and each sees the previous one's result. "wait" is not allowed in a trigger with this event, because the hit is only half resolved. Needs map format 3.

Editor: a unit is about to take damage — ‹Filter›

FieldTypeRequiredDescription
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitDamaging"}

unitDamaged

Unit has taken damage. Fires immediately after the hp is written, for every source of damage. Event damage = the amount that actually landed. Use it to react — a bloodlust stack, a retaliation, "the boss enrages below half". The victim of a killing blow is still alive with 0 hp here, so read hp rather than alive. "set event damage" does nothing on this event; there is nothing left to change. Needs map format 3.

Editor: a unit has taken damage — ‹Filter›

FieldTypeRequiredDescription
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitDamaged"}

Item events

itemPickedUp

Item picked up. Fires when a hero picks up an item. NOTE: buying does not fire it — watch itemPurchased as well if you mean "the hero now holds one".

Editor: an item is picked up — ‹Item›

FieldTypeRequiredDescription
itemIditemIdnoOnly this item id; absent = any.
{"k":"itemPickedUp"}

itemUsed

Item used. Fires when a hero consumes or activates an item — a potion, a scroll, a town portal, an active. Event unit = the hero, text = the item id. Needs map format 3.

Editor: a hero uses an item (‹Item›)

FieldTypeRequiredDescription
itemIditemIdnoOnly this item id; absent = any.
{"k":"itemUsed"}

itemPurchased

Item purchased. Fires when a hero buys an item from a shop. Gambling-den rolls do NOT fire it. Event unit = the hero, text = the item id. Needs map format 3.

Editor: a hero buys an item (‹Item›)

FieldTypeRequiredDescription
itemIditemIdnoOnly this item id; absent = any.
{"k":"itemPurchased"}

itemSold

Item sold. Fires when a hero sells an item. Event value = 1 if sold for XP, 0 if sold for gold. Needs map format 3.

Editor: a hero sells an item (‹Item›)

FieldTypeRequiredDescription
itemIditemIdnoOnly this item id; absent = any.
{"k":"itemSold"}

itemDropped

Item dropped. Fires when a hero drops an item, from the backpack or off the paper doll. A hero DEATH drop fires it too, once per item. Needs map format 3.

Editor: a hero drops an item (‹Item›)

FieldTypeRequiredDescription
itemIditemIdnoOnly this item id; absent = any.
{"k":"itemDropped"}

Combat events

abilityCastStart

Cast starts. Fires once when a cast is committed, after every cost and range check has passed. Event unit = caster, other unit = target unit (0 if none), value = wind-up length in ticks, eventSpellId = the spell, eventTargetPoint = the target tile. An ordinary RTS or AI cast has NO wind-up (only a possessed hero or a spell with rtsCastBar does), so start, effect and finished all land on the same tick. Boss telegraphs use a separate engine and fire none of these. Needs map format 3.

Editor: a unit starts casting ‹Spell id›

FieldTypeRequiredDescription
spellIdstringnoOnly this spell id; absent = any.
{"k":"abilityCastStart"}

abilityCastEffect

Cast resolves. Fires when the spell's effect actually resolves — the one to hang a consequence on. Event unit = caster, other unit = target unit, player = the caster's seat, eventSpellId = the spell, eventTargetPoint = the target tile. Needs map format 3.

Editor: a cast resolves (‹Spell id›)

FieldTypeRequiredDescription
spellIdstringnoOnly this spell id; absent = any.
{"k":"abilityCastEffect"}

abilityCastFinished

Cast finishes. Fires once when a cast ends normally. Exactly-once per cast for both instant and cast-bar spells. Needs map format 3.

Editor: a cast finishes (‹Spell id›)

FieldTypeRequiredDescription
spellIdstringnoOnly this spell id; absent = any.
{"k":"abilityCastFinished"}

abilityCastCancelled

Cast cancelled. Fires when a cast in progress is interrupted. Event text = the reason: move, death, damage, invalid or superseded. A cast REFUSED before it started (no mana, on cooldown, out of range, silenced, no line of sight) fires NOTHING, not even this. Sleep also strips a cast without firing it. Needs map format 3.

Editor: a cast is cancelled (‹Spell id›)

FieldTypeRequiredDescription
spellIdstringnoOnly this spell id; absent = any.
{"k":"abilityCastCancelled"}

projectileHits

Projectile hits. Fires when a projectile strikes its target or a bomb detonates. Event unit = target, other unit = shooter, value = damage.

Editor: a projectile hits matching ‹Tag›

FieldTypeRequiredDescription
tagstringnoMatch the shooter's authored tag, the spell id, the shooter's unit type or the projectile type.
{"k":"projectileHits"}

Orders events

orderIssued

Order issued. Fires once when a unit or selection is ordered. COVERS every player order (right-click, drag, minimap, HUD, hotkey, queued waypoints), every trigger order action, and orders arriving by lockstep, replay, cinematic, possession or a mode's bot. DOES NOT cover the heuristic AI or the LLM commander, which write movement directly instead of issuing commands — so on an AI seat this is near-silent and must not be used to police AI behaviour. Event unit = the LOWEST entity id ordered, other unit = target unit (0 if none), value = how many units the order addressed, text = the order kind, eventTargetPoint = the target tile ((-1,-1) for stop/hold). ONE signal per order, not one per unit. Needs map format 3.

Editor: a unit is ordered to ‹Order› by player ‹From seat›

FieldTypeRequiredDescription
order'move' | 'attack_move' | 'attack' | 'stop' | 'hold' | 'patrol' | 'follow'noOnly this order kind; absent = any.
playerplayerNumnoOnly orders from this seat; absent = any.
{"k":"orderIssued"}

Player events

playerEliminated

Player eliminated. Fires when a seat is eliminated.

Editor: a player is eliminated — ‹Player›

FieldTypeRequiredDescription
playerplayerNumnoOnly this seat; absent = any.
{"k":"playerEliminated"}

playerLeaves

Player leaves. Fires on the tick a seat's human leaves the match, under any leaver policy. NOT the same as elimination and neither implies the other: a leaver under abandon keeps a living base, and an eliminated player usually stays to watch. Event player = the seat that left. Needs map format 3.

Editor: a player leaves — ‹Player›

FieldTypeRequiredDescription
playerplayerNumnoOnly this seat; absent = any.
{"k":"playerLeaves"}

upgradeComplete

Upgrade completes. Fires when research completes; event text = upgrade id.

Editor: an upgrade completes — ‹Upgrade›

FieldTypeRequiredDescription
upgradeIdupgradeIdnoOnly this upgrade; absent = any.
{"k":"upgradeComplete"}

playerChats

Player chats. Fires when a seated player sends an all-chat line (team chat and whispers never fire it); event text = the line.

Editor: player ‹Player› sends chat matching "‹Pattern›" (‹Match mode›)

FieldTypeRequiredDescription
patternstringnoText to match; absent = any message.
matchMode'exact' | 'prefix' | 'contains'noHow pattern matches (default exact).
playerplayerNumnoOnly this seat.
{"k":"playerChats","pattern":"-reset","matchMode":"prefix"}

playerKeyPress

Player presses key. Fires when a player presses or releases a key (through lockstep); event text = key, value = 1 down / 0 up.

Editor: player ‹Player› presses ‹Key› (‹Key state›)

FieldTypeRequiredDescription
keykeyNamenoKey name, e.g. 'w', 'Space', 'ArrowUp'.
state'down' | 'up'nodown or up (absent = both).
playerplayerNumnoOnly this seat.
{"k":"playerKeyPress","key":"Space","state":"down"}

Variable events

variableChanges

Variable changes. Fires (in the cascade phase) when a GLOBAL variable is written with a different value.

Editor: variable ‹Variable› changes

FieldTypeRequiredDescription
namevarNameyesGlobal variable name.
{"k":"variableChanges","name":"score"}

UI events

dialogButton

Dialog button clicked. Fires when a player clicks a trigger dialog button (arrives through lockstep); event value = button index.

Editor: a dialog button is clicked on ‹Dialog›, button ‹Button index›

FieldTypeRequiredDescription
dialogIddialogIdnoOnly this dialog.
buttonIndexint (≥ 0)noOnly this 0-based button.
{"k":"dialogButton"}

uiFrameClicked

UI frame clicked. Fires when a player clicks one of your own HUD frames (arrives through lockstep, like a dialog button). Event player = the seat that clicked, text = the frame id. A click only counts when that seat can really see that frame right now — a frame that was destroyed, hidden, or shown to somebody else fires nothing, however the click arrived. Needs map format 3.

Editor: a UI frame is clicked: ‹Frame›

FieldTypeRequiredDescription
frameIdframeIdnoOnly this frame; absent = any.
{"k":"uiFrameClicked"}

Custom events

custom

Custom event. Fires when raiseEvent raises this name (same tick, capped cascade).

Editor: custom event ‹Event name› is raised

FieldTypeRequiredDescription
nameeventNameyesEvent name.
{"k":"custom","name":"boss_down"}

Cutscene events

cutsceneFinished

Cutscene finished. Fires when a cutscene ends. Event value: 0 played out, 1 skipped by every human viewer, 2 replaced by another scene, 3 stopped by a trigger.

Editor: cutscene ‹Scene› finishes

FieldTypeRequiredDescription
sceneIdsceneIdnoOnly this scene.
{"k":"cutsceneFinished"}

Conditions and expressions

Values. A trigger condition is any expression; the trigger runs only when all of its conditions are true.

Literal expressions

int

Integer — returns int. An integer literal. Non-integers are truncated.

Editor: ‹Value›

FieldTypeRequiredDescription
vnumberyesThe value.
{"k":"int","v":1}

real

Real number — returns real. A real-number literal.

Editor: ‹Value›

FieldTypeRequiredDescription
vnumberyesThe value.
{"k":"real","v":1}

bool

Boolean — returns bool. true or false.

Editor: ‹Value›

FieldTypeRequiredDescription
vboolyesThe value.
{"k":"bool","v":true}

str

Text — returns string. A string literal.

Editor: "‹Value›"

FieldTypeRequiredDescription
vstringyesThe value.
{"k":"str","v":"text"}

Geometry expressions

point

Point — returns point. A tile coordinate built from two numbers.

Editor: (‹Tile X›, ‹Tile Y›)

FieldTypeRequiredDescription
xexpr (number)yesTile X.
yexpr (number)yesTile Y.
{"k":"point","x":1,"y":1}

distance

Distance — returns real. Euclidean tile distance; either side may be a unit or a point.

Editor: distance from ‹From› to ‹To›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"distance","a":1,"b":1}

pointX

Point X — returns number. X of a point.

Editor: X of ‹Point›

FieldTypeRequiredDescription
pexpr (point)yesThe point.
{"k":"pointX","p":{"k":"regionCenter","region":"arena"}}

pointY

Point Y — returns number. Y of a point.

Editor: Y of ‹Point›

FieldTypeRequiredDescription
pexpr (point)yesThe point.
{"k":"pointY","p":{"k":"regionCenter","region":"arena"}}

regionCenter

Region centre — returns point. Integer centre tile of a region.

Editor: centre of ‹Region›

FieldTypeRequiredDescription
regionregionIdyesRegion id.
{"k":"regionCenter","region":"arena"}

randomPointInRegion

Random point in region — returns point. Random tile inside the region (always two PRNG draws).

Editor: a random point in ‹Region›

FieldTypeRequiredDescription
regionregionIdyesRegion id.
{"k":"randomPointInRegion","region":"arena"}

pointInRegion

Point in region — returns bool. True when the point (or unit) lies inside the region.

Editor: ‹Point› is inside ‹Region›

FieldTypeRequiredDescription
pexpr (point)yesPoint or unit.
regionregionIdyesRegion id.
{"k":"pointInRegion","p":{"k":"regionCenter","region":"arena"},"region":"arena"}

offsetPoint

Offset point — returns point. A point moved by (dx, dy) tiles.

Editor: ‹Point› offset by (‹Tiles X›, ‹Tiles Y›)

FieldTypeRequiredDescription
pexpr (point)yesPoint or unit.
dxexpr (number)yesTiles X.
dyexpr (number)yesTiles Y.
{"k":"offsetPoint","p":{"k":"regionCenter","region":"arena"},"dx":1,"dy":1}

polarOffset

Point at an angle — returns point. A point (or unit) moved distance tiles along angle. With angleBetween this is the whole of "spawn behind the hero", "ring of totems", "fire at this bearing". Needs map format 3.

Editor: ‹From› moved ‹Tiles› at ‹Direction›

FieldTypeRequiredDescription
pexpr (point)yesPoint or unit to start from.
angleexpr (number)yesDirection in RADIANS. Multiply by 57.29577951308232 for the degrees createUnits.facing wants.
distanceexpr (number)yesDistance in tiles; negative goes the other way.
{"k":"polarOffset","p":{"k":"regionCenter","region":"arena"},"angle":1,"distance":1}

angleBetween

Bearing from A to B — returns real. Direction from A to B in radians, -pi..pi. Either side may be a unit or a point. Due west is +pi, not -pi, so compare bearings with a tolerance rather than for equality. Needs map format 3.

Editor: bearing from ‹From› to ‹To›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"angleBetween","a":1,"b":1}

Unit expressions

nullUnit

No unit — returns unit. Entity id 0. Every property of it reads as a zero value.

Editor: no unit

No fields.

{"k":"nullUnit"}

unitProp

Unit property — returns any. Read a property of a unit. A unit that died THIS tick answers from its death snapshot; otherwise a missing unit gives the zero value.

Editor: ‹Property› of ‹Unit›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
prop'hp' | 'maxHp' | 'hpPercent' | 'mana' | 'maxMana' | 'x' | 'y' | 'level' | 'xp' | 'kills' | 'owner' | 'alive' | 'isHero' | 'isBuilding' | 'isFlying' | 'typeId'yesProperty to read.
{"k":"unitProp","unit":{"k":"eventUnit"},"prop":"hp"}

unitAboard

Unit aboard transport — returns bool. Whether the original unit is held in the original transport cargo. False for missing units or hulls. Needs map format 3.

Editor: ‹Unit› is aboard ‹Transport›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
transportexpr (unit)yesTransport to check.
{"k":"unitAboard","unit":{"k":"eventUnit"},"transport":{"k":"eventUnit"}}

unitPoint

Unit position — returns point. Tile position of a unit.

Editor: position of ‹Unit›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
{"k":"unitPoint","unit":{"k":"eventUnit"}}

entityByAid

Unit by authored id — returns unit. The placed entity carrying this authored id, or no unit.

Editor: the unit with authored id ‹Authored id›

FieldTypeRequiredDescription
aidaidyesAuthored id from the entity inspector.
{"k":"entityByAid","aid":"north_gate"}

unitHasBuff

Unit has buff — returns bool. True while this exact buff id is on the unit and has not run out. A buff whose remaining time has reached zero already answers false, one tick before the engine sweeps it up — so "re-apply when it runs out" does not double-cast. Matches the whole id, never a prefix. Needs map format 3.

Editor: ‹Unit› has buff ‹Buff id›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
buffIdstringyesBuff id to look for — the same id add buff used.
{"k":"unitHasBuff","unit":{"k":"eventUnit"},"buffId":"text"}

Variable expressions

var

Variable — returns any. Read a variable: a trigger/function local, a function parameter, a loop variable or a global (resolved in that order).

Editor: ‹Variable›[‹Index›]

FieldTypeRequiredDescription
namevarNameyesVariable name.
indexexpr (int)noElement index for an array variable. Out-of-range reads yield the zero value.
{"k":"var","name":"score"}

Arithmetic expressions

add

A + B — returns number. Sum. If either side is a string the two are concatenated.

Editor: ‹A› + ‹B›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"add","a":1,"b":1}

sub

A − B — returns number. Difference.

Editor: ‹A› − ‹B›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
bexpr (number)yesRight operand.
{"k":"sub","a":1,"b":1}

mul

A × B — returns number. Product.

Editor: ‹A› × ‹B›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
bexpr (number)yesRight operand.
{"k":"mul","a":1,"b":1}

div

A ÷ B — returns number. Quotient. Division by zero yields 0 — never Infinity or NaN.

Editor: ‹A› ÷ ‹B›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
bexpr (number)yesRight operand.
{"k":"div","a":1,"b":1}

mod

A mod B — returns number. Remainder (sign of A). Modulo by zero yields 0.

Editor: ‹A› mod ‹B›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
bexpr (number)yesRight operand.
{"k":"mod","a":1,"b":1}

neg

Negate — returns number. Arithmetic negation.

Editor: −‹A›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"neg","a":1}

abs

Absolute value — returns number. Absolute value.

Editor: |‹A›|

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"abs","a":1}

min

Minimum — returns number. The smaller of A and B.

Editor: min(‹A›, ‹B›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
bexpr (number)yesRight operand.
{"k":"min","a":1,"b":1}

max

Maximum — returns number. The larger of A and B.

Editor: max(‹A›, ‹B›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
bexpr (number)yesRight operand.
{"k":"max","a":1,"b":1}

clamp

Clamp — returns number. A limited to [lo, hi]; reversed bounds are swapped.

Editor: clamp(‹A›, ‹Minimum›, ‹Maximum›)

FieldTypeRequiredDescription
aexpr (number)yesValue to clamp.
loexpr (number)yesLower bound.
hiexpr (number)yesUpper bound.
{"k":"clamp","a":{"k":"var","name":"score"},"lo":0,"hi":100}

trunc

Truncate — returns int. Real to integer toward zero (Math.trunc) — the one real→int rule in the language.

Editor: trunc(‹A›)

FieldTypeRequiredDescription
aexpr (real)yesLeft operand.
{"k":"trunc","a":1.5}

floor

Floor — returns int. Largest integer at or below A. Needs map format 3.

Editor: floor(‹A›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"floor","a":1}

ceil

Ceiling — returns int. Smallest integer at or above A. Needs map format 3.

Editor: ceil(‹A›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"ceil","a":1}

round

Round — returns int. Nearest integer, halves going toward +Infinity — so round(2.5) is 3 and round(-2.5) is -2. Needs map format 3.

Editor: round(‹A›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"round","a":1}

sqrt

Square root — returns real. Square root. A negative A yields 0, never NaN. Needs map format 3.

Editor: √‹A›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"sqrt","a":1}

pow

A to the power B — returns real. A raised to B. A non-finite result yields 0. Needs map format 3.

Editor: ‹A› ^ ‹B›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
bexpr (number)yesRight operand.
{"k":"pow","a":1,"b":1}

sign

Sign — returns int. -1 for a negative A, 1 for a positive one, 0 for zero. Needs map format 3.

Editor: sign(‹A›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"sign","a":1}

lerp

Interpolate — returns real. A blended toward B by T: A + (B - A) x T. T is NOT clamped, so 2 overshoots and -1 extrapolates backwards. Needs map format 3.

Editor: blend ‹A› → ‹B› by ‹Blend factor›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
bexpr (number)yesRight operand.
texpr (number)yesBlend factor; 0 gives A, 1 gives B.
{"k":"lerp","a":1,"b":1,"t":1}

Maths expressions

sin

Sine — returns real. Sine of an angle in radians. Needs map format 3.

Editor: sin(‹Angle›)

FieldTypeRequiredDescription
aexpr (number)yesAngle in RADIANS. Multiply by 57.29577951308232 for the degrees createUnits.facing wants.
{"k":"sin","a":1}

cos

Cosine — returns real. Cosine of an angle in radians. Needs map format 3.

Editor: cos(‹Angle›)

FieldTypeRequiredDescription
aexpr (number)yesAngle in RADIANS. Multiply by 57.29577951308232 for the degrees createUnits.facing wants.
{"k":"cos","a":1}

tan

Tangent — returns real. Tangent of an angle in radians. Needs map format 3.

Editor: tan(‹Angle›)

FieldTypeRequiredDescription
aexpr (number)yesAngle in RADIANS. Multiply by 57.29577951308232 for the degrees createUnits.facing wants.
{"k":"tan","a":1}

atan2

Angle of a vector — returns real. Direction of the vector (X, Y) in radians, -pi..pi. Y comes first, as it does in every atan2. Due west is +pi, not -pi. Needs map format 3.

Editor: angle of (‹Horizontal component›, ‹Vertical component›)

FieldTypeRequiredDescription
yexpr (number)yesVertical component.
xexpr (number)yesHorizontal component.
{"k":"atan2","y":1,"x":1}

asin

Arc sine — returns real. Angle in radians whose sine is A. Outside -1..1 yields 0, never NaN. Needs map format 3.

Editor: asin(‹A›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"asin","a":1}

acos

Arc cosine — returns real. Angle in radians whose cosine is A. Outside -1..1 yields 0, never NaN. Needs map format 3.

Editor: acos(‹A›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"acos","a":1}

exp

e to the power A — returns real. e raised to A. A non-finite result yields 0. Needs map format 3.

Editor: e^‹A›

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"exp","a":1}

log

Natural logarithm — returns real. Natural log of A. A at or below zero yields 0, never -Infinity and never NaN. Needs map format 3.

Editor: ln(‹A›)

FieldTypeRequiredDescription
aexpr (number)yesLeft operand.
{"k":"log","a":1}

Comparison expressions

eq

A = B — returns bool. Equality. Strings compare by code unit; groups element-wise; points by x then y.

Editor: ‹A› = ‹B›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"eq","a":1,"b":1}

ne

A ≠ B — returns bool. Inequality.

Editor: ‹A› ≠ ‹B›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"ne","a":1,"b":1}

lt

A < B — returns bool. Less than.

Editor: ‹A› < ‹B›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"lt","a":1,"b":1}

le

A ≤ B — returns bool. Less than or equal.

Editor: ‹A› ≤ ‹B›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"le","a":1,"b":1}

gt

A > B — returns bool. Greater than.

Editor: ‹A› > ‹B›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"gt","a":1,"b":1}

ge

A ≥ B — returns bool. Greater than or equal.

Editor: ‹A› ≥ ‹B›

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
bexpr (any)yesRight operand.
{"k":"ge","a":1,"b":1}

Logic expressions

and

A and B — returns bool. Logical AND. Short-circuits: B is not evaluated when A is false.

Editor: ‹A› and ‹B›

FieldTypeRequiredDescription
aexpr (bool)yesLeft operand.
bexpr (bool)yesRight operand.
{"k":"and","a":true,"b":true}

or

A or B — returns bool. Logical OR. Short-circuits: B is not evaluated when A is true.

Editor: ‹A› or ‹B›

FieldTypeRequiredDescription
aexpr (bool)yesLeft operand.
bexpr (bool)yesRight operand.
{"k":"or","a":true,"b":true}

not

Not A — returns bool. Logical negation.

Editor: not ‹A›

FieldTypeRequiredDescription
aexpr (bool)yesLeft operand.
{"k":"not","a":true}

Time expressions

tick

Game tick — returns int. The current simulation tick (20 per second) — the only clock in the language.

Editor: the game tick

No fields.

{"k":"tick"}

rand

Random integer — returns int. Inclusive random integer from the synchronised game PRNG. Always consumes exactly one draw.

Editor: random ‹Minimum› to ‹Maximum›

FieldTypeRequiredDescription
minexpr (int)yesLower bound (inclusive).
maxexpr (int)yesUpper bound (inclusive).
{"k":"rand","min":1,"max":6}

randReal

Random real — returns real. Random real in [min, max) from the synchronised game PRNG. Always consumes exactly one draw, even when min equals max, because a conditional draw would advance the stream on one client and not another. Needs map format 3.

Editor: random real ‹Minimum› to ‹Maximum (exclusive)›

FieldTypeRequiredDescription
minexpr (number)yesLower bound (inclusive).
maxexpr (number)yesUpper bound (exclusive).
{"k":"randReal","min":1,"max":1}

timerRemaining

Timer ticks left — returns int. Ticks until the timer expires (0 if not running).

Editor: ticks left on ‹Timer›

FieldTypeRequiredDescription
timertimerIdyesTimer name.
{"k":"timerRemaining","timer":"wave_timer"}

timerRunning

Timer is running — returns bool. True while the timer runs and is not paused.

Editor: ‹Timer› is running

FieldTypeRequiredDescription
timertimerIdyesTimer name.
{"k":"timerRunning","timer":"wave_timer"}

Player expressions

playerResource

Player's resource — returns int. Current stock of one resource.

Editor: ‹Player›'s ‹Resource›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
resource'gold' | 'lumber' | 'stone' | 'oil'yesResource kind.
{"k":"playerResource","player":0,"resource":"gold"}

playerPop

Player's population — returns int. Population in use.

Editor: ‹Player›'s population

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"playerPop","player":0}

playerMaxPop

Player's population cap — returns int. Population cap.

Editor: ‹Player›'s population cap

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"playerMaxPop","player":0}

playerAlive

Player is alive — returns bool. True while the seat has not been eliminated or defeated.

Editor: ‹Player› is still alive

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"playerAlive","player":0}

playerTeam

Player's team — returns int. Team id of the seat, or -1.

Editor: ‹Player›'s team

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"playerTeam","player":0}

playerHasUpgrade

Player has upgrade — returns bool. True once the seat has completed the research.

Editor: ‹Player› has researched ‹Upgrade›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
upgradeIdupgradeIdyesUpgrade id.
{"k":"playerHasUpgrade","player":0,"upgradeId":"dwarf_forged_weapons_1"}

isAllied

Players are allied — returns bool. True when seats A and B are on the same team.

Editor: ‹A› is allied with ‹B›

FieldTypeRequiredDescription
aexpr (player)yesLeft operand.
bexpr (player)yesRight operand.
{"k":"isAllied","a":0,"b":0}

isEnemy

Players are enemies — returns bool. True when seats A and B are not allied.

Editor: ‹A› is an enemy of ‹B›

FieldTypeRequiredDescription
aexpr (player)yesLeft operand.
bexpr (player)yesRight operand.
{"k":"isEnemy","a":0,"b":0}

playerName

Player's name — returns string. Display name of a seat. Today this is always "Player 1", "Player 2"… — the lobby name is a per-client string and a trigger variable is hashed, so it is deliberately not read here. Needs map format 3.

Editor: ‹Player›'s name

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"playerName","player":0}

playerIsHuman

A human is at this seat — returns bool. True when a human is present: a human slot whose player has not left. An AI seat is false, and so is a seat whose human has gone. Needs map format 3.

Editor: ‹Player› is a human player

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"playerIsHuman","player":0}

playerCount

Number of players — returns int. How many seats match. The creep and neutral seats are never counted, so "alive" on a two-player map with creeps answers 2. Needs map format 3.

Editor: number of ‹Which seats› players

FieldTypeRequiredDescription
of'seated' | 'alive' | 'human' | 'ai'yesWhich seats to count.
{"k":"playerCount","of":"seated"}

isPointVisibleTo

Seat can see tile — returns bool. True when THAT SEAT's own units or completed buildings reveal the tile right now. It is the simulation's own vision test, not the fog you are looking at, so it answers the same on every client and in a replay. Allied vision is NOT folded in: ask about each ally, or use "players are allied". A seat that is not in the lobby owns nothing and answers false; the creep seat answers like any other. It does not know about night, possession or a submerged submarine's halved sight — it is the daylight baseline radius plus the sightRadius buff. It SCANS every revealer in the world, so it costs about what "units of player" costs; do not put it inside a big loop. Needs map format 3.

Editor: ‹Player› can see ‹Tile›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
atexpr (point)yesTile to test.
{"k":"isPointVisibleTo","player":0,"at":{"k":"regionCenter","region":"arena"}}

Group expressions

unitsInRegion

Units in region — returns unitGroup. Sorted group of units whose tile is inside the region.

Editor: units in ‹Region› matching ‹Filter›

FieldTypeRequiredDescription
regionregionIdyesRegion id.
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitsInRegion","region":"arena"}

unitsWithTag

Units with tag — returns unitGroup. Sorted group of placed entities sharing an authored tag.

Editor: units tagged ‹Tag› matching ‹Filter›

FieldTypeRequiredDescription
tagtagyesAuthored tag.
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitsWithTag","tag":"wave"}

unitsOfPlayer

Units of player — returns unitGroup. Sorted group of units owned by the seat.

Editor: units owned by ‹Player› matching ‹Filter›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitsOfPlayer","player":0}

unitsOfType

Units of type — returns unitGroup. Sorted group of units or buildings of one type id.

Editor: units of type ‹Unit type› matching ‹Filter›

FieldTypeRequiredDescription
unitTypeIdunitTypeIdyesUnit or building type id.
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitsOfType","unitTypeId":"dwarf_ironguard"}

groupCount

Group size — returns int. Number of units in a group.

Editor: number of units in ‹Unit group›

FieldTypeRequiredDescription
groupexpr (unitGroup)yesThe group.
{"k":"groupCount","group":{"k":"unitsInRegion","region":"arena"}}

groupAt

Unit at index — returns unit. 0-based element of the sorted group; out of range gives no unit.

Editor: unit ‹Index› of ‹Unit group›

FieldTypeRequiredDescription
groupexpr (unitGroup)yesThe group.
indexexpr (int)yes0-based index.
{"k":"groupAt","group":{"k":"unitsInRegion","region":"arena"},"index":1}

groupRandom

Random unit of group — returns unit. A random member (one PRNG draw, even for an empty group).

Editor: a random unit in ‹Unit group›

FieldTypeRequiredDescription
groupexpr (unitGroup)yesThe group.
{"k":"groupRandom","group":{"k":"unitsInRegion","region":"arena"}}

groupUnion

Group union — returns unitGroup. Members of A or B.

Editor: ‹A› together with ‹B›

FieldTypeRequiredDescription
aexpr (unitGroup)yesLeft operand.
bexpr (unitGroup)yesRight operand.
{"k":"groupUnion","a":{"k":"unitsInRegion","region":"arena"},"b":{"k":"unitsInRegion","region":"arena"}}

groupDiff

Group difference — returns unitGroup. Members of A not in B.

Editor: ‹A› except ‹B›

FieldTypeRequiredDescription
aexpr (unitGroup)yesLeft operand.
bexpr (unitGroup)yesRight operand.
{"k":"groupDiff","a":{"k":"unitsInRegion","region":"arena"},"b":{"k":"unitsInRegion","region":"arena"}}

groupHas

Group contains — returns bool. True when the unit is in the group.

Editor: ‹Unit group› contains ‹Unit›

FieldTypeRequiredDescription
groupexpr (unitGroup)yesThe group.
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
{"k":"groupHas","group":{"k":"unitsInRegion","region":"arena"},"unit":{"k":"eventUnit"}}

groupEmpty

Empty group — returns unitGroup. A group with no units.

Editor: an empty group

No fields.

{"k":"groupEmpty"}

unitsInRadius

Units within a radius — returns unitGroup. Sorted group of units within radius tiles of a point or unit. Measured on squared distance, which is exact on an integer grid; a radius below 0 matches nothing. Needs map format 3.

Editor: units within ‹Radius in tiles› of ‹Centre› matching ‹Filter›

FieldTypeRequiredDescription
atexpr (point)yesCentre — a point, or a unit whose tile is used.
radiusexpr (number)yesRadius in tiles, inclusive.
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"unitsInRadius","at":{"k":"regionCenter","region":"arena"},"radius":1}

closestUnit

Closest unit — returns unit. The nearest matching unit to a point or unit, or no unit. A tie goes to the lowest entity id, so the answer never depends on iteration order. Needs map format 3.

Editor: closest unit to ‹From› within ‹Maximum distance› matching ‹Filter›

FieldTypeRequiredDescription
atexpr (point)yesWhere to measure from — a point, or a unit whose tile is used.
filterfilternoOptional unit filter; every set field is ANDed. aliveOnly defaults to true.
maxRadiusexpr (number)noIgnore anything further than this many tiles; absent = search the whole map.
{"k":"closestUnit","at":{"k":"regionCenter","region":"arena"}}

groupSortBy

Group in order — returns unitGroup. The group reordered. Ties always break on the LOWEST entity id, in both directions — so 'desc' reverses the keys but is not exactly the reverse of 'asc' when two units share a key, and "the weakest" and "the strongest" pick the same one of a tied pair. The result is NOT id-sorted, so storing it in a unitGroup variable loses the order (variables are canonicalised on write) — use it inline, with forEachUnit or groupAt. Needs map format 3.

Editor: ‹Unit group› ordered by ‹Order by› ‹Direction› from ‹Measure from›

FieldTypeRequiredDescription
groupexpr (unitGroup)yesThe group.
by'hp' | 'maxHp' | 'hpPercent' | 'mana' | 'maxMana' | 'level' | 'xp' | 'kills' | 'x' | 'y' | 'distance' | 'id'yesWhat to order on.
order'asc' | 'desc'no'asc' (default) or 'desc'.
fromexpr (point)noReference point for by: 'distance'; absent measures from tile (0, 0).
{"k":"groupSortBy","group":{"k":"unitsInRegion","region":"arena"},"by":"hp"}

groupPickN

N random units of group — returns unitGroup. At most N random members, sorted. Consumes exactly min(N, group size) PRNG draws — both numbers are hashed sim state, so every client draws the same count. Needs map format 3.

Editor: ‹How many› random units of ‹Unit group›

FieldTypeRequiredDescription
groupexpr (unitGroup)yesThe group.
nexpr (int)yesHow many to pick. 0 or less gives an empty group.
{"k":"groupPickN","group":{"k":"unitsInRegion","region":"arena"},"n":1}

groupFilter

Group matching a filter — returns unitGroup. Members of the group that match the filter. The one way to narrow a group you already hold without rebuilding it from the world. Needs map format 3.

Editor: ‹Unit group› matching ‹Filter›

FieldTypeRequiredDescription
groupexpr (unitGroup)yesThe group.
filterfilteryesUnit filter; every set field is ANDed. aliveOnly defaults to true.
{"k":"groupFilter","group":{"k":"unitsInRegion","region":"arena"},"filter":{}}

Item expressions

heroHasItem

Unit has item — returns bool. True when the unit holds this item in its BACKPACK or has it EQUIPPED. Both halves, because "does he have the crown" does not mean "in his bag but not on his head". Needs map format 3.

Editor: ‹Unit› has ‹Item›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
itemIditemIdyesItem id to look for.
{"k":"heroHasItem","unit":{"k":"eventUnit"},"itemId":"healing_potion"}

heroItemCount

Unit item count — returns int. How many of this item the unit holds: backpack stack counts summed, plus one for each equipped copy. Needs map format 3.

Editor: count of ‹Item› on ‹Unit›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
itemIditemIdyesItem id to count.
{"k":"heroItemCount","unit":{"k":"eventUnit"},"itemId":"healing_potion"}

Event expressions

eventUnit

Triggering unit — returns unit. The unit the event is about (entered, died, trained, was attacked…). No unit when the event has none.

Editor: the triggering unit

No fields.

{"k":"eventUnit"}

eventOtherUnit

Other unit — returns unit. The killer for unitDies, the attacker for unitAttacked, the shooter for projectileHits.

Editor: the other unit

No fields.

{"k":"eventOtherUnit"}

eventPlayer

Triggering player — returns player. The seat the event is about, or -1.

Editor: the triggering player

No fields.

{"k":"eventPlayer"}

eventValue

Event value — returns number. Numeric payload: dialog button index, hero level, damage, raised value.

Editor: the event value

No fields.

{"k":"eventValue"}

eventString

Event text — returns string. String payload: upgrade id, item id, chat text, custom event name.

Editor: the event text

No fields.

{"k":"eventString"}

eventDamage

Event damage — returns real. The damage amount as it stands right now. Inside "unit is about to take damage" that is after every earlier trigger's "set event damage", so armour triggers compose; inside "unit has taken damage" it is the amount that landed. 0 on any other event. Needs map format 3.

Editor: the event damage

No fields.

{"k":"eventDamage"}

eventDamageType

Event damage element — returns string. The element the damage site tracks — physical, fire, and so on — or empty where it tracks none (a lava tile, a collapsing bridge). A different axis from the damage kind: a projectile can be fire and a spell can be physical. Needs map format 3.

Editor: the event damage element

No fields.

{"k":"eventDamageType"}

eventDamageKind

Event damage kind — returns string. Which door the damage came through: melee, projectile, spell, burn, thorns, cleave, and the rest. This is the axis a damage-type table or a "spell damage only" shield switches on. Empty on a non-damage event. Needs map format 3.

Editor: the event damage kind

No fields.

{"k":"eventDamageKind"}

eventSpellId

Event spell — returns string. The spell id of an abilityCast* event; '' on every other event. A separate node from eventString, which on a cancelled cast carries the cancel REASON. Needs map format 3.

Editor: event spell

No fields.

{"k":"eventSpellId"}

eventTargetPoint

Event target point — returns point. The target TILE of an abilityCast* or orderIssued event. (-1, -1) when the event had no ground target — a unit-targeted cast, or a stop / hold order. Tile 0,0 is a legal map corner, so 0 could not be the sentinel. Needs map format 3.

Editor: event target point

No fields.

{"k":"eventTargetPoint"}

UI expressions

counter

Counter value — returns number. Current value of an on-screen counter.

Editor: counter ‹Counter›

FieldTypeRequiredDescription
idcounterIdyesCounter id.
{"k":"counter","id":"lives"}

Trigger expressions

triggerFireCount

Trigger fire count — returns int. How many times a trigger has fired.

Editor: times ‹Trigger› has fired

FieldTypeRequiredDescription
triggerIdtriggerIdyesTrigger id.
{"k":"triggerFireCount","triggerId":"main"}

Text expressions

concat

Concatenate — returns string. A joined with B as strings.

Editor: ‹A› joined with ‹B›

FieldTypeRequiredDescription
aexpr (string)yesLeft operand.
bexpr (string)yesRight operand.
{"k":"concat","a":"text","b":"text"}

toStr

To text — returns string. Value as text. Non-integers print with decimals places (default 2).

Editor: ‹Value› as text to ‹Decimal places› dp

FieldTypeRequiredDescription
aexpr (any)yesLeft operand.
decimalsint (≥ 0, ≤ 6)noFixed decimal places, 0..6.
{"k":"toStr","a":1}

subStr

Substring — returns string. 0-based slice; out-of-range start gives empty text.

Editor: substring of ‹String› from ‹Start index› length ‹Length›

FieldTypeRequiredDescription
textexpr (string)yesSource text.
startexpr (int)yesStart index.
lengthexpr (int)noMaximum length; absent = to the end.
{"k":"subStr","text":"Hello world","start":0,"length":5}

strLen

Text length — returns int. Length in UTF-16 code units.

Editor: length of ‹String›

FieldTypeRequiredDescription
textexpr (string)yesThe text.
{"k":"strLen","text":"text"}

strFind

Find text — returns int. 0-based index of the first occurrence, or -1. An empty search text yields -1. Needs map format 3.

Editor: index of ‹Look for› in ‹String› from ‹From index›

FieldTypeRequiredDescription
textexpr (string)yesText to search.
findexpr (string)yesText to look for.
startexpr (int)noIndex to start from; negative counts as 0.
{"k":"strFind","text":"text","find":"text"}

strReplace

Replace text — returns string. Every occurrence replaced. An empty search text returns the text unchanged rather than inserting between every character. Needs map format 3.

Editor: ‹String› with ‹Replace› replaced by ‹With›

FieldTypeRequiredDescription
textexpr (string)yesSource text.
findexpr (string)yesText to replace.
toexpr (string)yesReplacement.
{"k":"strReplace","text":"text","find":"text","to":"text"}

strSplitPart

Split and take — returns string. Field index of the text split on sep, or empty text when the index is out of range. An empty separator treats the whole text as field 0. Needs map format 3.

Editor: part ‹Part (0-based)› of ‹String› split on ‹Separator›

FieldTypeRequiredDescription
textexpr (string)yesSource text.
sepexpr (string)yesSeparator.
indexexpr (int)yes0-based field index.
{"k":"strSplitPart","text":"text","sep":"text","index":1}

strSplitCount

Split count — returns int. How many fields strSplitPart can reach: separator count plus one, and 0 for empty text. Needs map format 3.

Editor: parts of ‹String› split on ‹Separator›

FieldTypeRequiredDescription
textexpr (string)yesSource text.
sepexpr (string)yesSeparator.
{"k":"strSplitCount","text":"text","sep":"text"}

strUpper

Upper case — returns string. ASCII a-z raised to A-Z. Every other code unit is left alone, ON PURPOSE: Unicode case mapping depends on which Unicode revision the browser shipped, and these strings are hashed. Needs map format 3.

Editor: upper case of ‹String›

FieldTypeRequiredDescription
textexpr (string)yesThe text.
{"k":"strUpper","text":"text"}

strLower

Lower case — returns string. ASCII A-Z lowered to a-z. Every other code unit is left alone — see strUpper. Needs map format 3.

Editor: lower case of ‹String›

FieldTypeRequiredDescription
textexpr (string)yesThe text.
{"k":"strLower","text":"text"}

strTrimAscii

Trim spaces — returns string. Strip leading and trailing ASCII whitespace (space, tab, newline, carriage return, vertical tab, form feed). Non-breaking spaces and the byte-order mark are NOT stripped, because the Unicode whitespace set has grown between browser releases. Needs map format 3.

Editor: trimmed ‹String›

FieldTypeRequiredDescription
textexpr (string)yesThe text.
{"k":"strTrimAscii","text":"text"}

strToInt

Text to integer — returns int. Parse text as a number and truncate toward zero. Anything unparseable yields 0. Surrounding ASCII whitespace is ignored. Needs map format 3.

Editor: ‹String› as an integer

FieldTypeRequiredDescription
textexpr (string)yesThe text.
{"k":"strToInt","text":"text"}

strToReal

Text to real — returns real. Parse text as a real number. Anything unparseable, infinite or NaN yields 0. Needs map format 3.

Editor: ‹String› as a real number

FieldTypeRequiredDescription
textexpr (string)yesThe text.
{"k":"strToReal","text":"text"}

formatTicks

Ticks as a clock — returns string. Ticks rendered as a clock. 20 ticks is one second; negatives clamp to 0. Minutes are not capped at 59, so an hour of "mm:ss" is "60:00". Needs map format 3.

Editor: ‹Ticks› as a clock (‹Layout›)

FieldTypeRequiredDescription
ticksexpr (int)yesTick count.
format'mm:ss' | 'm:ss' | 'h:mm:ss' | 'ss.t'noLayout (default mm:ss).
{"k":"formatTicks","ticks":1}

hashString

Hash text — returns int. Deterministic 32-bit FNV-1a hash.

Editor: hash of ‹String›

FieldTypeRequiredDescription
textexpr (string)yesThe text.
{"k":"hashString","text":"text"}

Physics expressions

unitVelocity

Unit velocity — returns real. Kinematic velocity component or speed (tiles/tick); 0 without kinematics.

Editor: ‹Axis› velocity of ‹Unit›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
axis'x' | 'y' | 'speed'yesComponent to read.
{"k":"unitVelocity","unit":{"k":"eventUnit"},"axis":"x"}

Save codes expressions

verifySaveCode

Read save code — returns any. Validate a save code for this map. With field, returns that field (or 0); without, returns 1 for a valid code and 0 otherwise.

Editor: save code ‹Code› field ‹Field› (valid?)

FieldTypeRequiredDescription
codeexpr (string)yesThe code text.
fieldstringnoField to extract; playerId returns the issuing seat.
{"k":"verifySaveCode","code":{"k":"var","name":"code"}}

Function expressions

call

Call function — returns any. Call a user-defined function that declares a return type and yield its return value. Arguments are evaluated left to right and coerced to the parameter types. Recursion past the depth cap yields the zero value.

Editor: ‹Function›(‹Arguments›)

FieldTypeRequiredDescription
fnfunctionNameyesFunction name.
argsexprListnoArguments, one per parameter, in order.
{"k":"call","fn":"double","args":[2]}

Hashtable expressions

hashtableGet

Hashtable value — returns any. Value stored under (key1, key2), or the zero value of the table type. Keys are integers or strings.

Editor: ‹Hashtable›[‹Parent key›][‹Child key›]

FieldTypeRequiredDescription
tablehashtableNameyesHashtable name.
key1expr (any)yesParent key (int or string).
key2expr (any)yesChild key (int or string).
{"k":"hashtableGet","table":"scores","key1":1,"key2":1}

hashtableHas

Hashtable has key — returns bool. True when a value is stored under (key1, key2).

Editor: ‹Hashtable› has [‹Parent key›][‹Child key›]

FieldTypeRequiredDescription
tablehashtableNameyesHashtable name.
key1expr (any)yesParent key.
key2expr (any)yesChild key.
{"k":"hashtableHas","table":"scores","key1":1,"key2":1}

hashtableCount

Hashtable size — returns int. Number of entries in the table, or under one parent key when key1 is set.

Editor: number of entries in ‹Hashtable› under ‹Parent key›

FieldTypeRequiredDescription
tablehashtableNameyesHashtable name.
key1expr (any)noParent key to count children of.
{"k":"hashtableCount","table":"scores"}

Actions

What a trigger does, run top to bottom.

Control flow actions

if

If / then / else. Run then when cond is true, else else.

Editor: if ‹Condition›

FieldTypeRequiredDescription
condexpr (bool)yesCondition.
thenactionsyesActions when true.
elseactionsnoActions when false.
{"k":"if","cond":true,"then":[]}

while

While. Repeat the body while cond holds, at most maxIterations (hard cap 10000) times per run.

Editor: while ‹Condition›

FieldTypeRequiredDescription
condexpr (bool)yesLoop condition, checked before each iteration.
bodyactionsyesLoop body.
maxIterationsint (≥ 1, ≤ 10000)noIteration cap (≤ 10000).
{"k":"while","cond":true,"body":[]}

forEachUnit

For each unit. Run the body once per unit of a group (snapshotted and sorted before the first iteration).

Editor: for each unit ‹Loop variable› in ‹Unit group›

FieldTypeRequiredDescription
groupexpr (unitGroup)yesGroup to iterate.
varNameloopVaryesLoop variable receiving each unit id; an undeclared name becomes a local.
bodyactionsyesLoop body.
{"k":"forEachUnit","group":{"k":"unitsInRegion","region":"arena"},"varName":"u","body":[]}

forEachInt

For each integer. Run the body for each integer from..to inclusive (at most 10000).

Editor: for ‹Loop variable› from ‹From› to ‹To›

FieldTypeRequiredDescription
varNameloopVaryesLoop variable; an undeclared name becomes a local.
fromexpr (int)yesFirst value.
toexpr (int)yesLast value (inclusive).
bodyactionsyesLoop body.
{"k":"forEachInt","varName":"i","from":1,"to":1,"body":[]}

wait

Wait. Suspend this trigger for N ticks (min 1) and resume at the next action. Locals and loop state survive, including across save/load. Not allowed inside functions.

Editor: wait ‹Ticks› ticks

FieldTypeRequiredDescription
ticksexpr (int)yesTicks to wait.
{"k":"wait","ticks":1}

raiseEvent

Raise custom event. Fire the custom event of this name later in the same tick.

Editor: raise custom event ‹Event name› with value ‹Value› and text ‹Text›

FieldTypeRequiredDescription
nameeventNameyesEvent name.
valueexpr (number)noEvent value payload.
textexpr (string)noEvent text payload (default: the name).
{"k":"raiseEvent","name":"boss_down"}

comment

Comment. Does nothing; documents the script.

Editor: // ‹Comment›

FieldTypeRequiredDescription
textstringyesComment text.
{"k":"comment","text":"text"}

Variable actions

setVar

Set variable. Write a variable (local, parameter, loop or global). Writing a global with a new value raises variableChanges.

Editor: set ‹Variable›[‹Index›] to ‹Value›

FieldTypeRequiredDescription
namevarNameyesVariable name. The variable must already exist — an assignment does NOT declare one.
indexexpr (int)noElement index for an array.
valueexpr (any)yesNew value (coerced to the variable type).
{"k":"setVar","name":"score","value":1}

addVar

Add to variable. Add a number to a numeric variable.

Editor: add ‹Amount› to ‹Variable›[‹Index›]

FieldTypeRequiredDescription
namevarNameyesVariable name. The variable must already exist — this does NOT declare one.
indexexpr (int)noElement index for an array.
deltaexpr (number)yesAmount to add.
{"k":"addVar","name":"score","delta":1}

Unit actions

setEventDamage

Set event damage. Replace the damage this hit is about to do. Only works in a trigger with a "unit is about to take damage" (unitDamaging) event — the validator refuses it anywhere else, because anywhere else it would silently do nothing. A result that is not a finite number leaves the damage UNCHANGED rather than zeroing it, so a broken formula reads as "my armour does nothing" instead of as accidental invulnerability; otherwise it is clamped to 0..1000000000. Needs map format 3.

Editor: set the event damage to ‹Damage›

FieldTypeRequiredDescription
amountexpr (number)yesThe new damage amount. Read the old one with "event damage".
{"k":"setEventDamage","amount":1}

addBuff

Add buff. Put a stat buff on a unit. The same buff id REFRESHES rather than stacks: duration, source and stat are overwritten, and the modifier is overwritten only when the new one is at least as strong — the engine's own rule, not a second one. A duration of -1 is permanent. NOTE: trigger buffs are hashed and lockstep-safe but are NOT saved — like every spell-applied buff, they are dropped by save/load. Needs map format 3.

Editor: buff ‹Unit›: ‹Stat› by ‹Amount› for ‹Duration in ticks› ticks as ‹Buff id›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
buffIdstringyesYour id for this buff. Re-using it refreshes the existing one; remove buff and unit has buff take the same id.
stat'damage' | 'damagePct' | 'siegeDamage' | 'armor' | 'attackSpeed' | 'lifesteal' | 'damageMirror' | 'thorns' | 'critChance' | 'dodgeChance' | 'blockChance' | 'blockValue' | 'parryChance' | 'hitBonus' | 'blind' | 'speed' | 'speedPct' | 'maxHpPct' | 'hpRegen' | 'manaRegen' | 'poison' | 'spellPower' | 'sightRadius' | 'productionSpeed' | 'gatherRatePct'yesWhat it modifies. Only these are read by the engine — any other name would be stored and ignored.
modifierexpr (number)yesHow much to add. Negative debuffs. A non-finite value makes the action do nothing.
durationTicksexpr (int)yesHow long, in ticks (20 = 1 second). -1 is permanent; 0 or less otherwise does nothing.
{"k":"addBuff","unit":{"k":"eventUnit"},"buffId":"text","stat":"damage","modifier":1,"durationTicks":1}

removeBuff

Remove buff. Take one buff off a unit, matching the WHOLE id. Aura buffs are left alone: AuraSystem re-stamps those every tick, so removing one would come straight back and read as a broken action. Needs map format 3.

Editor: remove buff ‹Buff id› from ‹Unit›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
buffIdstringyesBuff id to remove.
{"k":"removeBuff","unit":{"k":"eventUnit"},"buffId":"text"}

addAbility

Add ability. Give a unit a spell it can cast. A unit with no caster slot gets one. Granting a spell it already has does nothing, so this is safe to call every tick. Needs map format 3.

Editor: give ‹Unit› the ability ‹Spell›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
spellIdspellIdyesSpell id to grant.
{"k":"addAbility","unit":{"k":"eventUnit"},"spellId":"berserk"}

removeAbility

Remove ability. Take a spell away from a unit. Removing one it does not have does nothing. This does not silence: a cast already in flight resolves. Needs map format 3.

Editor: take the ability ‹Spell› from ‹Unit›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
spellIdspellIdyesSpell id to remove.
{"k":"removeAbility","unit":{"k":"eventUnit"},"spellId":"berserk"}

Trigger actions

enableTrigger

Enable/disable trigger. Turn a trigger on or off.

Editor: set trigger ‹Trigger› enabled to ‹Enabled›

FieldTypeRequiredDescription
triggerIdtriggerIdyesTrigger id.
onboolyesEnabled.
{"k":"enableTrigger","triggerId":"main","on":true}

runTrigger

Run trigger. Run another trigger's actions inline in this event context.

Editor: run trigger ‹Trigger› (checking its conditions: ‹Check conditions›)

FieldTypeRequiredDescription
triggerIdtriggerIdyesTrigger id.
checkConditionsboolnoEvaluate its conditions first (and count it as fired).
{"k":"runTrigger","triggerId":"main"}

stopTrigger

Stop trigger. Abandon the rest of this trigger. Not allowed inside functions (use return).

Editor: stop running this trigger

No fields.

{"k":"stopTrigger"}

Function actions

callFunction

Call function. Call a user-defined function as a statement, optionally storing its return value.

Editor: call ‹Function›(‹Arguments›) and store the result in ‹Store result in›[‹Index›]

FieldTypeRequiredDescription
fnfunctionNameyesFunction name.
argsexprListnoArguments, one per parameter, in order.
intoVarvarNamenoVariable receiving the return value (function must declare returns). It must ALREADY exist — declared in vars, or a local, parameter or loop variable in scope. Unlike a loop variable, this does NOT declare one, and an undeclared name is an error.
intoIndexexpr (int)noElement index when intoVar is an array.
{"k":"callFunction","fn":"double","args":[2]}

return

Return. Leave the current function, yielding value. At trigger level (no value allowed) it stops the trigger.

Editor: return ‹Value›

FieldTypeRequiredDescription
valueexpr (any)noReturn value (functions with a return type).
{"k":"return"}

Hashtable actions

hashtableSet

Hashtable set. Store a value under (key1, key2). New keys past the table cap are dropped.

Editor: set ‹Hashtable›[‹Parent key›][‹Child key›] to ‹Value›

FieldTypeRequiredDescription
tablehashtableNameyesHashtable name.
key1expr (any)yesParent key (int or string).
key2expr (any)yesChild key (int or string).
valueexpr (any)yesValue (coerced to the table type).
{"k":"hashtableSet","table":"scores","key1":1,"key2":1,"value":1}

hashtableRemove

Hashtable remove. Remove the value under (key1, key2).

Editor: remove ‹Hashtable›[‹Parent key›][‹Child key›]

FieldTypeRequiredDescription
tablehashtableNameyesHashtable name.
key1expr (any)yesParent key.
key2expr (any)yesChild key.
{"k":"hashtableRemove","table":"scores","key1":1,"key2":1}

hashtableClear

Hashtable clear. Remove every entry, or only those under key1.

Editor: clear ‹Hashtable› under ‹Parent key›

FieldTypeRequiredDescription
tablehashtableNameyesHashtable name.
key1expr (any)noParent key to flush; absent = whole table.
{"k":"hashtableClear","table":"scores"}

Units actions

createUnits

Create units. Spawn N units (max 500) for a player at a point.

Editor: create ‹Count› × ‹Unit type› for ‹Player› at ‹At point› facing ‹Facing (degrees)›° and store them in ‹Store in›

FieldTypeRequiredDescription
unitTypeIdunitTypeIdyesUnit type id (base game or a defOverrides clone).
countexpr (int)yesHow many.
playerexpr (player)yesSeat id (0-based) of the player.
atexpr (point)yesSpawn tile.
facingexpr (int)noFacing in degrees.
intoVarvarNamenounitGroup variable receiving the created ids. It must ALREADY exist — declared in vars, or a local, parameter or loop variable in scope. Unlike a loop variable, this does NOT declare one, and an undeclared name is an error.
{"k":"createUnits","unitTypeId":"dwarf_ironguard","count":1,"player":0,"at":{"k":"regionCenter","region":"arena"}}

removeUnit

Remove unit. Remove a unit outright — no death, corpse or bounty.

Editor: remove ‹Unit› from the game

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
{"k":"removeUnit","unit":{"k":"eventUnit"}}

killUnit

Kill unit. Kill a unit through the normal death path.

Editor: kill ‹Unit›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
{"k":"killUnit","unit":{"k":"eventUnit"}}

setUnitHp

Set unit HP. Set HP (clamped to 0..max).

Editor: set HP of ‹Unit› to ‹Value› (as a percentage: ‹Value is a percentage›)

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
valueexpr (number)yesHP or percentage.
percentboolnoTreat value as a percentage of max HP.
{"k":"setUnitHp","unit":{"k":"eventUnit"},"value":1}

setUnitMana

Set unit mana. Set mana (clamped).

Editor: set mana of ‹Unit› to ‹Value›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
valueexpr (number)yesMana.
{"k":"setUnitMana","unit":{"k":"eventUnit"},"value":1}

setUnitOwner

Change owner. Give a unit to another seat.

Editor: give ‹Unit› to ‹Player›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"setUnitOwner","unit":{"k":"eventUnit"},"player":0}

setUnitInvulnerable

Set invulnerable. Toggle invulnerability.

Editor: set ‹Unit› invulnerable to ‹Invulnerable›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
onboolyesInvulnerable.
{"k":"setUnitInvulnerable","unit":{"k":"eventUnit"},"on":true}

setUnitProp

Set unit stat. Write one live combat or movement stat. It does NOT cover hp, mana, owner or invulnerability - those have their own actions, and a second way to write them would drift. maxHp and maxMana move the CURRENT value by the same amount, so a buffed unit is not left at 40/900; lowering a max clamps the current down. Values clamp at 0, and attackSpeed / moveSpeed at a small positive floor (0 attacks per second is a division, 0 speed is a unit that never finishes a path). sightRadius writes the fog revealer and does nothing on a unit that has none, because giving fog vision to something that had none is a bigger decision than setting a number. Needs map format 3.

Editor: set ‹Stat› of ‹Unit› to ‹Value›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
prop'damage' | 'range' | 'attackSpeed' | 'maxHp' | 'armor' | 'magicResist' | 'moveSpeed' | 'maxMana' | 'manaRegen' | 'sightRadius'yesStat to write. attackSpeed is ATTACKS PER SECOND, not a cooldown in seconds - there is no attackCooldown field on a unit.
valueexpr (number)yesNew value.
{"k":"setUnitProp","unit":{"k":"eventUnit"},"prop":"damage","value":1}

faceUnit

Face unit toward point. Turn a living stationary unit toward a tile using its ordinary turn rate. Does not move it, cancel orders or turn structures. Missing, dead, moving or coincident targets do nothing. Needs map format 3.

Editor: turn ‹Unit› toward ‹Toward point›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
towardexpr (point)yesTile to face. Evaluated only for an eligible stationary unit.
{"k":"faceUnit","unit":{"k":"eventUnit"},"toward":{"k":"regionCenter","region":"arena"}}

moveUnit

Move unit instantly. Teleport a unit to a tile.

Editor: move ‹Unit› to ‹To point›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
toexpr (point)yesDestination tile.
{"k":"moveUnit","unit":{"k":"eventUnit"},"to":{"k":"regionCenter","region":"arena"}}

playAnimation

Play animation. Request a finite saved cinematic pose on a stationary living unit. Movement, death and scene completion release it; missing model clips do not perform.

Editor: play animation ‹Animation name› on ‹Unit› (loop: ‹Loop›) for ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
animationstringyesCanonical clip slot: idle, attack, gather, build, special_1/2/3, sleep or sitting. cast aliases special_1. There is no invented talk or living death clip.
loopboolnoWhether to loop the animation.
durationTicksint (≥ 1)noFinite pose window (default 20 ticks, capped at 1200). Loops retain normal clip speed; one-shots fit this window.
{"k":"playAnimation","unit":{"k":"eventUnit"},"animation":"text"}

Hero actions

heroAddXp

Give hero XP. Grant XP to ONE hero and resolve every level it crosses, inside this action. A reviving hero is skipped. Safe to call from a heroLevels trigger: trigger signals are drained at the top of the next tick, so the level-up has already finished and there is no mid-level-up state to reason about. Needs map format 3.

Editor: give ‹XP› XP to ‹Unit›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
amountexpr (int)yesXP to grant. Zero or negative does nothing.
{"k":"heroAddXp","unit":{"k":"eventUnit"},"amount":1}

heroSetLevel

Set hero level. Raise a hero TO a level. It grants the XP rather than writing the level, so the hero gets every point of growth the levels are worth and is indistinguishable from one that earned them. LOWERING IS A NO-OP, not an approximation: the engine records the level but not the deltas used to reach it. The target is clamped to the match's level cap first, so asking for a million costs the same as asking for the cap. Needs map format 3.

Editor: raise ‹Unit› to level ‹Level›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
levelexpr (int)yesLevel to reach. Clamped to the match level cap; a level at or below the current one does nothing.
{"k":"heroSetLevel","unit":{"k":"eventUnit"},"level":1}

heroRevive

Revive hero. Finish a hero's revival now: clear the countdown, restore health and mana to full, and optionally move it. IT CANNOT RESURRECT A HERO WHOSE ENTITY IS GONE - a dead hero is destroyed and its progress banked, and respawning one is not exposed to triggers. Use it on a hero that still exists: one counting down a revive, or one left at zero HP. On a hero already up and whole it does nothing. Needs map format 3.

Editor: revive ‹Unit› at ‹Tile›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
atexpr (point)noTile to put the hero on. Absent leaves it where it is.
{"k":"heroRevive","unit":{"k":"eventUnit"}}

Item actions

itemCreate

Create item on ground. Put an item on the ground. The tile is a request: the engine walks an expanding ring for a free walkable tile, and an item asked for on deep water floats there instead of being dragged ashore. It hands back NO handle, so a map cannot refer to the item it made. An unknown item id creates nothing. Needs map format 3.

Editor: create ‹Item› at ‹Tile›

FieldTypeRequiredDescription
itemIditemIdyesItem id to create.
atexpr (point)yesTile to create it on.
{"k":"itemCreate","itemId":"healing_potion","at":{"k":"regionCenter","region":"arena"}}

itemGive

Give item to unit. Put an item in a unit's BACKPACK. It does not auto-equip - equipping applies stat effects and set bonuses, which is a different request. Consumables stack to the item's cap. When the bag is full the remainder lands on the ground at the unit's feet rather than vanishing. Needs map format 3.

Editor: give ‹Item› to ‹Unit› x‹Count›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
itemIditemIdyesItem id to give.
countexpr (int)noHow many (default 1).
{"k":"itemGive","unit":{"k":"eventUnit"},"itemId":"healing_potion"}

itemRemove

Remove item from unit. Take an item out of a unit's BACKPACK. Equipped gear is not touched: pulling gear off has to reverse its stat effects and recompute the set bonus. Removes across stacks, lowest slot first. Asking for more than the unit holds removes what it holds. Needs map format 3.

Editor: remove ‹Item› from ‹Unit› x‹Count›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
itemIditemIdyesItem id to remove.
countexpr (int)noHow many (default 1).
{"k":"itemRemove","unit":{"k":"eventUnit"},"itemId":"healing_potion"}

Group actions

addUnitToGroup

Add unit to group. Add a unit to a unitGroup variable.

Editor: add ‹Unit› to ‹Group variable›

FieldTypeRequiredDescription
varNamevarNameyesAn already-declared unitGroup variable; this does not create one.
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
{"k":"addUnitToGroup","varName":"squad","unit":{"k":"eventUnit"}}

removeUnitFromGroup

Remove unit from group. Remove a unit from a unitGroup variable.

Editor: remove ‹Unit› from ‹Group variable›

FieldTypeRequiredDescription
varNamevarNameyesAn already-declared unitGroup variable; this does not create one.
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
{"k":"removeUnitFromGroup","varName":"squad","unit":{"k":"eventUnit"}}

clearGroup

Clear group. Empty a unitGroup variable.

Editor: clear ‹Group variable›

FieldTypeRequiredDescription
varNamevarNameyesAn already-declared unitGroup variable; this does not create one.
{"k":"clearGroup","varName":"squad"}

Orders actions

boardTransport

Board transport. Issue ordinary boarding inside the tick. The unit walks into reach before the transport system boards it; owner, capacity and terrain rules still apply. Needs map format 3.

Editor: board ‹Units› onto ‹Transport›

FieldTypeRequiredDescription
unitsexpr (unitGroup)yesOriginal units to board.
transportexpr (unit)yesOriginal transport.
{"k":"boardTransport","units":{"k":"unitsInRegion","region":"arena"},"transport":{"k":"eventUnit"}}

order

Order units. Issue an order to a group, applied inside the tick (never through lockstep).

Editor: order ‹Units› to ‹Order› at ‹Target point› targeting ‹Target unit› (queued: ‹Queue behind current order›)

FieldTypeRequiredDescription
unitsexpr (unitGroup)yesUnits to order (a single unit also works).
order'move' | 'attack_move' | 'attack' | 'stop' | 'hold' | 'patrol' | 'follow'yesOrder kind.
toexpr (point)noTarget tile for move / attack_move / patrol.
targetexpr (unit)noTarget unit for attack / follow.
queueboolnoQueue after current orders.
{"k":"order","units":{"k":"unitsInRegion","region":"arena"},"order":"attack_move","to":{"k":"regionCenter","region":"arena"}}

Economy actions

setResource

Set resource. Set a player's resource stock (rounded, ≥ 0).

Editor: set ‹Player›'s ‹Resource› to ‹Value›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
resource'gold' | 'lumber' | 'stone' | 'oil'yesResource kind.
valueexpr (int)yesNew amount.
{"k":"setResource","player":0,"resource":"gold","value":1}

addResource

Add resource. Add to a player's resource stock (rounded, ≥ 0).

Editor: give ‹Player› ‹Amount› ‹Resource›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
resource'gold' | 'lumber' | 'stone' | 'oil'yesResource kind.
deltaexpr (int)yesAmount to add (negative subtracts).
{"k":"addResource","player":0,"resource":"gold","delta":1}

setAlliance

Set alliance. Ally B to A's team, or put B back on its own team.

Editor: set ‹A› and ‹B› allied to ‹Allied›

FieldTypeRequiredDescription
aexpr (player)yesLeft operand.
bexpr (player)yesRight operand.
alliedboolyesAllied.
{"k":"setAlliance","a":0,"b":0,"allied":true}

setBuildableRegion

Restrict building. Limit where a seat may build: a list of regions, [] for nowhere, or null to restore the default.

Editor: restrict building for ‹Player› to ‹Regions›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
regionsregionId[] | nullyesRegion ids, or null.
{"k":"setBuildableRegion","player":0,"regions":["arena"]}

setTechAllowed

Allow or forbid a research. Allow or forbid ONE upgrade for ONE seat, mid-match. Forbidding it greys the button out AND refuses the order at the lockstep door, so a forged command spends nothing — the rule is one shared predicate, not a check in the menu. It does NOT remove a research the seat has already completed, and it does not stop one already in the queue; it stops the next order. The lobby's own disabled-research list still applies on top: this can only ever take a research away, never hand back one the match rules removed. Allowing an upgrade that was never forbidden does nothing. Needs map format 3.

Editor: set ‹Upgrade› allowed for ‹Player› to ‹Allowed›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
upgradeIdupgradeIdyesUpgrade id.
allowedboolyesTrue allows it (the default state), false forbids it.
{"k":"setTechAllowed","player":0,"upgradeId":"dwarf_forged_weapons_1","allowed":true}

setPopCap

Set population cap. Set a seat's population cap outright, or LEAVE value OUT to clear it and hand the seat back to the cap its buildings provide. It is a SEPARATE number from the building total, not a write to it: farms and town halls keep adding and removing their own capacity underneath, so destroying a farm never eats into an authored cap and clearing the cap restores exactly the right number with no recount. Clamped to 0..5000, and 0 is a real cap meaning "this seat trains nothing". A value that is not a finite number CLEARS the cap rather than writing it, so a broken formula reads as "my trigger did nothing" instead of as an unlimited army. Needs map format 3.

Editor: set ‹Player›'s population cap to ‹Cap›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
valueexpr (int)noThe cap. ABSENT clears the authored cap and returns the seat to its building-derived one.
{"k":"setPopCap","player":0}

revealArea

Reveal an area. Lift the fog on a disc of map for ONE seat, for a while. It works the way the Reveal spell works — it drops an invisible watcher that sees for you — so the ground stays EXPLORED afterwards (dimmed, remembered) even though the live vision goes away when the timer runs out, and anything standing inside it can be targeted while it lasts. Its teammates see through it too, exactly as they see through your scout. A radius of 0..64 tiles and a duration of 1..12000 ticks (10 minutes); leave the duration out for 100 ticks (5 seconds). There is no permanent reveal and no way to take vision AWAY — for a whole-map reveal, use the map's fog rule instead of a trigger. Each call costs one of the per-tick spawn budget, so a loop revealing a thousand tiles stops at the budget rather than freezing the match. Needs map format 3.

Editor: reveal ‹Radius (tiles)› tiles around ‹Centre tile› to ‹Player› for ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
atexpr (point)yesCentre tile.
radiusexpr (int)yesRadius in tiles (0..64).
durationTicksint (≥ 1, ≤ 12000)noHow long the reveal lasts, in ticks (default 100 = 5 seconds, max 12000).
{"k":"revealArea","player":0,"at":{"k":"regionCenter","region":"arena"},"radius":1}

Outcome actions

victory

Victory. Declare a seat victorious.

Editor: declare victory for ‹Player›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"victory","player":0}

defeat

Defeat. Declare a seat defeated.

Editor: declare defeat for ‹Player›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
{"k":"defeat","player":0}

setObjective

Set a campaign objective. Complete, fail or advance ONE campaign mission objective. This is the campaign's own objective list — the one that decides whether a mission is won — and NOT set quest, which writes the trigger layer's quest log and works in every mode. Outside a campaign mission it does nothing at all, which the map validator reports. Needs map format 3.

Editor: mark campaign objective ‹Objective id› ‹Set to› by ‹Progress amount›

FieldTypeRequiredDescription
objectiveIdstringyesThe objective's id, as the mission defines it.
state'completed' | 'failed' | 'progress'yesWhat to do to it.
amountexpr (number)noProgress amount, for progress only. Absent counts as 1. Reaching the objective's target completes it.
{"k":"setObjective","objectiveId":"text","state":"completed"}

Timers actions

startTimer

Start timer. Start (or restart) a named timer.

Editor: start timer ‹Timer› for ‹Ticks› ticks (repeating: ‹Repeating›)

FieldTypeRequiredDescription
timertimerIdyesTimer name.
ticksexpr (int)yesDuration in ticks (≥ 1).
periodicboolnoRestart on expiry.
{"k":"startTimer","timer":"wave_timer","ticks":1}

pauseTimer

Pause timer. Pause a timer.

Editor: pause timer ‹Timer›

FieldTypeRequiredDescription
timertimerIdyesTimer name.
{"k":"pauseTimer","timer":"wave_timer"}

resumeTimer

Resume timer. Resume a paused timer.

Editor: resume timer ‹Timer›

FieldTypeRequiredDescription
timertimerIdyesTimer name.
{"k":"resumeTimer","timer":"wave_timer"}

stopTimer

Stop timer. Stop and delete a timer.

Editor: stop timer ‹Timer›

FieldTypeRequiredDescription
timertimerIdyesTimer name.
{"k":"stopTimer","timer":"wave_timer"}

timerWindowShow

Show a timer window. Put a named timer's countdown on screen with a title beside it. The window holds only the title and the audience — the clock itself is the timer, so the two can never drift apart. Showing a window for a timer nothing ever starts is a blank countdown, which the map validator reports. Needs map format 3.

Editor: show timer ‹Timer› as "‹Title›" to ‹Shown to›

FieldTypeRequiredDescription
timertimerIdyesTimer name, as start timer named it.
titletextyesTitle template shown beside the countdown.
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"timerWindowShow","timer":"wave_timer","title":"Hello","players":null}

timerWindowHide

Hide a timer window. Take a timer window off screen. The timer keeps running — this is presentation only, and stop timer is what stops the clock. Needs map format 3.

Editor: hide the timer window for ‹Timer›

FieldTypeRequiredDescription
timertimerIdyesTimer name.
{"k":"timerWindowHide","timer":"wave_timer"}

UI actions

showText

Show text. Show a text banner, resolved in the sim.

Editor: show ‹Text› to ‹Shown to› for ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
texttextyesText template (a bare string is accepted).
durationTicksint (≥ 1)noDisplay time in ticks (default 100).
{"k":"showText","players":null,"text":"Hello"}

clearText

Clear text. Clear banners for these seats (null = all).

Editor: clear on-screen text for ‹Shown to›

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"clearText","players":null}

setCounter

Set counter. Create or update an on-screen counter.

Editor: set counter ‹Counter id› — ‹Label› — to ‹Value› for ‹Shown to› at position ‹Sort position›

FieldTypeRequiredDescription
idcounterIdyesCounter id.
labeltextyesLabel template.
valueexpr (number)yesValue.
playersnumber[] | nullnoSeats that see this, or null/absent for everyone.
orderintnoSort position.
{"k":"setCounter","id":"lives","label":"Hello","value":1}

removeCounter

Remove counter. Remove a counter.

Editor: remove counter ‹Counter id›

FieldTypeRequiredDescription
idcounterIdyesCounter id.
{"k":"removeCounter","id":"lives"}

setLeaderboardTitle

Leaderboard title. Set the leaderboard title ("" hides it).

Editor: set the leaderboard title to ‹Title› for ‹Shown to›

FieldTypeRequiredDescription
titletextyesTitle template.
playersnumber[] | nullnoSeats that see this, or null/absent for everyone.
{"k":"setLeaderboardTitle","title":"Hello"}

setLeaderboardRow

Leaderboard row. Create or update a leaderboard row.

Editor: set leaderboard row ‹Row id› — ‹Label› — to ‹Value› at position ‹Sort position›

FieldTypeRequiredDescription
rowIdrowIdyesRow id.
labeltextyesLabel template.
valueexpr (number)yesValue.
orderintnoSort position.
{"k":"setLeaderboardRow","rowId":"p1","label":"Hello","value":1}

removeLeaderboardRow

Remove leaderboard row. Remove a leaderboard row.

Editor: remove leaderboard row ‹Row id›

FieldTypeRequiredDescription
rowIdrowIdyesRow id.
{"k":"removeLeaderboardRow","rowId":"p1"}

clearLeaderboard

Clear leaderboard. Remove every row and the title.

Editor: clear the leaderboard

No fields.

{"k":"clearLeaderboard"}

showDialog

Show dialog. Open a modal dialog; clicks fire dialogButton.

Editor: show dialog ‹Dialog id› titled ‹Title›, saying ‹Body›, with buttons ‹Buttons›, to ‹Shown to›

FieldTypeRequiredDescription
dialogIddialogIdyesDialog id.
titletextyesTitle template.
bodytextyesBody template.
buttonstextListyesButton labels (at least one).
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"showDialog","dialogId":"menu","title":"Choose","body":"Pick a reward.","buttons":["Gold","Lumber"],"players":null}

hideDialog

Hide dialog. Close a dialog.

Editor: hide dialog ‹Dialog id›

FieldTypeRequiredDescription
dialogIddialogIdyesDialog id.
{"k":"hideDialog","dialogId":"menu"}

ping

Ping minimap. Ping a tile on the minimap.

Editor: ping ‹At point› for ‹Shown to› in ‹Colour› for ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
atexpr (point)yesTile to ping.
colorHexcolorHexnoColour (default #ffcc00).
durationTicksint (≥ 1)noDuration in ticks (default 60).
{"k":"ping","players":null,"at":{"k":"regionCenter","region":"arena"}}

playSound

Play sound. Play a sound effect (base game or map custom sound).

Editor: play sound ‹Sound› for ‹Shown to›

FieldTypeRequiredDescription
soundIdsoundIdyesSound id: any shipped sound effect, or a custom sound this map registers. The bare name only — no directory and no extension, so dwarf_ack_1, not voice/dwarf_ack_1.mp3.
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"playSound","soundId":"explosion","players":null}

createUIFrame

Create UI frame. Create or replace a declarative HUD frame.

Editor: create UI frame ‹Frame ID› at ‹Anchor› (‹X offset (px)›, ‹Y offset (px)›) size ‹Width (px)›×‹Height (px)› titled ‹Title› saying ‹Text› progress ‹Progress 0..1› in ‹Progress colour› styled ‹Style› for ‹Shown to› visible ‹Visible› clickable ‹Clickable›

FieldTypeRequiredDescription
frameIdframeIdyesFrame id.
anchor'top_left' | 'top_center' | 'top_right' | 'center_left' | 'center' | 'center_right' | 'bottom_left' | 'bottom_center' | 'bottom_right'yesScreen anchor.
xexpr (number)yesX offset from the anchor (px).
yexpr (number)yesY offset from the anchor (px).
widthexpr (number)yesWidth (px).
heightexpr (number)yesHeight (px).
titletextnoTitle template.
texttextnoBody template.
progressexpr (real)noProgress bar fill 0..1.
progressColorcolorHexnoProgress bar colour.
styleuiStylenoVisual style overrides.
playersnumber[] | nullnoSeats that see this, or null/absent for everyone.
visibleboolnoVisible (default true).
clickableboolnoLet this panel be CLICKED. Off by default, and a panel that leaves it off is invisible to the mouse — clicks, drags and wheel zoom pass straight through it to the map, exactly as every panel has always behaved. Turn it on for a panel that is a button, and a click on it fires uiFrameClicked for the seat that clicked. A clickable panel still sits UNDER the game's own HUD, so it can never swallow a click meant for a HUD control; and a click only counts if the panel is visible and shown to that seat, which the engine checks on every client.
{"k":"createUIFrame","frameId":"hud","anchor":"top_left","x":1,"y":1,"width":1,"height":1}

updateUIFrame

Update UI frame. Update fields of an existing frame.

Editor: update UI frame ‹Frame ID› title ‹Title› text ‹Text› progress ‹Progress 0..1› colour ‹Progress colour› visible ‹Visible› clickable ‹Clickable›

FieldTypeRequiredDescription
frameIdframeIdyesFrame id.
titletextnoTitle template.
texttextnoBody template.
progressexpr (real)noProgress 0..1.
progressColorcolorHexnoProgress bar colour.
visibleboolnoVisible.
clickableboolnoArm or disarm this panel as a button. Let this panel be CLICKED. Off by default, and a panel that leaves it off is invisible to the mouse — clicks, drags and wheel zoom pass straight through it to the map, exactly as every panel has always behaved. Turn it on for a panel that is a button, and a click on it fires uiFrameClicked for the seat that clicked. A clickable panel still sits UNDER the game's own HUD, so it can never swallow a click meant for a HUD control; and a click only counts if the panel is visible and shown to that seat, which the engine checks on every client.
{"k":"updateUIFrame","frameId":"hud"}

destroyUIFrame

Destroy UI frame. Remove a frame.

Editor: destroy UI frame ‹Frame ID›

FieldTypeRequiredDescription
frameIdframeIdyesFrame id.
{"k":"destroyUIFrame","frameId":"hud"}

clearUIFrames

Clear UI frames. Remove every frame.

Editor: clear all UI frames for ‹Shown to›

FieldTypeRequiredDescription
playersnumber[] | nullnoSeats that see this, or null/absent for everyone.
{"k":"clearUIFrames"}

setQuest

Set quest. Create or update a quest-log entry.

Editor: set quest ‹Quest ID› "‹Title›" to ‹State›: ‹Description› icon ‹Icon› at position ‹Sort position›

FieldTypeRequiredDescription
questIdquestIdyesQuest id.
titletextyesTitle template.
descriptiontextyesDescription template.
state'active' | 'completed' | 'failed'yesQuest state.
iconstringnoIcon key.
orderintnoSort position.
{"k":"setQuest","questId":"main_quest","title":"Defend the gate","description":"Survive ten waves.","state":"active"}

clearQuests

Clear quests. Remove every quest.

Editor: clear all quests

No fields.

{"k":"clearQuests"}

playSoundAt

Play sound at a place. A sound effect at a tile: panned and quietened by distance, and HIDDEN BY FOG — a listener who cannot see the place does not hear it, because a sound is information. Use play sound instead for a UI cue that should always play at full volume. WARNING: the FIRST play of a sound the client has not loaded yet is SILENT — it starts the download and returns, and plays from the next request on. Only about a quarter of the sound library is preloaded, so a once-only dramatic cue may play nothing at all. Play it somewhere harmless earlier in the map, or use a sound the match has already made. Needs map format 3.

Editor: play sound ‹Sound› at ‹Where› for ‹Shown to›

FieldTypeRequiredDescription
soundIdsoundIdyesSound to play (base game or map custom sound).
atexpr (point)yesTile to play it at — a point, or a unit whose tile is used.
playersnumber[] | nullyesSeats that see this, or null for everyone.
reachTilesexpr (number)noWiden the fog test by this many tiles, for something whose noise carries further than its centre. Default 0.
{"k":"playSoundAt","soundId":"explosion","at":{"k":"regionCenter","region":"arena"},"players":null}

playMusic

Play music. Start a soundtrack for these seats, replacing whatever is playing and stopping the automatic battle shuffler. Music keys are a different list from sound ids — the picker offers the shipped soundtrack. A track the client has not loaded is fetched and then played, so it starts a moment late the first time rather than not at all. Needs map format 3.

Editor: play music ‹Track› for ‹Shown to›

FieldTypeRequiredDescription
musicIdmusicIdyesSoundtrack key.
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"playMusic","musicId":"dwarf_battle_anvils","players":null}

stopMusic

Stop music. Silence the soundtrack for these seats. KNOWN LIMITATION: after a play music this is exactly what it says. On its own, with the automatic battle shuffler still running, the music stops now and the shuffler starts its next track when the current one would have ended. Needs map format 3.

Editor: stop music for ‹Shown to›

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"stopMusic","players":null}

floatingText

Floating text. A word that floats up off a tile and fades — the same thing the game draws for "+10 gold" and "Level 3!". HIDDEN BY FOG: a viewer who cannot see the tile does not see the word, because a word floating over an enemy hero would report where the enemy hero is. Use show text for a banner that must always be read. Needs map format 3.

Editor: float ‹Text› off ‹Where› for ‹Shown to› in ‹Colour›

FieldTypeRequiredDescription
atexpr (point)yesTile it floats off — a point, or a unit whose tile is used.
texttextyesText template (a bare string is accepted).
playersnumber[] | nullyesSeats that see this, or null for everyone.
colorHexcolorHexnoColour (default #ffffff).
{"k":"floatingText","at":{"k":"regionCenter","region":"arena"},"text":"Hello","players":null}

playEffect

Play a visual effect. A spell's visual effect at a tile, with NONE of its gameplay: no damage, no mana, no cooldown, no caster. Effects are named by SPELL ID because that is the vocabulary the engine's own effect pipeline reads, so every shipped spell's look is available and a typo is an error rather than a silent nothing. Hidden by fog, like every other effect in the game. Needs map format 3.

Editor: play the ‹Effect (a spell)› effect at ‹Where› for ‹Shown to›

FieldTypeRequiredDescription
spellIdspellIdyesSpell whose visual to play. Its gameplay is NOT run — only its look.
atexpr (point)yesTile to play it at — a point, or a unit whose tile is used.
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"playEffect","spellId":"berserk","at":{"k":"regionCenter","region":"arena"},"players":null}

multiboardSet

Create or replace a multiboard. A titled grid of text — the multi-column scoreboard the leaderboard cannot be. REPLACES rather than merges: calling this again on the same board id resets its size, title, audience and every cell, so use set multiboard cell to change one number. Rows and columns past the engine grid cap are clamped, and boards past the board cap are refused. Needs map format 3.

Editor: multiboard ‹Board id› "‹Title›", ‹Rows› x ‹Columns›, for ‹Shown to›

FieldTypeRequiredDescription
boardIdstringyesYour id for this board. Re-using it replaces the board; the cell and remove actions take the same id.
titletextyesTitle template. Empty text hides the header.
rowsexpr (int)yesRows the grid declares.
colsexpr (int)yesColumns the grid declares.
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"multiboardSet","boardId":"text","title":"Hello","rows":1,"cols":1,"players":null}

multiboardCell

Set a multiboard cell. Write one cell. Rows and columns are 0-BASED. Does nothing when the board does not exist or the cell falls outside the grid it declared — both of which the map validator reports, because at runtime an unwritten cell and a cell written to a board that is not there look identical. Needs map format 3.

Editor: multiboard ‹Board id› cell ‹Row (0-based)›,‹Column (0-based)› = ‹Cell text›

FieldTypeRequiredDescription
boardIdstringyesBoard id, as create or replace a multiboard named it.
rowexpr (int)yes0-based row.
colexpr (int)yes0-based column.
texttextyesCell text template.
{"k":"multiboardCell","boardId":"text","row":1,"col":1,"text":"Hello"}

multiboardRemove

Remove a multiboard. Take the board off screen and forget every cell in it. Removing one that is not there does nothing. Needs map format 3.

Editor: remove multiboard ‹Board id›

FieldTypeRequiredDescription
boardIdstringyesBoard id.
{"k":"multiboardRemove","boardId":"text"}

Cutscene actions

playCutscene

Play cutscene. Start a map scene for these seats; the sim records only the start.

Editor: play cutscene ‹Scene› for ‹Shown to›

FieldTypeRequiredDescription
sceneIdsceneIdyesScene id.
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"playCutscene","sceneId":"intro","players":null}

stopCutscene

Stop cutscene. End running cutscenes for these seats.

Editor: stop the cutscene playing for ‹Shown to›

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"stopCutscene","players":null}

fadeScreen

Fade screen. Fade screen in or out with color and duration.

Editor: fade screen ‹Fade type› for ‹Shown to› in ‹Colour› over ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
type'in' | 'out'yesFade type: in or out.
colorHexcolorHexnoFade colour (default #000000).
durationTicksint (≥ 1)noTransition duration in ticks (default 20 = 1 sec).
{"k":"fadeScreen","players":null,"type":"in"}

Camera actions

cameraPan

Pan camera. Pan the camera to a point over a duration.

Editor: pan camera for ‹Shown to› to ‹Point› over ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
toexpr (point)yesTarget tile.
durationTicksint (≥ 0)noPan duration in ticks.
{"k":"cameraPan","players":null,"to":{"k":"regionCenter","region":"arena"}}

cameraSetZoom

Set camera zoom. Change the camera zoom.

Editor: set camera zoom for ‹Shown to› to ‹Zoom› over ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
zoomexpr (real)yesZoom factor.
durationTicksint (≥ 0)noTransition in ticks.
{"k":"cameraSetZoom","players":null,"zoom":1.5}

cameraLock

Lock camera. Lock the camera to a unit or a point.

Editor: lock camera for ‹Shown to› to ‹Follow unit› at ‹Hold point›

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
unitexpr (unit)noUnit to follow.
atexpr (point)noPoint to hold.
{"k":"cameraLock","players":null,"unit":{"k":"eventUnit"}}

cameraUnlock

Unlock camera. Release a camera lock.

Editor: unlock camera for ‹Shown to›

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"cameraUnlock","players":null}

cameraSetBounds

Camera bounds. Confine the camera to a region, or null to clear.

Editor: confine camera for ‹Shown to› to ‹Region›

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
regionregionId | nullyesRegion id, or null.
{"k":"cameraSetBounds","players":null,"region":"arena"}

cameraShake

Shake camera. Shake the camera.

Editor: shake camera for ‹Shown to› at ‹Intensity (0–1)› for ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
intensityexpr (real)yesShake intensity.
durationTicksint (≥ 0)noDuration in ticks.
{"k":"cameraShake","players":null,"intensity":1.5}

cameraReset

Reset camera. Clear locks, bounds and zoom overrides.

Editor: reset camera for ‹Shown to›

FieldTypeRequiredDescription
playersnumber[] | nullyesSeats that see this, or null for everyone.
{"k":"cameraReset","players":null}

Physics actions

applyImpulse

Apply impulse. Give a unit a kinematic velocity.

Editor: apply velocity (‹Velocity X›, ‹Velocity Y›) to ‹Unit› with friction ‹Friction› bounce ‹Bounce› for ‹Duration (ticks)› ticks

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
vxexpr (real)yesVelocity X (tiles/tick).
vyexpr (real)yesVelocity Y (tiles/tick).
frictionexpr (real)noPer-tick velocity multiplier.
bounceexpr (real)noRestitution on collision.
ticksexpr (int)noMaximum duration in ticks.
{"k":"applyImpulse","unit":{"k":"eventUnit"},"vx":1.5,"vy":1.5}

setUnitKinematics

Set kinematics. Tune kinematic parameters of a unit.

Editor: set kinematics of ‹Unit› friction ‹Friction› bounce ‹Bounce› stop below ‹Minimum speed›

FieldTypeRequiredDescription
unitexpr (unit)yesThe unit (entity id). A dead or missing unit is harmless: reads give zero values, writes do nothing.
frictionexpr (real)noPer-tick velocity multiplier.
bounceexpr (real)noRestitution on collision.
minSpeedCutoffexpr (real)noSpeed below which motion stops.
{"k":"setUnitKinematics","unit":{"k":"eventUnit"}}

Save codes actions

generateSaveCode

Generate save code. Encode named values into a tamper-evident code bound to this map, stored in a string variable.

Editor: generate save code for ‹Player› with ‹Data› into ‹Target variable›

FieldTypeRequiredDescription
playerexpr (player)yesSeat id (0-based) of the player.
toVarvarNameyesAn already-declared string variable to receive the code; this does not create one.
dataexprRecordyesField name → value expression.
{"k":"generateSaveCode","player":0,"toVar":"code","data":{"level":3}}

world actions

setTimeOfDay

Set Time of Day. Sets the Day/Night cycle time of day (0..1) and progression speed.

Editor: set time of day to ‹Time of day (0..1)› at speed ‹Speed multiplier›

FieldTypeRequiredDescription
progressexpr (any)yesTime of day from 0 (dawn) to 1 (next dawn).
speedexpr (any)noSpeed multiplier for day/night progression (0 = pause).
{"k":"setTimeOfDay","progress":1}

Chain actions

travelToZone

Travel to zone. Send the match to another ZONE: a different map, played as part of the same chain, carrying whatever the chain's carry-over list nominates (trigger variables, quests, each seat's resources, hero progress). The zone must be declared in the map's chain table. SINGLE-PLAYER ONLY — a zone hop replaces the map, and multiplayer hashes the terrain every turn, so the engine refuses the hop in a multiplayer match rather than letting it half-work. The zone must also declare respawn: true: a zone is REBUILT from its map file every time you enter it, so enemies come back and a building you destroyed is whole again. respawn: false ("remember this zone as I left it") is refused, because per-zone persistence is not built yet and quietly regenerating the zone instead would make the map lie to you. Nothing happens inside the action itself — it asks for the hop, the rest of the trigger still runs, and the match is replaced a moment later. Two gateways firing on the same tick: the first one wins. Needs map format 3.

Editor: travel to zone ‹Zone id› arriving at ‹Arrive at region›

FieldTypeRequiredDescription
zonestringyesZone id to travel to, as declared in the map's chain table.
entryRegionstringnoRegion in the destination to arrive at. Overrides the zone's own default; leave empty to use it.
{"k":"travelToZone","zone":"text"}

Script structure

TriggerScript

FieldTypeRequiredDescription
versionint (≥ 1, ≤ 1)yesAlways 1.
varsvarDeclsyesGlobal variables, initialised in order on map init.
regionsregionDefsyesNamed tile rectangles (RegionDef[]).
triggerstriggerDefsyesTriggers (TriggerDef[]), evaluated in array order.
saveCodeSaltstringnoBinds save codes to this map; defaults to the map name.
functionsfunctionDefsnoUser-defined functions (FunctionDef[]).
hashtableshashtableDeclsnoDeclared hashtables (HashtableDecl[]).
chainchainSpecnoZone chain: the maps this one can travel to, and the state that travels with the player.

VarDecl

FieldTypeRequiredDescription
namestringyesIdentifier: letters, digits and _, not starting with a digit or __.
typevarTypeyesValue type.
arrayboolnoFixed-length array.
arraySizeint (≥ 1)noArray length (globals ≤ 8192, locals ≤ 1024).
initexpr (any)noInitial value (globals: at map init; locals: at each execution start).

RegionDef

FieldTypeRequiredDescription
idstringyesRegion id.
xintyesTop-left tile X.
yintyesTop-left tile Y.
wint (≥ 1)yesWidth in tiles (≥ 1).
hint (≥ 1)yesHeight in tiles (≥ 1).
namestringnoEditor label.

TriggerDef

FieldTypeRequiredDescription
idstringyesStable trigger id.
namestringnoEditor label.
enabledboolnoInitially enabled (default true).
runOnceboolnoFire at most once.
eventseventsyesEvents (any one fires the trigger).
conditionsexprListnoConditions, all of which must hold. They see globals only.
localsvarDeclsnoPer-execution local variables; survive wait and save/load.
actionsactionsyesActions, run top to bottom.

FunctionDef

FieldTypeRequiredDescription
namestringyesFunction identifier.
descriptionstringnoDocumentation.
paramsparamsnoTyped parameters (≤ 16, scalars only).
returnsvarTypenoReturn type; absent = returns nothing.
localsvarDeclsnoPer-call locals.
actionsactionsyesBody. May not contain wait or stopTrigger.

FunctionParam

FieldTypeRequiredDescription
namestringyesParameter identifier.
typevarTypeyesParameter type.
descriptionstringnoDocumentation.

HashtableDecl

FieldTypeRequiredDescription
namestringyesHashtable identifier.
valueTypevarTypeyesType every stored value is coerced to.
maxEntriesint (≥ 1, ≤ 16384)noEntry cap (≤ 16384).
descriptionstringnoDocumentation.

UnitFilter

FieldTypeRequiredDescription
playersintListnoOwner must be one of these seats.
ofPlayerexpr (player)noOwner must equal this seat.
alliedToexpr (player)noOwner must be allied to this seat.
enemyOfexpr (player)noOwner must not be allied to this seat.
unitTypeIdsunitTypeIdListnoUnit/building type must be one of these.
tagsstringListnoAuthored tag must be one of these.
aliveOnlyboolnoOnly living units (default true).
heroesOnlyboolnoOnly heroes.
buildingsOnlyboolnoOnly buildings.
excludeBuildingsboolnoNo buildings.
flyingOnlyboolnoOnly flyers.
excludeFlyingboolnoNo flyers.
excludingexpr (unitGroup)noDrop these units.

UIFrameStyle

FieldTypeRequiredDescription
backgroundColorcolorHexnoHex colour; anything else renders the default.
borderColorcolorHexnoHex colour; anything else renders the default.
textColorcolorHexnoHex colour; anything else renders the default.
fontSizenumbernoFont size (px).
borderRadiusnumbernoCorner radius (px).
paddingnumbernoPadding (px).