Skip to main content
Flow control turns effect lists into sequences and decisions: pause between lines, branch on conditions, loop, and pick random outcomes.

delay

Pauses the remaining lines of the current effect list, then resumes. This is the backbone of telegraphed attacks. Alias: wait The duration is positional: delay 0.5s, delay 20.
A delay inside a named effect pauses that effect only, not whatever called it.

run

Runs a named effect. Its lines inherit this line’s targets unless they set their own @. Aliases: effect, skill The effect id is positional:

if

Runs one body when a condition holds, optionally another when it doesn’t. Alias: branch

loop

Runs a body a fixed number of times.

while

Re-checks a condition on an interval and runs the body while it holds. It checks first, then runs.

Bodies: named effects or inline blocks

A body (then / else / effect) is either a named effect id, resolved mob-local first exactly like run, or an inline block {stmt;stmt;...}:
  • Statements are full effect lines, mechanic plus optional @targeter, separated by ;.
  • Blocks nest: a statement can itself be an if/loop/while with its own block.
  • A block may span multiple lines, and continuation lines may start with - for readability. The loader joins them before YAML parsing, so the raw multi-line form doesn’t need to be valid YAML on its own.
Rules for blocks:
  • No #triggers inside a block. The trigger belongs to the outer line.
  • No comments inside a multi-line block.
  • A malformed or empty block fails the whole line at load time, logged and skipped.
  • Prefer a named effect over a block when the body should be reusable or run-able. Blocks are for short one-off branches.

randomskill

Runs one randomly chosen named effect. Great for varied attack patterns. Alias: randomeffect

randommessage

Sends one randomly chosen message. Alias: randommsg

Conditions

if and while share a small condition language over variables. A condition is one or more comparisons joined by && and ||, where && binds tighter:
  • Operators: >= <= > < == !=.
  • Truthy check: a lone operand with no comparison is true when the value is set and non-zero, non-empty and not "false". Example: if{cond=var.enraged;then=...}.
  • Operands: numbers; variable references without angle brackets (var.x, target.var.x, global.var.x, world.var.x, skill.var.x); the keywords random (alias chance, a fresh 0-1 roll per evaluation, so random < 0.3 is a 30% chance), health and maxhealth (the casting mob’s), and time (world ticks). Anything else is a string literal, bare word, no quotes needed.
  • Both sides numeric means numeric comparison. Otherwise case-insensitive string equality, == and != only; ordered operators on strings are always false.
  • Unset variables count as 0 in numeric comparisons and "" in string ones.
  • target.var.x reads from the line’s first target.
  • A malformed condition fails the whole line at load time, logged and skipped, like any other parse error.

Behavior notes

  • A branch or loop body runs with the caller’s context: same targets (unless its lines set their own @targeter) and the same skill. variable scope, so loop counters via var{...} work across iterations.
  • A delay inside a looped effect pauses that iteration only, not the loop schedule.
  • Spaced loop and while stop early if the mob dies or despawns. while’s max is a hard safety cap against infinite loops.

The counter pattern