MUD Scripting with Lua
Mudlet's Lua environment allows sophisticated MUD automation, but ad-hoc scripts become unmaintainable when MUD codebases update or when sharing across servers. This guide implements a modular architecture using namespace isolation, event-driven handlers, and automated migration layers to create portable script packages that survive codebase changes and distribute cleanly via Mudlet's module system.

Audit Existing Triggers and Extract Domain Patterns
Before refactoring, export your current Mudlet profile triggers and aliases. Identify repeated regex patterns across multiple triggers (e.g., health prompts, room titles). Create a mapping document that categorizes patterns by MUD system type (combat, navigation, communication) to determine which should become shared library functions versus standalone triggers.
⚠ Common Pitfalls
- •Avoid copying color codes directly; Mudlet uses \x1b for ANSI escape sequences in regex
- •Do not export sensitive passwords stored in aliases; sanitize before committing to Git
Implement Namespace Isolation in Lua
Create a root table structure that prevents global namespace pollution. Define your package as a table named after your project (e.g., MyMudUtils) and nest all functions, state variables, and sub-modules within it. Use local references at the file scope for internal helpers that should not be exposed to Mudlet's global environment or other packages.
-- mymudutils.lua
local MyMudUtils = MyMudUtils or {}
MyMudUtils._VERSION = "1.0.0"
MyMudUtils._AUTHOR = "muddev"
-- Private state
local internalCache = {}
-- Public API
function MyMudUtils.setup()
internalCache.triggers = {}
end
return MyMudUtils⚠ Common Pitfalls
- •Never use global variables without the package prefix; they persist across profile reloads and cause conflicts
- •Avoid naming tables 'triggers' or 'aliases' as these clash with Mudlet's internal tables
Build the Event Registration Core
Design a registration system that wraps Mudlet's registerAnonymousEventHandler to allow multiple listeners per event type. This decouples your triggers from Mudlet's internal event system, enabling you to unregister and re-register handlers programmatically during migrations without restarting the client.
function MyMudUtils.registerEvent(eventName, handlerFunc)
if not MyMudUtils.eventRegistry then
MyMudUtils.eventRegistry = {}
end
local handlerId = registerAnonymousEventHandler(eventName, handlerFunc)
table.insert(MyMudUtils.eventRegistry, {
id = handlerId,
event = eventName,
active = true
})
return handlerId
end⚠ Common Pitfalls
- •Failing to store handler IDs prevents cleanup during package updates
- •Event names in Mudlet are case-sensitive; 'sysDataSendRequest' differs from 'SysDataSendRequest'
Create a Centralized Pattern Registry
Move all regex patterns into a centralized table indexed by logical names (e.g., 'healthPrompt', 'roomExits'). This abstraction layer allows you to update patterns in one location when the MUD changes its prompt format, rather than hunting through individual triggers. Implement a pattern validator that tests regex compilation at load time.
MyMudUtils.patterns = {
healthPrompt = [[^(\d+)/(\d+)h (\d+)/(\d+)m]],
roomExits = [[\[Exits: ([^\]]+)\]]]
}
function MyMudUtils.validatePatterns()
for name, pattern in pairs(MyMudUtils.patterns) do
local ok, err = pcall(string.match, "test", pattern)
if not ok then
echo("ERROR: Invalid pattern '" .. name .. "': " .. err .. "\n")
end
end
end⚠ Common Pitfalls
- •Magic numbers in regex capture groups break when MUD adds color codes; use non-greedy wildcards .*? where possible
- •Lua patterns use % for escapes, not \; ensure consistency if mixing regex types
Implement Migration Handlers for Version Updates
Add a version check that runs on profile load. Compare the current package version against a stored version in Mudlet's save table. If versions differ, execute migration functions that update trigger patterns, rename saved variables, or restructure data formats to match the new codebase requirements without losing user configuration.
function MyMudUtils.migrate()
local currentVersion = getMudletHomeDir() .. "/MyMudUtils/version.txt"
local lastVersion = io.exists(currentVersion) and io.open(currentVersion):read("*l") or "0.0.0"
if lastVersion < "1.0.0" then
-- Rename old variable format
if myOldVariable then
MyMudUtils.config.newVariable = myOldVariable
myOldVariable = nil
end
end
-- Write new version
local f = io.open(currentVersion, "w")
f:write(MyMudUtils._VERSION)
f:close()
end⚠ Common Pitfalls
- •Migration logic must handle nil values gracefully; never assume the variable exists from previous versions
- •Always backup user data before destructive migrations using copy() on tables
Package for Distribution with Metadata
Create the Mudlet module structure by organizing your Lua files, XML trigger definitions, and a config.lua into a directory. Generate a module metadata file that specifies dependencies, minimum Mudlet version, and installation instructions. Zip the directory with the exact structure Mudlet expects for drag-and-drop installation.
-- config.lua
return {
name = "MyMudUtils",
version = "1.0.0",
author = "muddev",
description = "Modular utility package for MUD automation",
min_mudlet_version = "4.14",
dependencies = {},
triggers = {
"health_monitor.xml",
"navigation_helper.xml"
}
}⚠ Common Pitfalls
- •XML files must use UTF-8 encoding without BOM; Mudlet fails to import with BOM present
- •Relative paths in require() statements break when users install to different directories; use getMudletHomeDir() for path construction
Debug Using Mudlet's Error Console and Echo Testing
Test the package by loading it in a clean Mudlet profile. Use the Debug console (Settings -> General -> Show errors in main window) to catch Lua syntax errors. Create a test harness that simulates MUD output using feedTriggers() to verify pattern matching without connecting to the server. Check that migrations run correctly by manually downgrading the version file and reloading.
-- test_harness.lua
function MyMudUtils.testPatterns()
local testLine = "100/100h 50/50m"
local h, hm, m, mm = testLine:match(MyMudUtils.patterns.healthPrompt)
if h == "100" then
echo("Health pattern: PASS\n")
else
echo("Health pattern: FAIL - got " .. tostring(h) .. "\n")
end
end
feedTriggers("100/100h 50/50m\n")
MyMudUtils.testPatterns()⚠ Common Pitfalls
- •feedTriggers() does not trigger Lua event handlers registered via registerAnonymousEventHandler; use raiseEvent() for those tests
- •Debug output in Mudlet appears below the main window; scroll down or use openUserWindow() to capture logs
What you built
This modular architecture separates concerns into isolated namespaces, centralizes pattern management, and provides migration pathways for long-term maintenance. By packaging as a Mudlet module with version metadata, you enable clean distribution across MUD communities while protecting user configurations from breaking changes. Test thoroughly in isolated profiles before distributing to production environments.