Mudlet Code Snippets - post any useful ones you might have here!



  • For all of the many times you want to run a command (or set of commands) repeatedly:

    ^loop (\d+) (.*)$
    local t={} ; i=1
    for str in string.gmatch(matches[3], "([^"..";".."]+)") do
    	t[i] = str
    	i = i + 1
    for i=1,tonumber(matches[2]) do
    	for _,v in ipairs(t) do
    Usage: loop <#> <commands separated by ;>

    loop 15 put spike in hole;get spike from hole
  • edited August 2018
    Rough calculation of the value of a level 40 figurine. Ignores divine realm size. You can specify whether it's a miniature figurine or not.

    ^esteem (mini )?(\d+)$
    local value
    local tatval
    local poteenval
    local bothval
    local figurineesteem
    local miniaturemult
    local ministring
    figurineesteem = tonumber(matches[3])
    if matches[2] == "mini " then
    	miniaturemult = 0.02 * 40
    	ministring = "a mini w/ "
    	miniaturemult = 0
    	ministring = ""
    value = figurineesteem * 100 * (1 + (2) + miniaturemult)
    tatval = value * 1.1
    poteenval = value * 1.5
    bothval = tatval * 1.5
    cecho(string.format("<green>You have %s%s esteem? It's worth:\n"..
    			"     With no buffs: %s essence\n"..
    			" With divinetattoo: %s essence\n"..
    			"       With poteen: %s essence\n"..
    			"         With both: %s essence\n",

    ETA: That won't work without this function, which you can just drop in a script somewhere. It just adds commas to numbers.
    function format_int(number)
      local i, j, minus, int, fraction = tostring(number):find('([-]?)(%d+)([.]?%d*)')
      -- reverse the int-string and append a comma to all blocks of 3 digits
      int = int:reverse():gsub("(%d%d%d)", "%1,")
      -- reverse the int-string back remove an optional comma and put the 
      -- optional minus and fractional part back
      return minus .. int:reverse():gsub("^,", "") .. fraction

  • Reyl said:
    If anyone else is still using the old M&MF influencing thing, and is curious to know which denizens in the room you've influenced already, try putting this in a script/alias/trigger/whatever:

    function checkInfluenced(bool)
    	local long = bool or false
    	for k, v in pairs(mmi.roomnpcs) do 
    		if v.influencable and v.influenced then
    			if long then cecho("<PaleGreen>"..v.longname.."\n") else cecho("<PaleGreen>X") end
    		elseif v.influencable and not v.influenced then
    			if long then cecho("<antique_white>"..v.longname.."\n") else cecho("<antique_white>.") end
    In this quick little example I clumsily hacked together, you can choose whether you want to see the names of the denizens in the room by passing in "true" - false, or just nothing, will give you the short version.



    I love this, so I modified it to do what I most often want: give me a number

    function influencedNumber()
    	local total = 0
    	local done = 0
    	for k,v in pairs(mmi.roomnpcs) do
    		if v.influencable then
    			total = total + 1
    		if v.influencable and v.influenced then
    			done = done + 1
    	cecho("<PaleGreen>Influenced "..done.." out of "" for this room.\n")
    Or, if you have a filter function:

    function influencedNumber()
    	local influencable = filter_dict(function(x) return x.influencable end, mmi.roomnpcs)
    	local influenced = filter_dict(function(x) return x.influenced end, influencable)
    	cecho("<PaleGreen>Influenced "..#influenced.." out of "..#influencable.." for this room.\n")

  • On the heels of my triple post... One more and then I'm going to bed.

    A bit of functional programming in Lua:

    function map(func, array)
      local new_array = {}
      for i,v in ipairs(array) do
        new_array[i] = func(v)
      return new_array
    function remove_if(func, arr)
      local new_array = {}
      for _,v in arr do
        if not func(v) then table.insert(new_array, v) end
      return new_array
    function filter(func, arr)
      local new_array = {}
      for _,v in arr do
        if func(v) then table.insert(new_array, v) end
      return new_array
    function filter_dict(func, dict)
      local new_dict = {}
      for k,v in pairs(dict) do
        if func(v) then table.insert(new_dict, v) end
      return new_dict

  • That's cool! I can really recommend Microlight, you can wrangle it into Mudlet and use a lot of functional patterns.
  • edited August 2018
    Look up information on a player using the Lusternia API.

    ^api (\w+) ?(\w+)?$
    -- downloads the lusternia API page for the chosen player, displays the info (or a single field)
    local saveto = getMudletHomeDir().."/apiscrape.txt"
    local url = ""..matches[2]..".json"
    local field = matches[3] or nil
      function(_, filename)
        if filename ~= saveto then
          return true -- keep the event handler since this was not our file
        local f, s, webpage =
      	if f then webpage = f:read("*a"); io.close(f) end
    		local contents = yajl.to_value(webpage)
    		if field ~= nil then echo(field..": "..contents[field].."\n")	else display(contents) end
    downloadFile(saveto, url)
    cecho("<white>Downloading <green>"..url.."<white> to <green>"..saveto.."\n")

  • edited November 2019
    <pre class="CodeBlock"><code>(?i)^path track (.+)$

    local command<br>function arriveAndDoThing()<br>&nbsp; if command then<br>&nbsp;&nbsp;&nbsp; send(command)<br>&nbsp;&nbsp;&nbsp; command = nil<br>&nbsp; end<br>end<br>registerAnonymousEventHandler("mmapper arrived", "arriveAndDoThing")<br>if gmcp.Room.Info.environment == "aether" then<br>&nbsp; command = matches[1]<br>&nbsp; mmp.gotoRoom(6831)<br>else<br>&nbsp; send(matches[1])<br>end

    If you're in a manse that you've mapped out and linked to the aetherplex, this alias lets you PATH TRACK directly from it. (By going to the aetherplex first, then using the game-side pathing from there.)
  • edited November 2019
    You know what I hate? Curios. You know. Those singles and other packs you get from the Wheel, amirite? Use this trigger in Mudlet to sell your pieces. Make sure you have 500 gold per piece you want to sell.

    ^(\d+)(\s+)(Rare|Piece)(\s+)(.+) <--- set to regex

    send("CURIOMARKET ADD sell piece " ..matches[2].." FOR 2 credits") <--- change to whatever amount you want to put your pieces up for.

    Once the trigger is set up, just do CURIO LIST PIECES.

    Her voice firm and commanding, Terentia, the Even Bladed says to you, "You have kept your oath to Me, Parhelion. You have sworn to maintain Justice in these troubled times."

    Yet if a boon be granted me, unworthy as I am, let it be for a steady hand with a clear eye and a fury most inflaming.
  • edited November 2019
    Quick snippet for refilling poisons in a shop. First, put this in a script (and replace the numbers with the keg numbers for your shop)

    poisons = {</div><div>&nbsp; &nbsp;["Senso"] = {keg = 202456},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["Haemotox"] = {keg = 229176},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["Escozul"] = {keg = 239005},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["Calcise"] = {keg = 239131},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["Botulinum"] = {keg = 282486},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["niricol"] = {keg = 235353},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["mactans"] = {keg = 242137},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["contortrin"] = {keg = 186445},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["aleutian"] = {keg = 157300},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["mantakaya"] = {keg = 298434},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["dendroxin"] = {keg = 185760},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["saxitin"] = {keg = 227656},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["ibululu"] = {keg = 190539},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["hadrudin"] = {keg = 235156},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["mellitin"] = {keg = 184909},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["pyrotoxin"] = {keg = 100579},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["calcise"] = {keg = 185875},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["inyoka"] = {keg = 190135},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["tetrodin"] = {keg = 201089},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["crotamine"] = {keg = 189122},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["morphite"] = {keg = 282455},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["chansu"] = {keg = 204039},&nbsp; &nbsp;</div><div>&nbsp; &nbsp;["charybdon"] = {keg = 298391},</div><div>&nbsp; &nbsp;["dulak"] = {keg = 203484},</div><div>&nbsp; &nbsp;["anerod"] = {keg = 166527},</div><div>}</div>

    Then, in an alias:
    for k,v in pairs(poisons) do sendAll("get "..v["keg"], "rift drain "..k.." to "..v["keg"], "drop "..v["keg"]) end

  • DaraiusDaraius Shevat The juror's taco spot
    I can never wrap my head around that pairs stuff.
    I used to make cakes.

    Estarra the Eternal says, "Give Shevat the floor please."
  • edited November 2019
    It's pretty straightforward! Consider a table with keys and values. pairs returns two iterators (lists that you can loop over); the first is the keys, the second is the values associated with those keys. So if you have

    mytable = {

    And you do
    for k,v in pairs(mytable) do

    then each time through the loop, k will be the next key (first time a, then b, then c), and v will be the value associated with that key (first time 1, then 2, then 3).

    It APPEARS to get more complicated in my keg example, because the values are themselves tables, but just think of v as a variable that will have whatever the appropriate value is.
  • Since someone asked in an in-game clan, here's a quick code snippet to convert a list of comms (of the form "commname ### commname ### commname ###") to a sum:

    s = "abc 123 def 456"
    a = 0
    for v in s:gmatch ("%d+") do
        a = a + tonumber(v)
  • function esteemFigurine()<br>&nbsp; if tonumber(gmcp.Char.Vitals.esteem) > 250 then<br>&nbsp;&nbsp;&nbsp; send("imbue figurine with 250 esteem")<br>&nbsp; end<br>end<br>registerAnonymousEventHandler("gmcp.Char.Vitals", "esteemFigurine")
    Just a little tidbit to automatically imbue a figurine with esteem
  • edited February 2020

    Crummy Incomplete Influencing Snippets Made In a Haste Without Proper Management of Memory or Coding But Hey They Work

    Script file. Call it whatever you want.

    inf_type = {
    &nbsp; ["charity"] = {"begging", "supplication", "wheedling"},
    &nbsp; ["empower"] = {"compliments", "admiration", "praise"},
    &nbsp; ["weaken"] = {"teasing", "mockery", "derision"},
    &nbsp; ["seduction"] = {"flattery", "charm", "beguiling"},
    &nbsp; ["paranoia"] = {},
    &nbsp; ["amnesty"] = {"amnesty"}

    Triggers. Make a folder. Name it Influencing. YOU MUST NAME IT "Influencing"! Deactivate the folder. Put a new trigger in it.

    First trigger. Called mine Influence Prompt.

    The line (perl regex) : ^\d+h, \d+m, \d+e, \d+p ([Bex\-]+)$

    The code:
    if matches[2] == "Bex-" then
    &nbsp;send("influence " .. inf_tar .. " with " .. inf_type[inf_type_spec][inf_type_num])
    &nbsp;inf_type_num = inf_type_num + 1
    &nbsp;if inf_type_num > table.getn(inf_type[inf_type_spec]) then
    &nbsp; inf_type_num = 1
    Second trigger. Called mine Influence Target Missing.

    First line (exact match) :  You detect nothing here by that name.
    Second line (exact match) : I do not recognize anything called that here.
    Third line (exact match) : You cannot see that being here.
    Fourth line (exact match) : Ahh, I am truly sorry, but I do not see anyone by that name here.
    Fifth line (exact match) : Nothing can be seen here by that name.

    The code:

    Third trigger. Called mine Influence Done.

    First line (perl regex) : ^.* keeps asking h(?:im|er)self why s?he considered giving so much away, and pays you no attention\.$
    Second line (perl regex) : ^.* is so caught up in admiring h(?:im|er)self that s?he barely notices you\.$

    The code:


    Lastly, the alias. Appropriate uses are "inf tar whatever", "inf type whatever", "inf on", and "inf off"

    The line: ^inf (on|off|(?:tar ([\d\w]+))|(?:type (charity|empower|weaken|seduction|paranoia|amnesty)))$

    The code:
    if matches[2] == "on" then
    &nbsp; enableTrigger("Influencing")
    &nbsp; inf_type_num = 1
    elseif matches[2] == "off" then
    &nbsp; disableTrigger("Influencing")
    elseif matches[2]:match("^tar") then
    &nbsp; echo("Influencing target: " .. matches[3])
    &nbsp; inf_tar = matches[3]
    &nbsp; echo("Influencing type: " .. matches[4])
    &nbsp; inf_type_spec = matches[4]
    send(" ")

    Hope this helps someone.

    Edit: I don't know what happened in this post, but here it is on PasteBin, too:

  • Timestamps on every prompt!

    Create a new trigger, make it the last one in your list of triggers.

    For the line, click the dropdown menu and select prompt.

    For the code...

    now ="*t")
    if now["month"] < 10 then
      now["month"] = "0" .. now["month"]
    if now["day"] < 10 then
      now["day"] = "0" .. now["day"]
    if now["hour"] < 10 then
      now["hour"] = "0" .. now["hour"]
    if now["min"] < 10 then
      now["min"] = "0" .. now["min"]
    if now["sec"] < 10 then
      now["sec"] = "0" .. now["sec"]
    cecho("<pale_turquoise>" .. now["year"] .. "-" .. now["month"] .. "-" .. now["day"] .. " @ " .. now["hour"] .. ":" .. now["min"] .. ":" .. now["sec"])

    This is what you see:

    5100h, 6700m, 6300e, 10p Bex-2020-02-10 @ 13:39:31
  • edited February 2020
    You can remove all that conditional logic by using string.format. The format specifier %02d says "take a number, and format it to a width of at least 2 characters, filling with 0s"

    local now ="*t")
    cecho(string.format("<pale_turquoise>%d-%d-%d @ %02d:%02d:%02d", now["year"], now["month"], now["day"], now["hour"], now["min"], now["sec"]))
  • edited March 2020

    Toss this in an alias and it creates a room and sets the area, for when you want to map something like a timequake.

  • edited June 2020
    local colors =
        blue = 36073,
        brown = 11811,
        black = 11600,
        yellow = 9888,
        red = 10509,
        steel = 10185,
        white = 10457,
        purple = 47812,
        green = 9985,
        crystal = 12652,
        wooden = 10992,
    local exitScript = [[script:sendAll("outr %sbutton", "touch %sbutton", false)]]
    function mapperButtons()
        table.contains(gmcp.Room.Info.details, "the Prime Material Plane") and
        table.contains(gmcp.Room.Info.details, "outdoors")
        for color, room in pairs(colors) do
          mmp.tempSpecialExit(gmcp.Room.Info.num, room, exitScript:format(color,color), 20)
        for color, room in pairs(colors) do
          mmp.tempSpecialExit(148, room, exitScript:format(color,color), 20)
    registerAnonymousEventHandler("mmp link externals", "mapperButtons")

    The script I used for integrating buttons into mudlet mapper's pathfinding when I was aethertrading.
    It will only use them to path to bubbles - it won't use buttons as a shortcut.
    Just toss it in a script and it's good to go!

  • Hi all, keep those goodies coming! There's nothing much better than a coder who shares. o:)
  • local alertIDs = {"267079", "315983"}
    function itemAlert()
      local addEvent = gmcp.Char.Items.Add
      if addEvent.location ~= "inv" then
      for _, checkId in pairs(alertIDs) do
        if == checkId then
            "<sky_blue>" .. string.title( .. " has returned to your inventory!"
    registerAnonymousEventHandler("gmcp.Char.Items.Add", "itemAlert")

    Small snippet that lets you watch for things returning to your inventory that might not give a message otherwise, like artifacts resetting after you loaned them out.

  • edited October 2020
    Maeko said:
    You can remove all that conditional logic by using string.format. The format specifier %02d says "take a number, and format it to a width of at least 2 characters, filling with 0s"

    local now ="*t")
    cecho(string.format("<pale_turquoise>%d-%d-%d @ %02d:%02d:%02d", now["year"], now["month"], now["day"], now["hour"], now["min"], now["sec"]))
    The above is equivalent to:
    local time = getTime(true, "yyyy-MM-dd @ hh:mm:ss")
    Further, this variant works for those of us with linebreak prompts:
    local time = getTime(true, "yyyy-MM-dd @ hh:mm:ss")
    if line == "" then -- we've got a linebreak prompt
    -- Insert at end of line
    moveCursor(#getCurrentLine(), getLineNumber())
  • Stat delta calculation and echoing to prompt. Add this to a trigger with "prompt" selected:
    myStats = myStats or {}
    local tracked = {
    local short = {
      ["hp"]      = "h",
      ["mp"]      = "m",
      ["ego"]     = "e",
      ["essence"] = "xp",
      ["nl"]      = "xp",
    local out = {}
    local vitals = table.deepcopy(gmcp.Char.Vitals)
    if not (vitals.hp  == "0"
        and  == "0"
        and vitals.ego == "0"
        and vitals.pow == "0")
      for _, stat in ipairs(tracked) do
        if myStats[stat] and vitals[stat] and myStats[stat] ~= vitals[stat] then
          local delta = tonumber(vitals[stat]) - tonumber(myStats[stat])
          local short = short[stat] or ""
          local color = "<green>"
          if delta < 0 then color = "<red>" end
          out[#out+1] = string.format("%s%+d%s", color, delta, short)
        myStats[stat] = vitals[stat]
      out[#out+1] = "<ansiRed>BLACKOUT!"
    if myStats.level and myStats.level ~= gmcp.Char.Status.level then
      local delta = tonumber(gmcp.Char.Status.level) - tonumber(myStats.level)
      local color = "<green>"
      if delta < 0 then color = "<red>" end
      out[#out+1] = string.format("%s%+d level!", color, delta)
    myStats.level = gmcp.Char.Status.level
    if line == "" then -- we've got a linebreak prompt
    moveCursor(#getCurrentLine(), getLineNumber())
    local out = table.concat(out, "<reset>, ")
    if #out > 0 then cinsertText(" "..out) end

    Ignores blackout. Pretty much zero performance impact.
  • edited October 2020
    Quickly tell your buddies where you are.

    local chan = matches[2] or "clt1"
    local vnum = gmcp.Room.Info.num
    local room =
    local area = gmcp.Room.Info.area
    local out = string.format("%s I am at v%s (%s) in %s.", chan, vnum, room, area)
    send(out, false)

    Type "here" or "here channel" (where channel is one of ct, gt, clt, etc etc).
    Looks like:
    here echo
    I am at v4133 (Sombre Lane near the construction site) in the City of Magnagora.

    Defaults to clt1, edit
    or "clt1"
    if you want to change that.
  • QuixoteQuixote Manchester, UK
    edited October 2020
    function discordWebhookTest(discord_username, avatarurl, message)
      local httpdone = registerAnonymousEventHandler('sysPostHttpDone', 
        function(event, rurl, response)
          if rurl == url then display(r) else return true end
        end, true)
      local httperror = registerAnonymousEventHandler('sysPostHttpError', 
        function(event, response, rurl)
          if rurl == url then display(r) else return true end
        end, true)
      local url = "<Put Your Webhook Endpoint Here>"
      local data = {
        username = discord_username, 
        avatar_url = avatarurl,
        content = message
      local header = {
        ["Content-Type"] = "application/json",
        --["Content-Length"] = data:len()
      postHTTP(yajl.to_string(data), url, header)
    This function pretty much speaks for itself. 

    Ever wanted to send a message to a Discord server webhook? Now you can!

    Have fun!
  • Echo room vnums after each room title. Put this in any script.
    function echoRoomNums()
      local vnum = gmcp.Room.Info.num
      local name =" %(")[1]
      tempPromptTrigger([[killTrigger(]]..tempBeginOfLineTrigger(name, function()
        local colour = string.format("<%s,%s,%s>", getFgColor())
        local text = string.format("<%s>v%s", mmp.settings.echocolour, vnum)
        local cmd = string.format([[mmp.gotoRoom("%s")]], vnum)
        local hint = "Go to "..vnum
        decho(" "..colour.."(")
        cechoLink(text, cmd, hint, true)
      end)..[[)]], 1)
    echoRoomNumsHandler = echoRoomNumsHandler or registerAnonymousEventHandler("gmcp.Room.Info", echoRoomNums)
    Looks like this:
  • edited October 2020
    restock.mpackage consists of one alias, script, and trigger group that:

    1. Preempts WARES commands by requesting the current rift list via GMCP
    2. Interprets the list and indexes it by desc (a bottle of sparkling Golden Tonic) and shortname (goldentonic)
    3. Catches the shop wares entries and tells you how much you have in the rift, if any
    4. Gives you a single click option to restock (buying your deficit from 2k, or however many they have)

    Looks like this:
  • edited November 2020
    sktrack = sktrack or {}
    sktrack.skills = sktrack.skills or {}

    function sktrack.updateSkill()
      local newSkillTable = {}
      for _, skill in pairs(gmcp.Char.Skills.Groups) do
        local skillname =
        if sktrack.skills[skillname] then
          newSkillTable[skillname] = sktrack.skills[skillname]
          local skills = string.format("Char.Skills.Get %s", yajl.to_string({group =}))
      send(" ")
      sktrack.skills = newSkillTable

    if sktrack.updateHandler then
    sktrack.updateHandler =
      registerAnonymousEventHandler("gmcp.Char.Skills.Groups", "sktrack.updateSkill")

    function sktrack.updateFull()

    function sktrack.gotSkillData()
      local tempTable = {}
      for _, skill in pairs(gmcp.Char.Skills.List.list) do
        tempTable[skill:lower()] = true
      sktrack.skills[] = tempTable

    function sktrack.hasSkill(group, skill)
      return (sktrack.skills[group] and sktrack.skills[group][skill]) ~= nil

    if sktrack.listHandler then
    sktrack.listHandler = registerAnonymousEventHandler("gmcp.Char.Skills.List", "sktrack.gotSkillData")

    small chunk of code to maintain a table (sktrack.skills) which stays up to date with current skillsets and skills.
  • edited November 2020
    Sometimes colouring is good, so I made this to quickly see (and sometimes ignore) OOC clans with a quick recolouring and reformatting of certain clans. I've included org OOC clans that I was able to find, to add more just follow the Perl regex format to add new clans. Download here.

  • SelenitySelenity My first MC to stay in Serenwilde
    edited December 2020
    Tired of spinning the wheel yourself? Here's some code. Hoping it looks decent on posting, because it looks ugly typing it up.

    First of all, you'll need this function I made because I don't remember what the Mudlet version of it is.

    function inArray(array_, key)
      result = table.index_of(array_, key)
      return result and true or false

    Next, you need to create two triggers. The first trigger has two regex patterns. The first is

    ^The Wheel of Tzaraziko crackles with a brilliant display of colours, landing on ([\w ]+) as you stare intently.$

    The second is

    ^The Wheel of Tzaraziko crackles with a brilliant display of colours, rewarding you with .*\.$

    Then, it has this code:

    if matches[2] == nil or inArray({"CURIOS", "A BUFF", "CREDITS"}, matches[2]) then
      send("spin wheel")
      send("spin wheel inner")

    As for the second trigger, make the pattern the exact match

    You have spun this coin three times already. It is time to try your chance on the inner wheel. SPIN WHEEL INNER to proceed.

    Have it send the code

    send("spin wheel inner")

    And you're done!

Sign In or Register to comment.