No active sessions yet.

No games yet.

No conversations yet.

No characters yet.

Rule bodies

A rule body is not free JavaScript — every line is a step call or an if.

This is the rule that catches everyone once, human and AI alike.

Every line in a rule body must be a step call or an if. No variables. No loops. No function declarations.

What works

if ($.player.fields.satiety <= 0) {
  if ($.dial('starvationDamagePerHour') > 0) {
    $.damage({ amount: $.dial('starvationDamagePerHour') })
  }
}

Branching is fine. Nesting is fine. Arithmetic inside an argument is fine.

What is rejected

var rate = $.dial('starvationDamagePerHour')
$.damage({ amount: rate })

var is not a step. And it does not fail alone — it takes the whole body with it. The rule does not partially run; it does not run.

That is the trap: you get a rule that silently never fires, and the cause is a line that looks like ordinary, correct JavaScript.

Say it again without the variable

Whatever you wanted the variable for, put it in the argument:

$.damage({ amount: $.dial('starvationDamagePerHour') })

If you used it twice, write it twice. Bodies are short by design; the duplication you are avoiding costs less than the rule not running.

The conditional operator is fine inside an argument

// WORKS — ?: lives inside the argument
$.adjustField({ field: "satiety", by: -($.timed
  ? ($.event.minutes / 60) * $.dial('foodDrainPerHour')
  : $.dial('foodDrainPerTurn')) })

It is a ?: used as a statement, outside any argument, that fails.

When you genuinely need code

$.script(`
  for (var i = 0; i < 3; i++) { $.damage(1) }
`)

$.script() takes a real block of JavaScript. The cost: you lose the round-trip to the visual editor, and the body becomes opaque to anyone editing with steps. Reach for it last.

Inside a script, the verbs are positional rather than object-shaped, and the list is shorter:

  • $.damage(...)
  • $.heal(...)
  • $.adjustField(...)
  • $.setField(...)
  • $.narrate(...)
  • $.refuse(...)
  • $.giveItem(...)
  • $.setWorldState(...)
  • $.passTime(...)

A script may record at most 200 steps. That is a bound on runaway loops, not a budget to spend — real rules record one or two.

Code view and step view are one rule

The editor shows a rule either as visual steps or as code. They are two renderings of the same artifact — editing either edits the same rule.

The round-trip is lossless or refused: roll tables (whose entries are not in the text) and step types the renderer cannot yet write stay read-only rather than being guessed at. You will never silently lose a step by switching views.

Image: docs/rule-code-and-steps.png The same rule shown twice side by side — the visual step list and the code view — so the correspondence between one step and one line is obvious.

Next

Hooks — when your rule body actually runs.