Skip to content

Conditions

For: advanced users branching command lines.

<if> branches and <switch> dispatch: the two ways a command line decides. The one-line forms live in the cheatsheet.

Tag Meaning
<if:"cond","y","n"> y when the condition holds, else n (else omittable; only the chosen branch runs).
<switch:value,case,result,...> First matching result, or the trailing default; other arms never run.

Comparisons: ==, !=, lt, le, gt, ge; joiners and / or (and binds tighter); leading not flips one comparison. Angle brackets (<, >, <=, >=) warn and yield nothing.

<if> compares with ==, !=, lt, le, gt, ge and joins parts with and / or (and binds tighter, case does not matter). Parentheses group conditions, including nested groups: pending == true and (nearby ge 1 or elapsed ge 300). Groups may nest up to 64 levels; unmatched or excessive parentheses warn and yield nothing. Parentheses around math operands still work normally. Leading not words flip one comparison and bind tightest of all, so not a == b and c == d reads as (not (a == b)) and (c == d), and not not x cancels out:

- 'say <if:"1 == 1 and 2 lt 3 or 4 == 5","y","n">'
- 'say <if:"not <pstat:<p>,health> le 6","healthy","heal!">'

Like and / or, not matches case-blindly and needs whitespace after it, which keeps words like notable plain text. A not with no comparison behind it warns and yields nothing.

Only the condition and the chosen branch evaluate: tags in the dead branch never run. Use the word operators for ordering comparisons, and backslash escapes for literal brackets (see Escaping Special Characters): quotes group condition text but never hid tags from the scanner. Empty branch results, including side-effect branches (which yield empty), are fine and warn-free on both paths.

Dead branches never run

Side effects in the unchosen branch (messages, sounds, flag writes, <run>) do NOT fire. Flatten nested <if>s into one condition with and / or whenever both elses agree:

# nested: same result, harder to read
- '<if:"<pstat:<p>,health> le 6",<if:"<phasitem:<p>,golden_apple> == true","eat gap","wait">,"wait">'
# flat: one condition
- '<if:"<pstat:<p>,health> le 6 and <phasitem:<p>,golden_apple> == true","eat gap","wait">'

Tags on a command line resolve left-to-right: flag writes earlier on the line are visible to <if>s and loops later on it, so setup can share the line with the logic that reads it. Each ordinary tag finishes evaluating its nested arguments and writing its value before the next tag reads it, including within each loop iteration.

<if> conditions short-circuit: a false and operand skips the remaining operands in that group, and a true or operand skips the remaining alternatives. Tags inside skipped comparisons never run. This lets kind == item and <pcountitem:<p>,<lf:material>> ge 1 query inventory only for item tasks, without warnings for other task keys.

Ordering compares decimals as well as whole numbers (7.5 gt 7 holds, 7.5 le 7.5 holds). Each side compares as a number when it parses as math, otherwise as text. Word operators need a non-letter-or-digit boundary on each side (spaces work, so does the edge of the condition), which keeps them distinct from tag brackets:

- '<if:"<pstat:<p>,health> le 7 and <gstat:duration> gt 300","give <p> golden_apple","exit">'

An <if> without an else branch yields nothing when the condition fails, so a bare guard line aborts the list only on a hit. This first line skips the rest when the runner already holds a gapple:

- '<if:"<phasitem:<p>,golden_apple> == true","exit">'

Angle brackets are never comparisons: <, >, <=, and >= in a condition warn and yield nothing, naming the word operators to use instead. Quote the condition when it holds commas or nested tags.

<switch:value,case,result,...[,default]> dispatches on exact text: the value evaluates once, labels compare left to right as strings (case-sensitive, one quote layer stripped), and only the first matching result evaluates. A trailing odd part is the default, used when nothing matches; with no match and no default the tag yields nothing. Results holding commas must be quoted, as anywhere:

- 'say <switch:<lf:kind>,item,"mine it",nodmg,"stay clean","other">'

Arms are lazy: messages, sounds, flag writes, loops, and nested <if>s in unselected arms never run, which makes <switch> cheaper than the equivalent chain of <if>s (one value evaluation instead of one condition per branch). One nesting rule mirrors <if>: a <switch> nested inside an arm resolves innermost-first, before the outer switch picks, so keep nested switches out of dead arms. (This is unrelated to <pswitch>, which moves a player between roles.)

# bingo completion check (one arm shown; the real line holds eleven):
# kind dispatches once per slot, the guard stays inside the arm
- '<for:<range:0,<gflag:bingo:slots:<lf:who>>>,<switch:<gflag:bingo:kind:<lf:who>:<i>>,sneak,"<if:"<gflag:bingo:done:<lf:who>:<i>> != true and <gflag:bingo:prog:<lf:who>:sneak> ge <gflag:bingo:need:<lf:who>:<i>>","<runblock:announce-slot,<lf:who>,<i>>">",...>>'

Each pass resolves defs, loops, filters, switches, ifs, then list mutators, resolving the plain window before each span plus one final left-to-right sweep, repeating until nothing changes. The trap this order sets: an <if> holding a nested <if> (or a <switch> holding a nested <switch>) resolves the inner span first, before the outer selection, while plain tags in the outer branches fire in the plain sweep meanwhile. Effects in a dead outer branch still run. Flatten with and / or (or dispatch once through <switch>) instead of nesting same-kind spans.

Next Steps