Modules, require and walking

Lua · Updated 09 November 2026

What each botwithus module gives you, loading your own files, actions and the two walking styles.

The modules

Module What it gives you
botwithus the umbrella: run, stopping, npcs, players, objects, Game, Tile, Actions, Events, Input, clients, Variables
botwithus.game the Game your script gets as ctx.game: :self(), :npcs(), :players(), :objects(), interface checks, :clocks(), walking, :queue_actions(), :poll_events(), breaks, varp and varbit reads
botwithus.config settings fields: int_field, string_field, bool_field, choice_field, item_id_field
botwithus.entities fluent queries: :of_type(), :within(), :where(), :nearest(), :all()
botwithus.tile Tile, with 8-directional distance
botwithus.actions action ids and builders: walk_to(x, y), component_click(...), dialogue_option(...)
botwithus.events decodes the events from Game:poll_events(), such as action_executed and action_refused
botwithus.variables the varp state names: SET, DEFAULT, NO_SUCH_VARP, UNAVAILABLE
botwithus.input the game's input dialog: Input.dialog(game) with :enter_amount(...), :enter_text(...) and more

Loading your own files

The script's own folder is put first on package.path. So a script can require the files next to it: require("helpers") finds helpers.lua or helpers/init.lua beside your script.

Lua separates package.path entries with ;, so this does not work from a folder whose name contains ;.

Finding things

local tree = bot.objects(ctx.game):of_type(TREE):nearest(me.tile)

bot.npcs(game), bot.players(game) and bot.objects(game) start a query. :of_type(id) and :where(fn) filter it, and :nearest(tile) or :all() finish it.

Acting

ctx.game:do_action(a) queues one action and returns true, or false and the error:

ctx.game:do_action({ id = 3, p1 = tree.id, p2 = tree.tile.x, p3 = tree.tile.y })

ctx.game:queue_actions(list) sends several actions in one go. The game queues all of them or none, and the call raises if they were refused. :try_queue_actions(list) reports the same outcome without raising.

An action the game queued can still be dropped later if its target never becomes clickable. ctx.game:poll_events() then returns an action_refused event for it.

Walking: two styles

  • ctx.game:walk_to(x, y) queues one walk hop and returns straight away. You write the loop: step, ctx:sleep_ticks, repeat.
  • ctx.game:walk(x, y, plane, radius) does a full walk. It plans the route, walks it, re-plans as needed and carries out its transitions (doors, stairs, teleports, dialogue) until it arrives. It blocks for the whole route and returns arrived, err. ctx.game:walk_cancel() stops it.
local bot  = require("botwithus")
local Tile = bot.Tile

local BANK   = Tile.new(3165, 3486, 0)
local RADIUS = 3

function script.on_loop(ctx)
  local me = ctx.game:self()
  if me.tile.plane == BANK.plane and me.tile:distance(BANK) <= RADIUS then
    return -1
  end

  local arrived, err = ctx.game:walk(BANK.x, BANK.y, BANK.plane, RADIUS)
  if not arrived then
    io.write(("banker: walk did not arrive (%s); stopping\n"):format(tostring(err)))
    return -1
  end
  return 0
end

ctx.game:walk_ex(...) is the same blocking walk and returns a result table instead: status, the step or transition a failed walk failed on, re-plans used, elapsed time and the walker's events.

Breaks and varps

  • ctx.game:schedule_break(300) holds the action queue for 300 seconds. ctx.game:interrupt_break() ends it early.
  • ctx.game:read_varp(id) and :read_varbit(id) return a table with a state beside the value. Decide on the state, not the value alone.
  • ctx.game:local_health() returns current, max life points, or nil while unknown.

Next: Logs and running.