Functions

Function formulas

A function is a named formula you can reuse anywhere. Formulas do integer math: add, subtract, multiply, floor-divide (</), ceil-divide (>/) and remainder (%).

  • World variables: [WorldVar] or [.WorldVar] (a leading dot always refers to a world variable);
  • Scene variables: [Scene.var] (e.g. [Forest.coins]);
  • Object variables: [Scene.Object.var] (e.g. [Forest.chest.openCount]); the first segment may be the scene name (or its id);
  • Bag items: [.bag.itemId] (type [ and pick an item from the completion — its item number is inserted automatically; shared items resolve by source identity) — read how many you carry, and scripts can change it; trials read 0;
  • Call other functions: functionName().

In the function library, typing [ auto-completes variables and functions; “Try it” (试算) shows the result and variable changes instantly — see the effect the moment you finish editing.

An if branch may also be a single expression: if [key] == 1 then [key] else [coin] end — the whole if is one value (the last line is the return value) and can sit inside a larger formula. Condition and compute values can also reference a pure function directly.

💡
Pure arithmetic functions are always safe in conditions — they write no state and give the same result within a step. Renames follow along too: renaming a function updates every formula that calls it, and renaming a scene updates the scene name inside formulas.

Script functions

Functions can do more than math. Write three kinds of statements, one per line, to make a function act: set to assign, if … then … else … end to branch, for … times … end to loop a bounded number of times; _rand(n) gives a random integer from 0 to n (inclusive).

set can also write the bag: set [.bag.itemId] = … — it only changes the current user's bag; in a multiplayer world everyone has their own. Trials never touch the real bag.

Loops can also carry a counter: for [`i] = 1 .. 52 times … end — each round the counter is set to the current number, counting from 1 to 52, fifty-two rounds in all; when the start is greater than the end, it runs zero times. The counter exists only within this one call.

  • for counter [`i] = start .. end times: loop with a number — each round sets the counter to the current value (and when start exceeds end, it runs zero times); the counter is a temporary, like a local variable, gone after the call.
  • Local variables [`i]: backtick inside the brackets — created fresh on every call, valid only within that call, reads 0 before first assignment, gone afterwards; never stored in the world, saves or multiplayer shared state;
  • Holes {expr}: computed subscripts inside names — [.tb_{cur}] dynamically picks the variable matching cur's current value;
  • Self-binding [..v]: the variable of “the object or timer that is calling me” — put one effect on any number of objects and each changes only itself; in a trial there is no calling object, so it reads 0 and writes do nothing — at runtime the actual caller decides.

“Cost ≈ N steps” estimates the cost live: each run has a step budget, and exceeding it stops the function mid-run.

⚠️
Functions containing set / for / _rand (or calling such functions) cannot be used in conditions — they write state or roll dice. Put them in effects only.
if [.tb_{cur}] == 0 then
set [.tb_{cur}] = 1
end

for [`i] = 1 .. 3 times
set [.tb_{`i}] = [`i]
end
💡
All 52 cards of the Bi Qi world are built on holes and self-binding: each card is one number, one effect rules them all, and every card changes only itself — and its shuffle and deal functions are a live lesson in the for counter, counting 1 to 52 as cards land in hands one by one. A whole deck of cards, zero special mechanics.