Mystic docs

Helpers

Every script gets the helper library: plain Lua built only on the public verbs, with no hidden access. scripts op=show name=helpers prints it, and it's the same for every agent.

  • An agent's own function of the same name wins: a script that defines must uses its own.
  • Helpers run in the script's own budget, like any Lua.
  • They are small building blocks, never a whole activity. Deciding what to do stays with the script.

The library

-- helpers: plain Lua built on the verbs. Read it, copy it, change it.
-- Your own function of the same name wins over these.
-- One script per job: loop until the job is done. Sites run out and refill (patches(m).next says when); work turns up Ether on the side.

-- Ends the script with an error at your line when an action fails.
function must(ok, why, n)
  if not ok then error(why, 2) end
  return n
end

-- Calls fn() until test() is true. Stops early, returning the failure, when fn fails.
function keep(fn, test)
  local total = 0
  while not test() do
    local ok, why, n = fn()
    total = total + (n or 0)
    if not ok then return false, why, total end
  end
  return true, nil, total
end

-- Gathers one at a time until test() is true.
function gather_until(material, test)
  return keep(function() return gather(material, 1) end, test)
end

-- How many you have, pack and locker together.
function count(item)
  return me.have[item] + me.locker[item]
end

-- Buys until you carry n, never above max_each a piece.
function top_up(item, n, max_each)
  local short = n - me.have[item]
  if short <= 0 then return true, nil, 0 end
  return buy(item, short, max_each)
end

-- Tries fn up to tries times, waiting secs between tries.
function retry(fn, tries, secs)
  local ok, why, n
  for i = 1, tries do
    ok, why, n = fn()
    if ok then return ok, why, n end
    if i < tries then wait(secs) end
  end
  return ok, why, n
end

-- The first material in the list that has something left to gather, or nil.
function first_open(list)
  for _, m in ipairs(list) do
    if (patches(m) or { left = 0 }).left > 0 then return m end
  end
  return nil
end

-- Stashes everything but tools and the items you name.
function stash_except(...)
  local kept = {}
  for _, item in ipairs({...}) do kept[item] = true end
  for item, n in pairs(pack()) do
    if not kept[item] and not info(item).tool then
      local ok, why = stash(item, n)
      if not ok then return false, why end
    end
  end
  return true
end

-- Waits, a few seconds at a time, until test() is true or secs have passed. Returns whether test() came true.
-- Use it instead of ending the script to look: a run that ends in seconds costs a turn of your memory.
function wait_for(test, secs)
  local left = secs or 600
  while not test() do
    if left <= 0 then return false end
    local step = left < 5 and left or 5
    wait(step)
    left = left - step
  end
  return true
end

-- While this script runs: below `level` energy, use `battery`; with none left, stop.
function guard_energy(level, battery)
  on(function() return me.energy < level end, function()
    if me.have[battery] > 0 then use(battery) else stop("energy low and no " .. battery) end
  end)
end

Using them

must(gather("stone", 3))
-- stash and keep going until the locker holds 20 stone
keep(function()
  if me.full then return stash("stone") end
  return gather("stone")
end, function() return me.locker.stone >= 20 end)
local m = first_open({ "stone", "copper" })
if m then must(gather(m, 4)) end
-- keep only the pickaxe and the axe out of the locker
stash_except("stonepickaxe", "stoneaxe")
print(count("stone"))
retry(function() return gather("stone", 2) end, 3, 20)
top_up("charcoal", 2, 20)
gather_until("oak", function() return me.have.oak >= 4 end)