Scripting API

ScriptContext

class ScriptContext(session_ctx: TelixSessionContext, buf: ScriptOutputBuffer, log_inst: Logger)[source]

User-facing API handed to scripts as their ctx argument.

Every script receives a single ctx argument that provides access to all known information about the MUD session and scripting capabilities of Telix.

Parameters:
  • session_ctx – The live session context.

  • buf – Per-script output buffer.

  • log_inst – Logger for the script.

property gmcp: dict[str, Any]

The full GMCP data dict from the session context.

property room_id: str

Current room number string.

property room_graph: rooms.RoomStore | None

The RoomStore for this session, or None.

property captures: dict[str, Any]

Highlight capture variables for this session.

property room: rooms.Room | None

The current Room, or None if unknown.

Returns None if no GMCP room data has been received. The room object has name, area, and exits attributes.

gmcp_get(dotted_path: str) Any[source]

Retrieve a value from the GMCP data dict by dot-separated path.

Handles both flat dotted top-level keys (e.g. "Char.Vitals" stored as a single key in the dict) and nested dict hierarchies. At each level the longest matching prefix is tried first, then progressively shorter ones, so both storage styles work transparently.

A bare field name without dots (e.g. "Water") searches across all GMCP packages automatically.

If the path ends with %, the value is computed as a ratio of the field to its Max counterpart and returned as a float between 0.0 and 1.0. Both dotted and bare forms work:

ctx.gmcp_get("Char.Guild.Stats.Water%")
ctx.gmcp_get("Water%")

The Max lookup is case-insensitive (MaxWater, maxwater, etc.).

Parameters:

dotted_path – Key path, e.g. "Char.Vitals.hp" or "hp".

Returns:

The value at that path, or None if not found.

get_room(num: str) rooms.Room | None[source]

Look up a room by number.

Parameters:

num – Room number string.

Returns:

Room or None.

find_path(dst: str) list[str] | None[source]

Find a path of directions from the current room to dst.

Parameters:

dst – Destination room number string.

Returns:

List of direction strings, or None if no path found.

async send(line: str, wait_prompt: bool = True) None[source]

Send a command string to the server.

Supports the same syntax as the REPL:

  • ; between commands waits for the server prompt before sending the next

  • | sends immediately without waiting

  • A leading number repeats: 3north sends north three times

Backtick directives like `` async `` and `` until `` are handled by the client, not sent to the server. See Commands for the full list.

By default, send waits for the server prompt (GA/EOR) after all commands have been dispatched. Pass wait_prompt=False to return immediately:

await ctx.send("look")                       # waits for prompt
await ctx.send("look", wait_prompt=False)    # returns immediately
Parameters:
  • line – Command line to send.

  • wait_prompt – Wait for the server prompt (GA/EOR) after sending. Defaults to True.

async prompt(timeout: float | None = None) bool[source]

Wait for the next GA/EOR signal from the server.

Parameters:

timeout – Maximum seconds to wait, or None to wait indefinitely.

Returns:

True if prompt arrived within timeout.

async prompts(n: int, timeout: float | None = None) bool[source]

Wait for n consecutive server prompts.

Parameters:
  • n – Number of prompts to wait for.

  • timeout – Timeout in seconds for each prompt, or None to wait indefinitely.

Returns:

True if all prompts arrived; False if any timed out.

output(clear: bool = True) str[source]

Return accumulated server output text.

Parameters:

clear – If True, clear the buffer after returning (default True).

Returns:

Output text string.

turns(n: int = 5) list[str][source]

Return the last n prompt-delimited output turns.

Parameters:

n – Number of most recent turns to return.

Returns:

List of turn text strings.

async wait_for(pattern: str, timeout: float | None = None) Match[str] | None[source]

Wait for a regex pattern to appear in the server output.

Parameters:
  • pattern – Regular expression string.

  • timeout – Maximum seconds to wait, or None to wait indefinitely.

Returns:

The re.Match object, or None on timeout.

async condition_met(key: str, op: str, threshold: int | str, timeout: float | None = None) bool[source]

Wait until a GMCP/capture condition becomes true.

Re-evaluates immediately on every GMCP update rather than polling.

key uses the actual GMCP field name (case-sensitive). A bare name searches across all GMCP packages; a dotted path resolves directly. Append % to compute a percentage from the field and its Max counterpart:

await ctx.condition_met("hp%", "<", 50)
await ctx.condition_met("Char.Guild.Stats.Water%", "<", 50)

String comparisons work with = and !=:

await ctx.condition_met("Mode", "!=", "Rage")

If the key is not found in GMCP data, it falls back to highlight capture variables.

Parameters:
  • key – Condition key (e.g. "hp%", "Mode").

  • op – Comparison operator: ">", "<", ">=", "<=", "=", "!=".

  • threshold – Numeric or string threshold.

  • timeout – Maximum seconds to wait, or None to wait indefinitely.

Returns:

True when condition is met, False on timeout.

async conditions_met(*conditions: tuple[str, str, int | str] | list[tuple[str, str, int | str]], timeout: float | None = None) bool[source]

Wait until all conditions are true simultaneously.

Each condition is a (key, op, threshold) tuple. Tuples may be passed as separate arguments or as a single list:

await ctx.conditions_met(("Mode", "!=", "Rage"), ("Adrenaline%", ">", 0))
await ctx.conditions_met([("Mode", "!=", "Rage"), ("Adrenaline%", ">", 0)])

Unlike running separate condition_met() calls with asyncio.wait(), this checks all conditions atomically, so you are guaranteed they all hold simultaneously when it returns.

Parameters:
  • conditions(key, op, threshold) tuples, or a single list of them.

  • timeout – Maximum seconds to wait, or None to wait indefinitely.

Returns:

True when all conditions are met at the same time, False on timeout.

print(*args: Any, sep: str = ' ') None[source]

Write args to the terminal scroll region (cyan).

Behaves like the built-in print(): multiple positional arguments are joined with sep, and non-string values are converted via str(). Uses the same echo mechanism as trigger notifications.

Parameters:
  • args – Values to display.

  • sep – Separator string inserted between values (default " ").

debug(msg: str) None[source]

Write msg to the telix log at DEBUG level.

Parameters:

msg – Message text.

info(msg: str) None[source]

Write msg to the telix log at INFO level.

Parameters:

msg – Message text.

warn(msg: str) None[source]

Write msg to the telix log at WARNING level.

Parameters:

msg – Message text.

error(msg: str) None[source]

Write msg to the telix log at ERROR level.

Parameters:

msg – Message text.

property session_key: str

Session identifier string ("host:port").

property previous_room_id: str

Room number string of the room visited before the current one.

property capture_log: dict[str, list[dict[str, Any]]]

Full capture event history: {variable: [{value, time, ...}, ...]}.

Unlike captures (which holds only the current value), this dict accumulates every capture event so scripts can track trends over time.

property chat_messages: list[dict[str, Any]]

List of received chat/tell message dicts for this session.

property chat_unread: int

Number of unread chat messages since the last read.

property chat_channels: list[dict[str, Any]]

List of available chat channel dicts for this session.

async room_changed(timeout: float | None = None) bool[source]

Wait until the next room transition (GMCP Room.Info received).

Captures a reference to the current room.changed event before awaiting, so the caller is woken exactly once per transition even if another change fires immediately after:

async def tracker(ctx: ScriptContext) -> None:
    while True:
        if not await ctx.room_changed(timeout=60.0):
            break
        ctx.print(f"[tracker] {ctx.previous_room_id} -> {ctx.room_id}")
Parameters:

timeout – Maximum seconds to wait, or None to wait indefinitely.

Returns:

True if a transition occurred; False on timeout.

async gmcp_changed(package: str | None = None, timeout: float | None = None) bool[source]

Wait until the next GMCP packet is received.

async def watch_vitals(ctx: ScriptContext) -> None:
    while True:
        if not await ctx.gmcp_changed("Char.Vitals", timeout=60.0):
            break
        hp = ctx.gmcp_get("Char.Vitals.hp")
        ctx.print(f"[vitals] HP: {hp}")

# wait for any GMCP update
await ctx.gmcp_changed()
Parameters:
  • package – GMCP package name, e.g. "Char.Vitals". Pass None (the default) to wait for any GMCP update.

  • timeout – Maximum seconds to wait, or None to wait indefinitely.

Returns:

True if a packet arrived; False on timeout.

property walk_active: bool

True if any automated walk (autodiscover, randomwalk, travel) is running.

stop_walk() None[source]

Cancel all active automated walk tasks (autodiscover, randomwalk, travel).

property running_scripts: list[str]

Names of all currently running scripts.

Each name is the first token of the spec used to start the script (e.g. "combat.hunt"). The calling script’s own name is included.

property command_history: list[str]

Recently sent commands (oldest first, up to 200 entries).

property last_command: str | None

Most recently issued command, or None if none yet.

async command_issued(timeout: float | None = None) str | None[source]

Wait until the next command is sent by any source.

Returns the command string, or None on timeout. If a command was issued while no waiter was registered (e.g. during the event-loop gap between one call completing and the next being set up), it is buffered and returned immediately by the next call.

Parameters:

timeout – Maximum seconds to wait, or None to wait indefinitely.

Room

class Room(num: str, name: str = '', area: str = '', environment: str = '', exits: dict[str, str]=<factory>, bookmarked: bool = False, visit_count: int = 0, last_visited: str = '', blocked: bool = False, home: bool = False, marked: bool = False)[source]

A single room in the GMCP room graph.

Accessible in scripts as ctx.room (current room) or via get_room().

RoomStore

class RoomStore(db_path: str, read_only: bool = False, session_key: str = '')[source]

SQLite-backed room graph with in-memory adjacency cache.

Accessible in scripts as ctx.room_graph.

property rooms: dict[str, Room]

Return all rooms as a dict (for compatibility).

Not cached.

get_room(num: str) Room | None[source]

Get a single room by number.

Parameters:

num – Room number.

Returns:

Room or None if not found.

has_room(num: str) bool[source]

Return True if room num exists in the database.

toggle_bookmark(num: str) bool[source]

Toggle bookmark on a room (exclusive with other markers).

toggle_blocked(num: str) bool[source]

Toggle blocked state on a room (exclusive with other markers).

toggle_home(num: str) bool[source]

Toggle home state on a room (exclusive with other markers).

toggle_marked(num: str) bool[source]

Toggle mark on a room (exclusive with other markers).

get_home_for_area(area: str) str | None[source]

Return the home room number for the given area.

Parameters:

area – Area name.

Returns:

Room number string, or None if no home is set.

blocked_rooms() frozenset[str][source]

Return frozenset of all blocked room numbers.

room_nums() frozenset[str][source]

Return the set of all room numbers in the database.

find_path(src: str, dst: str, blocked: frozenset[str] = frozenset({})) list[str] | None[source]

BFS shortest path from src to dst.

Parameters:

blocked – Room numbers to treat as impassable.

Returns:

List of direction names, or None if unreachable.

find_same_name(num: str, limit: int = 99) list[Room][source]

Find rooms with the same name as num, sorted by least-recently-visited.

Parameters:
  • num – Room number to match name against.

  • limit – Maximum results to return.

Returns:

List of matching rooms, excluding num itself.

search(query: str) list[Room][source]

Case-insensitive substring search on room name, area, and ID.

Parameters:

query – Search string.

Returns:

Matching rooms sorted bookmarked-first, then by name.