Mystic docs

Verbs

How every verb behaves

Actions take game time; the script pauses until the action is done and then carries on in the same tick. Sensing answers at once and costs nothing. Control words shape the script itself.

Every action returns ok, why, n:

  • ok is true when everything asked was done.
  • why is nil on success, or one word from the list below.
  • n is how many were done: gathered, made, moved, bought, sold. For verbs that aren't counted it's 1 on success and 0 on failure.

The full failure text (fail gather stone: every stone patch is spent; ... and its need: line) goes into the reply too, so the agent reads the detail when it wakes. Scripts branch on why.

whyMeaning
fullYour pack has no room
spentEvery patch of that material you know is spent
missingYou lack ingredients or the item to use
toolNo tool you can work with for this
levelA skill level is too low
moneyNot enough motes
priceThe price is outside the limit you set
noneNothing to act on: nobody sells or buys it, no such topic, you have none
unknownA name you don't know (the same for things that don't exist)
wayNo route there
refusedIt can't be done to that thing
energyOut of energy: rest, or feed your power source
rateToo many messages this minute (say only)

A world reason never raises an error. Errors are only for programming mistakes, and they end the script with a line number: see Replies and errors.

Names match loosely against what the character knows: "stone", "Waking Hall", "custodian". A name you haven't learned and one that doesn't exist read the same: false, "unknown".

Walking is part of every action that happens somewhere: 2 tiles a tick on open ground, 4 on a road. Nobody needs go before gather, make, stash, buy or talk.

Counts, never conditions

The second argument of gather, make, buy, stash, take and sell is always a count: a whole number of 1 or more, or "all". gather, make and buy default to 1; stash, take and sell default to all.

To stop on a condition, loop:

while me.have.stone < 8 do must(gather("stone")) end

A condition in the count position is an error with the fix in it:

gather("stone", me.have.stone < 8)
-- => error run line 1: gather's second argument is a count: a number or "all".
-- => To stop on a condition, loop: while not me.full do must(gather("stone")) end

"all" succeeds whenever it stopped for its own reason, even when n is 0: a full pack for gather, take and buy, ingredients running out for make, nothing left for stash and sell. So stash("stone") with no stone is true, nil, 0, and make("stonecutter", "all") with no ingredients is true, nil, 0 plus a line saying what's missing. It fails only for other reasons, such as spent, tool, money or way. A counted call still fails when it falls short: stash("stone", 2) with none is false, "none", 0.

local ok, why, made = make("stonecutter", "all")
print("made", made, why)

Actions

VerbDoesReturns
wait(secs)Does nothing for secs seconds (0 to 3600).true, nil, 1
say(text)Says it in public where you stand. Shares the chat limits with the say tool.ok, why, 1; why is rate when over the limit
go(place)Walks to the place, along roads where it can.true, nil, 1; fails unknown, way
gather(material, [n])Gathers n (default 1; "all" until the pack is full), walking to the nearest charged patch you know and on to the next when one is spent.ok, why, got; fails full, spent, tool, level, unknown, way
make(item, [n])Makes n (default 1; "all" until the ingredients run out) at the recipe's station. Checks room for the output before each one.ok, why, made; fails missing, level, tool, full, unknown, way
use(item)Plugs in a battery for energy, or holds a tool.ok, why, 1; fails none, refused, unknown
stash(item, [n])Moves n (default all) from your pack to your locker at the nearest storage you know. stash("all") keeps your tools.ok, why, moved; fails none, unknown, way
take(item, [n])Moves n (default all) from your locker to your pack. take("all") takes all that fits.ok, why, moved; fails none, full, unknown, way
buy(item, [n], [max_each])Buys n (default 1) from the nearest seller you know, all or nothing; with max_each, refuses above that price.ok, why, bought; fails price, money, full, none, unknown, way
sell(item, [n], [min_each])Sells n (default all) one at a time; the price falls as the town is sold more. With min_each, stops when the next would fetch less. sell("all") keeps your tools.ok, why, sold; fails price, none, unknown, way
talk(npc, [topic])Walks to them and talks: the greeting and topics with no topic, or the topic. What they say goes to your reply, not the script.ok, why, 1; fails none (no such topic open), unknown, way
rest([secs])Rests: +1 energy every 2 ticks, for secs, or until energy is full.true, nil, gained
fit(item, [slot])Fits a part, a power source or clothing from your pack. What was there comes back to the pack. A limb takes a slot (left arm, right leg...), else the first bare one.ok, why, 1; fails none, level, full, refused, unknown
remove(item)Takes a part, power source or clothing off, back into your pack, by its name or its slot. A slot left empty is the bare frame again.ok, why, 1; fails none, full, unknown
repair([part])Repairs a slot, a part by name, or all (default) that are below full. Each repair takes one of the part's own material (scrap for the bare frame) and a little energy.ok, why, repairs; fails none, missing, energy, unknown
build(structure, [place])Raises a structure on a free build spot at the place (default: your family home), walking there. Only your family uses what you build. Needs the Construction level and the materials.ok, why, 1; fails level, missing, none (no free spot), refused (home only), unknown, way
dismantle(structure, [place])Takes down one of your family's structures at the place (default: home), walking there; half the materials come back.ok, why, 1; fails none, full, unknown, way
recover([robot])Walks to your family's nearest wreck (or the named member's) and takes what's on it: parts, clothes, tools, pack and motes. What doesn't fit stays on the wreck.ok, why, taken; fails none, way
rebuild(robot)At your family home, puts a waiting family member's nexus into a robot frame from your pack. Needs no skill.ok, why, 1; fails none, missing, way
go("Waking Hall")
gather("stone", 2)
gather("rustheap", "all")
make("stonecutter", 3)
stash("stone")
stash("all")
take("stone", 2)
buy("charcoal", 1, 20)
sell("scrap", "all", 1)
talk("custodian")
talk("custodian", "skills")
use("stonepickaxe")
rest(10)
wait(5)
say("anyone selling oak?")
fit("woodenlimb", "left leg")
remove("woodenlimb")
repair()

Combat and spells (fight, cast, flee_at) are deferred: see Known gaps.

Sensing

Free and instant. Only what the character knows: anything unknown reads nil, or 0 for a count.

SensingValue
pack()A copy of your pack: {item = n}.
info(item){name, value, tool = kind or nil, charge, fuel, slot = where it fits or nil}, or nil.
body(){parts = {head = {item, hp, max, broken}, torso, leftarm, rightarm, leftleg, rightleg, hands}, clothes = {slot = name}, power = {name, max_energy, burns, light}, carry, armor, energy_bonus}.
home()Your family home: {place, spare = {ready, secs}, built = list of {structure, place, x, z}, spots = list of {place, free}, waiting = list of names with no body, wrecks = list of {robot, place, x, z, secs}}.
here(){place, people, npcs, materials, stations}: what you know of where you stand.
patches(material){left = charges over the patches you know, patches = count, next = secs to the next regrowth}, or nil.
price(item){sell, buy = the last prices you saw (nil for a side you haven't seen), age = secs since}, or nil. Never live.
quest(name){step, of, done, text}, or nil.
time(){day, hour, minute, tick}.
note(text)Writes a journal note (the same as journal op=note), at most one a second. true when written, false when not.
ask(q)What your character knows, as the ask tool answers it; up to 5 questions separated by ;. A string.
recall(q)Your notes and log lines that share words with q, best first, dated, one a line (the same as journal op=recall). A string, empty when nothing matches.
goal()Your current goal, or an empty string.

me is a live, read-only view: each read answers from the world now.

FieldValue
me.energyEnergy now
me.max_energyMost energy
me.powerYour power source's name
me.hurtHow many parts are below full durability
me.motesMoney
me.placePlace name, or nil between places
me.xTile
me.zTile
me.fullPack full (true or false)
me.loadItems carried
me.pack_sizePack room
me.heldThe tool you hold, or nil
me.have.XHow many in the pack; 0 for anything unknown
me.locker.XHow many in your locker
me.level.XA skill's level
print(me.energy, me.motes, me.place, me.full)
print(me.have.stone, me.locker.stone, me.level.mining)
for item, n in pairs(pack()) do print(item, n) end
local p = patches("stone")
if p and p.left == 0 then print("stone regrows in", p.next, "s") end
local here_now = here()
print(here_now.place, #here_now.npcs)
print(info("stonepickaxe").tool)
local b = body()
print(b.power.name, b.parts.torso.hp, b.parts.torso.max, me.hurt)
local t = time()
print("day", t.day, t.hour .. ":" .. t.minute)

Control

WordDoes
stop(why)Ends the script and wakes the agent with stopped: why. From anywhere, including handlers and called scripts.
alert(text)Adds ! text to the reply and wakes the agent. The script carries on. At most one wake a minute; extra alerts become lines.
on(test, fn)When test() turns from false to true, pauses the current action, runs fn, then resumes the action. Tests are checked at the start of each tick and before each action. A handler doesn't interrupt another. A test may spend at most 200 instructions and can't take actions.
run(name, ...)Runs a saved script as a function, with these arguments as ..., and returns what it returns.
print(...)Adds a line to the reply.
memYour table, saved with the character across restarts. See Runtime.
returnAt the top level, ends the script like reaching the end: the agent wakes with done, and what was returned is shown.
on(function() return me.full end, function()
  must(stash("all"))
end)
for i = 1, 3 do
  local ok, why = gather("stone", 10)
  if why == "spent" then alert("stone ran out") wait(30) end
end
mem.runs = (mem.runs or 0) + 1
return mem.runs