Difference between revisions of "Area 51"

From Mudlet
Jump to navigation Jump to search
 
(75 intermediate revisions by 8 users not shown)
Line 16: Line 16:
 
=Basic Essential Functions=
 
=Basic Essential Functions=
 
:These functions are generic functions used in normal scripting. These deal with mainly everyday things, like sending stuff and echoing to the screen.
 
:These functions are generic functions used in normal scripting. These deal with mainly everyday things, like sending stuff and echoing to the screen.
 
= sendCmdLine, PR #7828 =
 
 
'''sendCmdLine(command)''' – Sets the text of the main command line or a custom command line to the specified string, but does '''not''' send it to the server. This is useful for scripting command previews, suggestion systems, or autofill behavior in Mudlet.
 
 
== Syntax ==
 
<syntaxhighlight lang="lua">
 
sendCmdLine(command)
 
</syntaxhighlight>
 
 
== Parameters ==
 
{| class="wikitable"
 
! Parameter
 
! Type
 
! Description
 
|-
 
| command
 
| string
 
| The text to set in the command line.
 
|}
 
 
== Return value ==
 
Returns `true` if the command line was successfully updated, `false` otherwise.
 
 
== Example ==
 
<syntaxhighlight lang="lua">
 
sendCmdLine("cast fireball at goblin")
 
</syntaxhighlight>
 
This will place the command `cast fireball at goblin` into the active command line without sending it. The user can edit or press enter to send it.
 
 
== Notes ==
 
* This function is primarily intended for scripting support tools, such as suggestion completions or history cycling.
 
* To send the command to the server, use the [[send|send()]] function instead.
 
 
== See also ==
 
* [[send]]
 
* [[expandAlias]]
 
* [[selectCmdLineText]]
 
* [[resetCmdLineAction]]
 
  
 
=Database Functions=
 
=Database Functions=
Line 65: Line 26:
 
: A collection of functions for interacting with the file system.
 
: A collection of functions for interacting with the file system.
  
==saveProfile, PR #7982 open==
+
=Mapper Functions=
;saveProfile([location, [filename]])
+
: A collection of functions that manipulate the mapper and its related features.
 +
 
 +
==getMapInfo, PR #8963==
 +
;getMapInfo()
  
:Saves the current Mudlet profile to disk, which is equivalent to pressing the "Save Profile" button.
+
:Returns a table of all registered map info contributors mapped to their enabled/disabled state. This allows scripts to query which map info contributors (such as "Short" or "Full") are currently active.
  
;Parameters
+
:See also: [[Manual:Lua_Functions#enableMapInfo|enableMapInfo()]], [[Manual:Lua_Functions#disableMapInfo|disableMapInfo()]]
* ''location:''
 
:(optional) folder to save the profile to. If not given, the profile will go into the [[Mudlet_File_Locations|default location]].
 
  
* ''filename:''
+
{{MudletVersion|4.21}}
:(optional) save the profile as the filename. If the filename doesn't end with ''.xml'' this function will automatically save it as ''filename.xml''. If not given, the profile will be saved with the default ''DATE#TIME.xml'' filename format.
+
 
 +
;Returns
 +
* A table with contributor names as keys and boolean values indicating whether each is enabled, or ''nil'' and an error message if no map is loaded.
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- save profile to the .../mudlet/profiles/profileName/current folder
+
-- check which map info contributors are active
saveProfile()
+
local info = getMapInfo()
 +
for name, enabled in pairs(info) do
 +
  print(name .. " is " .. (enabled and "enabled" or "disabled"))
 +
end
  
-- save to the desktop on Windows:
+
-- check if a specific contributor is enabled
saveProfile([[C:\Users\yourusername\Desktop]])
+
local info = getMapInfo()
 
+
if info["Short"] then
-- alternately, save to the desktop with the name system.xml:
+
  echo("Short map info is enabled.\n")
saveProfile([[C:\Users\yourusername\Desktop]],"system")
+
end
 
</syntaxhighlight>
 
</syntaxhighlight>
 
{{MudletVersion|https://github.com/Mudlet/Mudlet/pull/7982}}
 
 
=Mapper Functions=
 
: A collection of functions that manipulate the mapper and its related features.
 
  
 
==setRoomBorderColor, PR #8758==
 
==setRoomBorderColor, PR #8758==
Line 134: Line 96:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==getRoomBorderColor, PR #8758==
 
;r, g, b, a = getRoomBorderColor(roomID)
 
  
:Returns the custom border color for a room, if one has been set.
 
  
:See also: [[#setRoomBorderColor|setRoomBorderColor()]], [[#clearRoomBorderColor|clearRoomBorderColor()]]
+
== setRoomUserData #PR9299 ==
 +
;setRoomUserData(roomID, key (as a string), value (as a string))
 +
 
 +
:Stores information about a room under a given key. Similar to Lua's key-value tables, except only strings may be used here. One advantage of using userdata is that it's stored within the map file itself - so sharing the map with someone else will pass on the user data. You can have as many keys as you'd like.
  
{{MudletVersion|4.21}}
+
There are also some default variables you can change for different effects.
  
;Parameters
+
{| class="wikitable"
 +
|+ table of default variables for setRoomUserData()
 +
|-
 +
! Variable !! Effect
 +
|-
 +
| room.ui_showName || toggle displaying of the room nam
 +
|-
 +
| room.ui_nameOffset || "x y" an offset to move the text - integers separated by a space
 +
|-
 +
| room.ui_nameFont || the name of the font to use on the name label
 +
|-
 +
| room.ui_nameSize || the size of the font to use on the name label
 +
|-
 +
| room.ui_nameColor || the colour to set the name label text
 +
|-
 +
| room.ui_borderColor || the colour of the room border
 +
|-
 +
| room.ui_borderThickness || the thickness of the room border
 +
|-
 +
|}
 +
 
 +
 
 +
:Returns true if successfully set.
 +
: See also: [[#clearRoomUserData|clearRoomUserData()]], [[#clearRoomUserDataItem|clearRoomUserDataItem()]], [[#getAllRoomUserData|getAllRoomUserData()]], [[#getRoomUserData|getRoomUserData()]], [[#searchRoomUserData|searchRoomUserData()]]
 +
 
 +
 
 +
;Example
 +
<syntaxhighlight lang="lua">
 +
-- can use it to store room descriptions...
 +
setRoomUserData(341, "description", "This is a plain-looking room.")
 +
 
 +
-- or whenever it's outdoors or not...
 +
setRoomUserData(341, "outdoors", "true")
 +
 
 +
-- how how many times we visited that room
 +
local visited = getRoomUserData(341, "visitcount")
 +
visited = (tonumber(visited) or 0) + 1
 +
setRoomUserData(341, "visitcount", tostring(visited))
 +
 
 +
-- can even store tables in it, using the built-in yajl.to_string function
 +
setRoomUserData(341, "some table", yajl.to_string({name = "bub", age = 23}))
 +
display("The denizens name is: "..yajl.to_value(getRoomUserData(341, "some table")).name)
 +
</syntaxhighlight>
 +
 
 +
==getRoomBorderColor, PR #8758==
 +
;r, g, b, a = getRoomBorderColor(roomID)
 +
 
 +
:Returns the custom border color for a room, if one has been set.
 +
 
 +
:See also: [[#setRoomBorderColor|setRoomBorderColor()]], [[#clearRoomBorderColor|clearRoomBorderColor()]]
 +
 
 +
{{MudletVersion|4.21}}
 +
 
 +
;Parameters
 
* ''roomID:''
 
* ''roomID:''
 
: The ID of the room to get the border color for.
 
: The ID of the room to get the border color for.
Line 188: Line 203:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==setRoomBorderThickness, PR #8758==
+
==setRoomBorderStyle, PR #8985==
;setRoomBorderThickness(roomID, thickness)
+
;setRoomBorderStyle(roomID, style)
  
:Sets a custom border thickness for an individual room on the 2D map. When set, this thickness overrides the global default for that specific room.
+
:Sets the border style for a specific room on the map. This allows visually distinguishing rooms with dashed or dotted borders instead of the
 +
default solid border - useful for marking temporary, unvisited, or special rooms.
  
:See also: [[#getRoomBorderThickness|getRoomBorderThickness()]], [[#clearRoomBorderThickness|clearRoomBorderThickness()]], [[#setRoomBorderColor|setRoomBorderColor()]]
+
:See also: [[#setRoomBorderColor|setRoomBorderColor()]], [[#setRoomBorderThickness|setRoomBorderThickness()]], [[#getRoomBorderStyle|getRoomBorderStyle()]], [[#clearRoomBorderStyle|clearRoomBorderStyle()]]
  
 
{{MudletVersion|4.21}}
 
{{MudletVersion|4.21}}
Line 199: Line 215:
 
;Parameters
 
;Parameters
 
* ''roomID:''
 
* ''roomID:''
: The ID of the room to set the border thickness for.
+
: The ID of the room to set the border style for.
* ''thickness:''
+
* ''style:''
: The border thickness (1-10).
+
: The border style to apply. Valid values: ''"dashed"'' (or ''"dash line"'') for a dashed border, ''"dotted"'' (or ''"dot line"'') for a dotted border, or ''"solid"'' to reset to the default solid border.
 
+
 
 
;Returns
 
;Returns
* ''true'' on success, or ''nil'' and an error message if no map is loaded, the room ID is invalid, or the thickness is out of range.
+
* ''true'' on success, or ''nil'' and an error message if no map is loaded or the room ID is invalid.
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Set room 1 to have a thick border
+
-- set room 1234 to have a dashed border
setRoomBorderThickness(1, 5)
+
setRoomBorderStyle(1234, "dashed")
 +
 
 +
-- set room 1234 to have a dotted border
 +
setRoomBorderStyle(1234, "dotted")
  
-- Highlight important rooms with thick red borders
+
-- reset room 1234 back to solid border
local importantRooms = {1, 5, 10, 15}
+
setRoomBorderStyle(1234, "solid")
for _, roomID in ipairs(importantRooms) do
 
    setRoomBorderColor(roomID, 255, 0, 0)
 
    setRoomBorderThickness(roomID, 3)
 
end
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==getRoomBorderThickness, PR #8758==
+
==getRoomBorderStyle, PR #8985==
;thickness = getRoomBorderThickness(roomID)
+
;getRoomBorderStyle(roomID)
  
:Returns the custom border thickness for a room, if one has been set.
+
:Returns the border style for a specific room on the map.
  
:See also: [[#setRoomBorderThickness|setRoomBorderThickness()]], [[#clearRoomBorderThickness|clearRoomBorderThickness()]]
+
:See also: [[#setRoomBorderStyle|setRoomBorderStyle()]], [[#clearRoomBorderStyle|clearRoomBorderStyle()]]
  
 
{{MudletVersion|4.21}}
 
{{MudletVersion|4.21}}
Line 230: Line 245:
 
;Parameters
 
;Parameters
 
* ''roomID:''
 
* ''roomID:''
: The ID of the room to get the border thickness for.
+
: The ID of the room to get the border style for.
  
 
;Returns
 
;Returns
* The thickness value (1-10) if a custom thickness is set, or ''nil'' if the room uses the global default thickness. Returns ''nil'' and an error message if no map is loaded or the room ID is invalid.
+
* ''"dashed"'' if the room has a dashed border, ''"dotted"'' if the room has a dotted border, or ''nil'' if the room has the default solid border.
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Check if room 1 has a custom border thickness
+
local style = getRoomBorderStyle(1234)
local thickness = getRoomBorderThickness(1)
+
if style then
if thickness then
+
  echo(f"Room 1234 has a {style} border.\n")
    echo(string.format("Room 1 has custom border thickness: %d\n", thickness))
 
 
else
 
else
    echo("Room 1 uses the global border thickness\n")
+
  echo("Room 1234 has a solid (default) border.\n")
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==clearRoomBorderThickness, PR #8758==
+
==clearRoomBorderStyle, PR #8985==
;clearRoomBorderThickness(roomID)
+
;clearRoomBorderStyle(roomID)
  
:Removes the custom border thickness from a room, causing it to use the global default thickness.
+
:Resets the border style for a specific room back to the default solid border.
  
:See also: [[#setRoomBorderThickness|setRoomBorderThickness()]], [[#getRoomBorderThickness|getRoomBorderThickness()]]
+
:See also: [[#setRoomBorderStyle|setRoomBorderStyle()]], [[#getRoomBorderStyle|getRoomBorderStyle()]]
  
 
{{MudletVersion|4.21}}
 
{{MudletVersion|4.21}}
Line 257: Line 271:
 
;Parameters
 
;Parameters
 
* ''roomID:''
 
* ''roomID:''
: The ID of the room to clear the custom border thickness from.
+
: The ID of the room to clear the border style for.
  
 
;Returns
 
;Returns
Line 264: Line 278:
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Reset room 1 to use the global border thickness
+
-- reset room 1234 back to solid border
clearRoomBorderThickness(1)
+
clearRoomBorderStyle(1234)
 
 
-- Clear all custom border settings from a room
 
clearRoomBorderColor(1)
 
clearRoomBorderThickness(1)
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
==setRoomBorderThickness, PR #8758==
 +
;setRoomBorderThickness(roomID, thickness)
  
==exportAreaImage PR#8156==
+
:Sets a custom border thickness for an individual room on the 2D map. When set, this thickness overrides the global default for that specific room.
; exportAreaImage(areaID, filePath[, zLevel])
 
  
:Exports an area from the mapper as an image file. This function allows you to save a visual representation of a specific area (or a specific Z level within that area) to disk as an image. The exported image will show rooms, exits, and other map elements as they appear in the 2D mapper.
+
:See also: [[#getRoomBorderThickness|getRoomBorderThickness()]], [[#clearRoomBorderThickness|clearRoomBorderThickness()]], [[#setRoomBorderColor|setRoomBorderColor()]]
  
:The image is rendered at a fixed 2.0x zoom level to provide good quality output while maintaining reasonable file sizes.
+
{{MudletVersion|4.21}}
 
 
;See also: [[Manual:Mapper_Functions#createMapImageLabel|createMapImageLabel()]], [[Manual:Mapper_Functions#createMapLabel|createMapLabel()]]
 
 
 
{{MudletVersion|4.20}}
 
 
 
{{note}} This function requires the mapper to be open and a valid map to be loaded. It will return an error if no map is present or if the specified area ID doesn't exist.
 
  
 
;Parameters
 
;Parameters
* ''areaID:''
+
* ''roomID:''
: Area ID number of the area to export as an image.
+
: The ID of the room to set the border thickness for.
* ''filePath:''
+
* ''thickness:''
: File path where the image should be saved. Should include the desired file extension (e.g., ".png", ".jpg"). When exporting all Z levels, this will be used as a template for generating individual filenames.
+
: The border thickness (1-10).
* ''zLevel:''
 
: (optional) Can be one of the following:
 
:: ''integer'' - exports only the specific Z level within the area
 
:: ''true'' - exports all Z levels in the area as separate image files
 
:: ''nil/omitted'' - exports the current player's Z level
 
  
 
;Returns
 
;Returns
* ''success:'' boolean - true if the export was successful, false if it failed
+
* ''true'' on success, or ''nil'' and an error message if no map is loaded, the room ID is invalid, or the thickness is out of range.
* ''errorMessage:'' string - only returned when success is false, contains the error message describing what went wrong
 
  
 
;Example
 
;Example
 
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Export the current player's Z level of area 1 to a PNG file
+
-- Set room 1 to have a thick border
exportAreaImage(1, "/home/user/mymap.png")
+
setRoomBorderThickness(1, 5)
  
-- Export only Z level 0 of area 5 to a JPG file
+
-- Highlight important rooms with thick red borders
exportAreaImage(5, "/home/user/level0.jpg", 0)
+
local importantRooms = {1, 5, 10, 15}
 +
for _, roomID in ipairs(importantRooms) do
 +
    setRoomBorderColor(roomID, 255, 0, 0)
 +
    setRoomBorderThickness(roomID, 3)
 +
end
 +
</syntaxhighlight>
  
-- Export area 10, Z level -1 (basement level)
+
==getRoomBorderThickness, PR #8758==
exportAreaImage(10, "basement_map.png", -1)
+
;thickness = getRoomBorderThickness(roomID)
  
-- Export ALL Z levels in area 12 as separate images
+
:Returns the custom border thickness for a room, if one has been set.
-- This will create files like: mymap_level_0.png, mymap_level_1.png, mymap_level_-1.png, etc.
 
local success, error = exportAreaImage(12, "mymap.png", true)
 
if success then
 
  echo("All Z levels exported successfully!")
 
else
 
  echo("Export failed: " .. error)
 
end
 
  
-- Export all Z levels in multiple areas
+
:See also: [[#setRoomBorderThickness|setRoomBorderThickness()]], [[#clearRoomBorderThickness|clearRoomBorderThickness()]]
for areaID, areaName in pairs(getAreaTable()) do
 
  local filename = string.format("%s_area_%d.png", areaName, areaID)
 
  local success, error = exportAreaImage(areaID, filename, true)
 
  if success then
 
    echo("Exported all Z levels for area: " .. areaName)
 
  else
 
    echo("Failed to export area " .. areaName .. ": " .. error)
 
  end
 
end
 
  
-- Get a list of all Z levels in an area and export them individually
+
{{MudletVersion|4.21}}
local areaID = 5
 
local area = getAreaTable()[areaID]
 
if area then
 
  -- Get all Z levels by examining rooms in the area
 
  local zLevels = {}
 
  for roomID in pairs(getAreaRooms(areaID)) do
 
    local x, y, z = getRoomCoordinates(roomID)
 
    if z and not zLevels[z] then
 
      zLevels[z] = true
 
    end
 
  end
 
  
  -- Export each Z level individually with custom naming
+
;Parameters
  for zLevel in pairs(zLevels) do
+
* ''roomID:''
     local filename = string.format("area_%s_floor_%d.png", area, zLevel)
+
: The ID of the room to get the border thickness for.
    exportAreaImage(areaID, filename, zLevel)
+
 
     echo("Exported Z level " .. zLevel .. " to " .. filename)
+
;Returns
  end
+
* The thickness value (1-10) if a custom thickness is set, or ''nil'' if the room uses the global default thickness. Returns ''nil'' and an error message if no map is loaded or the room ID is invalid.
 +
 
 +
;Example
 +
<syntaxhighlight lang="lua">
 +
-- Check if room 1 has a custom border thickness
 +
local thickness = getRoomBorderThickness(1)
 +
if thickness then
 +
     echo(string.format("Room 1 has custom border thickness: %d\n", thickness))
 +
else
 +
     echo("Room 1 uses the global border thickness\n")
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==createMapLabel, merged #7598==
+
==clearRoomBorderThickness, PR #8758==
;labelID = createMapLabel(areaID, text, posX, posY, posZ, fgRed, fgGreen, fgBlue, bgRed, bgGreen, bgBlue[, zoom, fontSize, showOnTop, noScaling, fontName, foregroundTransparency, backgroundTransparency, temporary, outlineRed, outlineGreen, outlineBlue])
+
;clearRoomBorderThickness(roomID)
  
:Creates a text label on the map at given coordinates, with the given background and foreground colors. It can go above or below the rooms, scale with zoom or stay a static size. From Mudlet 4.17.0 an additional parameter (assumed to be false if not given from then) makes the label NOT be saved in the map file which, if the image can be regenerated on future loading from a script can reduce the size of the saved map somewhat. It returns a label ID that you can use later for deleting it.
+
:Removes the custom border thickness from a room, causing it to use the global default thickness.
  
:The coordinates 0,0 are in the middle of the map, and are in sync with the room coordinates - so using the x,y values of [[#getRoomCoordinates|getRoomCoordinates()]] will place the label near that room.
+
:See also: [[#setRoomBorderThickness|setRoomBorderThickness()]], [[#getRoomBorderThickness|getRoomBorderThickness()]]
  
: See also: [[#getMapLabel|getMapLabel()]], [[#getMapLabels|getMapLabels()]], [[#deleteMapLabel|deleteMapLabel]], [[#createMapImageLabel|createMapImageLabel()]]
+
{{MudletVersion|4.21}}
  
<div class="toccolours mw-collapsible mw-collapsed" style="overflow:auto;">
+
;Parameters
<div style="font-weight:bold;line-height:1.6;">Historical Version Note</div>
+
* ''roomID:''
<div class="mw-collapsible-content">
+
: The ID of the room to clear the custom border thickness from.
{{note}} Some changes were done prior to 4.13 (which exactly? function existed before!) - see corresponding PR and update here!
 
</div></div>
 
  
;Parameters
+
;Returns
* ''areaID:''
+
* ''true'' on success, or ''nil'' and an error message if no map is loaded or the room ID is invalid.
: Area ID where to put the label.
 
* ''text:''
 
: The text to put into the label. To get a multiline text label add a '\n' between the lines.
 
* ''posX, posY, posZ:''
 
: Position of the label in (floating point numbers) room coordinates.
 
* ''fgRed, fgGreen, fgBlue:''
 
: Foreground color or text color of the label.
 
* ''bgRed, bgGreen, bgBlue:''
 
: Background color of the label.
 
* ''zoom:''
 
: (optional) Zoom factor of the label if noScaling is false. Higher zoom will give higher resolution of the text and smaller size of the label. Default is 30.0.
 
* ''fontSize:''
 
: (optional, but needed if zoom is provided) Size of the font of the text. Default is 50.
 
* ''showOnTop:''
 
: (optional) If true the label will be drawn on top of the rooms and if it is false the label will be drawn as a background, defaults to true if not given.
 
* ''noScaling:''
 
: (optional) If true the label will have the same size when you zoom in and out in the mapper, If it is false the label will scale when you zoom the mapper, defaults to true if not given.
 
* ''fontName:''
 
: (optional) font name to use.
 
* ''foregroundTransparency''
 
: (optional) transparency of the text on the label, defaults to 255 (in range of 0 to 255) or fully opaque if not given.
 
* ''backgroundTransparency''
 
: (optional) transparency of the label background itself, defaults to 50 (in range of 0 to 255) or significantly transparent if not given.
 
* ''temporary''
 
: (optional) if true does not save the image that the label makes in map save files, defaults to false if not given, or for prior versions of Mudlet.
 
* ''outlineRed, outlineGreen, outlineBlue''
 
: (optional) the outline colour of the displayed text
 
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- the first 50 is some area id, the next three 0,0,0 are coordinates - middle of the area
+
-- Reset room 1 to use the global border thickness
-- 255,0,0 would be the foreground in RGB, 23,0,0 would be the background RGB
+
clearRoomBorderThickness(1)
-- zoom is only relevant when when you're using a label of a static size, so we use 0
 
-- and we use a font size of 20 for our label, which is a small medium compared to the map
 
local labelid = createMapLabel( 50, "my map label", 0,0,0, 255,0,0, 23,0,0, 0,20)
 
 
 
-- to create a multi line text label add '\n' between lines
 
-- the position is placed somewhat to the northeast of the center of the map
 
-- this label will be scaled as you zoom the map.
 
local labelid = createMapLabel( 50, "1. Row One\n2. Row 2", .5,5.5,0, 255,0,0, 23,0,0, 30,50, true, false)
 
 
 
local x,y,z = getRoomCoordinates(getPlayerRoom())
 
createMapLabel(getRoomArea(getPlayerRoom()), "my map label", x,y,z, 255,0,0, 23,0,0, 0,20, false, true, "Ubuntu", 255, 100)
 
 
 
-- create a temporary, multiline label with purple text and a white outline
 
lua createMapLabel(1, "This is a really long text\nwith multiple lines.", 0, 0, 0, 125, 0, 125, 0, 0, 0, 50, 48, true, false, "Noto Sans", 255, 0, true, 255, 255, 255)
 
  
 +
-- Clear all custom border settings from a room
 +
clearRoomBorderColor(1)
 +
clearRoomBorderThickness(1)
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==getRoomsByPosition1, PR #8619==
 
;roomTable = getRoomsByPosition1(areaID, x,y,z)
 
  
:Returns an indexed table of all rooms at the given coordinates in the given area, or an empty table if there are none. This function can be useful for checking if a room exists at certain coordinates, or whenever you have rooms overlapping.  This returns exactly the same thing as [[#getRoomsByPosition|getRoomsByPosition()]] except the table is indexed at 1, not zero.
+
==mapSymbolFontInfo, PR #4038 closed==
 
 
: See also: [[#getRoomsByPosition|getRoomsByPosition()]], [[#getRoomCoordinates|getRoomCoordinates()]]
 
 
 
==mapSymbolFontInfo, PR #4038 closed==
 
 
;mapSymbolFontInfo()
 
;mapSymbolFontInfo()
 
: See also: [[#setupMapSymbolFont|setupMapSymbolFont()]]
 
: See also: [[#setupMapSymbolFont|setupMapSymbolFont()]]
Line 722: Line 661:
 
: Miscellaneous functions.
 
: Miscellaneous functions.
  
== openIRC ==
+
== playSpatialSound, PR #8452 open ==
  
;openIRC()
+
* '''playSpatialSound(settings table)'''
  
:Opens the IRC client window for the current profile. Creates the IRC client if it doesn't already exist.
+
Plays spatial audio files with 3D positioning using Qt6's SpatialAudio framework. Allows precise positioning, occlusion effects, room acoustics, and environmental audio for immersive gameplay experiences.
 
 
:See also: [[#sendIrc|sendIrc()]], [[#getIrcNick|getIrcNick()]], [[#getIrcServer|getIrcServer()]], [[#getIrcChannels|getIrcChannels()]]
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
-- configure IRC and open the window
 
setConfig("ircHostName", "irc.libera.chat")
 
setConfig("ircHostPort", 6697)
 
setConfig("ircHostSecure", true)
 
setConfig("ircChannels", "#mudlet")
 
setConfig("ircNickName", "MyNickname")
 
 
 
openIRC()
 
</syntaxhighlight>
 
 
 
{{Note}} The IRC configuration UI has been removed from Settings. Use [[#setConfig|setConfig()]] to configure IRC settings.
 
 
 
== setConfig, getConfig IRC options ==
 
 
 
The following IRC configuration options have been added to [[Manual:Lua_Functions#setConfig|setConfig()]] and [[Manual:Lua_Functions#getConfig|getConfig()]]:
 
  
 
{| class="wikitable"
 
{| class="wikitable"
! Option !! Type !! Description
 
 
|-
 
|-
| <code>ircHostName</code> || string || IRC server hostname (default: "irc.libera.chat")
+
! Required
 +
! Key
 +
! Purpose
 +
! Default
 +
! Description
 
|-
 
|-
| <code>ircHostPort</code> || number || IRC server port (default: 6667, use 6697 for SSL)
+
| Yes
 +
| key
 +
| <unique identifier>
 +
|
 +
| Unique key to identify this spatial sound source for later updates or removal.
 
|-
 
|-
| <code>ircHostSecure</code> || boolean || Whether to use SSL/TLS connection
+
| Yes
 +
| name
 +
| <file name>
 +
|
 +
| Name of the audio file. May contain directory information (i.e. ambient/forest.ogg). May be part of the profile (i.e. getMudletHomeDir().. "/spatial/wind.wav") or on the local device (i.e. "C:/Users/YourName/Documents/sound.mp3").
 
|-
 
|-
| <code>ircChannels</code> || string || Space-separated list of channels to join (e.g., "#mudlet #help")
+
| No
 +
| url
 +
| <url>
 +
|
 +
| Resource location where the audio file may be downloaded. Only required if file is to be downloaded remotely.
 
|-
 
|-
| <code>ircNickName</code> || string || Your IRC nickname
+
| No
|-
+
| position
| <code>ircPassword</code> || string || IRC server password (if required)
+
| {azimuth, elevation, distance}
 +
| {0, 0, 1}
 +
| 3D position as a table: azimuth (horizontal angle in degrees, 0-360), elevation (vertical angle in degrees, -90 to 90), distance (in meters, > 0).
 +
|-
 +
| No
 +
| volume
 +
| 1 to 100
 +
| 50
 +
| Volume level relative to master spatial audio volume.
 +
|-
 +
| No
 +
| occlusion
 +
| 0.0 to 1.0
 +
| 0.0
 +
| Occlusion factor simulating objects blocking the sound path.
 +
|-
 +
| No
 +
| loops
 +
| -1 or >= 1
 +
| 1
 +
| Number of times to loop. -1 for infinite looping.
 +
|-
 +
| No
 +
| room
 +
| {dimensions, reverb, reflection, material}
 +
|
 +
| Room acoustics configuration table.
 
|}
 
|}
  
;setConfig examples
+
See also: [[Manual:Lua Functions#updateSpatialSound|updateSpatialSound()]], [[Manual:Lua Functions#stopSpatialSound|stopSpatialSound()]], [[Manual:Lua Functions#removeSpatialSound|removeSpatialSound()]], [[Manual:Lua Functions#getSpatialSounds|getSpatialSounds()]]
<syntaxhighlight lang="lua">
+
 
-- configure IRC to connect to Libera Chat with SSL
+
{{MudletVersion|4.??}}
setConfig("ircHostName", "irc.libera.chat")
 
setConfig("ircHostPort", 6697)
 
setConfig("ircHostSecure", true)
 
setConfig("ircChannels", "#mudlet #mygamechannel")
 
setConfig("ircNickName", "CoolPlayer123")
 
</syntaxhighlight>
 
  
;getConfig examples
+
* '''Example'''
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- read current IRC configuration
+
-- Play forest ambience behind the player
local hostname = getConfig("ircHostName")
+
playSpatialSound({
local port = getConfig("ircHostPort")
+
    key = "forest_ambience",
local secure = getConfig("ircHostSecure")
+
    name = "ambient/forest_birds.ogg",
local channels = getConfig("ircChannels")
+
    position = {180, 0, 5}, -- behind player, 5 meters away 
local nickname = getConfig("ircNickName")
+
    volume = 30,
 
+
    loops = -1 -- infinite loop
echo(string.format("IRC: %s@%s:%d (SSL: %s)\n", nickname, hostname, port, tostring(secure)))
+
})
echo("Channels: " .. channels .. "\n")
 
</syntaxhighlight>
 
 
 
== setLinkStyle, PR #8527 ==
 
  
;setLinkStyle(labelName, linkColor, linkVisitedColor, [underline])
+
-- Play footsteps with room acoustics
:Sets the color styling for clickable HTML hyperlinks within a label. This allows customization of how links appear before and after being clicked.
+
playSpatialSound({
 +
    key = "footsteps",
 +
    name = "effects/footstep_stone.wav",
 +
    position = {45, -10, 2}, -- front-right, slightly below, 2 meters
 +
    volume = 60,
 +
    room = {
 +
        dimensions = {10, 3, 8}, -- 10m wide, 3m high, 8m deep
 +
        reverb = 0.3,
 +
        reflection = 0.7,
 +
        material = "sheetrock"
 +
    }
 +
})
  
{{MudletVersion|4.20+}}
+
-- Download and play remote spatial sound
 +
playSpatialSound({
 +
    key = "wind_howl",
 +
    name = "wind.ogg",
 +
    url = "https://example.com/sounds/",
 +
    position = {270, 45, 10}, -- left side, elevated, distant
 +
    volume = 40,
 +
    occlusion = 0.2 -- partially blocked
 +
})
 +
</syntaxhighlight>
  
See also: [[Manual:Lua_Functions#resetLinkStyle|resetLinkStyle]], [[Manual:Lua_Functions#clearVisitedLinks|clearVisitedLinks]], [[Manual:Lua_Functions#createLabel|createLabel]], [[Manual:Lua_Functions#echo|echo]]
+
== updateSpatialSound, PR #8452 open ==
  
;Parameters
+
* '''updateSpatialSound(key, settings table)'''
* ''labelName:''
 
: The name of the label to apply link styling to.
 
* ''linkColor:''
 
: The color for unvisited links. Can be a color name (e.g., "cyan"), hex code (e.g., "#00ffff"), or RGB string (e.g., "rgb(0,255,255)"). Pass an empty string "" to not change the unvisited link color.
 
* ''linkVisitedColor:''
 
: The color for visited links (links that have been clicked). Can be a color name, hex code, or RGB string. Pass an empty string "" to not change the visited link color.
 
* ''underline:''
 
: (optional) Whether links should be underlined. Defaults to true if omitted.
 
  
{{note}} Links must be in HTML format using <code>&lt;a href="..."&gt;text&lt;/a&gt;</code>. The label will track which links have been clicked and automatically change their color to the visited color.
+
Updates properties of an existing spatial audio source without stopping playback.
  
;Example
+
* '''Parameters'''
<syntaxhighlight lang="lua">
 
-- Create a label with clickable links
 
createLabel("navigationLabel", 10, 10, 400, 100, 1)
 
setLinkStyle("navigationLabel", "cyan", "purple")
 
  
-- Echo some HTML links to the label
+
• key: Unique identifier of the spatial sound source to update
echo("navigationLabel", [[
+
• settings table: Table containing properties to update (same format as playSpatialSound)
  <a href="send:north">Go North</a> |
 
  <a href="send:south">Go South</a> |
 
  <a href="https://mudlet.org">Mudlet Website</a>
 
]])
 
  
-- Links will appear cyan, and turn purple after being clicked
+
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]]
  
-- You can disable underlining
+
{{MudletVersion|4.??}}
setLinkStyle("navigationLabel", "#00ff00", "#ff00ff", false)
 
</syntaxhighlight>
 
  
{{note}} Link URL schemes supported:
+
* '''Example'''
* '''send:command''' - Sends the command to the game immediately
+
<syntaxhighlight lang="lua">
* '''prompt:text''' - Puts text in the command line for editing
+
-- Move sound to new position
* '''http:// or https://''' - Opens URL in external browser 
+
updateSpatialSound("forest_ambience", {
* '''No scheme''' - Executes as Lua code
+
    position = {90, 0, 3} -- move to right side, closer
 +
})
  
 +
-- Update volume and add occlusion
 +
updateSpatialSound("footsteps", {
 +
    volume = 80,
 +
    occlusion = 0.5
 +
})
  
== resetLinkStyle, PR #8527 ==
+
-- Update multiple properties
 +
updateSpatialSound("wind_howl", {
 +
    position = {315, 30, 15},
 +
    volume = 25,
 +
    occlusion = 0.8
 +
})
 +
</syntaxhighlight>
  
;resetLinkStyle(labelName)
+
== stopSpatialSound, PR #8452 open ==
:Resets the hyperlink styling on a label to the default Qt colors (typically blue links).
 
  
{{MudletVersion|4.20+}}
+
* '''stopSpatialSound(key)'''
  
See also: [[Manual:Lua_Functions#setLinkStyle|setLinkStyle]], [[Manual:Lua_Functions#clearVisitedLinks|clearVisitedLinks]]
+
Stops playback of a spatial audio source but keeps the source available for later use.
  
;Parameters
+
* '''Parameters'''
* ''labelName:''
 
: The name of the label to reset link styling for.
 
  
;Example
+
• key: Unique identifier of the spatial sound source to stop
<syntaxhighlight lang="lua">
 
-- Set custom link colors
 
setLinkStyle("myLabel", "red", "darkred")
 
  
-- Later, reset to defaults
+
* '''Returns'''
resetLinkStyle("myLabel")
 
</syntaxhighlight>
 
  
 +
• boolean: true on success, false if source not found
  
== clearVisitedLinks, PR #8527 ==
+
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]], [[Manual:Lua Functions#removeSpatialSound|removeSpatialSound()]]
  
;clearVisitedLinks(labelName)
+
{{MudletVersion|4.??}}
:Clears the visited link history for a label, causing all links to display in the unvisited link color again.
 
  
{{MudletVersion|4.20+}}
+
* '''Example'''
 +
<syntaxhighlight lang="lua">
 +
-- Stop the forest ambience
 +
stopSpatialSound("forest_ambience")
 +
 
 +
-- Stop footsteps when player stops walking 
 +
if not moving then
 +
    stopSpatialSound("footsteps")
 +
end
 +
</syntaxhighlight>
  
See also: [[Manual:Lua_Functions#setLinkStyle|setLinkStyle]], [[Manual:Lua_Functions#resetLinkStyle|resetLinkStyle]]
+
== pauseSpatialSound, PR #8452 open ==
  
;Parameters
+
* '''pauseSpatialSound(key)'''
* ''labelName:''
+
 
: The name of the label to clear the visited link history for.
+
Pauses playback of a spatial audio source, allowing it to be resumed later from the same position.
 +
 
 +
* '''Parameters'''
  
{{note}} This does not change the link colors - it only resets which links are considered "visited". Links will revert to the unvisited color until clicked again.
+
• key: Unique identifier of the spatial sound source to pause
  
;Example
+
* '''Returns'''
<syntaxhighlight lang="lua">
 
-- Clear the visited links history
 
clearVisitedLinks("navigationLabel")
 
  
-- All links in the label will now show in the unvisited color again,
+
• boolean: true on success, false if source not found
-- even if they were previously clicked
 
</syntaxhighlight>
 
  
==  playSpatialSound, PR #8452  ==
+
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]], [[Manual:Lua Functions#stopSpatialSound|stopSpatialSound()]]
  
* '''playSpatialSound(settings table)'''
+
{{MudletVersion|4.??}}
  
Plays spatial audio files with 3D positioning using Qt6's SpatialAudio framework. Allows precise positioning, occlusion effects, room acoustics, and environmental audio for immersive gameplay experiences.
+
* '''Example'''
 +
<syntaxhighlight lang="lua">
 +
-- Pause ambient sound temporarily
 +
pauseSpatialSound("forest_ambience")
  
{| class="wikitable"
+
-- Resume by playing again (will continue from pause position)
|-
+
playSpatialSound({
! Required
+
    key = "forest_ambience",
! Key
+
    name = "ambient/forest_birds.ogg",
! Purpose
+
    position = {180, 0, 5}
! Default
+
})
! Description
+
</syntaxhighlight>
|-
+
 
| Yes
+
== removeSpatialSound, PR #8452 open ==
| key
+
 
| <unique identifier>
+
* '''removeSpatialSound(key)'''
|
+
 
| Unique key to identify this spatial sound source for later updates or removal.
+
Completely removes a spatial audio source, stopping playback and freeing resources.
|-
+
 
| Yes
+
* '''Parameters'''
| name
+
 
| <file name>
+
• key: Unique identifier of the spatial sound source to remove
|
+
 
| Name of the audio file. May contain directory information (i.e. ambient/forest.ogg). May be part of the profile (i.e. getMudletHomeDir().. "/spatial/wind.wav") or on the local device (i.e. "C:/Users/YourName/Documents/sound.mp3").
+
* '''Returns'''
|-
+
 
| No
+
• boolean: true on success, false if source not found
| url
 
| <url>
 
|
 
| Resource location where the audio file may be downloaded. Only required if file is to be downloaded remotely.
 
|-
 
| No
 
| position
 
| {azimuth, elevation, distance}
 
| {0, 0, 1}
 
| 3D position as a table: azimuth (horizontal angle in degrees, 0-360), elevation (vertical angle in degrees, -90 to 90), distance (in meters, > 0).
 
|-
 
| No
 
| volume
 
| 1 to 100
 
| 50
 
| Volume level relative to master spatial audio volume.
 
|-
 
| No
 
| occlusion
 
| 0.0 to 1.0
 
| 0.0
 
| Occlusion factor simulating objects blocking the sound path.
 
|-
 
| No
 
| loops
 
| -1 or >= 1
 
| 1
 
| Number of times to loop. -1 for infinite looping.
 
|-
 
| No
 
| room
 
| {dimensions, reverb, reflection, material}
 
|
 
| Room acoustics configuration table.
 
|}
 
  
See also: [[Manual:Lua Functions#updateSpatialSound|updateSpatialSound()]], [[Manual:Lua Functions#stopSpatialSound|stopSpatialSound()]], [[Manual:Lua Functions#removeSpatialSound|removeSpatialSound()]], [[Manual:Lua Functions#getSpatialSounds|getSpatialSounds()]]
+
See also: [[Manual:Lua Functions#stopSpatialSound|stopSpatialSound()]], [[Manual:Lua Functions#getSpatialSounds|getSpatialSounds()]]
  
{{MudletVersion|4.20}}
+
{{MudletVersion|4.??}}
  
 
* '''Example'''
 
* '''Example'''
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Play forest ambience behind the player
+
-- Remove completed sound effect
playSpatialSound({
+
removeSpatialSound("door_slam")
    key = "forest_ambience",
 
    name = "ambient/forest_birds.ogg",
 
    position = {180, 0, 5}, -- behind player, 5 meters away 
 
    volume = 30,
 
    loops = -1 -- infinite loop
 
})
 
  
-- Play footsteps with room acoustics
+
-- Clean up old ambient sounds
playSpatialSound({
+
for _, key in ipairs({"old_wind", "old_rain", "old_birds"}) do
    key = "footsteps",
+
    removeSpatialSound(key)
    name = "effects/footstep_stone.wav",
+
end
    position = {45, -10, 2}, -- front-right, slightly below, 2 meters
 
    volume = 60,
 
    room = {
 
        dimensions = {10, 3, 8}, -- 10m wide, 3m high, 8m deep
 
        reverb = 0.3,
 
        reflection = 0.7,
 
        material = "sheetrock"
 
    }
 
})
 
 
 
-- Download and play remote spatial sound
 
playSpatialSound({
 
    key = "wind_howl",
 
    name = "wind.ogg",
 
    url = "https://example.com/sounds/",
 
    position = {270, 45, 10}, -- left side, elevated, distant
 
    volume = 40,
 
    occlusion = 0.2 -- partially blocked
 
})
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== updateSpatialSound, PR #8452 ==
+
== getSpatialSounds, PR #8452 open ==
  
* '''updateSpatialSound(key, settings table)'''
+
* '''getSpatialSounds()'''
  
Updates properties of an existing spatial audio source without stopping playback.
+
Returns a list of all currently active spatial audio sources.
  
* '''Parameters'''
+
* '''Returns'''
  
key: Unique identifier of the spatial sound source to update
+
table: Indexed table containing the keys of all active spatial sound sources
• settings table: Table containing properties to update (same format as playSpatialSound)
 
  
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]]
+
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]], [[Manual:Lua Functions#removeSpatialSound|removeSpatialSound()]]
  
{{MudletVersion|4.20}}
+
{{MudletVersion|4.??}}
  
 
* '''Example'''
 
* '''Example'''
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Move sound to new position
+
-- List all active spatial sounds
updateSpatialSound("forest_ambience", {
+
local activeSounds = getSpatialSounds()
     position = {90, 0, 3} -- move to right side, closer
+
for i, soundKey in ipairs(activeSounds) do
})
+
     echo("Active spatial sound: " .. soundKey .. "\n")
 +
end
  
-- Update volume and add occlusion
+
-- Stop all spatial sounds
updateSpatialSound("footsteps", {
+
for _, soundKey in ipairs(getSpatialSounds()) do
     volume = 80,
+
     stopSpatialSound(soundKey)
    occlusion = 0.5
+
end
})
 
  
-- Update multiple properties
+
-- Check if specific sound is playing
updateSpatialSound("wind_howl", {
+
local activeSounds = getSpatialSounds()
    position = {315, 30, 15},
+
local isPlaying = table.contains(activeSounds, "forest_ambience")
    volume = 25,
 
    occlusion = 0.8
 
})
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== stopSpatialSound, PR #8452 ==
+
== setSpatialListener, PR #8452 open ==
  
* '''stopSpatialSound(key)'''
+
* '''setSpatialListener(settings table)'''
  
Stops playback of a spatial audio source but keeps the source available for later use.
+
Sets the position and orientation of the spatial audio listener (the player's ears).
  
* '''Parameters'''
+
{| class="wikitable"
 +
|-
 +
! Required
 +
! Key
 +
! Purpose
 +
! Default
 +
! Description
 +
|-
 +
| No
 +
| position
 +
| {x, y, z}
 +
| {0, 0, 0}
 +
| 3D position of the listener in world coordinates.
 +
|-
 +
| No
 +
| rotation
 +
| {yaw, pitch, roll}
 +
| {0, 0, 0}
 +
| Orientation of the listener's head: yaw (left/right), pitch (up/down), roll (tilt).
 +
|}
  
• key: Unique identifier of the spatial sound source to stop
+
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]]
  
* '''Returns'''
+
{{MudletVersion|4.??}}
  
• boolean: true on success, false if source not found
+
* '''Example'''
 
+
<syntaxhighlight lang="lua">
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]], [[Manual:Lua Functions#removeSpatialSound|removeSpatialSound()]]
+
-- Set listener at origin, facing north
 +
setSpatialListener({
 +
    position = {0, 0, 0},
 +
    rotation = {0, 0, 0}
 +
})
  
{{MudletVersion|4.20}}
+
-- Player moved to new room and is facing east 
 +
setSpatialListener({
 +
    position = {10, 0, 5},
 +
    rotation = {90, 0, 0} -- 90 degrees yaw = facing east
 +
})
  
* '''Example'''
+
-- Looking up at the sky
<syntaxhighlight lang="lua">
+
setSpatialListener({
-- Stop the forest ambience
+
    rotation = {0, 45, 0} -- 45 degrees pitch up
stopSpatialSound("forest_ambience")
+
})
 
 
-- Stop footsteps when player stops walking 
 
if not moving then
 
    stopSpatialSound("footsteps")
 
end
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== pauseSpatialSound, PR #8452 ==
+
== setSpatialMasterVolume, PR #8452 open ==
  
* '''pauseSpatialSound(key)'''
+
* '''setSpatialMasterVolume(volume)'''
  
Pauses playback of a spatial audio source, allowing it to be resumed later from the same position.
+
Sets the master volume for all spatial audio sources.
  
 
* '''Parameters'''
 
* '''Parameters'''
  
key: Unique identifier of the spatial sound source to pause
+
volume: Master volume level (0-100)
  
 
* '''Returns'''
 
* '''Returns'''
  
• boolean: true on success, false if source not found
+
• boolean: true on success
  
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]], [[Manual:Lua Functions#stopSpatialSound|stopSpatialSound()]]
+
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]]
  
{{MudletVersion|4.20}}
+
{{MudletVersion|4.??}}
  
 
* '''Example'''
 
* '''Example'''
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Pause ambient sound temporarily
+
-- Set moderate spatial audio volume
pauseSpatialSound("forest_ambience")
+
setSpatialMasterVolume(60)
 +
 
 +
-- Mute all spatial audio
 +
setSpatialMasterVolume(0)
  
-- Resume by playing again (will continue from pause position)
+
-- Maximum spatial audio volume
playSpatialSound({
+
setSpatialMasterVolume(100)
    key = "forest_ambience",
 
    name = "ambient/forest_birds.ogg",
 
    position = {180, 0, 5}
 
})
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== removeSpatialSound, PR #8452 ==
+
== playSpatialTestTone, PR #8452 open ==
  
* '''removeSpatialSound(key)'''
+
* '''playSpatialTestTone(settings table)'''
  
Completely removes a spatial audio source, stopping playback and freeing resources.
+
Plays a generated test tone at a specific spatial position for testing and calibration purposes.
  
* '''Parameters'''
+
{| class="wikitable"
 
+
|-
key: Unique identifier of the spatial sound source to remove
+
! Required
 
+
! Key
* '''Returns'''
+
! Purpose
 
+
! Default
• boolean: true on success, false if source not found
+
! Description
 
+
|-
See also: [[Manual:Lua Functions#stopSpatialSound|stopSpatialSound()]], [[Manual:Lua Functions#getSpatialSounds|getSpatialSounds()]]
+
| Yes
 
+
| key
{{MudletVersion|4.20}}
+
| <unique identifier>
 
+
|
* '''Example'''
+
| Unique key to identify this test tone source.
<syntaxhighlight lang="lua">
+
|-
-- Remove completed sound effect
+
| Yes
removeSpatialSound("door_slam")
+
| type
 
+
| "white", "pink", or "sine"
-- Clean up old ambient sounds
+
|
for _, key in ipairs({"old_wind", "old_rain", "old_birds"}) do
+
| Type of test tone to generate.
    removeSpatialSound(key)
+
|-
end
+
| Yes
</syntaxhighlight>
+
| duration
 
+
| <seconds>
==  getSpatialSounds, PR #8452  ==
+
|
 
+
| Duration of the test tone in seconds.
* '''getSpatialSounds()'''
+
|-
 
+
| Yes
Returns a list of all currently active spatial audio sources.
+
| azimuth
 +
| <degrees>
 +
|
 +
| Horizontal angle (0-360 degrees).
 +
|-
 +
| Yes
 +
| elevation
 +
| <degrees>
 +
|
 +
| Vertical angle (-90 to 90 degrees).
 +
|-
 +
| Yes
 +
| distance
 +
| <meters>
 +
|
 +
| Distance from listener in meters.
 +
|-
 +
| No
 +
| frequency
 +
| <Hz>
 +
| 440
 +
| Frequency for sine wave test tones.
 +
|-
 +
| No
 +
| volume
 +
| 1 to 100
 +
| 50
 +
| Volume of the test tone.
 +
|-
 +
| No
 +
| loops
 +
| -1 or >= 1
 +
| 1
 +
| Number of loops (-1 for infinite).
 +
|}
  
* '''Returns'''
+
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]], [[Manual:Lua Functions#stopSpatialSound|stopSpatialSound()]]
  
• table: Indexed table containing the keys of all active spatial sound sources
+
{{MudletVersion|4.??}}
 
 
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]], [[Manual:Lua Functions#removeSpatialSound|removeSpatialSound()]]
 
 
 
{{MudletVersion|4.20}}
 
  
 
* '''Example'''
 
* '''Example'''
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- List all active spatial sounds
+
-- Test speaker positions with white noise
local activeSounds = getSpatialSounds()
+
playSpatialTestTone({
for i, soundKey in ipairs(activeSounds) do
+
    key = "test_left",
     echo("Active spatial sound: " .. soundKey .. "\n")
+
     type = "white",
end
+
    duration = 2,
 +
    azimuth = 270,  -- left side
 +
    elevation = 0,
 +
    distance = 2,
 +
    volume = 70
 +
})
  
-- Stop all spatial sounds
+
-- Test frequency response with sine wave
for _, soundKey in ipairs(getSpatialSounds()) do
+
playSpatialTestTone({
     stopSpatialSound(soundKey)
+
    key = "test_1khz",
end
+
    type = "sine",
 +
    frequency = 1000,
 +
    duration = 3,
 +
    azimuth = 0,    -- front center
 +
    elevation = 0,
 +
    distance = 1,
 +
     volume = 50
 +
})
  
-- Check if specific sound is playing
+
-- Test distance with pink noise
local activeSounds = getSpatialSounds()
+
playSpatialTestTone({
local isPlaying = table.contains(activeSounds, "forest_ambience")
+
    key = "test_distant",
 +
    type = "pink",
 +
    duration = 5,
 +
    azimuth = 180,  -- behind
 +
    elevation = 0,
 +
    distance = 10,  -- far away
 +
    volume = 80,
 +
    loops = 2
 +
})
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== setSpatialListener, PR #8452  ==
+
==getCustomLoginTextId, PR #3952 open==
 +
;getCustomLoginTextId()
  
* '''setSpatialListener(settings table)'''
+
Returns the Id number of the custom login text setting from the profile's preferences. Returns ''0'' if the option is disabled or a number greater than that for the item in the table; note it is possible if using an old saved profile in the future that the number might be higher than expected. As a design policy decision it is not permitted for a script to change the setting, this function is intended to allow a script or package to check that the setting is what it expects.
 +
 
 +
Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined ''doLogin()'' function, a replacement for which is shown below.
 +
:See also: [[#getCharacterName|getCharacterName()]], [[#sendCharacterName|sendCharacterName()]], [[#sendCustomLoginText|sendCustomLoginText()]], [[#sendPassword|sendPassword()]].
  
Sets the position and orientation of the spatial audio listener (the player's ears).
+
{{note}} Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952
  
 +
Only one custom login text has been defined initially:
 
{| class="wikitable"
 
{| class="wikitable"
 +
|+Predefined custom login texts
 
|-
 
|-
! Required
+
!Id!!Custom text!!Introduced in Mudlet version
! Key
 
! Purpose
 
! Default
 
! Description
 
 
|-
 
|-
| No
+
|1|| "connect {character name} {password}"||TBD
| position
+
|}
| {x, y, z}
+
 
| {0, 0, 0}
+
The addition of further texts would be subject to negotiation with the Mudlet Makers.
| 3D position of the listener in world coordinates.
+
 
|-
+
;Example
| No
+
<syntaxhighlight lang="lua">
| rotation
+
-- A replacement for the default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
| {yaw, pitch, roll}
+
function doLogin()
| {0, 0, 0}
+
  if getCustomLoginTextId() ~= 1 then
| Orientation of the listener's head: yaw (left/right), pitch (up/down), roll (tilt).
+
    -- We need this particular option but it is not permitted for a script to change the setting, it can only check what it is
|}
+
    echo("\nUnable to login - please select the 'connect {character name} {password}` custom login option in the profile preferences.\n")
 +
  else
 +
    tempTime(2.0, [[sendCustomLoginText()]], 1)
 +
  end
 +
end
 +
</syntaxhighlight>
 +
 
 +
==sendCharacterName, PR #3952 open==
 +
;sendCharacterName()
  
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]]
+
Sends the name entered into the "Character name" field on the Connection Preferences form directly to the game server. Returns ''true'' unless there is nothing set in that entry in which case a ''nil'' and an error message will be returned instead.
  
{{MudletVersion|4.20}}
+
Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined ''doLogin()'' function that may be replaced for more sophisticated requirements.
 +
:See also: [[#getCharacterName|getCharacterName()]], [[#sendCharacterPassword|sendCharacterPassword()]], [[#sendCustomLoginText|sendCustomLoginText()]], [[#getCustomLoginTextId|getCustomLoginTextId()]].
  
* '''Example'''
+
{{note}} Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952
<syntaxhighlight lang="lua">
 
-- Set listener at origin, facing north
 
setSpatialListener({
 
    position = {0, 0, 0},
 
    rotation = {0, 0, 0}
 
})
 
  
-- Player moved to new room and is facing east 
+
== sendCharacterPassword, PR #3952 open==
setSpatialListener({
+
;sendCharacterPassword()
    position = {10, 0, 5},
 
    rotation = {90, 0, 0} -- 90 degrees yaw = facing east
 
})
 
  
-- Looking up at the sky
+
Sends the password entered into the "Password" field on the Connection Preferences form directly to the game server. Returns ''true'' unless there is nothing set in that entry or it is too long after (or before) a connection was successfully made in which case a ''nil'' and an error message will be returned instead.
setSpatialListener({
 
    rotation = {0, 45, 0} -- 45 degrees pitch up
 
})
 
</syntaxhighlight>
 
  
==  setSpatialMasterVolume, PR #8452  ==
+
Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined ''doLogin()'' function, reproduced below, that may be replaced for more sophisticated requirements.
 +
:See also: [[#getCharacterName|getCharacterName()]], [[#sendCustomLoginText|sendCustomLoginText()]], [[#getCustomLoginTextId|getCustomLoginTextId()]], [[#sendCharacterName|sendCharacterName()]].
  
* '''setSpatialMasterVolume(volume)'''
+
{{note}} Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952
  
Sets the master volume for all spatial audio sources.
+
;Example
 +
<syntaxhighlight lang="lua">
 +
-- The default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
 +
function doLogin()
 +
  if getCharacterName() ~= "" then
 +
    tempTime(2.0, [[sendCharacterName()]], 1)
 +
    tempTime(3.0, [[sendCharacterPassword()]], 1)
 +
  end
 +
end
 +
</syntaxhighlight>
  
* '''Parameters'''
+
==sendCustomLoginText, PR #3952 open==
 +
;sendCustomLoginText()
  
• volume: Master volume level (0-100)
+
Sends the custom login text (which does NOT depend on the user's choice of GUI language) selected in the preferences for this profile. The {password} (and {character name} if present) fields will be replaced with the values entered into the "Password" and "Character name" fields on the Connection Preferences form and then sent directly to the game server. Returns ''true'' unless there is nothing set in either of those entries (though only if required for the character name) or it is too long after (or before) a connection was successfully made or if the custom login feature is disabled, in which case a ''nil'' and an error message will be returned instead.
  
* '''Returns'''
+
Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined ''doLogin()'' function, a replacement for which is shown below.
 +
:See also: [[#getCharacterName|getCharacterName()]], [[#sendCharacterName|sendCharacterName()]], [[#sendPassword|sendPassword()]], [[#getCustomLoginTextId|getCustomLoginTextId()]].
  
• boolean: true on success
+
{{note}} Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952
  
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]]
+
Only one custom login text has been defined initially:
 +
{| class="wikitable"
 +
|+Predefined custom login texts
 +
|-
 +
!Id!!Custom text!!Introduced in Mudlet version
 +
|-
 +
|1||"connect {character name} {password}"||TBD
 +
|}
  
{{MudletVersion|4.20}}
+
The addition of further texts would be subject to negotiation with the Mudlet Makers.
  
* '''Example'''
+
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Set moderate spatial audio volume
+
-- A replacement for the default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
setSpatialMasterVolume(60)
+
function doLogin()
 +
  if getCustomLoginTextId() ~= 1 then
 +
    -- We need this particular option but it is not permitted for a script to change the setting, it can only check what it is
 +
    echo("\nUnable to login - please select the 'connect {character name} {password}` custom login option in the profile preferences.\n")
 +
  else
 +
    tempTime(2.0, [[sendCustomLoginText()]], 1)
 +
  end
 +
end
 +
</syntaxhighlight>
  
-- Mute all spatial audio
+
=Mudlet Object Functions=
setSpatialMasterVolume(0)
+
: A collection of functions that manipulate Mudlet's scripting objects - triggers, aliases, and so forth.
  
-- Maximum spatial audio volume
+
==createComposer PR #8114 open==
setSpatialMasterVolume(100)
 
</syntaxhighlight>
 
  
==  playSpatialTestTone, PR #8452  ==
+
; ok = createComposer(title, text, callbackFunction)
  
* '''playSpatialTestTone(settings table)'''
+
Creates a Composer dialog window with the given title and initial text, and registers a Lua function to handle the result. When the user clicks **Save** or **Cancel**, the Composer closes and your callback function is invoked with two arguments: the resulting text and a boolean indicating whether the user saved (true) or canceled editing (false).
  
Plays a generated test tone at a specific spatial position for testing and calibration purposes.
+
;See also: [[Manual:Lua_Functions#getComposerText|getComposerText()]], [[Manual:Lua_Functions#setComposerText|setComposerText()]], [[Manual:Lua_Functions#getComposerTitle|getComposerTitle()]], [[Manual:Lua_Functions#setComposerTitle|setComposerTitle()]]
  
{| class="wikitable"
+
{{MudletVersion|4.20}}
|-
+
 
! Required
+
;Parameters
! Key
+
* ''title:'' 
! Purpose
+
: The title of the Composer window.
! Default
+
* ''text:'' 
! Description
+
: The initial text content in the Composer. You can use <code>\n</code> to start a new line, <code>\t</code> for tabulators, etc.
|-
+
* ''callbackFunction:'' 
| Yes
+
: A Lua function to call when the Composer closes. It will receive two parameters:
| key
+
:* A string with the text the user entered.
| <unique identifier>
+
:* A boolean value – `true` if the user clicked **Save**, `false` if they clicked **Cancel**.
|
+
 
| Unique key to identify this test tone source.
+
;Returns
|-
+
* Boolean `true` if the Composer was successfully created, otherwise nil + error (for example, if another Composer is already open).
| Yes
+
 
| type
+
;Example
| "white", "pink", or "sine"
+
<syntaxhighlight lang="lua">
|
+
-- Create a Composer window for editing a note
| Type of test tone to generate.
+
createComposer("Edit Note", "Default text", function(editedText, isSaved)
|-
+
    if isSaved then
| Yes
+
        echo(f"Saved text: {editedText}\n")
| duration
+
    else
| <seconds>
+
        echo("Edit was canceled.\n")
|
+
    end
| Duration of the test tone in seconds.
+
end)
|-
+
</syntaxhighlight>
| Yes
+
 
| azimuth
+
==getComposerText PR #8114 open==
| <degrees>
+
 
|
+
; text = getComposerText()
| Horizontal angle (0-360 degrees).
+
 
|-
+
Returns the current text from the Composer window, if it is open.
| Yes
+
 
| elevation
+
;See also: [[Manual:Lua_Functions#createComposer|createComposer()]], [[Manual:Lua_Functions#setComposerText|setComposerText()]]
| <degrees>
+
 
|
+
{{MudletVersion|4.20}}
| Vertical angle (-90 to 90 degrees).
+
 
|-
+
;Parameters
| Yes
+
* (none)
| distance
 
| <meters>
 
|
 
| Distance from listener in meters.
 
|-
 
| No
 
| frequency
 
| <Hz>
 
| 440
 
| Frequency for sine wave test tones.
 
|-
 
| No
 
| volume
 
| 1 to 100
 
| 50
 
| Volume of the test tone.
 
|-
 
| No
 
| loops
 
| -1 or >= 1
 
| 1
 
| Number of loops (-1 for infinite).
 
|}
 
  
See also: [[Manual:Lua Functions#playSpatialSound|playSpatialSound()]], [[Manual:Lua Functions#stopSpatialSound|stopSpatialSound()]]
+
;Returns
 +
* The text currently displayed in the Composer, or nil + error if the Composer is not open.
  
{{MudletVersion|4.20}}
+
;Example
 
 
* '''Example'''
 
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Test speaker positions with white noise
+
-- Retrieve and print the current text from the Composer
playSpatialTestTone({
+
local currentText = getComposerText()
    key = "test_left",
+
if currentText then
     type = "white",
+
     echo(f"Current text in Composer: {currentText}\n")
    duration = 2,
+
else
    azimuth = 270,  -- left side
+
     echo("No Composer is open.\n")
    elevation = 0,
+
end
    distance = 2,
 
     volume = 70
 
})
 
 
 
-- Test frequency response with sine wave
 
playSpatialTestTone({
 
    key = "test_1khz",
 
    type = "sine",
 
    frequency = 1000,
 
    duration = 3,
 
    azimuth = 0,    -- front center
 
    elevation = 0,
 
    distance = 1,
 
    volume = 50
 
})
 
 
 
-- Test distance with pink noise
 
playSpatialTestTone({
 
    key = "test_distant",
 
    type = "pink",
 
    duration = 5,
 
    azimuth = 180,  -- behind
 
    elevation = 0,
 
    distance = 10,  -- far away
 
    volume = 80,
 
    loops = 2
 
})
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==deleteMiniConsole, PR #8387==
 
  
;deleteMiniConsole(miniConsoleName)
+
==getComposerTitle PR #8114 open==
:Deletes a miniconsole with the given name. This performs complete cleanup, removing the miniconsole from memory and all tracking structures.
 
  
{{note}} If you are using the Geyser layout manager, use <code>myMiniConsole:delete()</code> instead. This will handle proper cleanup from Geyser's internal structures.
+
; title = getComposerTitle()
  
{{note}} While hiding a miniconsole with [[Manual:Lua_Functions#hideWindow|hideWindow()]] keeps it in memory for later use, deleting it completely removes it. Deleted miniconsoles cannot be shown again - you would need to create a new one. It's more efficient to hide/show miniconsoles than to delete and recreate them if you'll need them again.
+
Returns the current title from the Composer window, if it is open.
  
{{note}} The "main" console cannot be deleted.
+
;See also: [[Manual:Lua_Functions#createComposer|createComposer()]], [[Manual:Lua_Functions#setComposerTitle|setComposerTitle()]]
 
 
;See also: [[Manual:Lua_Functions#createMiniConsole|createMiniConsole()]], [[Manual:Lua_Functions#createConsole|createConsole()]], [[Manual:Lua_Functions#hideWindow|hideWindow()]], [[Manual:Lua_Functions#showWindow|showWindow()]]
 
  
 
{{MudletVersion|4.20}}
 
{{MudletVersion|4.20}}
  
 
;Parameters
 
;Parameters
* ''miniConsoleName'': The name of the miniconsole to delete.
+
* (none)
  
 
;Returns
 
;Returns
* true on success
+
* The current title of the Composer, or nil + error if the Composer is not open.
* false and an error message if the miniconsole doesn't exist
 
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Create a miniconsole
+
-- Print the Composer title
createMiniConsole("myConsole", 10, 10, 300, 200)
+
local currentTitle = getComposerTitle()
echo("myConsole", "Hello, World!")
+
if currentTitle then
 
+
    echo(f"Composer title: {currentTitle}\n")
-- Later, delete it completely
+
else
local success, err = deleteMiniConsole("myConsole")
+
    echo("No Composer is open.\n")
if not success then
 
  cecho(f"<red>Error: {err}\n")
 
 
end
 
end
 
-- With Geyser:
 
local myConsole = Geyser.MiniConsole:new({
 
  name = "myGeyserConsole",
 
  x = 100, y = 100,
 
  width = 300, height = 200,
 
})
 
 
-- Delete it (handles all cleanup automatically)
 
myConsole:delete()
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==deleteCommandLine, PR #8387==
+
==getKeyCode PR#8435 open==
  
;deleteCommandLine(commandLineName)
+
; keyCode, keyModifers = getKeyCode(keyID/keyName)
:Deletes a command line with the given name. This performs complete cleanup, removing the command line from memory and all tracking structures.
 
  
{{note}} If you are using the Geyser layout manager, use <code>myCommandLine:delete()</code> instead. This will handle proper cleanup from Geyser's internal structures.
+
: Returns numbers representing the key and any modifiers for a key-binding.
  
{{note}} While disabling a command line with [[Manual:Lua_Functions#disableCommandLine|disableCommandLine()]] keeps it in memory but hidden, deleting it completely removes it. Deleted command lines cannot be shown again - you would need to create a new one. It's more efficient to enable/disable command lines than to delete and recreate them if you'll need them again.
+
;See also: [[Manual:Mudlet_Object_Functions#enableKey|enableKey(...)]], [[Manual:Mudlet_Object_Functions#killKey|killKey(...)]], [[Manual:Mudlet_Object_Functions#tempKey|tempKey(...)]], [[Manual:Lua_Functions#findItems|findItems(...)]],
  
{{note}} The main command line ("main") cannot be deleted - attempting to do so will return false with an error message.
+
{{MudletVersion|tba https://github.com/Mudlet/Mudlet/pull/8435}}
  
;See also: [[Manual:Lua_Functions#createCommandLine|createCommandLine()]], [[Manual:Lua_Functions#enableCommandLine|enableCommandLine()]], [[Manual:Lua_Functions#disableCommandLine|disableCommandLine()]]
+
{{note}} If a name is given and it is used by more than one key then only the first one found will be considered by this function.
  
{{MudletVersion|4.20}}
+
{{note}} Modifiers vary between different operating systems and not all of them will be present or have the names given below for all users on all systems.
  
 
;Parameters
 
;Parameters
* ''commandLineName'': The name of the command line to delete. Cannot be "main".
+
* ''mandatoryParameter:''
 +
: either the ID (number) e.g. as returned by the permKey(...) or tempKey(...) functions; or the "name" (string) of a key-binding.
  
;Returns
+
;Returns  
* true on success
+
* Returns two values on success: the key code as used in the functions to create a key-binding; and any modifiers as a sum of the following (including as powers of two).
* false and an error message if the command line doesn't exist or is "main"
+
{| class="wikitable"
 +
|+ Modifiers table
 +
|-
 +
! Modifier !! Value (hex) !! Value (dec) !! 2<sup>''n''</sup>
 +
|-
 +
| Shift || 0x02000000 || 33,554,432 || 21
 +
|-
 +
| Control || 0x04000000 || 67,108,864 || 22
 +
|-
 +
| Alt || 0x08000000 || 134,217,728 || 23
 +
|-
 +
| Keypad || 0x10000000 || 268,435,456 || 24
 +
|-
 +
| GroupSwitch || 0x20000000 || 536,870,912 || 25
 +
|}
 +
 
 +
The list of key codes is rather long to include here, instead view the original code in the Mudlet GitHub repository [[https://github.com/Mudlet/Mudlet/blob/development/src/mudlet-lua/lua/KeyCodes.lua#L2|KeyCodes.lua]].
  
 +
* Returns two values on failure: a Lua '''nil''' and an error message,
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Create a custom command line
 
createCommandLine("myCommandLine", 10, 400, 300, 30)
 
  
-- Later, delete it completely
+
--[[Temporarily make Shift+Alt+T put something on the main console - and remember the ID for the key-binding
local success, err = deleteCommandLine("myCommandLine")
+
so it can be removed afterwards {as a temporary one it won't show up in the Editor!}]]--
if not success then
+
testKey = tempKey(mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"], mudlet.key["T"], [[echo("You pressed Shift+Alt+T didn't you!\n"]])
   cecho(f"<red>Error: {err}\n")
+
 
 +
----Try the combination and prove that it works, then use the function to check it:
 +
usedKey, usedModifiers = getKeyCode(testKey)
 +
if usedKey == mudlet.T and usedModifiers == (mudlet.keymodifier.Shift + mudlet.keymodifier.Alt) then
 +
   echo("It seems that the testKey (with ID = " .. testKey .. ") IS using the 'T' key and the 'Shift' and 'Alt' modifiers.\n")
 
end
 
end
 +
----AFTER testing this, do the following to remove all the traces:
 +
killKey(testKey)
 +
testKey = nil
 +
usedKey = nil
 +
usedModifiers = nil
  
-- This will fail - cannot delete main command line
+
--Now do the same with a permanent key-binding
local success, err = deleteCommandLine("main")
+
permKey("TestKey", "", mudlet.keymodifier["Shift"] + mudlet.keymodifier["Control"], mudlet.key["T"], [[echo("You pressed Shift+Cntl+T didn't you!\n"]])
-- success = false, err = "the main command line cannot be deleted"
 
  
-- With Geyser:
+
----Try the combination and prove that it works, then use the function to check it:
local myCommandLine = Geyser.CommandLine:new({
+
usedKey, usedModifiers = getKeyCode("TestKey")
  name = "myGeyserCommandLine",
+
if usedKey == mudlet.T and usedModifiers == (mudlet.keymodifier.Shift + mudlet.keymodifier.Alt) then
  x = 100, y = 400,
+
   echo("It seems that the testKey (with name = \"TestKey\" IS using the 'T' key and the 'Shift' and 'Control' modifiers.\n")
   width = 300, height = 30,
+
end
})
 
  
-- Delete it (handles all cleanup automatically)
+
----AFTER testing this, do the following to remove all the traces:
myCommandLine:delete()
+
usedKey = nil
</syntaxhighlight>
+
usedModifiers = nil
 +
----AND also look for the top level "Test Key" in the "Keys" view in the editor, select it, and click the "Delete" button to remove it.
  
==deleteScrollBox, PR #8387==
+
--[[Lastly, check to see if there is already a key binding for <Shift>+<Ctrl>+R
 +
For reuse let's make it a general function - which can be copied into the code for a profile]]--
 +
function isKeyUsed(soughtKey, soughtModifiers)
 +
  --first get the IDs of all the current key-bindings
 +
  local allKeys = findItems("", "keybinding", false)
  
;deleteScrollBox(scrollBoxName)
+
  --then scan through them looking for matches for the one we want
:Deletes a scrollbox with the given name. This performs complete cleanup, removing the scrollbox and all its contents from memory and tracking structures.
+
  for _, keyID in pairs(allKeys) do
 +
    local key, modifiers = getKeyCode(keyID)
 +
    if key == soughtKey and modifiers == soughtModifiers then
 +
      --got one!
 +
      return true
 +
    end
 +
  end
  
{{note}} If you are using the Geyser layout manager, use <code>myScrollBox:delete()</code> instead. This will handle proper cleanup from Geyser's internal structures.
+
  return false
 +
end
  
{{note}} While hiding a scrollbox with [[Manual:Lua_Functions#hideWindow|hideWindow()]] keeps it in memory for later use, deleting it completely removes it. Deleted scrollboxes cannot be shown again - you would need to create a new one. It's more efficient to hide/show scrollboxes than to delete and recreate them if you'll need them again.
+
----Now lets try it out - assuming that Alt+Shift+R hasn't been used so far
 +
if isKeyUsed(mudlet.key["R"], mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"]) then
 +
  echo "The Alt+Shift+R is already used!"
 +
else
 +
  echo "The Alt+Shift+R key-binding is available..."
 +
end
  
;See also: [[Manual:Lua_Functions#createScrollBox|createScrollBox()]]
+
----[[Let's define it temporarily to send "rent" to the game server (and mention it on screen)
 +
remembering the ID so we can delete the key-binding after use and then forget the ID]]----
 +
rentKey = tempKey(mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"], mudlet.key["R"], [[send("rent", true) killKey(]] .. rentKey .. [[) rentKey = nil]])
  
{{MudletVersion|4.20}}
+
----Now we can check for it (before we use it!)
 +
if isKeyUsed(mudlet.key["R"], mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"]) then
 +
  echo "The Alt+Shift+R is now used!"
 +
else
 +
  echo "The Alt+Shift+R isn't used now..."
 +
end
  
;Parameters
+
----[[It is left to the reader/user to press this combination at a suitable point - either whilst connected to
* ''scrollBoxName'': The name of the scrollbox to delete.
+
a MUD to which they want to save and presumable disconnect from - or whilst disconnected to just see the
 +
text on screen]]----
  
;Returns
+
--Finally some of the error messages
* true on success
+
----in this case an invalid keyID
* false and an error message if the scrollbox doesn't exist
+
local ok, err = getKeyCode(-1)
 +
if not ok then
 +
  debugc(f"Error: {err}\n")
 +
  return
 +
end
  
;Example
+
----and here providing the arguments as a table instead of an ID number or name string and a modifier:
<syntaxhighlight lang="lua">
+
local ok, err = getKeyCode({mudlet.key["R"], mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"]})
-- Create a scrollbox
+
if not ok then
createScrollBox("myScrollBox", 10, 10, 300, 400)
+
   debugc(f"Error: {err}\n")
 
+
  return
-- Later, delete it completely
 
local success, err = deleteScrollBox("myScrollBox")
 
if not success then
 
   cecho(f"<red>Error: {err}\n")
 
 
end
 
end
 
-- With Geyser:
 
local myScrollBox = Geyser.ScrollBox:new({
 
  name = "myGeyserScrollBox",
 
  x = 100, y = 100,
 
  width = 300, height = 400,
 
})
 
 
-- Delete it (handles all cleanup automatically)
 
myScrollBox:delete()
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Geyser Object Deletion, PR #8387==
+
; Additional development notes
  
;myGeyserObject:delete()
+
==setComposerText PR #8114 open==
:Deletes a Geyser object and all of its children. This method is available on all Geyser container types including Label, Gauge, MiniConsole, CommandLine, ScrollBox, and Mapper. It performs complete cleanup including:
 
* Recursively deleting all children
 
* Removing the object from parent containers
 
* Removing references from Geyser's tracking structures
 
* Calling the underlying C++ delete function where applicable
 
  
{{note}} This is the recommended way to delete Geyser objects as it handles all necessary cleanup automatically.
+
; setComposerText(newText)
  
{{note}} After calling delete(), the Lua variable still exists but the object it referenced is gone. You should set it to nil: <code>myLabel = nil</code>
+
Sets the text content of the Composer window, if it is open.
  
;See also: [[Manual:Lua_Functions#deleteLabel|deleteLabel()]], [[Manual:Lua_Functions#deleteMiniConsole|deleteMiniConsole()]], [[Manual:Lua_Functions#deleteCommandLine|deleteCommandLine()]], [[Manual:Lua_Functions#deleteScrollBox|deleteScrollBox()]]
+
;See also: [[Manual:Lua_Functions#createComposer|createComposer()]], [[Manual:Lua_Functions#getComposerText|getComposerText()]]
  
 
{{MudletVersion|4.20}}
 
{{MudletVersion|4.20}}
  
 
;Parameters
 
;Parameters
* None
+
* ''newText:'' 
 +
: The text to display in the Composer. You can use <code>\n</code> to start a new line, <code>\t</code> for tabulators, etc.
  
 
;Returns
 
;Returns
* Nothing
+
* Boolean `true` if the Title was successfully set, or nil + error if no Composer is open.
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Create a container with nested labels
+
-- Change the Composer text dynamically
local container = Geyser.Container:new({
+
setComposerText("Updated text for the Composer")
  name = "myContainer",
+
</syntaxhighlight>
  x = 100, y = 100,
 
  width = 400, height = 300,
 
})
 
  
local label1 = Geyser.Label:new({
+
==setComposerTitle PR #8114 open==
  name = "label1",
 
  x = 10, y = 10,
 
  width = 100, height = 30,
 
}, container)
 
  
local label2 = Geyser.Label:new({
+
; setComposerTitle(newTitle)
  name = "label2",
 
  x = 10, y = 50,
 
  width = 100, height = 30,
 
}, container)
 
  
-- Delete the entire container - automatically deletes label1 and label2 too
+
Sets the title of the Composer window, if it is open.
container:delete()
 
container = nil
 
  
-- Delete individual elements
+
;See also: [[Manual:Lua_Functions#createComposer|createComposer()]], [[Manual:Lua_Functions#getComposerTitle|getComposerTitle()]]
local myGauge = Geyser.Gauge:new({
 
  name = "healthGauge",
 
  x = 10, y = 10,
 
  width = 200, height = 20,
 
})
 
  
-- Later when you don't need it anymore
+
{{MudletVersion|4.20}}
myGauge:delete()
 
myGauge = nil
 
</syntaxhighlight>
 
  
==setConsoleBufferSize PR #8222==
+
;Parameters
;setConsoleBufferSize([consoleName], linesLimit, sizeOfBatchDeletion, [max])
+
* ''newTitle:'' 
:Sets the maximum number of lines a buffer (main window or a miniconsole) can hold. Default is 100,000.
+
: The title to display in the Composer.
:Returns nothing on success (up to '''Mudlet 4.16''') or ''true'' (from '''Mudlet 4.17'''); ''nil'' and an error message on failure.
 
  
;Parameters
+
;Returns
* ''consoleName:''
+
* Boolean `true` if the Title was successfully set, or nil + error if no Composer is open.
: (optional) The name of the window. If omitted, uses the main console.
 
* ''linesLimit:''
 
: Sets the amount of lines the buffer should have.
 
{{note}} Mudlet performs extremely efficiently with even huge numbers, but there is of course a limit to your computer's memory. As of Mudlet 4.7+, this amount will be capped to that limit on macOS and Linux (on Windows, it's capped lower as Mudlet on Windows is 32bit).
 
* ''sizeOfBatchDeletion:''
 
: Specifies how many lines should Mudlet delete at once when you go over the limit - it does it in bulk because it's efficient to do so.
 
* ''max:''
 
: Set to true if you'd like to set the ''linesLimit'' to the maximum allowed. This is only supported for the main console.
 
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- sets the main windows size to 1 million lines maximum - which is more than enough!
+
-- Change the Composer title dynamically
setConsoleBufferSize("main", 1000000, 1000)
+
setComposerTitle("Declaration of Independence")
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
= Networking Functions=
 +
:A collection of functions for managing networking.
  
==loadVideoFile, PR #7721 closed==
+
==getTelnetOptionsStatus PR #8962, open==
;loadVideoFile(settings table) or loadVideoFile(name, [url])
+
;getTelnetOptionsStatus()
:Loads video files from the Internet or the local file system to the "media" folder of the profile for later use with [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]] and [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]]. Although files could be loaded or streamed directly at playing time from [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], loadVideoFile() provides the advantage of loading files in advance.
+
: Returns the current status of telnet options that have been negotiated between Mudlet and the game server. This function is useful for debugging telnet protocol issues and understanding which features are currently enabled in your connection. The values returned are the same as those that would be reported back to the Server if it requested them via the telnet option number 5 (''STATUS'').
  
{{note}} Video files consume drive space on your device. Consider using the streaming feature of [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]] for large files.
+
: The function returns a table where each key is a telnet option number (0-255), and the value is a sub-table containing the option details. Only options that have been negotiated so far during the telnet session are included in the results. As nearly all options are handled separately in the two directions each numbered option has two statuses to report,
  
{| class="wikitable"
+
: See also: [[Manual:Supported_Protocols#Telnet|Telnet Protocols]]
!Required
 
!Key
 
!Value
 
! style="text-align:left;" |Purpose
 
|- style="color: green;"
 
| style="text-align:center;" |Yes
 
|name
 
|<file name>
 
| style="text-align:left;" |
 
*Name of the media file.
 
*May contain directory information (i.e. weather/maelstrom.mp4).
 
*May be part of the profile (i.e. getMudletHomeDir().. "/congratulations.mp4")
 
*May be on the local device (i.e. "C:/Users/YourNameHere/Movies/nevergoingtogiveyouup.mp4")
 
|- style="color: blue;"
 
| style="text-align:center;" |Maybe
 
|url
 
|<url>
 
| style="text-align:left;" |
 
*Resource location where the media file may be downloaded.
 
*Only required if file to load is not part of the profile or on the local file system.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
{{MudletVersion|4.21}}
  
{{MudletVersion|4.??}}
+
;Returns:
 +
* A table with telnet option numbers as keys, each containing:
 +
** ''Name:'' A string with the human-readable name of the telnet option (e.g., "ECHO (1)", "NAWS (31)", "MCCP2 (86)")
 +
** ''Server:'' (optional) Boolean indicating if the server (who sent the ''<IAC><WILL><OPTION>'' to which Mudlet replied''<IAC><DO><OPTION>'' to agree or ''<IAC><DONT><OPTION>'' to disagree to it) has this option enabled (''true'') or disabled (''false''). Only present if the server requested this option.
 +
** ''Mudlet:'' (optional) Boolean indicating if Mudlet (who sent the ''<IAC><WILL><OPTION>'' to which the Server replied ''<IAC><DO><OPTION>'' to agree or ''<IAC><DONT><OPTION>'' to disagree to it) has this option enabled (''true'') or disabled (''false''). Only present if Mudlet requested this option.
  
 
;Example
 
;Example
 +
<syntaxhighlight lang="lua">
 +
-- Display all negotiated telnet options
 +
local options = getTelnetOptionsStatus()
 +
 +
cecho("<cyan>Current Telnet Options Status:\n")
 +
for optionNumber, details in pairs(options) do
 +
  cecho(string.format("<white>Option %d: <yellow>%s<reset>\n", optionNumber, details.Name))
 +
 
 +
  if details.Server ~= nil then
 +
    if details.Server then
 +
      cecho("  <white>Server: <green>enabled<reset>\n")
 +
    else
 +
      cecho("  <white>Server: <red>disabled<reset>\n")
 +
    end
 +
  end
 +
 
 +
  if details.Mudlet ~= nil then
 +
    if details.Mudlet ~= nil then
 +
      cecho("  <white>Mudlet: <green>enabled<reset>\n")
 +
    else
 +
      cecho("  <white>Mudlet: <red>disabled<reset>\n")
 +
    end
 +
  end
 +
end
 +
</syntaxhighlight>
  
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
---- Table Parameter Syntax ----
+
-- Check if compression (MCCP2) is enabled
 +
local options = getTelnetOptionsStatus()
  
-- Download from the Internet
+
-- Option 86 is MCCP2 (Mud Client Compression Protocol 2)
loadVideoFile({
+
if options[86] and options[86].Server then
    name = "TextInMotion-VideoSample-1080p.mp4"
+
  cecho("<green>Compression is enabled!\n")
    , url = "https://d2qguwbxlx1sbt.cloudfront.net/"
+
else
})
+
  cecho("<red>Compression is not active.\n")
 +
end
 +
</syntaxhighlight>
  
-- OR download from the profile
+
<syntaxhighlight lang="lua">
loadVideoFile({name = getMudletHomeDir().. "/TextInMotion-VideoSample-1080p.mp4"})
+
-- Monitor telnet negotiation on connect
 +
function checkTelnetFeatures()
 +
  local options = getTelnetOptionsStatus()
 +
 
 +
  -- Check for common features
 +
  local features = {
 +
    [1] = "Echo",
 +
    [3] = "Suppress Go Ahead",
 +
    [24] = "Terminal Type",
 +
    [31] = "Negotiate Window Size (NAWS)",
 +
    [69] = "MSDP",
 +
    [86] = "MCCP2 Compression",
 +
    [201] = "GMCP"
 +
  }
 +
 
 +
  cecho("<cyan>Enabled Features:\n")
 +
  for optNum, name in pairs(features) do
 +
    if options[optNum] then
 +
      local status = "announced"
 +
      if options[optNum].Server and options[optNum].Mudlet then
 +
        status = "fully enabled"
 +
      elseif options[optNum].Server then
 +
        status = "server enabled"
 +
      elseif options[optNum].Mudlet then
 +
        status = "client enabled"
 +
      end
 +
      cecho(string.format("<white>%s: <green>%s\n", name, status))
 +
    end
 +
  end
 +
end
  
-- OR download from the local file system
+
registerAnonymousEventHandler("sysConnectionEvent", "checkTelnetFeatures")
loadVideoFile({name = "C:/Users/Tamarindo/Movies/TextInMotion-VideoSample-1080p.mp4"})
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==playVideoFile, PR #7721 closed==
+
{{note}} This function is primarily intended for debugging telnet protocol issues. Most users won't need to use it in normal scripts, as Mudlet handles telnet negotiation automatically. At the time of introduction there is a suspicion that the status of some options were not being correctly handled and this function was created to provide a means to monitor them.
;playVideoFile(settings table)
 
:Plays video files from the Internet or the local file system for later use with [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]]. Video files may be downloaded to the device and played, or streamed from the Internet when the value of the <code>stream</code> parameter is <code>true</code>.
 
  
{| class="wikitable"
+
{{note}} pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/8962
!Required
+
 
!Key
+
=String Functions=
!Value
+
:These functions are used to manipulate strings.
!Default
+
 
! style="text-align:left;" |Purpose
+
=Table Functions=
|- style="color: green;"
+
:These functions are used to manipulate tables. Through them you can add to tables, remove values, check if a value is present in the table, check the size of a table, and more.
| style="text-align:center;" |Yes
+
 
|name
+
=Text to Speech Functions=
|<file name>
+
: These functions are used to create sound from written words. Check out our [[Special:MyLanguage/Manual:Text-to-Speech|Text-To-Speech Manual]] for more detail on how this all works together.
|&nbsp;
+
 
| style="text-align:left;" |
+
=UI Functions=
*Name of the media file.
+
:These functions are used to construct custom user GUIs. They deal mainly with miniconsole/label/gauge creation and manipulation as well as displaying or formatting information on the screen.
*May contain directory information (i.e. weather/maelstrom.mp4).
 
*May be part of the profile (i.e. getMudletHomeDir().. "/cow.mp4")
 
*May be on the local device (i.e. "C:/Users/YourNameHere/Documents/nevergoingtogiveyouup.mp4")
 
*Wildcards ''*'' and ''?'' may be used within the name to randomize media files selection.
 
|-
 
| style="text-align:center;" |No
 
|volume
 
| 1 to 100
 
|50
 
| style="text-align:left;" |
 
*Relative to the volume set on the player's client.
 
|-
 
| style="text-align:center;" |No
 
|start
 
|<msec>
 
|0
 
| style="text-align:left;" |
 
*Begin play at the specified position in milliseconds.
 
|-
 
| style="text-align:center;" |No
 
|finish
 
|<msec>
 
|0
 
|
 
*Finish play at the specified position in milliseconds.
 
|-
 
| style="text-align:center;" |No
 
|loops
 
| -1, or >= 1
 
|1
 
| style="text-align:left;" |
 
*Number of iterations that the media plays.
 
* A value of -1 allows the media to loop indefinitely.
 
|- style="color: green;"
 
| style="text-align:center;" |Yes
 
|key
 
|<key>
 
|&nbsp;
 
| style="text-align:left;" |
 
*Identifies the label or window the video will appear on the user interface.
 
*Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
*Halts the play of current media files with the same "key" that have a different "name" or "url" while this media plays.
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
|&nbsp;
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
| style="text-align:center;" |No
 
|continue
 
|true or false
 
|true
 
| style="text-align:left;" |
 
*Continues playing matching new video files when true.
 
*Restarts matching new video files when false.
 
|-
 
| style="text-align:center;" |No
 
|close
 
|true or false
 
|false
 
|
 
*Closes the label or window when playback is complete.
 
|- style="color: blue;"
 
| style="text-align:center;" |Maybe
 
|url
 
|<url>
 
|&nbsp;
 
| style="text-align:left;" |
 
*Resource location where the media file may be downloaded.
 
*Only required if the file is to be downloaded remotely or for streaming from the Internet.
 
|- style="color: blue;"
 
| style="text-align:center;" |Maybe
 
|stream
 
|true or false
 
|false
 
| style="text-align:left;" |
 
*Streams files from the Internet when true.
 
*Download files when false (default).
 
*Used in combination with the `url` key.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
==createTextEdit, PR #8986==
 +
;createTextEdit([windowName,] name, x, y, width, height)
  
{{MudletVersion|4.??}}
+
:Creates a new multi-line text editor widget. The text edit can be placed inside the main window or a user window. It supports word wrap, custom
 +
fonts, stylesheets, placeholder text, and read-only mode. Use [[#deleteTextEdit|deleteTextEdit()]] to remove it.
  
;Example
+
:Standard window functions ([[Manual:Lua_Functions#moveWindow|moveWindow()]], [[Manual:Lua_Functions#resizeWindow|resizeWindow()]],
 +
[[Manual:Lua_Functions#showWindow|showWindow()]], [[Manual:Lua_Functions#hideWindow|hideWindow()]],
 +
[[Manual:Lua_Functions#raiseWindow|raiseWindow()]], [[Manual:Lua_Functions#lowerWindow|lowerWindow()]],
 +
[[Manual:Lua_Functions#setWindow|setWindow()]]) all work with text edit widgets. [[Manual:Lua_Functions#windowType|windowType()]] returns
 +
''"textedit"'' for these widgets.
  
<syntaxhighlight lang="lua">
+
:See also: [[#deleteTextEdit|deleteTextEdit()]], [[#getTextEditText|getTextEditText()]], [[#setTextEditText|setTextEditText()]]
---- Table Parameter Syntax ----
 
  
-- Stream a video file from the Internet and play it.
+
{{MudletVersion|4.21}}
playVideoFile({
 
    name = "TextInMotion-VideoSample-1080p.mp4"
 
    , key = "textinmotion" -- label or window to target playback
 
    , url = "https://d2qguwbxlx1sbt.cloudfront.net/"
 
    , stream = true
 
})
 
  
-- Play a video file from the Internet, storing it in the profile's media directory (i.e. /Users/Tamarindo/mudlet-data/profiles/StickMUD/media) so you don't need to download it over and over. You could add ", stream = false" below, but that is the default and is not needed.
+
;Parameters
 +
* ''windowName:''
 +
: (optional) The name of the parent user window. Defaults to the main window if omitted.
 +
* ''name:''
 +
: The name of the text edit to create.
 +
* ''x:''
 +
: The x-coordinate of the text edit.
 +
* ''y:''
 +
: The y-coordinate of the text edit.
 +
* ''width:''
 +
: The width of the text edit.
 +
* ''height:''
 +
: The height of the text edit.
  
playVideoFile({
+
;Returns
    name = "TextInMotion-VideoSample-1080p.mp4"
+
* ''true'' on success, or raises an error if the text edit could not be created.
    , key = "textinmotion" -- label or window to target playback
 
    , url = "https://d2qguwbxlx1sbt.cloudfront.net/"
 
})
 
  
-- Play a video file stored in the profile's media directory (i.e. /Users/Tamarindo/mudlet-data/profiles/StickMUD/media)
+
;Example
playVideoFile({
+
<syntaxhighlight lang="lua">
    name = "TextInMotion-VideoSample-1080p.mp4"
+
-- create a text edit on the main window
    , key = "textinmotion" -- label or window to target playback
+
createTextEdit("myEditor", 10, 10, 400, 200)
})
 
  
-- OR copy once from the game's profile, and play a video file stored in the profile's media directory
+
-- create a text edit inside a user window
---- [volume] of 75 (1 to 100)
+
createTextEdit("myUserWindow", "myEditor", 10, 10, 400, 200)
playVideoFile({
 
    name = getMudletHomeDir().. "/TextInMotion-VideoSample-1080p.mp4"
 
    , key = "textinmotion" -- label or window to target playback
 
    , volume = 75
 
})
 
  
-- OR copy once from the local file system, and play a video file stored in the profile's media directory
+
-- Geyser usage
---- [volume] of 75 (1 to 100)
+
local editor = Geyser.TextEdit:new({
playVideoFile({
+
name = "myEditor",
    name = "C:/Users/Tamarindo/Movies/TextInMotion-VideoSample-1080p.mp4"
+
x = 10, y = 10,
    , key = "textinmotion" -- label or window to target playback
+
width = 400, height = 200,
    , volume = 75
 
 
})
 
})
  
-- OR download once from the Internet, and play a video stored in the profile's media directory
+
-- set some text and a placeholder
---- [fadein] and increase the volume from 1 at the start position to default volume up until the position of 10 seconds
+
editor:setText("Hello world!")
---- [fadeout] and decrease the volume from default volume to one, 15 seconds from the end of the video
+
editor:setPlaceholder("Type here...")
---- [start] 5 seconds after position 0 (fadein scales its volume increase over a shorter duration, too)
 
---- [key] reference of "textinmotion" for targeting label or window playback
 
---- [tag] reference of "ambience" to stop any video later with the same tag
 
---- [continue] playing this video if another request for the same video comes in (false restarts it)  
 
---- [url] resource location where the file may be accessed on the Internet
 
---- [stream] download once from the Internet if the video does not exist in the profile's media directory when false (true streams from the Internet and will not download to the device)
 
playVideoFile({
 
    name = "TextInMotion-VideoSample-1080p.mp4"
 
    , volume = nil -- nil lines are optional, no need to use
 
    , start = 10000
 
    , finish = 20000
 
    , loops = nil -- nil lines are optional, no need to use
 
    , key = "textinmotion" -- label or window where this will play
 
    , tag = "ambience"
 
    , continue = true
 
    , close = true -- close the label or window when playback completes
 
    , url = "https://d2qguwbxlx1sbt.cloudfront.net/"
 
    , stream = false
 
})
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==stopVideos, PR #7721 closed==
+
==deleteTextEdit, PR #8986==
;stopVideos(settings table)
+
;deleteTextEdit(name)
:Stop all videos (no filter), or videos that meet a combination of filters (name, key, and tag) intended to be paired with [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]].
 
  
{| class="wikitable"
+
:Deletes a text edit widget. Raises the [[Manual:Event_Engine#sysTextEditDeleted|sysTextEditDeleted]] event with the text edit name as an
!Required
+
argument.
!Key
 
!Value
 
! style="text-align:left;" |Purpose
 
|-
 
| style="text-align:center;" |No
 
|name
 
|<file name>
 
| style="text-align:left;" |
 
*Name of the media file.
 
|-
 
| style="text-align:center;" |No
 
|key
 
|<key>
 
| style="text-align:left;" |
 
* Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
* Halts the play of current media files with the same "key" that have a different "name" or "url" while this media plays.
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
:See also: [[#createTextEdit|createTextEdit()]]
  
{{MudletVersion|4.??}}
+
{{MudletVersion|4.21}}
 +
 
 +
;Parameters
 +
* ''name:''
 +
: The name of the text edit to delete.
  
; Example
+
;Returns
 +
* ''true'' on success, or ''false'' and an error message if the text edit was not found.
  
 +
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
---- Table Parameter Syntax ----
+
deleteTextEdit("myEditor")
 +
</syntaxhighlight>
  
-- Stop all playing video files for this profile associated with the API
+
==getTextEditText, PR #8986==
stopVideos()
+
;getTextEditText(name)
  
-- Stop playing the text mp4 by name
+
:Returns the current plain text content of a text edit widget.
stopVideos({name = "TextInMotion-VideoSample-1080p.mp4"})
 
  
-- Stop playing the unique sound identified as "text"
+
:See also: [[#setTextEditText|setTextEditText()]], [[#clearTextEdit|clearTextEdit()]]
stopVideos({
+
 
    name = nil  -- nil lines are optional, no need to use
+
{{MudletVersion|4.21}}
    , key = "text" -- key
+
 
    , tag = nil  -- nil lines are optional, no need to use
+
;Parameters
})
+
* ''name:''
 +
: The name of the text edit to get the text from.
 +
 
 +
;Returns
 +
* The text content as a string, or raises an error if the text edit was not found.
 +
 
 +
;Example
 +
<syntaxhighlight lang="lua">
 +
local text = getTextEditText("myEditor")
 +
echo("Editor contains: " .. text .. "\n")
 +
 
 +
-- Geyser usage
 +
local text = myEditor:getText()
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==getPausedMusic, PR #7721 closed==
+
==setTextEditText, PR #8986==
;getPausedMusic(settings table)
+
;setTextEditText(name, text)
: List all paused music (no filter), or paused music that meets a combination of filters (name, key, and tag) intended to be paired with [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]].
 
  
{| class="wikitable"
+
:Sets the plain text content of a text edit widget, replacing any existing content.
!Required
+
 
!Key
+
:See also: [[#getTextEditText|getTextEditText()]], [[#clearTextEdit|clearTextEdit()]]
!Value
 
!Default
 
! style="text-align:left;" |Purpose
 
|-
 
| style="text-align:center;" |No
 
|name
 
|<file name>
 
|
 
| style="text-align:left;" |
 
*Name of the media file.
 
|-
 
| style="text-align:center;" |No
 
|key
 
|<key>
 
|
 
| style="text-align:left;" |
 
* Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
|
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
{{MudletVersion|4.21}}
  
{{MudletVersion|4.??}}
+
;Parameters
 +
* ''name:''
 +
: The name of the text edit.
 +
* ''text:''
 +
: The text to set.
  
; Example
+
;Returns
 +
* ''true'' on success, or raises an error if the text edit was not found.
  
 +
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
---- Table Parameter Syntax ----
+
setTextEditText("myEditor", "Hello world!")
  
-- List all paused music files for this profile associated with the API
+
-- Geyser usage
getPausedMusic()
+
myEditor:setText("Hello world!")
 +
</syntaxhighlight>
  
-- List all paused music matching the rugby mp3 name
+
==clearTextEdit, PR #8986==
getPausedMusic({name = "167124__patricia-mcmillen__rugby-club-in-spain.mp3"})
+
;clearTextEdit(name)
  
-- List all paused music matching the unique key of "rugby"
+
:Clears all text from a text edit widget.
getPausedMusic({
 
    name = nil  -- nil lines are optional, no need to use
 
    , key = "rugby" -- key
 
    , tag = nil  -- nil lines are optional, no need to use
 
})
 
</syntaxhighlight>
 
  
== getPausedSounds, PR #7721 closed==
+
:See also: [[#setTextEditText|setTextEditText()]], [[#getTextEditText|getTextEditText()]]
;getPausedSounds(settings table)
 
:List all paused sounds (no filter), or paused sounds that meets a combination of filters (name, key, tag, and priority) intended to be paired with [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]].
 
  
{| class="wikitable"
+
{{MudletVersion|4.21}}
!Required
 
!Key
 
!Value
 
!Default
 
! style="text-align:left;" |Purpose
 
|-
 
| style="text-align:center;" | No
 
|name
 
|<file name>
 
|
 
| style="text-align:left;" |
 
*Name of the media file.
 
|-
 
| style="text-align:center;" |No
 
|key
 
|<key>
 
|
 
| style="text-align:left;" |
 
* Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
|
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
;Parameters
 +
* ''name:''
 +
: The name of the text edit to clear.
  
{{MudletVersion|4.??}}
+
;Returns
 
+
* ''true'' on success, or raises an error if the text edit was not found.
; Example
 
  
 +
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
---- Table Parameter Syntax ----
+
clearTextEdit("myEditor")
  
-- List all paused sounds for this profile associated with the API
+
-- Geyser usage
getPausedSounds()
+
myEditor:clear()
 +
</syntaxhighlight>
  
-- List all paused sounds matching the rugby mp3 name
+
==setTextEditReadOnly, PR #8986==
getPausedSounds({name = "167124__patricia-mcmillen__rugby-club-in-spain.mp3"})
+
;setTextEditReadOnly(name, state)
  
-- List the paused sound matching the unique key of "rugby"
+
:Sets whether a text edit widget is read-only. When read-only, the user cannot edit the text but can still select and copy it.
getPausedSounds({
 
    name = nil  -- nil lines are optional, no need to use
 
    , key = "rugby" -- key
 
    , tag = nil  -- nil lines are optional, no need to use
 
})
 
</syntaxhighlight>
 
  
== getPausedVideos, PR #7721 closed==
+
:See also: [[#createTextEdit|createTextEdit()]]
;getPausedVideos(settings table)
 
:List all paused videos (no filter), or playing videos that meets a combination of filters (name, key, and tag) intended to be paired with [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]].
 
  
{| class="wikitable"
+
{{MudletVersion|4.21}}
!Required
 
!Key
 
!Value
 
!Default
 
! style="text-align:left;" |Purpose
 
|-
 
| style="text-align:center;" | No
 
|name
 
|<file name>
 
|
 
| style="text-align:left;" |
 
*Name of the media file.
 
|-
 
| style="text-align:center;" |No
 
|key
 
|<key>
 
|
 
| style="text-align:left;" |
 
*Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
|
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPlayingVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
;Parameters
 +
* ''name:''
 +
: The name of the text edit.
 +
* ''state:''
 +
: ''true'' to make the text edit read-only, ''false'' to make it editable.
  
{{MudletVersion|4.??}}
+
;Returns
 +
* ''true'' on success, or raises an error if the text edit was not found.
  
; Example
+
;Example
 +
<syntaxhighlight lang="lua">
 +
-- make it read-only to display content
 +
setTextEditReadOnly("myEditor", true)
  
<syntaxhighlight lang="lua">
+
-- make it editable again
---- Table Parameter Syntax ----
+
setTextEditReadOnly("myEditor", false)
  
-- List all paused videos files for this profile associated with the API
+
-- Geyser usage
getPausedVideos()
+
myEditor:setReadOnly(true)
 +
</syntaxhighlight>
  
-- List all paused videos matching the unique textinmotion key name
+
==setTextEditPlaceholder, PR #8986==
getPausedVideos({name = "textinmotion"})
+
;setTextEditPlaceholder(name, text)
  
-- List all paused videos matching the textinmotion mp4 name
+
:Sets the placeholder text displayed when the text edit is empty. The placeholder text is shown in a lighter color and disappears when the user
getPausedVideos({name = "TextInMotion-VideoSample-1080p.mp4"})
+
starts typing.
  
-- List all paused videos matching the unique key of "textinmotion"
+
:See also: [[#createTextEdit|createTextEdit()]]
getPausedVideos({
 
    name = nil  -- nil lines are optional, no need to use
 
    , key = "textinmotion" -- key
 
    , tag = nil  -- nil lines are optional, no need to use
 
})
 
</syntaxhighlight>
 
==getPlayingVideos, PR #7721 closed==
 
; getPlayingVideos(settings table)
 
:List all playing videos (no filter), or playing videos that meets a combination of filters (name, key, and tag) intended to be paired with [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]].
 
  
{| class="wikitable"
+
{{MudletVersion|4.21}}
!Required
 
!Key
 
!Value
 
!Default
 
! style="text-align:left;" |Purpose
 
|-
 
| style="text-align:center;" | No
 
|name
 
|<file name>
 
|
 
| style="text-align:left;" |
 
*Name of the media file.
 
|-
 
| style="text-align:center;" |No
 
|key
 
|<key>
 
|
 
| style="text-align:left;" |
 
* Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
|
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
;Parameters
 +
* ''name:''
 +
: The name of the text edit.
 +
* ''text:''
 +
: The placeholder text to display.
  
{{MudletVersion|4.??}}
+
;Returns
 
+
* ''true'' on success, or raises an error if the text edit was not found.
; Example
 
  
 +
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
---- Table Parameter Syntax ----
+
setTextEditPlaceholder("myEditor", "Write your message here...")
  
-- List all playing videos files for this profile associated with the API
+
-- Geyser usage
getPlayingVideos()
+
myEditor:setPlaceholder("Write your message here...")
 +
</syntaxhighlight>
  
-- List all playing videos matching the unique textinmotion key name
+
==setTextEditStyleSheet, PR #8986==
getPlayingVideos({name = "textinmotion"})
+
;setTextEditStyleSheet(name, css)
  
-- List all playing videos matching the textinmotion mp4 name
+
:Applies a Qt stylesheet to a text edit widget for custom visual styling, such as colors, borders, and padding.
getPlayingVideos({name = "TextInMotion-VideoSample-1080p.mp4"})
 
  
-- List all playing videos matching the unique key of "textinmotion"
+
:See also: [[#createTextEdit|createTextEdit()]]
getPlayingVideos({
 
    name = nil  -- nil lines are optional, no need to use
 
    , key = "textinmotion" -- key
 
    , tag = nil  -- nil lines are optional, no need to use
 
})
 
</syntaxhighlight>
 
  
==pauseMusic, PR #7721 closed==
+
{{MudletVersion|4.21}}
;pauseMusic(settings table)
 
:Pause all music (no filter), or music that meet a combination of filters (name, key, and tag) intended to be paired with [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]].
 
  
{| class="wikitable"
+
;Parameters
!Required
+
* ''name:''
!Key
+
: The name of the text edit.
!Value
+
* ''css:''
! style="text-align:left;" |Purpose
+
: A Qt stylesheet string.
|-
 
| style="text-align:center;" |No
 
|name
 
|<file name>
 
| style="text-align:left;" |
 
*Name of the media file.
 
|-
 
| style="text-align:center;" |No
 
|key
 
|<key>
 
| style="text-align:left;" |
 
*Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
*Pauses the play of current media files with the same "key" that have a different "name" or "url" while this media plays.
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
;Returns
 +
* ''true'' on success, or raises an error if the text edit was not found.
  
{{MudletVersion|4.??}}
+
;Example
 +
<syntaxhighlight lang="lua">
 +
setTextEditStyleSheet("myEditor", [[
 +
QPlainTextEdit {
 +
background-color: #1a1a2e;
 +
color: #e0e0e0;
 +
border: 1px solid #444;
 +
padding: 5px;
 +
}
 +
]])
  
; Example
+
-- Geyser usage
 +
myEditor:setStyleSheet([[
 +
QPlainTextEdit {
 +
background-color: #1a1a2e;
 +
color: #e0e0e0;
 +
border: 1px solid #444;
 +
padding: 5px;
 +
}
 +
]])
 +
</syntaxhighlight>
  
<syntaxhighlight lang="lua">
+
==setTextEditFont, PR #8986==
---- Table Parameter Syntax ----
+
;setTextEditFont(name, fontName)
  
-- Pause all playing music files for this profile associated with the API
+
:Sets the font family of a text edit widget.
pauseMusic()
 
  
-- Pause playing the music matching the rugby mp3 name
+
:See also: [[#setTextEditFontSize|setTextEditFontSize()]]
pauseMusic({name = "167124__patricia-mcmillen__rugby-club-in-spain.mp3"})
 
  
-- Pause playing the unique music identified as "rugby"
+
{{MudletVersion|4.21}}
pauseMusic({
 
    name = nil  -- nil lines are optional, no need to use
 
    , key = "rugby" -- key
 
    , tag = nil  -- nil lines are optional, no need to use
 
})
 
</syntaxhighlight>
 
  
==pauseSounds, PR #7721 closed ==
+
;Parameters
;pauseSounds(settings table)
+
* ''name:''
:Pause all sounds (no filter), or sounds that meet a combination of filters (name, key, and tag) intended to be paired with [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]].
+
: The name of the text edit.
 +
* ''fontName:''
 +
: The name of the font family to use (e.g. ''"Ubuntu Mono"'', ''"Courier New"'').
  
{| class="wikitable"
+
;Returns
!Required
+
* ''true'' on success, or raises an error if the text edit was not found.
!Key
 
!Value
 
! style="text-align:left;" |Purpose
 
|-
 
| style="text-align:center;" |No
 
|name
 
|<file name>
 
| style="text-align:left;" |
 
*Name of the media file.
 
|-
 
| style="text-align:center;" |No
 
|key
 
|<key>
 
| style="text-align:left;" |
 
* Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
*Pauses the play of current media files with the same "key" that have a different "name" or "url" while this media plays.
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseVideos|pauseVideos()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
;Example
 +
<syntaxhighlight lang="lua">
 +
setTextEditFont("myEditor", "Ubuntu Mono")
  
{{MudletVersion|4.??}}
+
-- Geyser usage
 +
myEditor:setFont("Ubuntu Mono")
 +
</syntaxhighlight>
  
; Example
+
==setTextEditFontSize, PR #8986==
 +
;setTextEditFontSize(name, size)
  
<syntaxhighlight lang="lua">
+
:Sets the font size of a text edit widget in points.
---- Table Parameter Syntax ----
 
  
-- Pause all playing sound files for this profile associated with the API
+
:See also: [[#setTextEditFont|setTextEditFont()]]
pauseSounds()
 
  
-- Pause all playing sounds matching the rugby mp3 name
+
{{MudletVersion|4.21}}
getPlayingSounds({name = "167124__patricia-mcmillen__rugby-club-in-spain.mp3"})
 
  
-- Pause all playing sound matching the unique key of "rugby"
+
;Parameters
getPlayingSounds({
+
* ''name:''
    name = nil  -- nil lines are optional, no need to use
+
: The name of the text edit.
    , key = "rugby" -- key
+
* ''size:''
    , tag = nil  -- nil lines are optional, no need to use
+
: The font size in points.
})
 
</syntaxhighlight>
 
  
==pauseVideos, PR #7721 closed ==
+
;Returns
;pauseVideos(settings table)
+
* ''true'' on success, or raises an error if the text edit was not found.
:Pause all videos (no filter), or videos that meet a combination of filters (name, key, and tag) intended to be paired with [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]].
 
  
{| class="wikitable"
+
;Example
! Required
+
<syntaxhighlight lang="lua">
!Key
+
setTextEditFontSize("myEditor", 14)
!Value
 
! style="text-align:left;" |Purpose
 
|-
 
| style="text-align:center;" |No
 
|name
 
|<file name>
 
| style="text-align:left;" |
 
*Name of the media file.
 
|-
 
| style="text-align:center;" |No
 
|key
 
|<key>
 
| style="text-align:left;" |
 
* Uniquely identifies media files with a "key" that is bound to their "name" or "url".
 
*Pauses the play of current media files with the same "key" that have a different "name" or "url" while this media plays.
 
|-
 
| style="text-align:center;" |No
 
|tag
 
|<tag>
 
| style="text-align:left;" |
 
*Helps categorize media.
 
|-
 
|}
 
  
See also: [[Manual:Miscellaneous_Functions#getPausedMusic|getPausedMusic()]], [[Manual:Miscellaneous_Functions#getPausedSounds|getPausedSounds()]], [[Manual:Miscellaneous_Functions#getPausedVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#getPlayingMusic|getPlayingMusic()]], [[Manual:Miscellaneous_Functions#getPlayingSounds|getPlayingSounds()]], [[Manual:Miscellaneous_Functions#getPlayingVideos|getPausedVideos()]], [[Manual:Miscellaneous_Functions#loadMusicFile|loadMusicFile()]], [[Manual:Miscellaneous_Functions#loadSoundFile|loadSoundFile()]], [[Manual:Miscellaneous_Functions#loadVideoFile|loadVideoFile()]], [[Manual:Miscellaneous_Functions#pauseMusic|pauseMusic()]], [[Manual:Miscellaneous_Functions#pauseSounds|pauseSounds()]], [[Manual:Miscellaneous_Functions#playMusicFile|playMusicFile()]], [[Manual:Miscellaneous_Functions#playSoundFile|playSoundFile()]], [[Manual:Miscellaneous_Functions#playVideoFile|playVideoFile()]], [[Manual:Miscellaneous_Functions#purgeMediaCache|purgeMediaCache()]], [[Manual:Miscellaneous_Functions#receiveMSP|receiveMSP()]], [[Manual:Miscellaneous_Functions#stopMusic|stopMusic()]], [[Manual:Miscellaneous_Functions#stopSounds|stopSounds()]], [[Manual:Miscellaneous_Functions#stopVideos|stopVideos()]], [[Manual:Scripting#MUD_Client_Media_Protocol|Mud Client Media Protocol]]
+
-- Geyser usage
 +
myEditor:setFontSize(14)
 +
</syntaxhighlight>
  
{{MudletVersion|4.??}}
+
==setTextEditTabMovesFocus, PR #8986==
 +
;setTextEditTabMovesFocus(name, state)
  
; Example
+
:Controls whether pressing Tab in the text edit inserts a tab character or moves focus to the next widget. By default, Tab inserts a tab
 +
character.
  
<syntaxhighlight lang="lua">
+
:See also: [[#createTextEdit|createTextEdit()]]
---- Table Parameter Syntax ----
 
  
-- Pause all playing video files for this profile associated with the API
+
{{MudletVersion|4.21}}
pauseVideos()
 
  
-- Pause playing the text mp4 by name
+
;Parameters
pauseVideos({name = "TextInMotion-VideoSample-1080p.mp4"})
+
* ''name:''
 +
: The name of the text edit.
 +
* ''state:''
 +
: ''true'' to have Tab move focus to the next widget, ''false'' to have Tab insert a tab character (default behavior).
  
-- Pause playing the unique video identified as "text"
+
;Returns
pauseVideos({
+
* ''true'' on success, or raises an error if the text edit was not found.
    name = nil  -- nil lines are optional, no need to use
+
 
    , key = "text" -- key
+
;Example
    , tag = nil  -- nil lines are optional, no need to use
+
<syntaxhighlight lang="lua">
})
+
-- make Tab move focus instead of inserting a tab
 +
setTextEditTabMovesFocus("myEditor", true)
 +
 
 +
-- Geyser usage
 +
myEditor:setTabMovesFocus(true)
 
</syntaxhighlight>
 
</syntaxhighlight>
==getCustomLoginTextId, PR #3952 open==
 
;getCustomLoginTextId()
 
  
Returns the Id number of the custom login text setting from the profile's preferences. Returns ''0'' if the option is disabled or a number greater than that for the item in the table; note it is possible if using an old saved profile in the future that the number might be higher than expected. As a design policy decision it is not permitted for a script to change the setting, this function is intended to allow a script or package to check that the setting is what it expects.
+
---
 +
And here's the event documentation that should be added to the Events section (if one exists on Area 51), or noted alongside the functions:
  
Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined ''doLogin()'' function, a replacement for which is shown below.
+
==sysTextEditDeleted, PR #8986==
:See also: [[#getCharacterName|getCharacterName()]], [[#sendCharacterName|sendCharacterName()]], [[#sendCustomLoginText|sendCustomLoginText()]], [[#sendPassword|sendPassword()]].
 
  
{{note}} Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952
+
:Raised when a text edit widget is deleted via [[#deleteTextEdit|deleteTextEdit()]] or when the Geyser wrapper calls its ''type_delete'' method.
  
Only one custom login text has been defined initially:
+
;Arguments
{| class="wikitable"
+
* ''arg1:'' ''"sysTextEditDeleted"''
|+Predefined custom login texts
+
* ''arg2:'' The name of the deleted text edit.
|-
 
!Id!!Custom text!!Introduced in Mudlet version
 
|-
 
|1|| "connect {character name} {password}"||TBD
 
|}
 
 
 
The addition of further texts would be subject to negotiation with the Mudlet Makers.
 
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- A replacement for the default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
+
function onTextEditDeleted(event, name)
function doLogin()
+
echo("Text edit deleted: " .. name .. "\n")
  if getCustomLoginTextId() ~= 1 then
 
    -- We need this particular option but it is not permitted for a script to change the setting, it can only check what it is
 
    echo("\nUnable to login - please select the 'connect {character name} {password}` custom login option in the profile preferences.\n")
 
  else
 
    tempTime(2.0, [[sendCustomLoginText()]], 1)
 
  end
 
 
end
 
end
 +
registerAnonymousEventHandler("sysTextEditDeleted", onTextEditDeleted)
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==sendCharacterName, PR #3952 open==
 
;sendCharacterName()
 
  
Sends the name entered into the "Character name" field on the Connection Preferences form directly to the game server. Returns ''true'' unless there is nothing set in that entry in which case a ''nil'' and an error message will be returned instead.
+
==setBackgroundImage (updated), PR #8935==
  
Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined ''doLogin()'' function that may be replaced for more sophisticated requirements.
+
{{note}} As of Mudlet 4.21, [[#setBackgroundImage|setBackgroundImage()]] supports SVG files in addition to raster images (PNG, JPG, etc). Simply pass a path to an ''.svg''
:See also: [[#getCharacterName|getCharacterName()]], [[#sendCharacterPassword|sendCharacterPassword()]], [[#sendCustomLoginText|sendCustomLoginText()]], [[#getCustomLoginTextId|getCustomLoginTextId()]].
+
file. SVG backgrounds can then be transformed using [[#setSvgRotation|setSvgRotation()]], [[#setSvgShear|setSvgShear()]], and reset with
 +
[[#resetSvgTransform|resetSvgTransform()]]. SVG images are rendered at full resolution regardless of HiDPI scaling.
  
{{note}} Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952
+
;Example
 +
<syntaxhighlight lang="lua">
 +
-- set an SVG background on a label
 +
setBackgroundImage("myLabel", getMudletHomeDir() .. "/compass.svg", 4)
 +
 
 +
-- rotate it 45 degrees
 +
setSvgRotation("myLabel", 45)
 +
 
 +
-- Geyser usage
 +
myLabel:setBackgroundImage(getMudletHomeDir() .. "/compass.svg")
 +
myLabel:setSvgRotation(45)
 +
</syntaxhighlight>
 +
 
 +
==setSvgRotation, PR #8935==
 +
;setSvgRotation(labelName, angle)
 +
 
 +
:Sets the rotation angle for a label's SVG background image. The SVG is rotated around its center; label text and background color are unaffected. Requires the label to have an
 +
SVG background set via [[Manual:Lua_Functions#setBackgroundImage|setBackgroundImage()]].
  
== sendCharacterPassword, PR #3952 open==
+
:See also: [[#resetSvgRotation|resetSvgRotation()]], [[#setSvgShear|setSvgShear()]], [[#resetSvgTransform|resetSvgTransform()]]
;sendCharacterPassword()
 
  
Sends the password entered into the "Password" field on the Connection Preferences form directly to the game server. Returns ''true'' unless there is nothing set in that entry or it is too long after (or before) a connection was successfully made in which case a ''nil'' and an error message will be returned instead.
+
{{MudletVersion|4.21}}
  
Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined ''doLogin()'' function, reproduced below, that may be replaced for more sophisticated requirements.
+
;Parameters
:See also: [[#getCharacterName|getCharacterName()]], [[#sendCustomLoginText|sendCustomLoginText()]], [[#getCustomLoginTextId|getCustomLoginTextId()]], [[#sendCharacterName|sendCharacterName()]].
+
* ''labelName:''
 +
: The name of the label to rotate the SVG background for.
 +
* ''angle:''
 +
: Rotation angle in degrees (positive = clockwise).
  
{{note}} Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952
+
;Returns
 +
* ''true'' on success, or ''nil'' and an error message if the label is not found.
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- The default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
+
-- rotate the SVG background 45 degrees clockwise
function doLogin()
+
setSvgRotation("myLabel", 45)
  if getCharacterName() ~= "" then
+
 
    tempTime(2.0, [[sendCharacterName()]], 1)
+
-- rotate it upside down
    tempTime(3.0, [[sendCharacterPassword()]], 1)
+
setSvgRotation("myLabel", 180)
  end
+
 
end
+
-- Geyser usage
 +
myLabel:setSvgRotation(45)
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==sendCustomLoginText, PR #3952 open==
+
==resetSvgRotation, PR #8935==
;sendCustomLoginText()
+
;resetSvgRotation(labelName)
 +
 
 +
:Resets the SVG background image rotation to 0 degrees.
  
Sends the custom login text (which does NOT depend on the user's choice of GUI language) selected in the preferences for this profile. The {password} (and {character name} if present) fields will be replaced with the values entered into the "Password" and "Character name" fields on the Connection Preferences form and then sent directly to the game server. Returns ''true'' unless there is nothing set in either of those entries (though only if required for the character name) or it is too long after (or before) a connection was successfully made or if the custom login feature is disabled, in which case a ''nil'' and an error message will be returned instead.
+
:See also: [[#setSvgRotation|setSvgRotation()]], [[#resetSvgTransform|resetSvgTransform()]]
  
Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined ''doLogin()'' function, a replacement for which is shown below.
+
{{MudletVersion|4.21}}
:See also: [[#getCharacterName|getCharacterName()]], [[#sendCharacterName|sendCharacterName()]], [[#sendPassword|sendPassword()]], [[#getCustomLoginTextId|getCustomLoginTextId()]].
 
  
{{note}} Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952
+
;Parameters
 +
* ''labelName:''
 +
: The name of the label to reset the SVG rotation for.
  
Only one custom login text has been defined initially:
+
;Returns
{| class="wikitable"
+
* ''true'' on success, or ''nil'' and an error message if the label is not found.
|+Predefined custom login texts
 
|-
 
!Id!!Custom text!!Introduced in Mudlet version
 
|-
 
|1||"connect {character name} {password}"||TBD
 
|}
 
 
 
The addition of further texts would be subject to negotiation with the Mudlet Makers.
 
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- A replacement for the default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
+
resetSvgRotation("myLabel")
function doLogin()
+
 
  if getCustomLoginTextId() ~= 1 then
+
-- Geyser usage
    -- We need this particular option but it is not permitted for a script to change the setting, it can only check what it is
+
myLabel:resetSvgRotation()
    echo("\nUnable to login - please select the 'connect {character name} {password}` custom login option in the profile preferences.\n")
 
  else
 
    tempTime(2.0, [[sendCustomLoginText()]], 1)
 
  end
 
end
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
==setSvgShear, PR #8935==
 +
;setSvgShear(labelName, shearX, shearY)
  
==openMudletHomeDir, PR 8026, merged==
+
:Sets the shear (skew) for a label's SVG background image. The SVG is sheared around its center; label text and background color are unaffected. Requires the label to have an
;openMudletHomeDir()
+
SVG background set via [[Manual:Lua_Functions#setBackgroundImage|setBackgroundImage()]].
:Opens the current home directory of the current profile in your local system's file browser. This can be used to review or modify data stored there.
 
  
;See also:[[Manual:Lua_Functions#getMudletHomeDir|getMudletHomeDir()]]
+
:See also: [[#resetSvgShear|resetSvgShear()]], [[#setSvgRotation|setSvgRotation()]], [[#resetSvgTransform|resetSvgTransform()]]
 +
 
 +
{{MudletVersion|4.21}}
 +
 
 +
;Parameters
 +
* ''labelName:''
 +
: The name of the label to shear the SVG background for.
 +
* ''shearX:''
 +
: Horizontal shear factor.
 +
* ''shearY:''
 +
: Vertical shear factor.
 +
 
 +
;Returns
 +
* ''true'' on success, or ''nil'' and an error message if the label is not found.
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
openMudletHomeDir()
+
-- apply a horizontal skew to the SVG background
</syntaxhighlight>
+
setSvgShear("myLabel", 0.3, 0)
  
=Mudlet Object Functions=
+
-- apply both horizontal and vertical skew
: A collection of functions that manipulate Mudlet's scripting objects - triggers, aliases, and so forth.
+
setSvgShear("myLabel", 0.2, 0.1)
  
==createComposer PR #8114==
+
-- Geyser usage
 +
myLabel:setSvgShear(0.3, 0)
 +
</syntaxhighlight>
  
; ok = createComposer(title, text, callbackFunction)
+
==resetSvgShear, PR #8935==
 +
;resetSvgShear(labelName)
  
Creates a Composer dialog window with the given title and initial text, and registers a Lua function to handle the result. When the user clicks **Save** or **Cancel**, the Composer closes and your callback function is invoked with two arguments: the resulting text and a boolean indicating whether the user saved (true) or canceled editing (false).
+
:Resets the SVG background image shear to (0, 0).
  
;See also: [[Manual:Lua_Functions#getComposerText|getComposerText()]], [[Manual:Lua_Functions#setComposerText|setComposerText()]], [[Manual:Lua_Functions#getComposerTitle|getComposerTitle()]], [[Manual:Lua_Functions#setComposerTitle|setComposerTitle()]]
+
:See also: [[#setSvgShear|setSvgShear()]], [[#resetSvgTransform|resetSvgTransform()]]
  
{{MudletVersion|4.20}}
+
{{MudletVersion|4.21}}
  
 
;Parameters
 
;Parameters
* ''title:''
+
* ''labelName:''
: The title of the Composer window.
+
: The name of the label to reset the SVG shear for.
* ''text:'' 
 
: The initial text content in the Composer. You can use <code>\n</code> to start a new line, <code>\t</code> for tabulators, etc.
 
* ''callbackFunction:'' 
 
: A Lua function to call when the Composer closes. It will receive two parameters:
 
:* A string with the text the user entered.
 
:* A boolean value – `true` if the user clicked **Save**, `false` if they clicked **Cancel**.
 
  
 
;Returns
 
;Returns
* Boolean `true` if the Composer was successfully created, otherwise nil + error (for example, if another Composer is already open).
+
* ''true'' on success, or ''nil'' and an error message if the label is not found.
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Create a Composer window for editing a note
+
resetSvgShear("myLabel")
createComposer("Edit Note", "Default text", function(editedText, isSaved)
+
 
    if isSaved then
+
-- Geyser usage
        echo(f"Saved text: {editedText}\n")
+
myLabel:resetSvgShear()
    else
 
        echo("Edit was canceled.\n")
 
    end
 
end)
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==deleteAllNamedTriggers PR#7767==
+
==resetSvgTransform, PR #8935==
; deleteAllNamedTriggers(userName)
+
;resetSvgTransform(labelName)
  
:Deletes all named triggers and prevents them from matching. Information is deleted and cannot be retrieved.
+
:Resets all SVG transforms (rotation and shear) back to defaults, but preserves any SVG tint. This is a convenience function equivalent to calling both
 +
[[#resetSvgRotation|resetSvgRotation()]] and [[#resetSvgShear|resetSvgShear()]].
  
;See also: [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]], [[Manual:Lua_Functions#stopNamedTrigger|stopNamedTrigger()]]
+
:See also: [[#setSvgRotation|setSvgRotation()]], [[#setSvgShear|setSvgShear()]], [[#resetSvgRotation|resetSvgRotation()]], [[#resetSvgShear|resetSvgShear()]]
  
{{MudletVersion|4.20}}
+
{{MudletVersion|4.21}}
  
 
;Parameters
 
;Parameters
* ''userName:''
+
* ''labelName:''
: The user name the trigger was registered under.
+
: The name of the label to reset all SVG transforms for.
 +
 
 +
;Returns
 +
* ''true'' on success, or ''nil'' and an error message if the label is not found.
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
deleteAllNamedTriggers("Zooka") -- emergency stop or debugging situation, most likely.
+
-- reset all transforms at once
 +
resetSvgTransform("myLabel")
 +
 
 +
-- Geyser usage
 +
myLabel:resetSvgTransform()
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==deleteNamedTrigger PR#7767==
+
==getBorderColor, PR #8688 ==
; success = deleteNamedTrigger(userName, triggerName)
+
;getBorderColor()
  
:Deletes a named trigger with name triggerName and prevents it from matching any more. Information is deleted and cannot be retrieved.
+
:Returns the RGB values of the main window border color (the area outside the main console where the mapper, buttons, and other UI elements are placed).
  
;See also: [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]], [[Manual:Lua_Functions#stopNamedTrigger|stopNamedTrigger()]]
+
:See also: [[#setBorderColor|setBorderColor()]], [[#getBorderSizes|getBorderSizes()]], [[#getBackgroundColor|getBackgroundColor()]]
 
 
{{MudletVersion|4.20}}
 
  
;Parameters
 
* ''userName:''
 
: The user name the trigger was registered under.
 
* ''triggerName:''
 
: The name of the trigger to stop. Same used as when you called [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]]
 
 
;Returns
 
* true if successful, false if it didn't exist
 
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
local deleted = deleteNamedTrigger("Zooka", "automatic drinking trigger")
+
-- get the current border color
if deleted then
+
local r, g, b = getBorderColor()
  cecho("Drinking trigger deleted forever!")
+
echo(string.format("Border color is RGB(%d, %d, %d)\n", r, g, b))
else
 
  cecho("Drinking trigger doesn't exist and so could not be deleted.")
 
end
 
</syntaxhighlight>
 
  
 +
-- check if border is using default black color
 +
local r, g, b = getBorderColor()
 +
if r == 0 and g == 0 and b == 0 then
 +
  echo("Border is black - consider customizing it!\n")
 +
end
  
==getComposerText PR #8114==
+
-- store current color before changing it
 +
local oldR, oldG, oldB = getBorderColor()
 +
setBorderColor(50, 50, 50)
 +
-- later, restore the original color
 +
setBorderColor(oldR, oldG, oldB)
 +
</syntaxhighlight>
  
; text = getComposerText()
 
  
Returns the current text from the Composer window, if it is open.
+
==insertPopup, revised in PR #6925==
 
+
; insertPopup([windowName], text, {commands}, {hints}[{, tool-tips}][, useCurrentFormatElseDefault])
;See also: [[Manual:Lua_Functions#createComposer|createComposer()]], [[Manual:Lua_Functions#setComposerText|setComposerText()]]
+
:Creates text with a left-clickable link, and a right-click menu for more options at the end of the current line, like echo. The added text, upon being left-clicked, will do the first command in the list. Upon being right-clicked, it'll display a menu with all possible commands. The menu will be populated with hints, one for each line; if a tool-tips table is not provided the same hints will also be listed one-per-line as a tool-tip but if a matching number of tool-tips are provided they will be concatenated to provide a tool-tip when the text is hovered over by the pointer - these tool-tips can be ''rich-text'' to produce information formatted with additional content in the same manner as labels.
 
 
{{MudletVersion|4.20}}
 
  
 
;Parameters
 
;Parameters
* (none)
+
*''windowName:''
 +
:(optional) name of the window as a string to echo to. Use either ''main'' or omit for the main window, or the miniconsole's or user-window's name otherwise.
 +
*''text:''
 +
:the text string to display.
 +
*''{commands}:''
 +
:a table of lua code to do, in text strings or as functions (since Mudlet 4.11), i.e. <syntaxhighlight lang="lua" inline="">{[[send("hello")]], function() echo("hi!") end}</syntaxhighlight>.
 +
*''{hints}:''
 +
:a table of strings which will be shown on the right-click menu (and popup if no {tool-tips} table is provided). If a particular position in both the commands and hints table are both the empty string ''""'' but there is something in the tool-tips table, no entry for that position will be made in the context menu but the tool-tip can still display something which can include images or text.
 +
*''{tool-tips}:''
 +
:(optional) a table of possibly ''rich-text'' strings which will be shown on the popup if provided.
 +
*''useCurrentFormatElseDefault:''
 +
:(optional) a boolean value for using either the current formatting options (color, underline, italic and other effects) if ''true'' or the link default (blue underline) if ''false'', if omitted the default format is used.
  
;Returns
+
{{note}} Mudlet will distinguish between the optional tool-tips and the flag to switch between the standard link and the current text format by examining the type of the argument, as such this pair of arguments can be in either order.
* The text currently displayed in the Composer, or nil + error if the Composer is not open.
 
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- Retrieve and print the current text from the Composer
+
-- Create some text as a clickable with a popup menu, a left click will ''send "sleep"'':
local currentText = getComposerText()
+
insertPopup("activities to do", {function() send "sleep" end, function() send "sit" end, function() send "stand" end}, {"sleep", "sit", "stand"})
if currentText then
+
 
    echo(f"Current text in Composer: {currentText}\n")
+
-- alternatively, put commands as text (in [[ and ]] to use quotation marks inside)
else
+
insertPopup("activities to do", {[[send "sleep"]], [[send "sit"]], [[send "stand"]]}, {"sleep", "sit", "stand"})
    echo("No Composer is open.\n")
+
 
end
+
-- one can also provide helpful information
 +
 
 +
-- todo: an example with rich-text in the tool-tips(s)
 +
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
==selectAll, PR #8971==
 +
;selectAll(str, func)
 +
:Selects every instance of a string on the cursor's current line and executes a provided function for each one. Useful for applying formatting or other operations to repeated occurrences of a word or phrase.
 +
:See also: [[#selectString|selectString()]]
 +
;Parameters
 +
* ''str:''
 +
:The string to select every instance of.
 +
* ''func:''
 +
:The function to run for each selected instance of the string.
 +
;Example
 +
<syntaxhighlight lang="lua">
 +
-- bold every instance of "dragon" on the current line
 +
selectAll("dragon", function()
 +
  setBold(true)
 +
end)
 +
deselect()
 +
resetFormat()
 +
</syntaxhighlight>
  
==getComposerTitle PR #8114==
+
=Discord Functions=
 +
:All functions to customize the information Mudlet displays in Discord's rich presence interface. For an overview on how all of these functions tie in together, see our [[Special:MyLanguage/Manual:Scripting#Discord_Rich_Presence|Discord scripting overview]].
  
; title = getComposerTitle()
+
=Mud Client Media Protocol =
 +
:All GMCP functions to send sound and music events. For an overview on how all of these functions tie in together, see our [[Special:MyLanguage/Manual:Scripting#MUD_Client_Media_Protocol|MUD Client Media Protocol scripting overview]].
  
Returns the current title from the Composer window, if it is open.
+
== Client.Media.Spatial, PR #8452 open ==
  
;See also: [[Manual:Lua_Functions#createComposer|createComposer()]], [[Manual:Lua_Functions#setComposerTitle|setComposerTitle()]]
+
The Client.Media.Spatial family of GMCP packages extends the [[Manual:Scripting#Client.Media|Client.Media]] protocol to provide 3D positional audio capabilities. These packages allow games to create immersive spatial soundscapes with positioned audio sources and listener orientation.
  
 
{{MudletVersion|4.20}}
 
{{MudletVersion|4.20}}
  
;Parameters
+
=== Enabling Spatial Audio ===
* (none)
 
  
;Returns
+
Spatial audio requires the same settings as regular Client.Media:
* The current title of the Composer, or nil + error if the Composer is not open.
 
  
;Example
+
# The "Enable GMCP" box in the Miscellaneous section must be checked.
<syntaxhighlight lang="lua">
+
# The "Allow server to download and play media" box in the Game protocols section must be checked.
-- Print the Composer title
 
local currentTitle = getComposerTitle()
 
if currentTitle then
 
    echo(f"Composer title: {currentTitle}\n")
 
else
 
    echo("No Composer is open.\n")
 
end
 
</syntaxhighlight>
 
  
 +
=== Coordinate System ===
  
==getNamedTriggers PR#7767==
+
The spatial audio system uses a 3D coordinate system where:
; triggers = getNamedTriggers(userName)
+
* '''Azimuth''': Horizontal angle in degrees (0° = front, 90° = right, 180° = back, 270° = left)
 +
* '''Elevation''': Vertical angle in degrees (-90° = below, 0° = level, 90° = above)
 +
* '''Distance''': Distance from listener in arbitrary units (1.0 = close, higher values = farther)
  
:Returns a list of all the named triggers names as a table.
+
For listener positioning, a Cartesian coordinate system is used:
 +
* '''X''': Left/right position
 +
* '''Y''': Forward/back position 
 +
* '''Z''': Up/down position
  
;See also: [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]]
+
=== Playing Spatial Media ===
  
{{MudletVersion|4.20}}
+
Send Client.Media.Spatial.Play GMCP events to play positioned sound sources in 3D space.
  
;Parameters
+
{| class="wikitable"
* ''userName:''
+
|-
: The user name the triggers were registered under.
+
! Required !! Parameter !! Value !! Default !! Description
 
+
|-
;Returns
+
| Yes || "key" || <string> || || Unique identifier for this spatial audio source. Used for updates and stopping.
* a table of trigger names. { "automatic drinking trigger", "autoheal trigger" } for example. {} if none are registered
+
|-
 
+
| Yes || "name" || <file name> || || Name of the media file. May contain directory information (i.e. ambient/wind.wav).
;Example
+
|-
<syntaxhighlight lang="lua">
+
| Maybe || "url" || <url> || || Resource location where the media file may be downloaded. Only required if not using Client.Media.Default URL or if file is not cached.
  local triggers = getNamedTriggers("Zooka")
+
|-
  display(triggers)
+
| No || "volume" || 1 to 100 || 80 || Volume level relative to the master spatial audio volume.
  -- {}
+
|-
  registerNamedTriggers("Zooka", "Test1", "test string", "testFunction")
+
| No || "loops" || -1, or >= 1 || 1 || Number of times to loop the sound. -1 for infinite looping.
  triggers = getNamedTriggers("Zooka")
+
|-
  display(triggers)
+
| No || "position" || <array or object> || || 3D position of the sound source. See position formats below.
  -- { "Test1" }
+
|-
</syntaxhighlight>
+
| No || "occlusion" || 0.0 to 1.0 || 0.0 || Occlusion factor (0.0 = no occlusion, 1.0 = fully occluded/muffled).
 +
|-
 +
| No || "room" || <object> || || Room acoustics parameters. See room acoustics below.
 +
|}
  
 +
==== Position Formats ====
  
==registerNamedTrigger PR#7767==
+
Position can be specified as an array <code>[azimuth, elevation, distance]</code> or as an object:
; success = registerNamedTrigger(userName, triggerName, substring, functionReference, [expireAfter])
 
  
:Registers a named substring trigger with name triggerName. Named triggers are protected from duplication and can be stopped and resumed, unlike normal tempTriggers. A separate list is kept for each userName, to enforce name spacing and avoid collisions
+
<syntaxhighlight lang="text">
 +
// Array format
 +
Client.Media.Spatial.Play {
 +
  "key": "footsteps_player",
 +
  "name": "footsteps.wav",
 +
  "position": [45, 0, 2.5]
 +
}
  
;See also: [[Manual:Lua_Functions#tempTrigger|tempTrigger()]], [[Manual:Lua_Functions#stopNamedTrigger|stopNamedTrigger()]], [[Manual:Lua_Functions#resumeNamedTrigger|resumeNamedTrigger()]], [[Manual:Lua_Functions#deleteNamedTrigger|deleteNamedTrigger()]]
+
// Object format 
 +
Client.Media.Spatial.Play {
 +
  "key": "footsteps_player",
 +
  "name": "footsteps.wav",
 +
  "position": {
 +
    "azimuth": 45,
 +
    "elevation": 0,
 +
    "distance": 2.5
 +
  }
 +
}
 +
</syntaxhighlight>
  
{{MudletVersion|4.20}}
+
==== Room Acoustics ====
  
;Parameters
+
Room acoustics can enhance spatial realism by simulating reverb and reflections:
* ''userName:''
 
: The user name the trigger was registered under.
 
* ''triggerName:''
 
: The name of the trigger. Used to reference the trigger in other functions and prevent duplicates. Recommended to use descriptive names, "hp" is likely to collide with something else, "automatic drinking trigger" less so.
 
* ''substring:''
 
: The substring text to match.
 
* ''functionReference:''
 
: The function reference to run when the trigger matches. Can be the name of a function, "handlerFunction", or the lua function itself.
 
* ''expireAfter:''
 
: (optional) Delete trigger after a specified number of matches
 
;Returns
 
* true if successful, otherwise errors.
 
  
;Example
+
<syntaxhighlight lang="json">
<syntaxhighlight lang="lua">
+
Client.Media.Spatial.Play {
-- establish a named trigger called "automatic drinking trigger" which sends 'drink canteen' when thirsty
+
  "key": "cave_drip",
registerNamedTrigger("Zooka", "automatic drinking trigger", "You are thirsty.", function() send("drink canteen") end)
+
  "name": "water_drop.wav",
 +
  "position": [0, -45, 8],
 +
  "room": {
 +
    "dimensions": [20, 30, 5],
 +
    "reverb": 2.5,
 +
    "reflection": 1.8,
 +
    "material": "sheetrock"
 +
  }
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==resumeNamedTrigger PR#7767==
+
=== Updating Spatial Media ===
; success = resumeNamedTrigger(userName, triggerName)
 
  
:Resumes a named trigger with name triggerName and allows it to match again.
+
Send Client.Media.Spatial.Update GMCP events to modify properties of already playing spatial audio sources.
  
;See also: [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]], [[Manual:Lua_Functions#stopNamedTrigger|stopNamedTrigger()]]
+
{| class="wikitable"
 +
|-
 +
! Required !! Parameter !! Value !! Description
 +
|-
 +
| Yes || "key" || <string> || Unique identifier of the spatial audio source to update.
 +
|-
 +
| No || "position" || <array or object> || New 3D position for the sound source.
 +
|-
 +
| No || "volume" || 1 to 100 || New volume level.
 +
|-
 +
| No || "occlusion" || 0.0 to 1.0 || New occlusion factor.
 +
|}
  
{{MudletVersion|4.20}}
+
Example of moving a sound source:
 +
<syntaxhighlight lang="json">
 +
Client.Media.Spatial.Update {
 +
  "key": "footsteps_player",
 +
  "position": [90, 0, 3.0],
 +
  "volume": 60
 +
}
 +
</syntaxhighlight>
  
;Parameter
+
=== Stopping Spatial Media ===
* ''userName:''
 
: The user name the trigger was registered under.s
 
* ''triggerName:''
 
: The name of the trigger to resume. Same as used when you called [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]]
 
  
;Returns
+
Send Client.Media.Spatial.Stop GMCP events to stop spatial audio sources.
* true if successful, false if it didn't exist.
+
 
 +
{| class="wikitable"
 +
|-
 +
! Required !! Parameter !! Value !! Description
 +
|-
 +
| No || "key" || <string> || Unique identifier of the spatial audio source to stop. If omitted, stops all spatial audio.
 +
|}
  
;Example
+
Stop a specific source:
<syntaxhighlight lang="lua">
+
<syntaxhighlight lang="json">
local resumed = resumeNamedTrigger("Zooka", "automatic drinking trigger")
+
Client.Media.Spatial.Stop {
if resumed then
+
   "key": "footsteps_player"
   echo("Starting to automatically drink again.")
+
}
else
 
  echo("Drink trigger doesn't exist so cannot resume it.")
 
end
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==setComposerText PR #8114==
+
Stop all spatial audio:
 +
<syntaxhighlight lang="json">
 +
Client.Media.Spatial.Stop {}
 +
</syntaxhighlight>
  
; setComposerText(newText)
+
=== Listener Control ===
  
Sets the text content of the Composer window, if it is open.
+
Send Client.Media.Spatial.Listener GMCP events to control the listener's position and orientation in 3D space.
  
;See also: [[Manual:Lua_Functions#createComposer|createComposer()]], [[Manual:Lua_Functions#getComposerText|getComposerText()]]
+
{| class="wikitable"
 +
|-
 +
! Required !! Parameter !! Value !! Description
 +
|-
 +
| No || "position" || <array or object> || Listener position in 3D space [x, y, z] or {x, y, z}.
 +
|-
 +
| No || "rotation" || <array or object> || Listener rotation [yaw, pitch, roll] or {yaw, pitch, roll} in degrees.
 +
|}
  
{{MudletVersion|4.20}}
+
==== Listener Position ====
  
;Parameters
+
Position uses Cartesian coordinates:
* ''newText:'' 
 
: The text to display in the Composer. You can use <code>\n</code> to start a new line, <code>\t</code> for tabulators, etc.
 
  
;Returns
+
<syntaxhighlight lang="text">
* Boolean `true` if the Title was successfully set, or nil + error if no Composer is open.
+
// Array format: [x, y, z]
 +
Client.Media.Spatial.Listener {
 +
  "position": [5.0, -2.0, 1.5]
 +
}
  
;Example
+
// Object format
<syntaxhighlight lang="lua">
+
Client.Media.Spatial.Listener {
-- Change the Composer text dynamically
+
  "position": {
setComposerText("Updated text for the Composer")
+
    "x": 5.0,
 +
    "y": -2.0,
 +
    "z": 1.5
 +
  }
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==setComposerTitle PR #8114==
+
==== Listener Rotation ====
  
; setComposerTitle(newTitle)
+
Rotation controls where the listener is facing:
  
Sets the title of the Composer window, if it is open.
+
<syntaxhighlight lang="text">
 +
// Array format: [yaw, pitch, roll]
 +
Client.Media.Spatial.Listener {
 +
  "rotation": [180, -10, 0]
 +
}
  
;See also: [[Manual:Lua_Functions#createComposer|createComposer()]], [[Manual:Lua_Functions#getComposerTitle|getComposerTitle()]]
+
// Object format
 
+
Client.Media.Spatial.Listener {
{{MudletVersion|4.20}}
+
  "rotation": {
 +
    "yaw": 180,
 +
    "pitch": -10,
 +
    "roll": 0
 +
  }
 +
}
 +
</syntaxhighlight>
  
;Parameters
+
=== Usage Examples ===
* ''newTitle:'' 
 
: The title to display in the Composer.
 
  
;Returns
+
==== Basic Positioned Sound ====
* Boolean `true` if the Title was successfully set, or nil + error if no Composer is open.
+
<syntaxhighlight lang="json">
 
+
Client.Media.Spatial.Play {
;Example
+
  "key": "sword_clash",
<syntaxhighlight lang="lua">
+
  "name": "combat/sword_hit.wav",
-- Change the Composer title dynamically
+
  "position": [30, 0, 2],
setComposerTitle("Declaration of Independence")
+
  "volume": 85
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
==== Moving Ambient Sound ====
 +
<syntaxhighlight lang="text">
 +
// Start a moving creature sound
 +
Client.Media.Spatial.Play {
 +
  "key": "wolf_howl",
 +
  "name": "creatures/wolf_howl.wav",
 +
  "position": [-90, 10, 5],
 +
  "loops": 3
 +
}
  
==stopAllNamedTrigger PR#7767==
+
// Update its position as it moves
; stopAllNamedTrigger(userName)
+
Client.Media.Spatial.Update {
 
+
  "key": "wolf_howl",
:Stops all named triggers for userName and prevents them from firing any more. Information is retained and triggers can be resumed.
+
  "position": [-45, 5, 3]
 
+
}
;See also: [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]], [[Manual:Lua_Functions#stopNamedTrigger|stopNamedTrigger()]], [[Manual:Lua_Functions#resumeNamedTrigger|resumeNamedTrigger()]]
+
</syntaxhighlight>
 
 
{{MudletVersion|4.20}}
 
  
;Example
+
==== Environmental Audio with Room Acoustics ====
<syntaxhighlight lang="lua">
+
<syntaxhighlight lang="json">
stopAllNamedTriggers("Zooka") -- emergency stop situation, most likely.
+
Client.Media.Spatial.Play {
 +
  "key": "cathedral_organ",
 +
  "name": "music/organ_chord.wav",
 +
  "position": [0, 15, 20],
 +
  "volume": 70,
 +
  "room": {
 +
    "dimensions": [40, 80, 15],
 +
    "reverb": 3.0,
 +
    "reflection": 2.2,
 +
    "material": "sheetrock"
 +
  }
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==stopNamedTrigger PR#7767==
+
==== Dynamic Listener Movement ====
; success = stopNamedTrigger(userName, triggerName)
+
<syntaxhighlight lang="text">
 +
// Player turns to face north and moves forward
 +
Client.Media.Spatial.Listener {
 +
  "position": [0, 5, 0],
 +
  "rotation": [0, 0, 0]
 +
}
  
:Stops a named trigger with name triggerName and prevents it from firing any more. Information is stored so it can be resumed later if desired.
+
// Player turns to look northeast and up slightly
 +
Client.Media.Spatial.Listener {
 +
  "rotation": [45, 15, 0]
 +
}
 +
</syntaxhighlight>
  
;See also: [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]], [[Manual:Lua_Functions#resumeNamedTrigger|resumeNamedTrigger()]]
+
{{Note}} Spatial audio provides the most immersive experience when used with headphones or properly positioned stereo speakers. The 3D positioning effects may be less apparent with poor audio hardware.
  
{{MudletVersion|4.20}}
+
=== GMCP Spatial Audio Capability Detection ===
  
;Parameters
+
Mudlet provides three GMCP messages for server developers to detect and query spatial audio capabilities. These allow servers to adapt their audio content based on the client's actual capabilities and current settings.
* ''userName:''
+
 
: The user name the event handler was registered under.
+
==== Client.Media.Spatial.Capabilities ====
* ''triggerName:''
 
: The name of the trigger to stop. Same as used when you called [[Manual:Lua_Functions#registerNamedTrigger|registerNamedTrigger()]]
 
  
;Returns
+
Query the client's spatial audio capabilities to determine what features and formats are supported.
* true if successful, false if it didn't exist or was already stopped
 
  
;Example
+
'''Server sends:'''
<syntaxhighlight lang="lua">
+
<syntaxhighlight lang="json">
local stopped = stopNamedTrigger("Zooka", "automatic drinking trigger")
+
Client.Media.Spatial.Capabilities {}
if stopped then
 
  echo("No longer drinking automatically.")
 
else
 
  echo("Drinking trigger doesn't exist or already stopped; either way it won't fire any more.")
 
end
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
= Networking Functions=
+
'''Client responds with:'''
:A collection of functions for managing networking.
+
<syntaxhighlight lang="json">
 +
Client.Media.Spatial.Capabilities {
 +
  "version": "1.0",
 +
  "formats": ["wav", "mp3", "ogg", "flac", "aac", "m4a"],
 +
  "output_modes": ["stereo", "surround", "headphone"],
 +
  "room_materials": ["brick", "concrete", "wood", "metal", "glass", ...],
 +
  "max_sources": 32,
 +
  "distance_model": "inverse",
 +
  "coordinate_system": "spherical",
 +
  "features": {
 +
    "positioning": true,
 +
    "room_acoustics": true,
 +
    "occlusion": true,
 +
    "listener_control": true,
 +
    "test_tones": true,
 +
    "volume_control": true,
 +
    "loops": true
 +
  }
 +
}
 +
</syntaxhighlight>
  
=String Functions=
+
'''Response Fields:'''
:These functions are used to manipulate strings.
+
* '''version''': Protocol version (currently "1.0")
 +
* '''formats''': Array of supported audio file formats (detected at runtime based on Qt6 multimedia backend)
 +
* '''output_modes''': Available audio output configurations
 +
* '''room_materials''': Supported acoustic materials for room simulation
 +
* '''max_sources''': Maximum number of simultaneous spatial audio sources
 +
* '''distance_model''': Audio attenuation model used ("inverse")
 +
* '''coordinate_system''': Position coordinate system ("spherical" with azimuth/elevation/distance)
 +
* '''features''': Boolean flags indicating supported capabilities
  
=Table Functions=
+
===== Room Materials =====
:These functions are used to manipulate tables. Through them you can add to tables, remove values, check if a value is present in the table, check the size of a table, and more.
 
  
=Text to Speech Functions=
+
The room materials are baed on this list from [https://doc.qt.io/qt-6/qaudioroom.html#Material-enum Qt QAudioRoom's Material enum]. Mudlet is accepting the list of aliases as well.
: These functions are used to create sound from written words. Check out our [[Special:MyLanguage/Manual:Text-to-Speech|Text-To-Speech Manual]] for more detail on how this all works together.
 
 
 
=UI Functions=
 
:These functions are used to construct custom user GUIs. They deal mainly with miniconsole/label/gauge creation and manipulation as well as displaying or formatting information on the screen.
 
 
 
==getBorderColor, PR #8688 ==
 
;getBorderColor()
 
 
 
:Returns the RGB values of the main window border color (the area outside the main console where the mapper, buttons, and other UI elements are placed).
 
 
 
:See also: [[#setBorderColor|setBorderColor()]], [[#getBorderSizes|getBorderSizes()]], [[#getBackgroundColor|getBackgroundColor()]]
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
-- get the current border color
 
local r, g, b = getBorderColor()
 
echo(string.format("Border color is RGB(%d, %d, %d)\n", r, g, b))
 
 
 
-- check if border is using default black color
 
local r, g, b = getBorderColor()
 
if r == 0 and g == 0 and b == 0 then
 
  echo("Border is black - consider customizing it!\n")
 
end
 
 
 
-- store current color before changing it
 
local oldR, oldG, oldB = getBorderColor()
 
setBorderColor(50, 50, 50)
 
-- later, restore the original color
 
setBorderColor(oldR, oldG, oldB)
 
</syntaxhighlight>
 
  
 +
{| class="wikitable"
 +
|-
 +
! Material !! Aliases !! Description
 +
|-
 +
| transparent || air || The side of the room is open and won't contribute to reflections or reverb.
 +
|-
 +
| acousticceilingtiles || acoustictiles || Acoustic tiles that suppress most reflections and reverb.
 +
|-
 +
| brickbare || brick || Bare brick wall.
 +
|-
 +
| brickpainted || || Painted brick wall.
 +
|-
 +
| concreteblockcoarse || concrete || Raw concrete wall
 +
|-
 +
| concreteblockpainted || concretepainted || Painted concrete wall
 +
|-
 +
| curtainheavy || curtain, fabric || Heavy curtain. Will mostly reflect low frequencies
 +
|-
 +
| fiberglassinsulation || fiberglass, carpet || Fiber glass insulation. Only reflects very low frequencies
 +
|-
 +
| glassthin || glass || Thin glass wall
 +
|-
 +
| glassthick || || Thick glass wall
 +
|-
 +
| grass || || Grass
 +
|-
 +
| linoleumonconcrete || linoleum || Linoleum floor
 +
|-
 +
| marble || || Marble floor
 +
|-
 +
| metal || || Metal
 +
|-
 +
| parquetonconcrete || parquet, parquetonfiberboard || Parquet wooden floor on concrete
 +
|-
 +
| plasterrough || plaster || Rough plaster
 +
|-
 +
| plastersmooth || || Smooth plaster
 +
|-
 +
| plywoodpanel || plywood || Plywood panel
 +
|-
 +
| polishedconcreteortile || tile, polishedconcrete || Polished concrete or tiles
 +
|-
 +
| sheetrock || stone || Rock
 +
|-
 +
| wateroricesurface || water, ice, wateroriceereflector || Water or ice
 +
|-
 +
| woodceiling || || Wooden ceiling
 +
|-
 +
| woodpanel || wood || Wooden panel
 +
|-
 +
| uniformmaterial || uniform || Artificial material giving uniform reflections on all frequencies
 +
|}
  
==insertPopup, revised in PR #6925==
+
==== Client.Media.Spatial.Settings ====
; insertPopup([windowName], text, {commands}, {hints}[{, tool-tips}][, useCurrentFormatElseDefault])
+
 
:Creates text with a left-clickable link, and a right-click menu for more options at the end of the current line, like echo. The added text, upon being left-clicked, will do the first command in the list. Upon being right-clicked, it'll display a menu with all possible commands. The menu will be populated with hints, one for each line; if a tool-tips table is not provided the same hints will also be listed one-per-line as a tool-tip but if a matching number of tool-tips are provided they will be concatenated to provide a tool-tip when the text is hovered over by the pointer - these tool-tips can be ''rich-text'' to produce information formatted with additional content in the same manner as labels.
+
Query the client's current spatial audio configuration and user settings.
  
;Parameters
+
'''Server sends:'''
*''windowName:''
+
<syntaxhighlight lang="json">
:(optional) name of the window as a string to echo to. Use either ''main'' or omit for the main window, or the miniconsole's or user-window's name otherwise.
+
Client.Media.Spatial.Settings {}
*''text:''
+
</syntaxhighlight>
:the text string to display.
 
*''{commands}:''
 
:a table of lua code to do, in text strings or as functions (since Mudlet 4.11), i.e. <syntaxhighlight lang="lua" inline="">{[[send("hello")]], function() echo("hi!") end}</syntaxhighlight>.
 
*''{hints}:''
 
:a table of strings which will be shown on the right-click menu (and popup if no {tool-tips} table is provided). If a particular position in both the commands and hints table are both the empty string ''""'' but there is something in the tool-tips table, no entry for that position will be made in the context menu but the tool-tip can still display something which can include images or text.
 
*''{tool-tips}:''
 
:(optional) a table of possibly ''rich-text'' strings which will be shown on the popup if provided.
 
*''useCurrentFormatElseDefault:''
 
:(optional) a boolean value for using either the current formatting options (color, underline, italic and other effects) if ''true'' or the link default (blue underline) if ''false'', if omitted the default format is used.
 
  
{{note}} Mudlet will distinguish between the optional tool-tips and the flag to switch between the standard link and the current text format by examining the type of the argument, as such this pair of arguments can be in either order.
+
'''Client responds with:'''
 +
<syntaxhighlight lang="json">
 +
Client.Media.Spatial.Settings {
 +
  "master_volume": 80,
 +
  "listener": {
 +
    "position": [0, 0, 0],
 +
    "rotation": [0, 0, 0]
 +
  },
 +
  "room": {
 +
    "dimensions": [10, 10, 4],
 +
    "reverb_gain": 0.3,
 +
    "reflection_gain": 0.5,
 +
    "reverb_time": 1.0,
 +
    "reverb_brightness": 0.0
 +
  }
 +
}
 +
</syntaxhighlight>
  
;Example
+
'''Response Fields:'''
<syntaxhighlight lang="lua">
+
* '''master_volume''': Current master volume (0-100)
-- Create some text as a clickable with a popup menu, a left click will ''send "sleep"'':
+
* '''listener.position''': 3D listener position [x, y, z] in Cartesian coordinates
insertPopup("activities to do", {function() send "sleep" end, function() send "sit" end, function() send "stand" end}, {"sleep", "sit", "stand"})
+
* '''listener.rotation''': Listener orientation [yaw, pitch, roll] in degrees
 
+
* '''room.dimensions''': Room size [width, height, depth] in meters
-- alternatively, put commands as text (in [[ and ]] to use quotation marks inside)
+
* '''room.reverb_gain''': Reverberation intensity (0.0-5.0)
insertPopup("activities to do", {[[send "sleep"]], [[send "sit"]], [[send "stand"]]}, {"sleep", "sit", "stand"})
+
* '''room.reflection_gain''': Early reflection intensity (0.0-5.0)
 +
* '''room.reverb_time''': Reverberation decay time in seconds (0.0-20.0)
 +
* '''room.reverb_brightness''': Reverb frequency bias (-1.0 to 1.0)
  
-- one can also provide helpful information
+
==== Client.Media.Spatial.Status ====
  
-- todo: an example with rich-text in the tool-tips(s)
+
Query the current status of active spatial audio sources managed by the server.
  
 +
'''Server sends:'''
 +
<syntaxhighlight lang="json">
 +
Client.Media.Spatial.Status {}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==setWindowWrapHangingIndent, merged PR #7714==
+
'''Client responds with:'''
 
+
<syntaxhighlight lang="json">
;setWindowWrapHangingIndent(windowName, indentSize)
+
Client.Media.Spatial.Status {
 
+
  "engine_initialized": true,
:Sets how many spaces the second and all subsequent line(s) of text from a wrapped line will be indented.
+
  "source_count": 2,
 
+
  "max_sources": 32,
;See also: [[#setWindowWrap|setWindowWrap()]], [[#setWindowWrapIndent|setWindowWrapIndent()]]
+
  "active_sources": [
 
+
    {
{{MudletVersion|https://github.com/Mudlet/Mudlet/pull/7714}}
+
      "key": "ambient_forest",
 
+
      "status": "playing",
;Parameters
+
      "position": [45, 0, 5],
* ''windowName:''
+
      "volume": 60,
: Name of the "main" console or user-created miniconsole which you want to be wrapped differently. If you want to wrap the main window, use windowName "main".
+
      "occlusion": 0.0,
* ''indentSize:''
+
      "size": 1.0,
: Number of spaces which hanging wrapped lines are prefixed with.
+
      "loops": -1
 
+
    },
;Example
+
    {
<syntaxhighlight lang="lua">
+
      "key": "footsteps",
-- |Make wrapped text indent
+
      "status": "paused",
-- |  like this. (Keep going
+
      "position": [-90, -10, 2],
-- |  until a linebreak.)
+
      "volume": 80,
 
+
      "occlusion": 0.5,
setWindowWrap("main", 25)
+
      "size": 0.5,
setWindowWrapIndent("main", 0)          -- First line indent
+
      "loops": 1
setWindowWrapHangingIndent("main", 2)   -- subsequent line(s)
+
    }
</syntaxhighlight>
+
   ]
 +
}
 +
</syntaxhighlight>
  
==setWindowWrapIndent, merged PR #7714==
+
'''Response Fields:'''
 +
* '''engine_initialized''': Whether the spatial audio engine is ready
 +
* '''source_count''': Number of currently active sources
 +
* '''max_sources''': Maximum supported sources
 +
* '''active_sources''': Array of source objects with current state
 +
** '''key''': Server-assigned source identifier
 +
** '''status''': Current playback state ("playing", "paused", "stopped")
 +
** '''position''': Source position [azimuth, elevation, distance] in spherical coordinates
 +
** '''volume''': Current volume level (0-100)
 +
** '''occlusion''': Occlusion/obstruction level (0.0-4.0)
 +
** '''size''': Source spatial size (0.0+, affects audio spread)
 +
** '''loops''': Loop count (-1 for infinite, 0 for stopped, >0 for remaining loops)
  
;setWindowWrapIndent(windowName, indentSize)
+
=Supported Protocols=
  
:Sets how many spaces the first line of text from a wrapped line will be indented.  
+
== MXP FRAME and DEST Tags, PR #8577 4.21 ==
  
;See also: [[#setWindowWrap|setWindowWrap()]], [[#setWindowWrapHangingIndent|setWindowWrapHangingIndent()]]
+
MXP FRAME and DEST tags allow MUD servers to create multi-window layouts, directing game output to separate panels within Mudlet. This enables rich interfaces with dedicated areas for chat, inventory, status, and more.
  
{{MudletVersion|https://github.com/Mudlet/Mudlet/pull/7714}}
+
{{MudletVersion|4.21}}
  
;Parameters
+
=== Overview ===
* ''windowName:''
 
: Name of the "main" console or user-created miniconsole which you want to be wrapped differently. If you want to wrap the main window, use windowName "main".
 
* ''indentSize:''
 
: Number of spaces which wrapped lines are prefixed with.
 
  
;Example
+
FRAME creates a new window panel that can display game content.
<syntaxhighlight lang="lua">
 
-- |  Make wrapped text indent
 
-- |indent like this. (Only
 
-- |first line indented.)
 
  
setWindowWrap("main", 25)
+
DEST (destination) redirects subsequent text to a specific frame.
setWindowWrapIndent("main", 2)          -- First line indent
 
setWindowWrapHangingIndent("main", 0)  -- subsequent line(s)
 
</syntaxhighlight>
 
  
=Discord Functions=
+
=== FRAME Tag ===
:All functions to customize the information Mudlet displays in Discord's rich presence interface. For an overview on how all of these functions tie in together, see our [[Special:MyLanguage/Manual:Scripting#Discord_Rich_Presence|Discord scripting overview]].
 
  
=Mud Client Media Protocol =
+
Creates a named frame where content can be directed.
:All GMCP functions to send sound and music events. For an overview on how all of these functions tie in together, see our [[Special:MyLanguage/Manual:Scripting#MUD_Client_Media_Protocol|MUD Client Media Protocol scripting overview]].
 
  
== Client.Media.Spatial, PR #8452 ==
+
==== Basic Syntax ====
  
The Client.Media.Spatial family of GMCP packages extends the [[Manual:Scripting#Client.Media|Client.Media]] protocol to provide 3D positional audio capabilities. These packages allow games to create immersive spatial soundscapes with positioned audio sources and listener orientation.
+
<syntaxhighlight lang="xml">
 +
<FRAME name="frameName" title="Frame Title" align="left" width="25%" height="100%">
 +
</syntaxhighlight>
  
{{MudletVersion|4.20}}
+
==== Attributes ====
 
 
=== Enabling Spatial Audio ===
 
 
 
Spatial audio requires the same settings as regular Client.Media:
 
 
 
# The "Enable GMCP" box in the Miscellaneous section must be checked.
 
# The "Allow server to download and play media" box in the Game protocols section must be checked.
 
 
 
=== Coordinate System ===
 
 
 
The spatial audio system uses a 3D coordinate system where:
 
* '''Azimuth''': Horizontal angle in degrees (0° = front, 90° = right, 180° = back, 270° = left)
 
* '''Elevation''': Vertical angle in degrees (-90° = below, 0° = level, 90° = above)
 
* '''Distance''': Distance from listener in arbitrary units (1.0 = close, higher values = farther)
 
 
 
For listener positioning, a Cartesian coordinate system is used:
 
* '''X''': Left/right position
 
* '''Y''': Forward/back position 
 
* '''Z''': Up/down position
 
 
 
=== Playing Spatial Media ===
 
 
 
Send Client.Media.Spatial.Play GMCP events to play positioned sound sources in 3D space.
 
  
 
{| class="wikitable"
 
{| class="wikitable"
 +
! Attribute !! Required !! Description !! Default
 +
|-
 +
| NAME || Yes || Unique identifier for the frame || -
 +
|-
 +
| TITLE || No || Display title shown in the frame's tab || Same as NAME
 +
|-
 +
| INTERNAL || No || Frame appears inside the main window || Yes (default)
 
|-
 
|-
! Required !! Parameter !! Value !! Default !! Description
+
| EXTERNAL || No || Frame appears as a separate floating window || No
 
|-
 
|-
| Yes || "key" || <string> || || Unique identifier for this spatial audio source. Used for updates and stopping.
+
| FLOATING || No || Borderless frame without title bar || No
 
|-
 
|-
| Yes || "name" || <file name> || || Name of the media file. May contain directory information (i.e. ambient/wind.wav).
+
| ALIGN || No || Position: left, right, top, bottom || left
 
|-
 
|-
| Maybe || "url" || <url> || || Resource location where the media file may be downloaded. Only required if not using Client.Media.Default URL or if file is not cached.
+
| LEFT || No || Absolute horizontal position (pixels, %, or 'c' suffix) || -
 
|-
 
|-
| No || "volume" || 1 to 100 || 80 || Volume level relative to the master spatial audio volume.
+
| TOP || No || Absolute vertical position (pixels, %, or 'c' suffix) || -
 
|-
 
|-
| No || "loops" || -1, or >= 1 || 1 || Number of times to loop the sound. -1 for infinite looping.
+
| WIDTH || No || Frame width (pixels, %, or characters with 'c' suffix) || 25%
 
|-
 
|-
| No || "position" || <array or object> || || 3D position of the sound source. See position formats below.
+
| HEIGHT || No || Frame height (pixels, %, or characters with 'c' suffix) || 25%
 
|-
 
|-
| No || "occlusion" || 0.0 to 1.0 || 0.0 || Occlusion factor (0.0 = no occlusion, 1.0 = fully occluded/muffled).
+
| SCROLLING || No || Enable scrolling (YES/NO) || YES
 
|-
 
|-
| No || "room" || <object> || || Room acoustics parameters. See room acoustics below.
+
| ACTION || No || open (show), close (hide), or focus || open
 
|}
 
|}
  
==== Position Formats ====
+
==== Size Units ====
 +
 
 +
* '''Pixels''': <code>300px</code> or <code>300</code>
 +
* '''Percentage''': <code>25%</code> of available space
 +
* '''Characters''': <code>40c</code> for 40 characters width/height
  
Position can be specified as an array <code>[azimuth, elevation, distance]</code> or as an object:
+
==== CMUD Extension: DOCK ====
  
<syntaxhighlight lang="json">
+
{{Note|The DOCK attribute is a CMUD extension, not part of the official MXP 1.0 specification.}}
// Array format
 
Client.Media.Spatial.Play {
 
  "key": "footsteps_player",
 
  "name": "footsteps.wav",
 
  "position": [45, 0, 2.5]
 
}
 
  
// Object format 
+
<syntaxhighlight lang="xml">
Client.Media.Spatial.Play {
+
<FRAME name="tab2" INTERNAL align="client" DOCK="parentFrame">
  "key": "footsteps_player",
 
  "name": "footsteps.wav",
 
  "position": {
 
    "azimuth": 45,
 
    "elevation": 0,
 
    "distance": 2.5
 
  }
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==== Room Acoustics ====
+
When used with <code>align="client"</code>, the DOCK attribute creates a tabbed frame inside an existing frame.
  
Room acoustics can enhance spatial realism by simulating reverb and reflections:
+
==== Examples ====
  
<syntaxhighlight lang="json">
+
Create a left-aligned chat panel:
Client.Media.Spatial.Play {
+
<syntaxhighlight lang="xml">
  "key": "cave_drip",
+
<FRAME name="chat" title="Chat" align="left" width="30%">
  "name": "water_drop.wav",
 
  "position": [0, -45, 8],
 
  "room": {
 
    "dimensions": [20, 30, 5],
 
    "reverb": 2.5,
 
    "reflection": 1.8,
 
    "material": "sheetrock"
 
  }
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Updating Spatial Media ===
+
Create a status bar at the bottom:
 +
<syntaxhighlight lang="xml">
 +
<FRAME name="status" align="bottom" height="50">
 +
</syntaxhighlight>
  
Send Client.Media.Spatial.Update GMCP events to modify properties of already playing spatial audio sources.
+
Create a borderless floating frame:
 +
<syntaxhighlight lang="xml">
 +
<FRAME name="minimap" FLOATING width="200" height="200" LEFT="10" TOP="10">
 +
</syntaxhighlight>
  
{| class="wikitable"
+
Show an existing frame:
|-
+
<syntaxhighlight lang="xml">
! Required !! Parameter !! Value !! Description
+
<FRAME name="chat" action="open">
|-
+
</syntaxhighlight>
| Yes || "key" || <string> || Unique identifier of the spatial audio source to update.
 
|-
 
| No || "position" || <array or object> || New 3D position for the sound source.
 
|-
 
| No || "volume" || 1 to 100 || New volume level.
 
|-
 
| No || "occlusion" || 0.0 to 1.0 || New occlusion factor.
 
|}
 
  
Example of moving a sound source:
+
Close a frame:
<syntaxhighlight lang="json">
+
<syntaxhighlight lang="xml">
Client.Media.Spatial.Update {
+
<FRAME name="chat" action="close">
  "key": "footsteps_player",
 
  "position": [90, 0, 3.0],
 
  "volume": 60
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Stopping Spatial Media ===
+
=== DEST Tag ===
  
Send Client.Media.Spatial.Stop GMCP events to stop spatial audio sources.
+
Redirects text output to a named frame.
  
{| class="wikitable"
+
==== Syntax ====
|-
 
! Required !! Parameter !! Value !! Description
 
|-
 
| No || "key" || <string> || Unique identifier of the spatial audio source to stop. If omitted, stops all spatial audio.
 
|}
 
  
Stop a specific source:
+
<syntaxhighlight lang="xml">
<syntaxhighlight lang="json">
+
<DEST name="frameName">Text goes here</DEST>
Client.Media.Spatial.Stop {
 
  "key": "footsteps_player"
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Stop all spatial audio:
+
Or as a self-closing tag to set destination for all following text:
<syntaxhighlight lang="json">
+
<syntaxhighlight lang="xml">
Client.Media.Spatial.Stop {}
+
<DEST name="frameName">
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Listener Control ===
+
==== Attributes ====
 
 
Send Client.Media.Spatial.Listener GMCP events to control the listener's position and orientation in 3D space.
 
  
 
{| class="wikitable"
 
{| class="wikitable"
 +
! Attribute !! Required !! Description
 
|-
 
|-
! Required !! Parameter !! Value !! Description
+
| NAME || Yes || Target frame name (empty string returns to main window)
 
|-
 
|-
| No || "position" || <array or object> || Listener position in 3D space [x, y, z] or {x, y, z}.
+
| EOF || No || If present, clears all content in the frame before writing
 
|-
 
|-
| No || "rotation" || <array or object> || Listener rotation [yaw, pitch, roll] or {yaw, pitch, roll} in degrees.
+
| EOL || No || If present, clears the current line before writing
 
|}
 
|}
  
==== Listener Position ====
+
==== Examples ====
  
Position uses Cartesian coordinates:
+
Send text to a chat frame:
 +
<syntaxhighlight lang="xml">
 +
<DEST name="chat">Player says: Hello!</DEST>
 +
</syntaxhighlight>
  
<syntaxhighlight lang="json">
+
Clear frame and write new content:
// Array format: [x, y, z]
+
<syntaxhighlight lang="xml">
Client.Media.Spatial.Listener {
+
<DEST name="status" EOF>HP: 100/100  MP: 50/50</DEST>
  "position": [5.0, -2.0, 1.5]
+
</syntaxhighlight>
}
 
  
// Object format
+
Return output to main window:
Client.Media.Spatial.Listener {
+
<syntaxhighlight lang="xml">
  "position": {
+
<DEST name="">
    "x": 5.0,
 
    "y": -2.0,
 
    "z": 1.5
 
  }
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==== Listener Rotation ====
+
=== Complete Example ===
  
Rotation controls where the listener is facing:
+
A typical MXP sequence to set up a multi-panel interface:
  
<syntaxhighlight lang="json">
+
<syntaxhighlight lang="xml">
// Array format: [yaw, pitch, roll]
+
<!-- Create the frames -->
Client.Media.Spatial.Listener {
+
<FRAME name="chat" title="Chat" align="left" width="25%">
  "rotation": [180, -10, 0]
+
<FRAME name="status" title="Status" align="bottom" height="3c">
}
 
  
// Object format
+
<!-- Send content to chat frame -->
Client.Media.Spatial.Listener {
+
<DEST name="chat">
  "rotation": {
+
[Guild] Bob: Anyone want to group?
    "yaw": 180,
+
[Guild] Alice: Sure!
    "pitch": -10,
+
</DEST>
    "roll": 0
 
  }
 
}
 
</syntaxhighlight>
 
  
=== Usage Examples ===
+
<!-- Send content to status frame, clearing previous content -->
 +
<DEST name="status" EOF>HP: 100/100 | MP: 75/100 | XP: 45%</DEST>
  
==== Basic Positioned Sound ====
+
<!-- Return to main window for regular game output -->
<syntaxhighlight lang="json">
+
<DEST name="">
Client.Media.Spatial.Play {
+
You are standing in the town square.
  "key": "sword_clash",
 
  "name": "combat/sword_hit.wav",
 
  "position": [30, 0, 2],
 
  "volume": 85
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==== Moving Ambient Sound ====
+
=== Behavior Notes ===
<syntaxhighlight lang="json">
 
// Start a moving creature sound
 
Client.Media.Spatial.Play {
 
  "key": "wolf_howl",
 
  "name": "creatures/wolf_howl.wav",
 
  "position": [-90, 10, 5],
 
  "loops": 3
 
}
 
  
// Update its position as it moves
+
* Frames persist until explicitly closed with <code>action="close"</code>
Client.Media.Spatial.Update {
+
* Re-opening an existing frame shows it without changing its size or position (respects user customization)
  "key": "wolf_howl",
+
* Frame names are case-sensitive
  "position": [-45, 5, 3]
+
* Content sent via DEST inherits the formatting of the destination frame
}
+
* Frames reset on reconnect (don't persist between sessions)
</syntaxhighlight>
 
  
==== Environmental Audio with Room Acoustics ====
+
=== See Also ===
<syntaxhighlight lang="json">
 
Client.Media.Spatial.Play {
 
  "key": "cathedral_organ",
 
  "name": "music/organ_chord.wav",
 
  "position": [0, 15, 20],
 
  "volume": 70,
 
  "room": {
 
    "dimensions": [40, 80, 15],
 
    "reverb": 3.0,
 
    "reflection": 2.2,
 
    "material": "sheetrock"
 
  }
 
}
 
</syntaxhighlight>
 
  
==== Dynamic Listener Movement ====
+
* [[Manual:Lua_Functions#createMiniConsole|createMiniConsole()]] - Lua equivalent for creating sub-windows
<syntaxhighlight lang="json">
 
// Player turns to face north and moves forward
 
Client.Media.Spatial.Listener {
 
  "position": [0, 5, 0],
 
  "rotation": [0, 0, 0]
 
}
 
  
// Player turns to look northeast and up slightly
+
=Events =
Client.Media.Spatial.Listener {
+
:New or revised events that Mudlet can raise to inform a profile about changes. See [[Manual:Event_Engine#Mudlet-raised_events|Mudlet-raised events]] for the existing ones.
  "rotation": [45, 15, 0]
+
 
}
+
=UI Functions=
 +
:All functions that help you construct custom GUIs. They deal mainly with miniconsole/label/gauge creation and manipulation as well as displaying or formatting information on the screen.
 +
 
 +
==setTextFormat, PR #8983, open==
 +
;setTextFormat(windowName, r1, g1, b1, r2, g2, b2, bold, underline, italics, [strikeout], [overline], [reverse], [blink])
 +
: Sets current text format of selected window. This is a more convenient means to set all the individual features at once compared to using [[#setFgColor|setFgColor]](windowName, r,g,b), [[#setBold|setBold]](windowName, true), [[#setItalics|setItalics]](windowName, true), [[#setUnderline|setUnderline]](windowName, true), [[#setStrikeOut|setStrikeOut]](windowName, true).
 +
: See Also: [[Manual:Lua_Functions#getTextFormat|getTextFormat()]]
 +
 
 +
;Parameters
 +
* ''windowName''
 +
: Specify name of selected window. If empty string "" or "main" format will be applied to the main console
 +
* ''r1,g1,b1''
 +
: To color text background, give number values in RBG style
 +
* ''r2,g2,b2''
 +
: To color text foreground, give number values in RBG style
 +
* ''bold''
 +
: To format text bold, set to 1 or true, otherwise 0 or false
 +
* ''underline''
 +
: To underline text, set to 1 or true, otherwise 0 or false
 +
* ''italics''
 +
: To format text italic, set to 1 or true, otherwise 0 or false
 +
* ''strikeout''
 +
: (optional) To strike text out, set to 1 or true, otherwise 0 or false or simply no argument
 +
* ''overline''
 +
: (optional) To use overline, set to 1 or true, otherwise 0 or false or simply no argument
 +
* ''reverse''
 +
: (optional) To swap foreground and background colors, set to 1 or true, otherwise 0 or false or simply no argument
 +
* ''blink''
 +
: (optional) To make text blink, use "slow", "fast", or "none" (default). Requires "Enable blinking text" in Settings → Accessibility.
 +
 
 +
;Example:
 +
<syntaxhighlight lang="lua">
 +
--This script would create a mini text console and write with bold, struck-out, yellow foreground color and blue background color "This is a test".
 +
createMiniConsole( "con1", 0,0,300,100);
 +
setTextFormat("con1",0,0,255,255,255,0,true,0,false,1);
 +
echo("con1","This is a test")
 
</syntaxhighlight>
 
</syntaxhighlight>
  
{{Note}} Spatial audio provides the most immersive experience when used with headphones or properly positioned stereo speakers. The 3D positioning effects may be less apparent with poor audio hardware.
+
{{note}} In versions prior to 3.7.0 the error messages ''and this wiki'' were wrong in that they had the foreground color parameters as r1, g1 and b1 and the background ones as r2, g2 and b2.
  
=== GMCP Spatial Audio Capability Detection ===
+
=MudMaster Chat Protocol (MMCP)=
 +
:MMCP is a peer-to-peer protocol enabling out of band data to be sent to connected peers in the form of public or private chats, or general data.
 +
:See MMCP protocol documentation at: https://tintin.mudhalla.net/protocols/mmcp/
 +
:And at: https://mudstandards.org/mud/mmcp/
 +
:See also https://wiki.mudlet.org/w/Notes_on_MMCP
 +
{{MudletVersion| ?.??}}
  
Mudlet provides three GMCP messages for server developers to detect and query spatial audio capabilities. These allow servers to adapt their audio content based on the client's actual capabilities and current settings.
+
{{note}} pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/7765
  
==== Client.Media.Spatial.Capabilities ====
+
== Lua functions ==
 +
* Note for all functions using target as an argument, the argument can be the client chatname or ID of the client as seen in mmcp.displayClientList()
  
Query the client's spatial audio capabilities to determine what features and formats are supported.
+
===accept===
 +
;mmcp.accept(target)
 +
:Accepts an incoming connection request.
 +
;Parameters
 +
* ''target'':
 +
:* Incoming client name or ID.
  
'''Server sends:'''
+
{{note}} pending, not yet available in initial MMCP release.
<syntaxhighlight lang="json">
 
Client.Media.Spatial.Capabilities {}
 
</syntaxhighlight>
 
  
'''Client responds with:'''
+
===allowSnoop===
<syntaxhighlight lang="json">
+
;mmcp.allowSnoop(target)
Client.Media.Spatial.Capabilities {
+
:Toggles the Allow Snoop flag for a client, allowing them to initiate a snoop request which will forward them text you see from your game.
  "version": "1.0",
+
;Parameters
  "formats": ["wav", "mp3", "ogg", "flac", "aac", "m4a"],
+
* ''target'':
  "output_modes": ["stereo", "surround", "headphone"],
+
:* Client name or ID.
  "room_materials": ["brick", "concrete", "wood", "metal", "glass", ...],
+
 
  "max_sources": 32,
+
===call===
  "distance_model": "inverse",
+
;mmcp.call(host[, port])
  "coordinate_system": "spherical",
+
:Initiate an outgoing connection to another client.
  "features": {
+
;Parameters
    "positioning": true,
+
* ''host'':
    "room_acoustics": true,
+
:* IPv4 address or fully qualified domain name.
    "occlusion": true,
+
* ''port'':
    "listener_control": true,
+
:* (optional) Port to connect to. Default 4050.
    "test_tones": true,
+
 
    "volume_control": true,
+
;Example
    "loops": true
+
<syntaxhighlight lang="lua">
  }
+
local host = "1.2.3.4"
}
+
local port = 4050
 +
 
 +
mmcp.call(host, port)
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''Response Fields:'''
+
;You should see the following message:
* '''version''': Protocol version (currently "1.0")
+
<syntaxhighlight lang="text">
* '''formats''': Array of supported audio file formats (detected at runtime based on Qt6 multimedia backend)
+
[ CHAT ]  - Connecting to 1.2.3.4:4050...
* '''output_modes''': Available audio output configurations
+
[ CHAT ]  - Waiting for response from 1.2.3.4:4050...
* '''room_materials''': Supported acoustic materials for room simulation
+
[ CHAT ]  - Connection to ChatClient at 1.2.3.4:4050 accepted.
* '''max_sources''': Maximum number of simultaneous spatial audio sources
+
</syntaxhighlight>
* '''distance_model''': Audio attenuation model used ("inverse")
+
 
* '''coordinate_system''': Position coordinate system ("spherical" with azimuth/elevation/distance)
+
===chatAll===
* '''features''': Boolean flags indicating supported capabilities
+
;mmcp.chatAll(message)
 +
:Sends a message to all connected clients.
 +
;Parameters
 +
* ''message'':
 +
:* The message to send.
 +
 
 +
This message will have the format of:
 +
<Name> chats to everybody, '<message>'
  
===== Room Materials =====
+
You will see the message:
 +
You chat to everybody, '<message>'
  
The room materials are baed on this list from [https://doc.qt.io/qt-6/qaudioroom.html#Material-enum Qt QAudioRoom's Material enum]. Mudlet is accepting the list of aliases as well.
+
;Example
 +
<syntaxhighlight lang="lua">
 +
-- Alias: ChatAll
 +
-- Alias Pattern: ^chatAll (.*)
  
{| class="wikitable"
+
mmcp.chatAll(matches[2])
|-
+
</syntaxhighlight>
! Material !! Aliases !! Description
+
 
|-
+
===chatGroup===
| transparent || air || The side of the room is open and won't contribute to reflections or reverb.
+
;mmcp.chatGroup(group, message)
|-
+
:Sends a message to all clients in the specified group.
| acousticceilingtiles || acoustictiles || Acoustic tiles that suppress most reflections and reverb.
+
;Parameters
|-
+
* ''group'':
| brickbare || brick || Bare brick wall.
+
:* The group to send the message to.
|-
+
* ''message'':
| brickpainted || || Painted brick wall.
+
:* The message to send.
|-
+
 
| concreteblockcoarse || concrete || Raw concrete wall
+
The message will have the format of:
|-
+
<Name> chats to the group, '<message>'
| concreteblockpainted || concretepainted || Painted concrete wall
+
 
|-
+
You will see the message:
| curtainheavy || curtain, fabric || Heavy curtain. Will mostly reflect low frequencies
+
You chat to <<group>>, '<message>'
|-
+
 
| fiberglassinsulation || fiberglass, carpet || Fiber glass insulation. Only reflects very low frequencies
+
;Example
|-
+
<syntaxhighlight lang="lua">
| glassthin || glass || Thin glass wall
+
-- Alias: ChatGroup
|-
+
-- Alias Pattern: ^chatGroup ([a-zA-Z0-9]+) (.*)
| glassthick || || Thick glass wall
+
 
|-
+
mmcp.chatGroup(matches[2], matches[3])
| grass || || Grass
 
|-
 
| linoleumonconcrete || linoleum || Linoleum floor
 
|-
 
| marble || || Marble floor
 
|-
 
| metal || || Metal
 
|-
 
| parquetonconcrete || parquet, parquetonfiberboard || Parquet wooden floor on concrete
 
|-
 
| plasterrough || plaster || Rough plaster
 
|-
 
| plastersmooth || || Smooth plaster
 
|-
 
| plywoodpanel || plywood || Plywood panel
 
|-
 
| polishedconcreteortile || tile, polishedconcrete || Polished concrete or tiles
 
|-
 
| sheetrock || stone || Rock
 
|-
 
| wateroricesurface || water, ice, wateroriceereflector || Water or ice
 
|-
 
| woodceiling || || Wooden ceiling
 
|-
 
| woodpanel || wood || Wooden panel
 
|-
 
| uniformmaterial || uniform || Artificial material giving uniform reflections on all frequencies
 
|}
 
 
 
==== Client.Media.Spatial.Settings ====
 
 
 
Query the client's current spatial audio configuration and user settings.
 
 
 
'''Server sends:'''
 
<syntaxhighlight lang="json">
 
Client.Media.Spatial.Settings {}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''Client responds with:'''
+
===chatName===
<syntaxhighlight lang="json">
+
;mmcp.chatName([name])
Client.Media.Spatial.Settings {
+
:Sets or gets your current chat name visible to other clients.
  "master_volume": 80,
+
;Parameters
  "listener": {
+
* ''name'':
    "position": [0, 0, 0],
+
:* (optional) The new chat name to use.
    "rotation": [0, 0, 0]
+
;Returns
  },
+
:* If no name is specified, this function will return your current chat name.
  "room": {
 
    "dimensions": [10, 10, 4],
 
    "reverb_gain": 0.3,
 
    "reflection_gain": 0.5,
 
    "reverb_time": 1.0,
 
    "reverb_brightness": 0.0
 
  }
 
}
 
</syntaxhighlight>
 
  
'''Response Fields:'''
+
;Example
* '''master_volume''': Current master volume (0-100)
+
<syntaxhighlight lang="lua">
* '''listener.position''': 3D listener position [x, y, z] in Cartesian coordinates
+
-- Alias: ChatName
* '''listener.rotation''': Listener orientation [yaw, pitch, roll] in degrees
+
-- Alias Pattern: ^chatName (\S+)
* '''room.dimensions''': Room size [width, height, depth] in meters
 
* '''room.reverb_gain''': Reverberation intensity (0.0-5.0)
 
* '''room.reflection_gain''': Early reflection intensity (0.0-5.0)
 
* '''room.reverb_time''': Reverberation decay time in seconds (0.0-20.0)
 
* '''room.reverb_brightness''': Reverb frequency bias (-1.0 to 1.0)
 
  
==== Client.Media.Spatial.Status ====
+
mmcp.chatNAme(matches[2])
 +
</syntaxhighlight>
  
Query the current status of active spatial audio sources managed by the server.
+
===chatTo===
 +
;mmcp.chatTo(target, message)
 +
:Sends a message to a specific client.
 +
;Parameters
 +
* ''target'':
 +
:* Client name or ID.
 +
* ''message'':
 +
:* The message to send.
 +
 
 +
The target client will see the message:
 +
<Name> chats to you, '<message>'
 +
 
 +
You will see the message:
 +
You chat to <target>, '<message>'
 +
 
 +
;Example
 +
<syntaxhighlight lang="lua">
 +
-- Alias: ChatTo
 +
-- Alias Pattern: ^chatTo (.*?) (.*)
  
'''Server sends:'''
+
mmcp.chatTo(matches[2], matches[3])
<syntaxhighlight lang="json">
 
Client.Media.Spatial.Status {}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''Client responds with:'''
+
===deny===
<syntaxhighlight lang="json">
+
;mmcp.deny(target)
Client.Media.Spatial.Status {
+
:Denies an incoming connection request.
  "engine_initialized": true,
+
;Parameters
  "source_count": 2,
+
* ''target'':
  "max_sources": 32,
+
:* Client name or ID.
  "active_sources": [
+
 
    {
+
{{note}} pending, not yet available in initial MMCP release.
      "key": "ambient_forest",
+
 
      "status": "playing",
+
===disconnect===
      "position": [45, 0, 5],
+
;mmcp.disconnect(target)
      "volume": 60,
+
:Disconnects a connected client.
      "occlusion": 0.0,
+
;Parameters
      "size": 1.0,
+
* ''target'':
      "loops": -1
+
:* Client name or ID
    },
+
 
    {
+
===displayClientList===
      "key": "footsteps",
+
;mmcp.displayClientList()
      "status": "paused",
+
:Displays a table showing information about connected and pending clients.
      "position": [-90, -10, 2],
+
 
      "volume": 80,
+
;Example
      "occlusion": 0.5,
+
<syntaxhighlight lang="lua">
      "size": 0.5,
+
mmcp.displayClientList()
      "loops": 1
 
    }
 
  ]
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
'''Response Fields:'''
+
;You should see the following table
* '''engine_initialized''': Whether the spatial audio engine is ready
+
<syntaxhighlight lang="text">
* '''source_count''': Number of currently active sources
+
Id  Name                Address              Port  Group          Flags    ChatClient
* '''max_sources''': Maximum supported sources
+
==== ==================== ==================== ===== =============== ======== ================
* '''active_sources''': Array of source objects with current state
+
  1 ChatClient          1.2.3.4              4050                          Mudlet
** '''key''': Server-assigned source identifier
+
==== ==================== ==================== ===== =============== ======== ================
** '''status''': Current playback state ("playing", "paused", "stopped")
+
Color Key: Connected  Pending
** '''position''': Source position [azimuth, elevation, distance] in spherical coordinates
+
Flags: F - Firewall,       I - Ignored, P - Private, S - Serving
** '''volume''': Current volume level (0-100)
+
        n - Allow Snooping, N - Being Snooped
** '''occlusion''': Occlusion/obstruction level (0.0-4.0)
+
</syntaxhighlight>
** '''size''': Source spatial size (0.0+, affects audio spread)
 
** '''loops''': Loop count (-1 for infinite, 0 for stopped, >0 for remaining loops)
 
  
=Supported Protocols=
+
:* You may then use the mmcp lua commands referencing the client by their ID (1) or name (ChatClient)
  
== MXP FRAME and DEST Tags, PR #8577 ==
+
===emoteAll===
 +
;mmcp.emoteAll(message)
 +
:Sends an emote message to all connected clients.
 +
;Parameters
 +
* ''message'':
 +
:* The message to send.
  
MXP FRAME and DEST tags allow MUD servers to create multi-window layouts, directing game output to separate panels within Mudlet. This enables rich interfaces with dedicated areas for chat, inventory, status, and more.
+
Clients will see the message:
 +
<Name> <message>
  
{{MudletVersion|4.21}}
+
If you have enabled the "Prefix emote messages" option, you will see:
 +
You emote to everyone: '<Name> <message>'
  
=== Overview ===
+
Otherwise you will see:
 +
<Name> <message>
  
FRAME creates a new window panel that can display game content.
+
;Example
 +
<syntaxhighlight lang="lua">
 +
-- Alias: EmoteAll
 +
-- Alias Pattern: ^emoteAll (.*)
  
DEST (destination) redirects subsequent text to a specific frame.
+
local emoteStr = "says, '" .. matches[2] .. "'"
  
=== FRAME Tag ===
+
mmcp.emoteAll(emoteStr)
 +
</syntaxhighlight>
  
Creates a named frame where content can be directed.
+
===getClientFlags===
 +
;mmcp.getClientFlags(target)
 +
:Returns a string containing the client flags of a connected client.
 +
;Parameters
 +
* ''target'':
 +
:* Client name or ID.
 +
;Returns
 +
This string is an 8 character string where letters in the following positions have meaning:
 +
"12345678"
 +
*1: Reserved, blank
 +
*2: Reserved, blank
 +
*3: P if the connection is Private, otherwise blank
 +
*4: I if the connection is Ignored, otherwise blank
 +
*5: S if the client is being served, otherwise blank
 +
*6: F if the client is firewalled, otherwise blank
 +
*7: N if the client is snooping us, n if the client can snoop us, otherwise blank
 +
*8: Reserved, blank
  
==== Basic Syntax ====
+
===getClientList===
 +
;clientInfo = mmcp.getClientList()
 +
:Returns a lua table containing the following information for each connected client.
 +
;Returns
 +
*id: The ID of the client
 +
*name: The chat name of the client.
 +
*host: The hostname or IP address of the client.
 +
*port: The port the client (check if this is the reported port or port they connected from)
 +
*version: The MUD client and version of the client
  
<syntaxhighlight lang="xml">
+
;Example
<FRAME name="frameName" title="Frame Title" align="left" width="25%" height="100%">
+
<syntaxhighlight lang="lua">
 +
local clientList = mmcp.getClientList()
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==== Attributes ====
+
;The variable clientList will then contain:
 +
<syntaxhighlight lang="text">
 +
{ {
 +
    host = "1.2.3.4",
 +
    id = 1,
 +
    name = "ChatClient",
 +
    port = 4050,
 +
    version = "Mudlet"
 +
  } }
 +
</syntaxhighlight>
 +
 
 +
===ignore===
 +
;mmcp.ignore(target)
 +
:Toggles ignoring a client. You will not see chat messages from an ignored client.
 +
;Parameters
 +
* ''target'':
 +
:* Client name or ID.
 +
 
 +
===peek===
 +
;mmcp.peek(target)
 +
:Sends a request to the target client to peek at their connection list.
 +
;Parameters
 +
* ''target'':
 +
:* Client name or ID.
  
{| class="wikitable"
+
===ping===
! Attribute !! Required !! Description !! Default
+
;mmcp.ping(target)
|-
+
:Sends a ping request to a client.
| NAME || Yes || Unique identifier for the frame || -
+
;Parameters
|-
+
* ''target'':
| TITLE || No || Display title shown in the frame's tab || Same as NAME
+
:* Client name or ID.
|-
 
| INTERNAL || No || Frame appears inside the main window || Yes (default)
 
|-
 
| EXTERNAL || No || Frame appears as a separate floating window || No
 
|-
 
| FLOATING || No || Borderless frame without title bar || No
 
|-
 
| ALIGN || No || Position: left, right, top, bottom || left
 
|-
 
| LEFT || No || Absolute horizontal position (pixels, %, or 'c' suffix) || -
 
|-
 
| TOP || No || Absolute vertical position (pixels, %, or 'c' suffix) || -
 
|-
 
| WIDTH || No || Frame width (pixels, %, or characters with 'c' suffix) || 25%
 
|-
 
| HEIGHT || No || Frame height (pixels, %, or characters with 'c' suffix) || 25%
 
|-
 
| SCROLLING || No || Enable scrolling (YES/NO) || YES
 
|-
 
| ACTION || No || open (show), close (hide), or focus || open
 
|}
 
  
==== Size Units ====
+
===request===
 +
;mmcp.request(target)
 +
:Sends a request to the target client to request and connect to their public connections.
 +
:Mudlet will attempt to connect to each of the hosts returned by this command.
 +
;Parameters
 +
* ''target'':
 +
:* Client name or ID.
  
* '''Pixels''': <code>300px</code> or <code>300</code>
+
===sendSideChannel===
* '''Percentage''': <code>25%</code> of available space
+
;mmcp.sendSideChannel(channel, message)
* '''Characters''': <code>40c</code> for 40 characters width/height
+
:Sends an OOB (Out of band) message to all connected clients.
 
+
;Parameters
==== CMUD Extension: DOCK ====
+
* ''channel'':
 +
:* The channel to send the message on.
 +
* ''message'':
 +
:* The message to send.
  
{{Note|The DOCK attribute is a CMUD extension, not part of the official MXP 1.0 specification.}}
+
{{note}} This will only send to other Mudlet clients. Upon receipt of this message Mudlet will raise a sysMMCPSideChannelMessage containing
 +
the channel and message data.
  
<syntaxhighlight lang="xml">
+
;Example
<FRAME name="tab2" INTERNAL align="client" DOCK="parentFrame">
+
<syntaxhighlight lang="lua">
</syntaxhighlight>
+
-- myStats populated by prompt trigger
 +
local outStr = string.format("%s,%d,%d,%d,%d,%s",
 +
  mmcp.chatName(), myStats.hp, myStats.maxHp, myStats.mana, myStats.maxMana, myStats.buffs)
  
When used with <code>align="client"</code>, the DOCK attribute creates a tabbed frame inside an existing frame.
+
mmcp.sendSideChannel("stats", outStr)
  
==== Examples ====
+
-- Example event handling
 +
function handleStatsData(statsTable)
 +
  -- this should match the outStr format sent by mmcp.sendSideChannel
 +
  local name, hp, maxHp, mana, maxMana, buffs = string.match(statsTable, "(%S+),(%d+),(%d+),(%d+),(%d+),(.*)")
  
Create a left-aligned chat panel:
+
  -- do things with this data
<syntaxhighlight lang="xml">
+
end
<FRAME name="chat" title="Chat" align="left" width="30%">
 
</syntaxhighlight>
 
  
Create a status bar at the bottom:
+
function VStats.eventHandler(event, ...)
<syntaxhighlight lang="xml">
+
  if event == "sysMMCPSideChannelMessage" then
<FRAME name="status" align="bottom" height="50">
+
    if arg[2] == "stats" then -- check if its actually for us, arg[2] should match "stats" provided to mmcp.sendSideChannel
</syntaxhighlight>
+
      handleStatsData(arg[3])
 +
    end
 +
  end
 +
end
  
Create a borderless floating frame:
+
registerAnonymousEventHandler("sysMMCPSideChannelMessage", "VStats.eventHandler")
<syntaxhighlight lang="xml">
 
<FRAME name="minimap" FLOATING width="200" height="200" LEFT="10" TOP="10">
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Show an existing frame:
+
===serve===
<syntaxhighlight lang="xml">
+
;mmcp.serve(target)
<FRAME name="chat" action="open">
+
:Toggles the serve flag for a client, this clients chat messages will be sent to all other connected clients.
</syntaxhighlight>
+
;Parameters
 +
* ''target'':
 +
:* Client name or ID.
  
Close a frame:
+
===setDoNotDisturb===
<syntaxhighlight lang="xml">
+
;mmcp.setDoNotDisturb(target)
<FRAME name="chat" action="close">
+
:Toggles the Do Not Disturb flag, any incoming connections will be automatically denied.
</syntaxhighlight>
+
{{note}} pending, not yet available in initial MMCP release.
  
=== DEST Tag ===
+
===setGroup===
 +
;mmcp.setGroup(target, group)
 +
:Assigns a client to a chat group.
 +
;Parameters
 +
* ''target'':
 +
:* Client name or ID.
 +
* ''group'':
 +
:* The group name.
  
Redirects text output to a named frame.
+
{{note}} The group name is only visible to you.
  
==== Syntax ====
+
;Example
 +
<syntaxhighlight lang="lua">
 +
-- Alias: SetGroup
 +
-- Alias Pattern: ^setGroup ([a-zA-Z0-9]+) ?(.*)
  
<syntaxhighlight lang="xml">
+
mmcp.setGroup(matches[2], matches[3])
<DEST name="frameName">Text goes here</DEST>
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Or as a self-closing tag to set destination for all following text:
+
===setPrivate===
<syntaxhighlight lang="xml">
+
;mmcp.setPrivate(target)
<DEST name="frameName">
+
:Toggles the private flag for a client. Any clients set as private will not be listed in peek or connection requests.
</syntaxhighlight>
+
;Parameters
 
 
==== Attributes ====
 
 
 
{| class="wikitable"
 
! Attribute !! Required !! Description
 
|-
 
| NAME || Yes || Target frame name (empty string returns to main window)
 
|-
 
| EOF || No || If present, clears all content in the frame before writing
 
|-
 
| EOL || No || If present, clears the current line before writing
 
|}
 
 
 
==== Examples ====
 
 
 
Send text to a chat frame:
 
<syntaxhighlight lang="xml">
 
<DEST name="chat">Player says: Hello!</DEST>
 
</syntaxhighlight>
 
 
 
Clear frame and write new content:
 
<syntaxhighlight lang="xml">
 
<DEST name="status" EOF>HP: 100/100  MP: 50/50</DEST>
 
</syntaxhighlight>
 
 
 
Return output to main window:
 
<syntaxhighlight lang="xml">
 
<DEST name="">
 
</syntaxhighlight>
 
 
 
=== Complete Example ===
 
 
 
A typical MXP sequence to set up a multi-panel interface:
 
 
 
<syntaxhighlight lang="xml">
 
<!-- Create the frames -->
 
<FRAME name="chat" title="Chat" align="left" width="25%">
 
<FRAME name="status" title="Status" align="bottom" height="3c">
 
 
 
<!-- Send content to chat frame -->
 
<DEST name="chat">
 
[Guild] Bob: Anyone want to group?
 
[Guild] Alice: Sure!
 
</DEST>
 
 
 
<!-- Send content to status frame, clearing previous content -->
 
<DEST name="status" EOF>HP: 100/100 | MP: 75/100 | XP: 45%</DEST>
 
 
 
<!-- Return to main window for regular game output -->
 
<DEST name="">
 
You are standing in the town square.
 
</syntaxhighlight>
 
 
 
=== Behavior Notes ===
 
 
 
* Frames persist until explicitly closed with <code>action="close"</code>
 
* Re-opening an existing frame shows it without changing its size or position (respects user customization)
 
* Frame names are case-sensitive
 
* Content sent via DEST inherits the formatting of the destination frame
 
* Frames reset on reconnect (don't persist between sessions)
 
 
 
=== See Also ===
 
 
 
* [[Manual:Lua_Functions#createMiniConsole|createMiniConsole()]] - Lua equivalent for creating sub-windows
 
 
 
==OSC 8: Hyperlink Protocol==
 
 
 
OSC 8 is a standardized terminal escape sequence that enables clickable hyperlinks in terminal output. Mudlet extends the OSC 8 standard with enhanced styling and interactivity features, providing a safer and more powerful alternative to [[Manual:Supported_Protocols#MXP | MXP]].
 
 
 
{{MudletVersion|4.20}}
 
 
 
===Quick Start===
 
 
 
Want to try OSC 8 hyperlinks immediately? Send this command in Mudlet:
 
 
 
say !osc8-docs
 
 
 
 
 
[[File:OSC 8 Hyperlinks.png|411px|frameless]]
 
 
 
===Feature Overview===
 
 
 
{| class="wikitable"
 
! Feature !! Description !! Version
 
|-
 
| [[#Basic Links|Basic Links]] || Send commands, pre-fill input, open URLs || {{MudletVersion|4.20}}
 
|-
 
| [[#Tier_2:_Visual_Styling|Visual Styling]] || Colors, fonts, decorations || {{MudletVersion|4.20}}
 
|-
 
| [[#Interactive States|Interactive States]] || Hover, active, visited effects || {{MudletVersion|4.20}}
 
|-
 
| [[#Tooltips|Tooltips]] || Custom hover text || {{MudletVersion|4.20}}
 
|-
 
| [[#Context Menus|Context Menus]] || Right-click menus || {{MudletVersion|4.20}}
 
|-
 
| [[#Visibility|Visibility]] || Auto-hide/reveal links || {{MudletVersion|4.21}}
 
|-
 
| [[#Spoilers|Spoilers]] || Click-to-reveal hidden text || {{MudletVersion|4.21}}
 
|-
 
| [[#Disabled Links|Disabled Links]] || Non-clickable display links || {{MudletVersion|4.21}}
 
|-
 
| [[#Selection|Selection]] || Stateful toggle links || {{MudletVersion|4.21}}
 
|-
 
| [[#Compact Syntax|Compact Syntax]] || Shorthand property names || {{MudletVersion|4.21}}
 
|-
 
| [[#Presets|Presets]] || Reusable style templates || {{MudletVersion|4.21}}
 
|}
 
 
 
----
 
 
 
==Tier 1: Fundamentals==
 
 
 
===Understanding OSC Sequences===
 
 
 
====Purpose====
 
 
 
OSC (Operating System Command) sequences are part of the ANSI escape sequence family. They allow terminals to receive structured commands from servers, including hyperlink definitions.
 
 
 
====How It Works====
 
 
 
# Server sends an escape sequence starting with <code>ESC ]</code> (escape + right bracket)
 
# The sequence contains command data (like a URL)
 
# The sequence ends with a String Terminator: <code>ESC \</code> (escape + backslash)
 
# The terminal processes the command and renders the result
 
 
 
====Key Characters====
 
 
 
{| class="wikitable"
 
! Character !! ASCII !! Hex !! Description
 
|-
 
| ESC || 27 || 0x1B || Escape character - starts all ANSI sequences
 
|-
 
| ] || 93 || 0x5D || Right bracket - identifies OSC sequences
 
|-
 
| \ || 92 || 0x5C || Backslash - with ESC forms String Terminator
 
|-
 
| ; || 59 || 0x3B || Semicolon - separates parameters
 
|}
 
 
 
{{Note}} "Note: Mudlet requires proper termination with either ST (ESC ) or BEL (0x07). Missing terminators cause text to buffer without displaying (with a 8196-byte safety limit)."
 
 
 
===Basic Links===
 
 
 
====Purpose====
 
 
 
Create clickable text that performs actions when clicked—sending commands to the game, pre-filling input, or opening web pages.
 
 
 
{{MudletVersion|4.20}}
 
 
 
====How It Works====
 
 
 
OSC 8 hyperlinks work like HTML tags with opening and closing sequences:
 
 
 
# '''Opening sequence''' defines the link target: <code>ESC ] 8 ; ; URI ESC \</code>
 
# '''Link text''' appears between sequences (can include ANSI formatting)
 
# '''Closing sequence''' ends the clickable region: <code>ESC ] 8 ; ; ESC \</code>
 
 
 
====Structure====
 
 
 
ESC ] 8 ; params ; URI ESC \ visible text ESC ] 8 ; ; ESC \
 
      │    │      │                              │
 
      │    │      └── Link target (URL/command)  │
 
      │    └── Optional parameters (unused)      │
 
      └── OSC 8 identifier                        └── Empty = close link
 
 
 
====URI Schemes====
 
 
 
{| class="wikitable"
 
! Scheme !! Action !! Example !! Capability Variable
 
|-
 
| <code>send:</code> || Immediately sends command to game || <code>send:look</code> || OSC_HYPERLINKS_SEND
 
|-
 
| <code>prompt:</code> || Places command in input line for editing || <code>prompt:cast fireball</code> || OSC_HYPERLINKS_PROMPT
 
|-
 
| <code>http:</code> / <code>https:</code> || Opens in default web browser || <code>https://mudlet.org</code> || OSC_HYPERLINKS
 
|-
 
| <code>ftp:</code> || Opens in default handler || <code>ftp://files.example.com</code> || OSC_HYPERLINKS
 
|}
 
 
 
====Examples====
 
 
 
'''Send a command:'''
 
ESC ] 8 ; ; send:look ESC \ Look ESC ] 8 ; ; ESC \
 
 
 
'''Pre-fill input:'''
 
ESC ] 8 ; ; prompt:cast%20fireball ESC \ Cast Fireball ESC ] 8 ; ; ESC \
 
 
 
'''Open webpage:'''
 
ESC ] 8 ; ; https://www.mudlet.org ESC \ Visit Mudlet ESC ] 8 ; ; ESC \
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS = "1"
 
USERVAR OSC_HYPERLINKS_SEND = "1"
 
USERVAR OSC_HYPERLINKS_PROMPT = "1"
 
 
 
===Percent Encoding===
 
 
 
====Purpose====
 
 
 
JSON configuration is passed as a URL parameter, requiring special characters to be percent-encoded per [https://datatracker.ietf.org/doc/html/rfc3986 RFC 3986].
 
 
 
====How It Works====
 
 
 
# Special characters are replaced with <code>%XX</code> where XX is the hex value
 
# The entire JSON config object must be encoded
 
# Spaces in commands use <code>%20</code>
 
 
 
====Common Encodings====
 
 
 
{| class="wikitable"
 
! Character !! Encoded !! When to Encode
 
|-
 
| Space || <code>%20</code> || In commands: <code>cast%20fireball</code>
 
|-
 
| <code>"</code> || <code>%22</code> || In JSON strings
 
|-
 
| <code>{</code> || <code>%7B</code> || JSON object start
 
|-
 
| <code>}</code> || <code>%7D</code> || JSON object end
 
|-
 
| <code>:</code> || <code>%3A</code> || JSON key-value separator
 
|-
 
| <code>,</code> || <code>%2C</code> || JSON element separator
 
|-
 
| <code>&</code> || <code>%26</code> || In web URL query strings
 
|-
 
| <code>#</code> || <code>%23</code> || In web URL fragments
 
|}
 
 
 
====What to Encode====
 
 
 
'''Always encode:'''
 
* The entire JSON object in the <code>config</code> parameter
 
* Spaces in command URIs
 
 
 
'''Never encode:'''
 
* URI scheme (<code>send:</code>, <code>https://</code>)
 
* Parameter structure (<code>?</code>, <code>=</code>, <code>&</code> in URL structure)
 
 
 
====Example====
 
 
 
'''Human-readable:'''
 
<syntaxhighlight lang="json">
 
{"style": {"color": "red"}}
 
</syntaxhighlight>
 
 
 
'''Percent-encoded:'''
 
%7B%22style%22%3A%7B%22color%22%3A%22red%22%7D%7D
 
 
 
'''Complete URI:'''
 
send:attack?config=%7B%22style%22%3A%7B%22color%22%3A%22red%22%7D%7D
 
 
 
====Encoding Tools====
 
 
 
* '''JavaScript:''' <code>encodeURIComponent()</code>
 
* '''Python:''' <code>urllib.parse.quote()</code>
 
* '''Lua:''' <code>socket.url.escape()</code> or custom implementation
 
 
 
----
 
 
 
==Tier 2: Visual Styling==
 
 
 
===JSON Configuration===
 
 
 
====Purpose====
 
 
 
Mudlet extends OSC 8 with JSON-based configuration for rich visual customization while maintaining standard protocol compatibility.
 
 
 
{{MudletVersion|4.20}}
 
 
 
====How It Works====
 
 
 
# Append <code>?config=</code> to your URI
 
# Follow with percent-encoded JSON
 
# Mudlet parses the JSON and applies styling/behavior
 
 
 
====Structure====
 
 
 
SCHEME:COMMAND?config=PERCENT_ENCODED_JSON
 
 
 
====Configuration Object====
 
 
 
<syntaxhighlight lang="json">
 
{
 
  "style": { },      // Visual appearance
 
  "tooltip": "",    // Hover text
 
  "menu": [ ],      // Right-click options
 
  "visibility": { }, // Auto-hide/reveal
 
  "selection": { },  // Toggle state
 
  "spoiler": false,  // Hidden text
 
  "disabled": false  // Non-clickable
 
}
 
</syntaxhighlight>
 
 
 
===Style Properties===
 
 
 
====Purpose====
 
 
 
Control the visual appearance of hyperlink text including colors, fonts, and decorations.
 
 
 
====Properties====
 
 
 
{| class="wikitable"
 
! Property !! Type !! Description !! Example Values
 
|-
 
| <code>color</code> || String || Text foreground color || <code>"red"</code>, <code>"#ff0000"</code>, <code>"rgb(255,0,0)"</code>
 
|-
 
| <code>bg</code> || String || Background color || <code>"blue"</code>, <code>"#000080"</code>
 
|-
 
| <code>bold</code> || Boolean || Bold weight || <code>true</code>, <code>false</code>
 
|-
 
| <code>italic</code> || Boolean || Italic style || <code>true</code>, <code>false</code>
 
|-
 
| <code>underline</code> || Boolean/String || Underline style || <code>true</code>, <code>"wavy"</code>, <code>"dotted"</code>, <code>"dashed"</code>
 
|-
 
| <code>overline</code> || Boolean/String || Overline style || <code>true</code>, <code>"wavy"</code>, <code>"dotted"</code>, <code>"dashed"</code>
 
|-
 
| <code>strikethrough</code> || Boolean/String || Strikethrough style || <code>true</code>, <code>"wavy"</code>, <code>"dotted"</code>, <code>"dashed"</code>
 
|-
 
| <code>text-decoration-color</code> || String || Color for underline/overline/strikethrough || <code>"red"</code>, <code>"#ff0000"</code>
 
|}
 
 
 
{{Note}} OSC 8 links are '''not''' underlined by default (unlike traditional hyperlinks). Add <code>"underline": true</code> explicitly if desired.
 
 
 
====Color Formats====
 
 
 
Mudlet supports all standard color formats via Qt's QColor parser:
 
 
 
'''Named colors''' (147+ CSS3/X11 names):
 
"color": "red"
 
"color": "dodgerblue"
 
"color": "darkslategray"
 
 
 
'''Hexadecimal:'''
 
"color": "#ff0000"    // 6-digit
 
"color": "#f00"        // 3-digit shorthand
 
 
 
'''RGB function:'''
 
"color": "rgb(255, 0, 0)"      // Integer 0-255
 
"color": "rgb(100%, 0%, 0%)"  // Percentage
 
 
 
====Examples====
 
 
 
'''Red bold text:'''
 
<syntaxhighlight lang="json">
 
{"style": {"color": "red", "bold": true}}
 
</syntaxhighlight>
 
 
 
'''Blue background with white text:'''
 
<syntaxhighlight lang="json">
 
{"style": {"color": "white", "bg": "blue"}}
 
</syntaxhighlight>
 
 
 
'''Wavy green underline:'''
 
<syntaxhighlight lang="json">
 
{"style": {"underline": "wavy", "text-decoration-color": "green"}}
 
</syntaxhighlight>
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_STYLE_BASIC = "1"
 
 
 
===Interactive States===
 
 
 
====Purpose====
 
 
 
Add dynamic visual feedback with pseudo-class states, similar to CSS hover effects in web browsers.
 
 
 
{{MudletVersion|4.20}}
 
 
 
====How It Works====
 
 
 
# Define base style properties at the top level of <code>style</code>
 
# Add state-specific overrides as nested objects
 
# When a state activates, its properties override the base
 
# Multiple states can be active; higher priority wins
 
 
 
====Available States====
 
 
 
{| class="wikitable"
 
! State !! Trigger !! Priority !! Use Case
 
|-
 
| <code>active</code> || Mouse button pressed || 1 (highest) || Click feedback
 
|-
 
| <code>hover</code> || Mouse cursor over link || 2 || Highlight on mouseover
 
|-
 
| <code>focus-visible</code> || Keyboard focus indicator || 3 || Accessibility
 
|-
 
| <code>focus</code> || Any focus (keyboard/mouse) || 4 || Focus ring
 
|-
 
| <code>visited</code> || Link clicked previously || 5 || Show history
 
|-
 
| <code>selected</code> || Selection state active || 6 || Toggle indicators
 
|-
 
| <code>disabled</code> || Link is disabled || 7 || Unavailable options
 
|-
 
| <code>link</code> || Unvisited link || 8 || Distinct unvisited style
 
|-
 
| <code>any-link</code> || Always applies || 9 (lowest) || Universal styling
 
|}
 
 
 
{{Note}} The <code>visited</code> state resets when Mudlet restarts (session-scoped).
 
 
 
====Examples====
 
 
 
'''Hover color change:'''
 
<syntaxhighlight lang="json">
 
{
 
  "style": {
 
    "color": "blue",
 
    "hover": {"color": "red"}
 
  }
 
}
 
</syntaxhighlight>
 
 
 
'''Button-like press effect:'''
 
<syntaxhighlight lang="json">
 
{
 
  "style": {
 
    "bg": "green",
 
    "color": "white",
 
    "hover": {"bg": "lightgreen"},
 
    "active": {"bg": "darkgreen"}
 
  }
 
}
 
</syntaxhighlight>
 
 
 
'''Link vs visited states:'''
 
<syntaxhighlight lang="json">
 
{
 
  "style": {
 
    "link": {"color": "blue", "underline": true},
 
    "visited": {"color": "purple", "strikethrough": true}
 
  }
 
}
 
</syntaxhighlight>
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_STYLE_STATES = "1"
 
 
 
----
 
 
 
==Tier 3: Enhanced Interactivity==
 
 
 
===Tooltips===
 
 
 
====Purpose====
 
 
 
Display custom hover text to provide guidance, hints, or additional information about a link.
 
 
 
{{MudletVersion|4.20}}
 
 
 
====How It Works====
 
 
 
# Add <code>"tooltip"</code> property to JSON configuration
 
# Text appears when user hovers over the link
 
# Replaces default system tooltip
 
 
 
====Configuration====
 
 
 
{| class="wikitable"
 
! Property !! Type !! Description !! Default
 
|-
 
| <code>tooltip</code> || String || Custom hover text || Auto-generated based on link type
 
|}
 
 
 
====Examples====
 
 
 
'''Simple tooltip:'''
 
<syntaxhighlight lang="json">
 
{"tooltip": "Click to attack the enemy"}
 
</syntaxhighlight>
 
 
 
'''Tooltip with styling:'''
 
<syntaxhighlight lang="json">
 
{
 
  "style": {"color": "red", "bold": true},
 
  "tooltip": "Warning: This action cannot be undone!"
 
}
 
</syntaxhighlight>
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_TOOLTIP = "1"
 
 
 
===Context Menus===
 
 
 
====Purpose====
 
 
 
Provide multiple actions from a single link via right-click menus, enabling rich interaction without cluttering the display.
 
 
 
{{MudletVersion|4.20}}
 
 
 
[[File:OSC 8 Hyperlink Menus.mov|frameless]]
 
 
 
====How It Works====
 
 
 
# Left-click executes the primary URI action
 
# Right-click displays the context menu
 
# Each menu item can have its own command
 
# Use <code>"-"</code> to create visual separators
 
 
 
====Configuration====
 
 
 
{| class="wikitable"
 
! Property !! Type !! Description
 
|-
 
| <code>menu</code> || Array || Array of menu items
 
|}
 
 
 
'''Menu item format:'''
 
<syntaxhighlight lang="json">
 
{"Label Text": "scheme:command"}
 
</syntaxhighlight>
 
 
 
'''Separator:'''
 
<syntaxhighlight lang="json">
 
"-"
 
</syntaxhighlight>
 
 
 
====Examples====
 
 
 
'''Basic combat menu:'''
 
<syntaxhighlight lang="json">
 
{
 
  "menu": [
 
    {"Attack": "send:attack"},
 
    {"Defend": "send:defend"},
 
    "-",
 
    {"Flee": "send:flee"}
 
  ]
 
}
 
</syntaxhighlight>
 
 
 
'''Menu with tooltip:'''
 
<syntaxhighlight lang="json">
 
{
 
  "menu": [
 
    {"Fireball": "send:cast fireball"},
 
    {"Ice Bolt": "send:cast ice bolt"},
 
    "-",
 
    {"Heal": "send:cast heal"}
 
  ],
 
  "tooltip": "Right-click for spell options"
 
}
 
</syntaxhighlight>
 
 
 
{{Note}} Links with menus automatically show "Right-click for menu" tooltip if no custom tooltip is provided.
 
 
 
[[File:Screenshot 2025-10-17 at 7.48.38 AM.png|640x350px|frameless]]
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_MENU = "1"
 
 
 
----
 
 
 
==Tier 4: Dynamic Behavior==
 
 
 
===Visibility===
 
 
 
====Purpose====
 
 
 
Automatically hide or reveal hyperlink text based on time delays or user triggers. Perfect for temporary hints, dismissible prompts, or progressive disclosure interfaces.
 
 
 
{{MudletVersion|4.21}}
 
 
 
[[File:OSC 8 Hyperlink Visibility.mov|frameless]]
 
 
 
====How It Works====
 
 
 
'''Conceal action:'''
 
# Link appears normally when printed
 
# User clicks the link (starts delay timer if set) OR expire trigger fires
 
# After delay/trigger, link text is replaced with spaces
 
 
 
'''Reveal action:'''
 
# Link text replaced with spaces when printed (starts hidden)
 
# Delay timer starts immediately OR expire trigger fires
 
# Link text becomes visible
 
 
 
'''Reveal-then-conceal:'''
 
# Link starts hidden
 
# Reveals via delay or expire trigger
 
# After revealed, clicking hides it
 
 
 
====Configuration====
 
 
 
{| class="wikitable"
 
! Property !! Type !! Description !! Default
 
|-
 
| <code>action</code> || String/Array || '''Required.''' <code>"conceal"</code>, <code>"reveal"</code>, or <code>["reveal", "conceal"]</code> || —
 
|-
 
| <code>delay</code> || Number || Milliseconds before action (1000 = 1 second) || —
 
|-
 
| <code>expire</code> || Object || Triggers that immediately perform the action || —
 
|-
 
| <code>wholeline</code> || Boolean || Conceal entire line, not just link text (primarily for deletion) || <code>false</code>
 
|}
 
 
 
'''Expire triggers:'''
 
{| class="wikitable"
 
! Property !! Type !! Description !! Default
 
|-
 
| <code>input</code> || Boolean || Trigger when user sends any command || <code>false</code>
 
|-
 
| <code>prompt</code> || Boolean || Trigger on GA/EOR prompt from server || <code>false</code>
 
|-
 
| <code>output</code> || Boolean || Trigger when new output arrives after idle gap || <code>false</code>
 
|-
 
| <code>outputDelay</code> || Number || Milliseconds of silence defining idle gap || <code>500</code>
 
|}
 
 
 
====Examples====
 
 
 
'''Click to dismiss after delay:'''
 
<syntaxhighlight lang="json">
 
{"visibility": {"action": "conceal", "delay": 500}}
 
</syntaxhighlight>
 
 
 
'''Hide on next server prompt:'''
 
<syntaxhighlight lang="json">
 
{"visibility": {"action": "conceal", "expire": {"prompt": true}}}
 
</syntaxhighlight>
 
 
 
'''Hide when user sends a command:'''
 
<syntaxhighlight lang="json">
 
{"visibility": {"action": "conceal", "expire": {"input": true}}}
 
</syntaxhighlight>
 
 
 
'''Delayed hint (reveal after 5 seconds):'''
 
<syntaxhighlight lang="json">
 
{"visibility": {"action": "reveal", "delay": 5000}}
 
</syntaxhighlight>
 
 
 
'''Appear then click to dismiss:'''
 
<syntaxhighlight lang="json">
 
{"visibility": {"action": ["reveal", "conceal"], "delay": 3000}}
 
</syntaxhighlight>
 
 
 
'''Delete entire line on click:'''
 
<syntaxhighlight lang="json">
 
{"visibility": {"action": "conceal", "delay": 0, "wholeline": true}}
 
</syntaxhighlight>
 
 
 
[[File:Hyperlink Visibility.png|frameless|Try "say !osc8-docs" to try this demo in Mudlet]]
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_VISIBILITY = "1"
 
 
 
===Spoilers===
 
 
 
====Purpose====
 
 
 
Hide text content until clicked, with automatic styling and tooltip generation. A simpler alternative to visibility-based concealment for hints, secrets, and puzzle answers.
 
 
 
{{MudletVersion|4.21}}
 
 
 
[[File:OSC 8 Hyperlink Spoilers.mov|frameless]]
 
 
 
====How It Works====
 
 
 
# Link appears with background color matching text (invisible)
 
# Automatic "Click to reveal" tooltip guides the user
 
# First click reveals the hidden text
 
# Subsequent clicks execute the link function (unless disabled)
 
# Tooltip clears after reveal
 
 
 
====Configuration====
 
 
 
{| class="wikitable"
 
! Property !! Type !! Description !! Default
 
|-
 
| <code>spoiler</code> || Boolean || Enable spoiler behavior || <code>false</code>
 
|-
 
| <code>disabled</code> || Boolean || Prevent function execution after reveal || <code>false</code>
 
|}
 
 
 
====Automatic Styling====
 
 
 
Spoiler background is automatically generated based on the original background's luminance:
 
 
 
'''Formula:''' Y = 0.2126×R + 0.7152×G + 0.0722×B
 
 
 
{| class="wikitable"
 
! Luminance !! Background Generation
 
|-
 
| < 0.1 (very dark) || Fixed <code>rgb(40, 40, 40)</code>
 
|-
 
| < 0.5 (dark) || Original background lightened 140%
 
|-
 
| ≥ 0.5 (light) || Original background darkened 140%
 
|}
 
 
 
====Examples====
 
 
 
'''Basic spoiler:'''
 
<syntaxhighlight lang="json">
 
{"spoiler": true}
 
</syntaxhighlight>
 
 
 
'''Reveal-only spoiler (no function execution):'''
 
<syntaxhighlight lang="json">
 
{"spoiler": true, "disabled": true}
 
</syntaxhighlight>
 
 
 
'''Spoiler with custom revealed styling:'''
 
<syntaxhighlight lang="json">
 
{
 
  "spoiler": true,
 
  "style": {"color": "yellow", "italic": true}
 
}
 
</syntaxhighlight>
 
 
 
'''Spoiler with menu:'''
 
<syntaxhighlight lang="json">
 
{
 
  "spoiler": true,
 
  "menu": [
 
    {"Show Again": "send:hint"},
 
    {"Disable Hints": "send:hints off"}
 
  ]
 
}
 
</syntaxhighlight>
 
 
 
====Spoilers vs Visibility====
 
 
 
{| class="wikitable"
 
! Feature !! Spoilers !! Visibility
 
|-
 
| Automatic background || Yes (color-matched) || No (manual styling)
 
|-
 
| Automatic tooltip || Yes ("Click to reveal") || No (manual config)
 
|-
 
| First-click behavior || Reveal only || Execute function
 
|-
 
| State persistence || Per-instance || N/A
 
|-
 
| Best for || Hints, answers, secrets || Temporary UI elements
 
|}
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_SPOILER = "1"
 
 
 
===Disabled Links===
 
 
 
====Purpose====
 
 
 
Display links that cannot execute their function when clicked. Useful for locked content, unavailable options, or reveal-only spoilers.
 
 
 
{{MudletVersion|4.21}}
 
 
 
==== How It Works ====
 
 
 
# Link displays with optional disabled styling
 
# Left-click does nothing (no function execution)
 
# Right-click menus are blocked (completely non-interactive)
 
# Can combine with spoilers for reveal-only behavior
 
 
 
{{Note}} Disabled state is permanent. To re-enable, the server must send a new link.
 
 
 
====Configuration====
 
 
 
{| class="wikitable"
 
! Property !! Type !! Description !! Default
 
|-
 
| <code>disabled</code> || Boolean || Prevent link function execution || <code>false</code>
 
|}
 
 
 
====Styling====
 
 
 
Use the <code>disabled</code> pseudo-class for visual feedback:
 
 
 
<syntaxhighlight lang="json">
 
{
 
  "disabled": true,
 
  "style": {
 
    "color": "gray",
 
    "disabled": {
 
      "color": "darkgray",
 
      "strikethrough": true
 
    }
 
  }
 
}
 
</syntaxhighlight>
 
 
 
====Examples====
 
 
 
'''Basic disabled link:'''
 
<syntaxhighlight lang="json">
 
{"disabled": true}
 
</syntaxhighlight>
 
 
 
Disabled with menu defined (menu blocked):
 
<syntaxhighlight lang="json">
 
{
 
  "disabled": true,
 
  "menu": [
 
    {"Why locked?": "send:help locked"},
 
    {"Requirements": "send:requirements"}
 
  ],
 
  "tooltip": "Requires level 10 - menu blocked"
 
}
 
</syntaxhighlight>
 
 
 
{{note}} Even though a menu is defined, it will not appear because the link is disabled. Use this pattern when you want to prepare menu options for when the link becomes enabled.
 
 
 
'''Disabled spoiler (reveal-only):'''
 
<syntaxhighlight lang="json">
 
{"spoiler": true, "disabled": true}
 
</syntaxhighlight>
 
 
 
==== Common Use Cases ====
 
 
 
* '''Locked content''' - Options requiring prerequisites (completely non-interactive)
 
* '''Unavailable actions''' - Choices that can't be taken currently
 
* '''Cooldowns''' - Temporarily disabled abilities
 
* '''Information display''' - Show options without any interaction
 
* '''Reveal-only spoilers''' - Allow text reveal without triggering commands
 
* '''Future-proofing''' - Define menus that will work when link is re-enabled
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_DISABLED = "1"
 
 
 
----
 
 
 
==Tier 5: Stateful Links==
 
 
 
===Selection===
 
 
 
====Purpose====
 
 
 
Create interactive, toggleable links that maintain state—like radio buttons, checkboxes, reaction buttons, or voting systems.
 
 
 
{{MudletVersion|4.21}}
 
 
 
[[File:OSC 8 Hyperlink Selection.mov|frameless]]
 
 
 
====How It Works====
 
 
 
# Links are organized into named groups
 
# Clicking toggles the selection state
 
# Visual style updates immediately via <code>selected</code> pseudo-class
 
# Server receives callback with <code>&selected=true</code> or <code>&selected=false</code>
 
# In exclusive mode, selecting one deselects others in the group
 
 
 
====Selection Modes====
 
 
 
'''Radio Button Mode''' (<code>"exclusive": true</code>, default):
 
* Only one link per group can be selected
 
* Selecting a new link deselects others
 
* Use for: difficulty settings, class selection, single-choice options
 
 
 
'''Checkbox Mode''' (<code>"exclusive": false</code>):
 
* Multiple links per group can be selected
 
* Each toggles independently
 
* Use for: reactions, multi-select filters, feature toggles
 
 
 
====Configuration====
 
 
 
{| class="wikitable"
 
! Property !! Type !! Description !! Default
 
|-
 
| <code>group</code> || String || '''Required.''' Group identifier for related links || —
 
|-
 
| <code>value</code> || String || '''Required.''' Unique identifier within group || —
 
|-
 
| <code>toggle</code> || Boolean || Allow deselecting by clicking again || <code>true</code>
 
|-
 
| <code>selected</code> || Boolean || Initial selection state || <code>false</code>
 
|-
 
| <code>exclusive</code> || Boolean || Radio (true) vs checkbox (false) mode || <code>true</code>
 
|-
 
| <code>disabled</code> || Boolean || Prevent selection changes || <code>false</code>
 
|}
 
 
 
{{Note}} Selection state is per-console. Different windows maintain independent states.
 
 
 
====Server Callback====
 
 
 
When clicked, the URI is modified to include selection state:
 
 
 
* '''Selecting:''' <code>send:react?type=like&selected=true</code>
 
* '''Deselecting:''' <code>send:react?type=like&selected=false</code>
 
 
 
====Styling====
 
 
 
Use <code>selected</code> and <code>disabled</code> pseudo-classes:
 
 
 
<syntaxhighlight lang="json">
 
{
 
  "selection": {"group": "reactions", "value": "like"},
 
  "style": {
 
    "color": "gray",
 
    "selected": {"color": "blue", "bold": true},
 
    "disabled": {"color": "darkgray", "strikethrough": true},
 
    "hover": {"color": "lightblue"}
 
  }
 
}
 
</syntaxhighlight>
 
 
 
====Examples====
 
 
 
'''Social reactions (checkbox mode):'''
 
<syntaxhighlight lang="json">
 
{
 
  "selection": {
 
    "group": "post_123_reactions",
 
    "value": "thumbs_up",
 
    "exclusive": false
 
  },
 
  "style": {
 
    "color": "gray",
 
    "selected": {"color": "blue", "bold": true}
 
  }
 
}
 
</syntaxhighlight>
 
 
 
'''Difficulty selection (radio mode):'''
 
<syntaxhighlight lang="json">
 
{
 
  "selection": {
 
    "group": "difficulty",
 
    "value": "hard",
 
    "exclusive": true
 
  },
 
  "style": {
 
    "bg": "gray",
 
    "selected": {"bg": "red", "bold": true}
 
  }
 
}
 
</syntaxhighlight>
 
 
 
'''Pre-selected option:'''
 
<syntaxhighlight lang="json">
 
{
 
  "selection": {
 
    "group": "combat_mode",
 
    "value": "aggressive",
 
    "selected": true
 
  }
 
}
 
</syntaxhighlight>
 
 
 
'''Non-toggleable (must select different option):'''
 
<syntaxhighlight lang="json">
 
{
 
  "selection": {
 
    "group": "thread_following",
 
    "value": "thread_456",
 
    "toggle": false
 
  }
 
}
 
</syntaxhighlight>
 
 
 
'''Disabled option:'''
 
<syntaxhighlight lang="json">
 
{
 
  "selection": {
 
    "group": "poll",
 
    "value": "sold_out",
 
    "disabled": true
 
  },
 
  "style": {
 
    "disabled": {"strikethrough": true}
 
  }
 
}
 
</syntaxhighlight>
 
 
 
[[File:Screenshot 2025-10-17 at 7.26.36 AM.png|1119x308px|frameless|link management example]]
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_SELECTION = "1"
 
 
 
----
 
 
 
==Tier 6: Optimization==
 
 
 
===Compact Syntax===
 
 
 
====Purpose====
 
 
 
Reduce JSON size by 30-80% using single-letter property abbreviations. Especially valuable when generating many styled links.
 
 
 
{{MudletVersion|4.21}}
 
 
 
====How It Works====
 
 
 
# Replace verbose property names with abbreviations
 
# Mudlet recognizes both forms
 
# Can mix shorthand and full names in same config
 
# No functionality difference—purely size optimization
 
 
 
====Shorthand Mappings====
 
 
 
{| class="wikitable"
 
! Category !! Full Name !! Shorthand
 
|-
 
| rowspan="7" | '''Top-level''' || style || s
 
|-
 
| menu || m
 
|-
 
| tooltip || t
 
|-
 
| visibility || v
 
|-
 
| selection || sel
 
|-
 
| disabled || d
 
|-
 
| spoiler || sp
 
|-
 
| rowspan="8" | '''Style''' || color || c
 
|-
 
| bg || bg
 
|-
 
| bold || b
 
|-
 
| italic || i
 
|-
 
| underline || u
 
|-
 
| overline || o
 
|-
 
| strikethrough || st
 
|-
 
| text-decoration-color || tdc
 
|-
 
| rowspan="10" | '''Pseudo-class''' || hover || h
 
|-
 
| active || a
 
|-
 
| visited || vi
 
|-
 
| focus || f
 
|-
 
| focus-visible || fv
 
|-
 
| link || l
 
|-
 
| any-link || al
 
|-
 
| selected || sl
 
|-
 
| disabled || d
 
|}
 
 
 
'''Note:''' The <code>disabled</code> property appears in two categories:
 
* '''Top-level''' (<code>d</code>): Controls interactivity. <code>{"d":true}</code> prevents clicks.
 
* '''Pseudo-class''' (<code>ds</code>): Controls appearance. <code>{"s":{"d":{"c":"gray"}}}</code>
 
 
 
====Examples====
 
 
 
'''Full syntax (91 characters):'''
 
<syntaxhighlight lang="json">
 
{"style": {"color": "red", "bold": true, "hover": {"color": "yellow"}}}
 
</syntaxhighlight>
 
 
 
'''Shorthand syntax (54 characters):'''
 
<syntaxhighlight lang="json">
 
{"s": {"c": "red", "b": true, "h": {"c": "yellow"}}}
 
</syntaxhighlight>
 
 
 
'''Mixing formats:'''
 
<syntaxhighlight lang="json">
 
{"s": {"c": "red"}, "tooltip": "Full name works too"}
 
</syntaxhighlight>
 
 
 
====When to Use====
 
 
 
'''Use shorthand when:'''
 
* Generating 10+ links per line
 
* Network bandwidth constrained
 
* Links generated programmatically
 
 
 
'''Use full names when:'''
 
* One-off custom links
 
* Readability is priority
 
* Debugging configurations
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_COMPACT = "1"
 
 
 
===Presets===
 
 
 
====Purpose====
 
 
 
Define commonly-used styles once, then reference them by name. Reduces repetition and centralizes style management.
 
 
 
{{MudletVersion|4.21}}
 
 
 
====How It Works====
 
 
 
# Define preset at connection time using <code>preset:</code> URI scheme
 
# Reference preset in links with <code>?preset=NAME</code>
 
# Override preset properties with additional <code>&config=</code>
 
# Presets are session-scoped (cleared on disconnect)
 
 
 
====Defining Presets====
 
 
 
ESC ] 8 ; ; preset:NAME?config=JSON ESC \ ESC ] 8 ; ; ESC \
 
 
 
{{Note}} Preset definitions have '''empty text''' between sequences—they only register the style.
 
 
 
'''Example definitions:'''
 
ESC ] 8 ; ; preset:btn?config={"s":{"bg":"green","c":"white","b":true}} ESC \ ESC ] 8 ; ; ESC \
 
ESC ] 8 ; ; preset:danger?config={"s":{"c":"red","b":true}} ESC \ ESC ] 8 ; ; ESC \
 
 
 
====Using Presets====
 
 
 
'''Simple usage:'''
 
send:attack?preset=danger
 
 
 
'''With property overrides:'''
 
send:attack?preset=btn&config=%7B%22t%22%3A%22Attack%22%7D
 
 
 
====Deep Merge Behavior====
 
 
 
Override config is deep-merged with preset (override wins):
 
 
 
{| class="wikitable"
 
! Preset !! Override !! Result
 
|-
 
| <code>{"s":{"c":"red","b":true}}</code> || <code>{"s":{"c":"blue"}}</code> || <code>{"s":{"c":"blue","b":true}}</code>
 
|-
 
| <code>{"s":{"c":"red"}}</code> || <code>{"t":"Tooltip"}</code> || <code>{"s":{"c":"red"},"t":"Tooltip"}</code>
 
|}
 
 
 
====Size Comparison====
 
 
 
{| class="wikitable"
 
! Format !! Example !! Encoded Size !! Reduction
 
|-
 
| Full JSON || <code>{"style":{"color":"red","bold":true}}</code> || ~141 chars || Baseline
 
|-
 
| Shorthand || <code>{"s":{"c":"red","b":true}}</code> || ~88 chars || 38%
 
|-
 
| Preset || <code>?preset=danger</code> || ~17 chars || 88%
 
|}
 
 
 
{{Note}} Presets require initial definition overhead but pay off after 2-3 uses.
 
 
 
====Capability Detection====
 
 
 
USERVAR OSC_HYPERLINKS_PRESETS = "1"
 
 
 
----
 
 
 
==Reference==
 
 
 
===Quick Reference: JSON Structure===
 
 
 
<syntaxhighlight lang="json">
 
{
 
  "style": {
 
    "color": "value",
 
    "bg": "value",
 
    "bold": true,
 
    "italic": true,
 
    "underline": true,
 
    "overline": true,
 
    "strikethrough": true,
 
    "text-decoration-color": "value",
 
    "hover": { /* same properties */ },
 
    "active": { /* same properties */ },
 
    "visited": { /* same properties */ },
 
    "selected": { /* same properties */ },
 
    "disabled": { /* same properties */ }
 
  },
 
  "tooltip": "Hover text",
 
  "menu": [
 
    {"Label": "scheme:command"},
 
    "-",
 
    {"Label2": "scheme:command2"}
 
  ],
 
  "visibility": {
 
    "action": "conceal",
 
    "delay": 5000,
 
    "expire": {
 
      "input": true,
 
      "prompt": true,
 
      "output": true,
 
      "outputDelay": 500
 
    },
 
    "wholeline": false
 
  },
 
  "selection": {
 
    "group": "group_name",
 
    "value": "unique_value",
 
    "toggle": true,
 
    "selected": false,
 
    "exclusive": true,
 
    "disabled": false
 
  },
 
  "spoiler": false,
 
  "disabled": false
 
}
 
</syntaxhighlight>
 
 
 
===Quick Reference: NEW-ENVIRON Variables===
 
 
 
{| class="wikitable"
 
! Tier !! Variable !! Feature
 
|-
 
| rowspan="3" | 1 || OSC_HYPERLINKS || Basic protocol support
 
|-
 
| OSC_HYPERLINKS_SEND || <code>send:</code> scheme
 
|-
 
| OSC_HYPERLINKS_PROMPT || <code>prompt:</code> scheme
 
|-
 
| rowspan="2" | 2 || OSC_HYPERLINKS_STYLE_BASIC || Colors, bold, italic, decorations
 
|-
 
| OSC_HYPERLINKS_STYLE_STATES || Hover, active, visited states
 
|-
 
| rowspan="2" | 3 || OSC_HYPERLINKS_TOOLTIP || Custom tooltips
 
|-
 
| OSC_HYPERLINKS_MENU || Context menus
 
|-
 
| rowspan="3" | 4 || OSC_HYPERLINKS_VISIBILITY || Auto-hide/reveal
 
|-
 
| OSC_HYPERLINKS_SPOILER || Spoiler text
 
|-
 
| OSC_HYPERLINKS_DISABLED || Non-clickable links
 
|-
 
| 5 || OSC_HYPERLINKS_SELECTION || Stateful selection
 
|-
 
| rowspan="2" | 6 || OSC_HYPERLINKS_COMPACT || Shorthand syntax
 
|-
 
| OSC_HYPERLINKS_PRESETS || Style presets
 
|}
 
 
 
===Quick Reference: Shorthand Mappings===
 
 
 
{| class="wikitable"
 
! Full !! Short !! Full !! Short !! Full !! Short
 
|-
 
| style || s || color || c || hover || h
 
|-
 
| menu || m || bg || bg || active || a
 
|-
 
| tooltip || t || bold || b || visited || d
 
|-
 
| visibility || v || italic || i || focus || f
 
|-
 
| selection || sel || underline || u || selected || sl
 
|-
 
| spoiler || sp || strikethrough || st || disabled || d
 
|}
 
 
 
===Security & Limitations===
 
 
 
====Trusted URI Schemes====
 
 
 
Only these schemes are supported (others are rejected):
 
* <code>send:</code>, <code>prompt:</code>
 
* <code>http:</code>, <code>https:</code>, <code>ftp:</code>
 
* <code>preset:</code> (for definitions only)
 
 
 
====Limits====
 
 
 
* '''URL length:''' Maximum 4096 characters
 
* '''Invalid JSON:''' Silently ignored (link still works without styling)
 
* '''Multi-line visibility:''' Only single-line links support visibility management
 
 
 
==== Reserved Parameters ====
 
 
 
The following parameter names are '''reserved''' for Mudlet's OSC 8 extensions and cannot be used in web URLs without percent-encoding:
 
 
 
* <code>config</code> – JSON configuration for link styling and behavior
 
* <code>preset</code> – Named style preset reference
 
 
 
===== Impact on Web URLs =====
 
 
 
If your web URL contains these parameter names, they must be percent-encoded to avoid conflicts:
 
 
 
{| class="wikitable"
 
|-
 
! Original URL
 
! Corrected URL
 
|-
 
| <code><nowiki>https://example.com/?config=value</nowiki></code>
 
| <code><nowiki>https://example.com/?%63%6F%6E%66%69%67=value</nowiki></code>
 
|-
 
| <code><nowiki>https://api.game.com/?preset=normal</nowiki></code>
 
| <code><nowiki>https://api.game.com/?%70%72%65%73%65%74=normal</nowiki></code>
 
|}
 
 
 
===== Percent-Encoding Reference =====
 
 
 
{| class="wikitable"
 
|-
 
! Parameter
 
! Encoded Form
 
|-
 
| config
 
| %63%6F%6E%66%69%67
 
|-
 
| preset
 
| %70%72%65%73%65%74
 
|}
 
 
 
{{Note|Game servers should avoid using these parameter names in URLs sent via OSC 8 hyperlinks, or ensure proper percent-encoding is applied.}}
 
 
 
==Implementation Guidance==
 
 
 
===For Game Servers===
 
 
 
====Progressive Enhancement Strategy====
 
 
 
'''Level 1: Basic Links'''
 
* Detect <code>OSC_HYPERLINKS=1</code>
 
* Use simple <code>send:</code>/<code>prompt:</code> schemes
 
* Provide plain text fallbacks
 
 
 
'''Level 2: Visual Enhancement'''
 
* Check <code>OSC_HYPERLINKS_STYLE_BASIC=1</code>
 
* Add colors, bold, italic formatting
 
* Use full JSON property names
 
 
 
'''Level 3: Interactive Features'''
 
* Verify <code>OSC_HYPERLINKS_STYLE_STATES=1</code>
 
* Add hover, active, visited effects
 
 
 
'''Level 4: Advanced Interactions'''
 
* Check for MENU, TOOLTIP, VISIBILITY, SELECTION support
 
* Implement context menus and dynamic visibility
 
 
 
'''Level 5: Optimization'''
 
* Verify COMPACT and PRESETS support
 
* Define presets at connection time
 
* Use shorthand syntax for high-volume links
 
 
 
====Decision Tree====
 
 
 
OSC_HYPERLINKS support?
 
├─ NO → Use MXP, ANSI, or plain text
 
└─ YES → Use OSC 8 with detected feature level
 
    ├─ PRESETS? → Define presets, use ?preset=name
 
    ├─ COMPACT? → Use shorthand (s, c, m, etc.)
 
    └─ Otherwise → Use full JSON property names
 
 
 
===For Client Developers===
 
 
 
====Implementation Levels====
 
 
 
'''Level 1:''' Parse OSC 8 sequences, support send:/prompt:/http: schemes
 
 
 
'''Level 2:''' Parse JSON config, implement basic styling
 
 
 
'''Level 3:''' Implement pseudo-class states with priority
 
 
 
'''Level 4:''' Add menus, tooltips, visibility, selection managers
 
 
 
'''Level 5:''' Add shorthand expansion table
 
 
 
'''Level 6:''' Implement preset storage and deep merge
 
 
 
====Key Implementation Notes====
 
 
 
* Presets are session-scoped (clear on disconnect)
 
* Selection state is per-console (independent windows)
 
* Visibility only works on single-line links
 
* Spoiler background uses luminance formula: Y = 0.2126R + 0.7152G + 0.0722B
 
 
 
===See Also===
 
 
 
* [[Manual:Supported_Protocols#MXP|MXP Protocol]] - Alternative hyperlink protocol
 
 
 
===References===
 
 
 
* [https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda OSC 8 Specification] - Egmont Koblinger
 
* [https://en.wikipedia.org/wiki/ANSI_escape_code#OSC ANSI Escape Codes] - Wikipedia
 
* [https://datatracker.ietf.org/doc/html/rfc3986 RFC 3986] - URI Generic Syntax
 
* [https://www.w3.org/TR/css-text-decor-3/ CSS Text Decoration Level 3] - W3C
 
 
 
=Events =
 
:New or revised events that Mudlet can raise to inform a profile about changes. See [[Manual:Event_Engine#Mudlet-raised_events|Mudlet-raised events]] for the existing ones.
 
 
 
===sysLabelDeleted, PR #8387===
 
 
 
Raised when a label is successfully deleted via [[Manual:Lua_Functions#deleteLabel|deleteLabel()]] or Geyser's <code>Label:delete()</code> method. The event provides the name of the deleted label as an argument.
 
 
 
{{note}} This event is raised after the label has been marked for deletion but before Qt's event loop has completed the deletion. The label should be considered gone for practical purposes.
 
 
 
{{MudletVersion|4.20}}
 
 
 
;Event arguments
 
* ''event'': The event name: "sysLabelDeleted"
 
* ''labelName'': The name of the label that was deleted
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
-- Register an event handler for label deletion
 
function onLabelDeleted(event, labelName)
 
  cecho(f"<green>Label '{labelName}' has been deleted.\n")
 
 
 
  -- Clean up any references or related data
 
  if myLabelReferences[labelName] then
 
    myLabelReferences[labelName] = nil
 
  end
 
end
 
 
 
registerAnonymousEventHandler("sysLabelDeleted", onLabelDeleted)
 
 
 
-- Now when you delete a label, the handler will be called
 
createLabel("tempLabel", 50, 50, 100, 30, 1)
 
deleteLabel("tempLabel")
 
-- Output: Label 'tempLabel' has been deleted.
 
</syntaxhighlight>
 
 
 
===sysMiniConsoleDeleted, PR #8387===
 
 
 
Raised when a miniconsole is successfully deleted via [[Manual:Lua_Functions#deleteMiniConsole|deleteMiniConsole()]] or Geyser's <code>MiniConsole:delete()</code> method. The event provides the name of the deleted miniconsole as an argument.
 
 
 
{{note}} This event is raised after the miniconsole has been marked for deletion but before Qt's event loop has completed the deletion. The miniconsole should be considered gone for practical purposes.
 
 
 
{{MudletVersion|4.20}}
 
 
 
;Event arguments
 
* ''event'': The event name: "sysMiniConsoleDeleted"
 
* ''miniConsoleName'': The name of the miniconsole that was deleted
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
-- Register an event handler for miniconsole deletion
 
function onMiniConsoleDeleted(event, miniConsoleName)
 
  cecho(f"<green>MiniConsole '{miniConsoleName}' has been deleted.\n")
 
 
 
  -- Stop any timers or processes that were sending data to this console
 
  if chatTimers[miniConsoleName] then
 
    killTimer(chatTimers[miniConsoleName])
 
    chatTimers[miniConsoleName] = nil
 
  end
 
end
 
 
 
registerAnonymousEventHandler("sysMiniConsoleDeleted", onMiniConsoleDeleted)
 
 
 
-- Now when you delete a miniconsole, the handler will be called
 
createMiniConsole("chatWindow", 10, 10, 300, 200)
 
deleteMiniConsole("chatWindow")
 
-- Output: MiniConsole 'chatWindow' has been deleted.
 
</syntaxhighlight>
 
 
 
===sysCommandLineDeleted, PR #8387===
 
 
 
Raised when a command line is successfully deleted via [[Manual:Lua_Functions#deleteCommandLine|deleteCommandLine()]] or Geyser's <code>CommandLine:delete()</code> method. The event provides the name of the deleted command line as an argument.
 
 
 
{{note}} This event is raised after the command line has been marked for deletion but before Qt's event loop has completed the deletion. The command line should be considered gone for practical purposes.
 
 
 
{{note}} The main command line cannot be deleted, so this event will never be raised for it.
 
 
 
{{MudletVersion|4.20}}
 
 
 
;Event arguments
 
* ''event'': The event name: "sysCommandLineDeleted"
 
* ''commandLineName'': The name of the command line that was deleted
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
-- Register an event handler for command line deletion
 
function onCommandLineDeleted(event, commandLineName)
 
  cecho(f"<green>Command line '{commandLineName}' has been deleted.\n")
 
 
 
  -- Clean up any command history or aliases specific to this command line
 
  if commandLineHistory[commandLineName] then
 
    commandLineHistory[commandLineName] = nil
 
  end
 
end
 
 
 
registerAnonymousEventHandler("sysCommandLineDeleted", onCommandLineDeleted)
 
 
 
-- Now when you delete a command line, the handler will be called
 
createCommandLine("customInput", 10, 400, 300, 30)
 
deleteCommandLine("customInput")
 
-- Output: Command line 'customInput' has been deleted.
 
</syntaxhighlight>
 
 
 
===sysScrollBoxDeleted, PR #8387===
 
 
 
Raised when a scrollbox is successfully deleted via [[Manual:Lua_Functions#deleteScrollBox|deleteScrollBox()]] or Geyser's <code>ScrollBox:delete()</code> method. The event provides the name of the deleted scrollbox as an argument.
 
 
 
{{note}} This event is raised after the scrollbox has been marked for deletion but before Qt's event loop has completed the deletion. The scrollbox should be considered gone for practical purposes.
 
 
 
{{MudletVersion|4.20}}
 
 
 
;Event arguments
 
* ''event'': The event name: "sysScrollBoxDeleted"
 
* ''scrollBoxName'': The name of the scrollbox that was deleted
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
-- Register an event handler for scrollbox deletion
 
function onScrollBoxDeleted(event, scrollBoxName)
 
  cecho(f"<green>ScrollBox '{scrollBoxName}' has been deleted.\n")
 
 
 
  -- Clean up any content tables or buffers
 
  if scrollBoxContent[scrollBoxName] then
 
    scrollBoxContent[scrollBoxName] = nil
 
  end
 
end
 
 
 
registerAnonymousEventHandler("sysScrollBoxDeleted", onScrollBoxDeleted)
 
 
 
-- Now when you delete a scrollbox, the handler will be called
 
createScrollBox("messageBox", 10, 10, 300, 400)
 
deleteScrollBox("messageBox")
 
-- Output: ScrollBox 'messageBox' has been deleted.
 
</syntaxhighlight>
 
 
 
===sysConsoleSizeChanged, PR #7870===
 
This event is raised when the (scrollable part of) the main or a sub-console or a user-window changes in size. After the event name as the first argument (as is "standard") additional arguments contain:
 
* the name (string) of the console involved ("''main''" for the main console)
 
* the number of characters (''em-space'' equivalents) wide the new size is
 
* the number of lines tall the new size is
 
* the number of characters taken up by a visible time stamp (will be '''0''' if this detail is not visible).
 
 
 
{{MudletVersion| 4.20}}
 
 
 
{{note}} pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/7870
 
 
 
===sysLoadEvent, PR #7726 ===
 
 
 
Raised after Mudlet is done loading the profile, after all of the scripts, packages, and modules are installed. Note that when it does so, it also compiles and runs all scripts - which could be a good idea to initialize everything at once, but beware - scripts are also run when saved. Hence, hooking only on the sysLoadEvent would prevent multiple re-loads as you’re editing the script.
 
 
 
In '''4.20.0''' an extra boolean argument was provided which indicates whether the event is from loading a new profile (''true'') or after a call of the ''resetProfile()'' function (''false'').
 
 
 
{{note}} pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/7726
 
 
 
===sysMapWindowMousePressEvent, PR #6962===
 
Raised when the mouse is left-clicked on the mapper window.
 
 
 
{{MudletVersion| ?.??}}
 
 
 
{{note}} pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/6962
 
 
 
===sysSettingChanged, PR #7476 ===
 
This event is raised when a Preferences or Mudlet setting has changed.  The first argument contains the setting that was changed, further arguments detail the change.
 
 
 
Currently implemented sysSettingChanged events are;
 
 
 
*"main window font" - raised when the main window/console font has changed via API or Preferences window. Returns two additional arguments, the font family and the font size. e.g. {"main window font", "Times New Roman", 12 }
 
 
 
{{MudletVersion| ?.??}}
 
 
 
{{note}} pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/7476
 
 
 
=MudMaster Chat Protocol (MMCP) PR #7765=
 
:MMCP is a peer-to-peer protocol enabling out of band data to be sent to connected peers in the form of public or private chats, or general data.
 
:See MMCP protocol documentation at: https://tintin.mudhalla.net/protocols/mmcp/
 
:See https://wiki.mudlet.org/w/Notes_on_MMCP
 
{{MudletVersion| ?.??}}
 
 
 
{{note}} pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/7765
 
 
 
== Lua functions ==
 
* Note for all functions using target as an argument, the argument can be the client chatname or ID of the client as seen in mmcp.displayClientList()
 
 
 
===accept===
 
;mmcp.accept(target)
 
:Accepts an incoming connection request.
 
;Parameters
 
* ''target'':
 
:* Incoming client name or ID.
 
 
 
{{note}} pending, not yet available in initial MMCP release.
 
 
 
===allowSnoop===
 
;mmcp.allowSnoop(target)
 
:Toggles the Allow Snoop flag for a client, allowing them to initiate a snoop request which will forward them text you see from your game.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
 
 
===call===
 
;mmcp.call(host[, port])
 
:Initiate an outgoing connection to another client.
 
;Parameters
 
* ''host'':
 
:* IPv4 address or fully qualified domain name.
 
* ''port'':
 
:* (optional) Port to connect to. Default 4050.
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
local host = "1.2.3.4"
 
local port = 4050
 
 
 
mmcp.call(host, port)
 
</syntaxhighlight>
 
 
 
;You should see the following message:
 
<syntaxhighlight lang="lua">
 
[ CHAT ]  - Connecting to 1.2.3.4:4050...
 
[ CHAT ]  - Waiting for response from 1.2.3.4:4050...
 
[ CHAT ]  - Connection to ChatClient at 1.2.3.4:4050 accepted.
 
</syntaxhighlight>
 
 
 
===chatAll===
 
;mmcp.chatAll(message)
 
:Sends a message to all connected clients.
 
;Parameters
 
* ''message'':
 
:* The message to send.
 
 
 
This message will have the format of:
 
<Name> chats to everybody, '<message>'
 
 
 
You will see the message:
 
You chat to everybody, '<message>'
 
 
 
===chatGroup===
 
;mmcp.chatGroup(group, message)
 
:Sends a message to all clients in the specified group.
 
;Parameters
 
* ''group'':
 
:* The group to send the message to.
 
* ''message'':
 
:* The message to send.
 
 
 
The message will have the format of:
 
<Name> chats to the group, '<message>'
 
 
 
You will see the message:
 
You chat to <<group>>, '<message>'
 
 
 
===chatName===
 
;mmcp.chatName([name])
 
:Sets or gets your current chat name visible to other clients.
 
;Parameters
 
* ''name'':
 
:* (optional) The new chat name to use.
 
;Returns
 
:* If no name is specified, this function will return your current chat name.
 
 
 
===chatTo===
 
;mmcp.chatTo(target, message)
 
:Sends a message to a specific client.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
* ''message'':
 
:* The message to send.
 
 
 
The target client will see the message:
 
<Name> chats to you, '<message>'
 
 
 
You will see the message:
 
You chat to <target>, '<message>'
 
 
 
===deny===
 
;mmcp.deny(target)
 
:Denies an incoming connection request.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
 
 
{{note}} pending, not yet available in initial MMCP release.
 
 
 
===disconnect===
 
;mmcp.disconnect(target)
 
:Disconnects a connected client.
 
;Parameters
 
* ''target'':
 
:* Client name or ID
 
 
 
===displayClientList===
 
;mmcp.displayClientList()
 
:Displays a table showing information about connected and pending clients.
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
mmcp.displayClientList()
 
</syntaxhighlight>
 
 
 
;You should see the following table
 
<syntaxhighlight>
 
Id  Name                Address              Port  Group          Flags    ChatClient
 
==== ==================== ==================== ===== =============== ======== ================
 
  1 ChatClient          1.2.3.4              4050                          Mudlet
 
==== ==================== ==================== ===== =============== ======== ================
 
Color Key: Connected  Pending
 
Flags:  F - Firewall,      I - Ignored,  P - Private,  S - Serving
 
        n - Allow Snooping, N - Being Snooped
 
</syntaxhighlight>
 
 
 
:* You may then use the mmcp lua commands referencing the client by their ID (1) or name (ChatClient)
 
 
 
===emoteAll===
 
;mmcp.emoteAll(message)
 
:Sends an emote message to all connected clients.
 
;Parameters
 
* ''message'':
 
:* The message to send.
 
 
 
Clients will see the message:
 
<Name> <message>
 
 
 
If you have enabled the "Prefix emote messages" option, you will see:
 
You emote to everyone: '<Name> <message>'
 
 
 
Otherwise you will see:
 
<Name> <message>
 
 
 
===getClientFlags===
 
;mmcp.getClientFlags(target)
 
:Returns a string containing the client flags of a connected client.
 
;Parameters
 
 
* ''target'':
 
* ''target'':
 
:* Client name or ID.
 
:* Client name or ID.
;Returns
 
This string is an 8 character string where letters in the following positions have meaning:
 
"12345678"
 
*1: Reserved, blank
 
*2: Reserved, blank
 
*3: P if the connection is Private, otherwise blank
 
*4: I if the connection is Ignored, otherwise blank
 
*5: S if the client is being served, otherwise blank
 
*6: F if the client is firewalled, otherwise blank
 
*7: N if the client is snooping us, n if the client can snoop us, otherwise blank
 
*8: Reserved, blank
 
  
===getClientList===
+
===snoop===
;clientInfo = mmcp.getClientList()
+
;mmcp.snoop(target)
:Returns a lua table containing the following information for each connected client.
+
:Starts snooping a client. The target may first need to enable snooping on their client.
;Returns
 
*id: The ID of the client
 
*name: The chat name of the client.
 
*host: The hostname or IP address of the client.
 
*port: The port the client (check if this is the reported port or port they connected from)
 
*version: The MUD client and version of the client
 
 
 
;Example
 
<syntaxhighlight lang="lua">
 
local clientList = mmcp.getClientList()
 
</syntaxhighlight>
 
 
 
;The variable clientList will then contain:
 
<syntaxhighlight>
 
{ {
 
    host = "1.2.3.4",
 
    id = 1,
 
    name = "ChatClient",
 
    port = 4050,
 
    version = "Mudlet"
 
  } }
 
</syntaxhighlight>
 
 
 
===ignore===
 
;mmcp.ignore(target)
 
:Toggles ignoring a client. You will not see chat messages from an ignored client.
 
 
;Parameters
 
;Parameters
 
* ''target'':
 
* ''target'':
 
:* Client name or ID.
 
:* Client name or ID.
 
===peek===
 
;mmcp.peek(target)
 
:Sends a request to the target client to peek at their connection list.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
 
===ping===
 
;mmcp.ping(target)
 
:Sends a ping request to a client.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
 
===request===
 
;mmcp.request(target)
 
:Sends a request to the target client to request and connect to their public connections.
 
:Mudlet will attempt to connect to each of the hosts returned by this command.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
 
===sendSideChannel===
 
;mmcp.sendSideChannel(channel, message)
 
:Sends an OOB (Out of band) message to all connected clients.
 
;Parameters
 
* ''channel'':
 
:* The channel to send the message on.
 
* ''message'':
 
:* The message to send.
 
 
{{note}} This will only send to other Mudlet clients. Upon receipt of this message Mudlet will raise a sysMMCPSideChannelMessage containing
 
the channel and message data.
 
  
 
;Example
 
;Example
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
-- myStats populated by prompt trigger
+
-- Alias: ChatSnoop
local outStr = string.format("%s,%d,%d,%d,%d,%s",
+
-- Alias Pattern: ^chatSnoop (.*)
  mmcp.chatName(), myStats.hp, myStats.maxHp, myStats.mana, myStats.maxMana, myStats.buffs)
 
  
mmcp.sendSideChannel("stats", outStr)
+
mmcp.snoop(matches[2])
 
</syntaxhighlight>
 
</syntaxhighlight>
 
===serve===
 
;mmcp.serve(target)
 
:Toggles the serve flag for a client, this clients chat messages will be sent to all other connected clients.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
 
===setDoNotDisturb===
 
;mmcp.setDoNotDisturb(target)
 
:Toggles the Do Not Disturb flag, any incoming connections will be automatically denied.
 
{{note}} pending, not yet available in initial MMCP release.
 
 
===setGroup===
 
;mmcp.setGroup(target, group)
 
:Assigns a client to a chat group.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
* ''group'':
 
:* The group name.
 
 
{{note}} The group name is only visible to you.
 
 
===setPrivate===
 
;mmcp.setPrivate(target)
 
:Toggles the private flag for a client. Any clients set as private will not be listed in peek or connection requests.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
 
===snoop===
 
;mmcp.snoop(target)
 
:Starts snooping a client. The target may first need to enable snooping on their client.
 
;Parameters
 
* ''target'':
 
:* Client name or ID.
 
  
 
===startServer===
 
===startServer===
Line 5,214: Line 3,241:
 
end
 
end
  
registerNamedEventHandler(getProfileName(), "MMCP", "sysMMCPMessage", "mmcpEventHandler")
+
registerNamedEventHandler(getProfileName(), "MMCP", "sysMMCPChatMessage", "mmcpEventHandler")
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 5,264: Line 3,291:
  
 
=Security=
 
=Security=
 
== Password Management, PR #7956, #7882 ==
 
 
Starting with Mudlet 4.20.0, passwords are stored securely using your operating system's built-in credential manager.
 
 
=== How It Works ===
 
 
When you save a password in Mudlet (such as your game character password), it is automatically encrypted and stored in the most secure location available:
 
 
* '''macOS''': Stored in your macOS Keychain
 
* '''Windows''': Stored in Windows Credential Manager
 
* '''Linux''': Stored in your system's Secret Service (like GNOME Keyring or KWallet)
 
* '''Portable Mode''': Encrypted files in your Mudlet profile folder
 
 
=== Security Features ===
 
 
Your passwords are protected by:
 
 
* '''System-level encryption''' - Your operating system handles the encryption using industry-standard methods
 
* '''Per-profile isolation''' - Each Mudlet profile's passwords are kept separate
 
* '''Automatic fallback''' - If the system keychain is unavailable, Mudlet uses AES-256 encrypted files
 
* '''No plaintext storage''' - Passwords are never stored in readable form
 
 
=== What This Means for You ===
 
 
; You don't need to do anything special
 
: Mudlet handles password security automatically. Just enter your password when creating or editing a profile, and Mudlet takes care of the rest.
 
 
; Your passwords are more secure
 
: By using your operating system's credential manager, your passwords benefit from the same security that protects your system passwords and other sensitive data.
 
 
; Portable installations still work
 
: If you use Mudlet in portable mode (running from a USB drive, for example), passwords are stored as encrypted files that travel with your installation.
 
 
; Multiple profiles are supported
 
: Each profile's passwords are kept separate and secure, even if you have multiple characters on the same game.
 
 
=== Managing Your Passwords ===
 
 
Your passwords are automatically retrieved when you connect to a game. You can view or change them in the Connection Profiles dialog:
 
 
# Click the '''Connect''' button on the main toolbar (or press Alt+C)
 
# Select your profile from the list
 
# Click the '''Options''' tab
 
# Your password will be securely loaded from storage and can be edited here
 
 
You can also create new profiles with passwords directly from this dialog.
 
 
=== Technical Details ===
 
 
For users interested in the technical implementation:
 
 
* Passwords in system keychains use the native encryption provided by your OS
 
* File-based storage uses AES-256 encryption with PBKDF2-SHA256 key derivation
 
* Each profile has a unique encryption key stored in its profile directory
 
* HMAC authentication ensures password integrity
 
* All password operations include timeout protection and error handling
 
 
=== Privacy ===
 
 
Your passwords are stored locally on your computer and are never transmitted to Mudlet's servers or any third party. The only time a password is sent over the network is when you connect to your game server (using the connection method you've chosen).
 
 
=== Password Masking Feature ===
 
 
Mudlet automatically masks your password with asterisks when you connect to a game server that requests authentication. This protects your password from being visible on screen.
 
 
==== Disabling Password Masking ====
 
 
For users in trusted environments who prefer to see what they're typing, during password entry you can find an icon in the shape of an eye on the right side of the command line to unmask the password, or you can disable permanently disable password masking:
 
# Open the '''Profile Preferences''' dialog (Settings menu)
 
# Go to the '''Input Line''' tab
 
# Check the '''Disable password masking''' checkbox
 
 
=== Using Older Mudlet Versions (Before 4.20) ===
 
 
Starting with Mudlet 4.20, your saved passwords are stored securely using encryption. If you later use an older version of Mudlet (like 4.19.1 or earlier), here's what to expect:
 
 
* '''Your saved password may not appear''' – Older versions cannot read the new encrypted passwords, so the password field might be empty or show an outdated password.
 
* '''Simply re-enter your password''' – Just type your password again and continue playing normally.
 
* '''Your 4.20 passwords stay safe''' – Any password changes you make in an older version won't affect your encrypted passwords in 4.20+.
 
* '''No data loss occurs''' – When you return to Mudlet 4.20 or later, your securely stored passwords will still be there.
 
 
This design ensures that using an older Mudlet version temporarily won't corrupt or interfere with your modern encrypted password storage.
 

Latest revision as of 22:02, 25 May 2026

This page is for the development of documentation for Lua API functions that are currently being worked on. Ideally the entries here can be created in the same format as will be eventually used in Lua Functions and its sub-sites.

Note Note: Please use the Area_51/Template to add new entries in the sections below.

Note Note: Links to other functions need to include the wiki page name before the '#' character in the link identifier on the left side of the '|' divider between the identifier and the display text. e.g.

[[Manual:Lua_Functions#getCustomLines|getCustomLines()]]

rather than:

[[#getCustomLines|getCustomLines()]]

which would refer to a link within the current (in this case Area 51) section.

Note Note: The following headings reflect those present in the main Wiki area of the Lua API functions. It is suggested that new entries are added so as to maintain a sorted alphabetical order under the appropriate heading.


Basic Essential Functions

These functions are generic functions used in normal scripting. These deal with mainly everyday things, like sending stuff and echoing to the screen.

Database Functions

A collection of functions for helping deal with the database.

Date/Time Functions

A collection of functions for handling date & time.

File System Functions

A collection of functions for interacting with the file system.

Mapper Functions

A collection of functions that manipulate the mapper and its related features.

getMapInfo, PR #8963

getMapInfo()
Returns a table of all registered map info contributors mapped to their enabled/disabled state. This allows scripts to query which map info contributors (such as "Short" or "Full") are currently active.
See also: enableMapInfo(), disableMapInfo()
Mudlet VersionAvailable in Mudlet4.21+
Returns
  • A table with contributor names as keys and boolean values indicating whether each is enabled, or nil and an error message if no map is loaded.
Example
-- check which map info contributors are active
local info = getMapInfo()
for name, enabled in pairs(info) do
  print(name .. " is " .. (enabled and "enabled" or "disabled"))
end

-- check if a specific contributor is enabled
local info = getMapInfo()
if info["Short"] then
  echo("Short map info is enabled.\n")
end

setRoomBorderColor, PR #8758

setRoomBorderColor(roomID, r, g, b[, a])
Sets a custom border color for an individual room on the 2D map. When set, this color overrides the global map border color for that specific room.
See also: getRoomBorderColor(), clearRoomBorderColor(), setRoomBorderThickness()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to set the border color for.
  • r:
The red component of the color (0-255).
  • g:
The green component of the color (0-255).
  • b:
The blue component of the color (0-255).
  • a:
(optional) The alpha/transparency component (0-255). Defaults to 255 (fully opaque).
Returns
  • true on success, or nil and an error message if no map is loaded or the room ID is invalid.
Example
-- Set room 1 to have a red border
setRoomBorderColor(1, 255, 0, 0)

-- Set room 2 to have a semi-transparent blue border
setRoomBorderColor(2, 0, 0, 255, 128)

-- Mark all rooms with environment ID 5 (it could mean "outdoors" in your map, for example) with a green border
for _, roomID in ipairs(getRooms()) do
    if getRoomEnv(roomID) == 5 then
        setRoomBorderColor(roomID, 0, 200, 0)
    end
end


setRoomUserData #PR9299

setRoomUserData(roomID, key (as a string), value (as a string))
Stores information about a room under a given key. Similar to Lua's key-value tables, except only strings may be used here. One advantage of using userdata is that it's stored within the map file itself - so sharing the map with someone else will pass on the user data. You can have as many keys as you'd like.

There are also some default variables you can change for different effects.

table of default variables for setRoomUserData()
Variable Effect
room.ui_showName toggle displaying of the room nam
room.ui_nameOffset "x y" an offset to move the text - integers separated by a space
room.ui_nameFont the name of the font to use on the name label
room.ui_nameSize the size of the font to use on the name label
room.ui_nameColor the colour to set the name label text
room.ui_borderColor the colour of the room border
room.ui_borderThickness the thickness of the room border


Returns true if successfully set.
See also: clearRoomUserData(), clearRoomUserDataItem(), getAllRoomUserData(), getRoomUserData(), searchRoomUserData()


Example
-- can use it to store room descriptions...
setRoomUserData(341, "description", "This is a plain-looking room.")

-- or whenever it's outdoors or not...
setRoomUserData(341, "outdoors", "true")

-- how how many times we visited that room
local visited = getRoomUserData(341, "visitcount")
visited = (tonumber(visited) or 0) + 1
setRoomUserData(341, "visitcount", tostring(visited))

-- can even store tables in it, using the built-in yajl.to_string function
setRoomUserData(341, "some table", yajl.to_string({name = "bub", age = 23}))
display("The denizens name is: "..yajl.to_value(getRoomUserData(341, "some table")).name)

getRoomBorderColor, PR #8758

r, g, b, a = getRoomBorderColor(roomID)
Returns the custom border color for a room, if one has been set.
See also: setRoomBorderColor(), clearRoomBorderColor()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to get the border color for.
Returns
  • Four numbers (r, g, b, a) if a custom border color is set, or nil if the room uses the global default border color. Returns nil and an error message if no map is loaded or the room ID is invalid.
Example
-- Check if room 1 has a custom border color
local r, g, b, a = getRoomBorderColor(1)
if r then
    echo(string.format("Room 1 has custom border: RGB(%d, %d, %d) Alpha: %d\n", r, g, b, a))
else
    echo("Room 1 uses the global border color\n")
end

clearRoomBorderColor, PR #8758

clearRoomBorderColor(roomID)
Removes the custom border color from a room, causing it to use the global map border color setting.
See also: setRoomBorderColor(), getRoomBorderColor()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to clear the custom border color from.
Returns
  • true on success, or nil and an error message if no map is loaded or the room ID is invalid.
Example
-- Reset room 1 to use the global border color
clearRoomBorderColor(1)

-- Clear custom borders from all rooms in an area
for _, roomID in ipairs(getAreaRooms(5)) do
    clearRoomBorderColor(roomID)
end

setRoomBorderStyle, PR #8985

setRoomBorderStyle(roomID, style)
Sets the border style for a specific room on the map. This allows visually distinguishing rooms with dashed or dotted borders instead of the

default solid border - useful for marking temporary, unvisited, or special rooms.

See also: setRoomBorderColor(), setRoomBorderThickness(), getRoomBorderStyle(), clearRoomBorderStyle()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to set the border style for.
  • style:
The border style to apply. Valid values: "dashed" (or "dash line") for a dashed border, "dotted" (or "dot line") for a dotted border, or "solid" to reset to the default solid border.
Returns
  • true on success, or nil and an error message if no map is loaded or the room ID is invalid.
Example
-- set room 1234 to have a dashed border
setRoomBorderStyle(1234, "dashed")

-- set room 1234 to have a dotted border
setRoomBorderStyle(1234, "dotted")

-- reset room 1234 back to solid border
setRoomBorderStyle(1234, "solid")

getRoomBorderStyle, PR #8985

getRoomBorderStyle(roomID)
Returns the border style for a specific room on the map.
See also: setRoomBorderStyle(), clearRoomBorderStyle()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to get the border style for.
Returns
  • "dashed" if the room has a dashed border, "dotted" if the room has a dotted border, or nil if the room has the default solid border.
Example
local style = getRoomBorderStyle(1234)
if style then
  echo(f"Room 1234 has a {style} border.\n")
else
  echo("Room 1234 has a solid (default) border.\n")
end

clearRoomBorderStyle, PR #8985

clearRoomBorderStyle(roomID)
Resets the border style for a specific room back to the default solid border.
See also: setRoomBorderStyle(), getRoomBorderStyle()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to clear the border style for.
Returns
  • true on success, or nil and an error message if no map is loaded or the room ID is invalid.
Example
-- reset room 1234 back to solid border
clearRoomBorderStyle(1234)

setRoomBorderThickness, PR #8758

setRoomBorderThickness(roomID, thickness)
Sets a custom border thickness for an individual room on the 2D map. When set, this thickness overrides the global default for that specific room.
See also: getRoomBorderThickness(), clearRoomBorderThickness(), setRoomBorderColor()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to set the border thickness for.
  • thickness:
The border thickness (1-10).
Returns
  • true on success, or nil and an error message if no map is loaded, the room ID is invalid, or the thickness is out of range.
Example
-- Set room 1 to have a thick border
setRoomBorderThickness(1, 5)

-- Highlight important rooms with thick red borders
local importantRooms = {1, 5, 10, 15}
for _, roomID in ipairs(importantRooms) do
    setRoomBorderColor(roomID, 255, 0, 0)
    setRoomBorderThickness(roomID, 3)
end

getRoomBorderThickness, PR #8758

thickness = getRoomBorderThickness(roomID)
Returns the custom border thickness for a room, if one has been set.
See also: setRoomBorderThickness(), clearRoomBorderThickness()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to get the border thickness for.
Returns
  • The thickness value (1-10) if a custom thickness is set, or nil if the room uses the global default thickness. Returns nil and an error message if no map is loaded or the room ID is invalid.
Example
-- Check if room 1 has a custom border thickness
local thickness = getRoomBorderThickness(1)
if thickness then
    echo(string.format("Room 1 has custom border thickness: %d\n", thickness))
else
    echo("Room 1 uses the global border thickness\n")
end

clearRoomBorderThickness, PR #8758

clearRoomBorderThickness(roomID)
Removes the custom border thickness from a room, causing it to use the global default thickness.
See also: setRoomBorderThickness(), getRoomBorderThickness()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • roomID:
The ID of the room to clear the custom border thickness from.
Returns
  • true on success, or nil and an error message if no map is loaded or the room ID is invalid.
Example
-- Reset room 1 to use the global border thickness
clearRoomBorderThickness(1)

-- Clear all custom border settings from a room
clearRoomBorderColor(1)
clearRoomBorderThickness(1)


mapSymbolFontInfo, PR #4038 closed

mapSymbolFontInfo()
See also: setupMapSymbolFont()

Note Note: pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/4038

returns
  • either a table of information about the configuration of the font used for symbols in the (2D) map, the elements are:
  • fontName - a string of the family name of the font specified
  • onlyUseThisFont - a boolean indicating whether glyphs from just the fontName font are to be used or if there is not a glyph for the required grapheme (character) then a glyph from the most suitable different font will be substituted instead. Should this be true and the specified font does not have the required glyph then the replacement character (typically something like ) could be used instead. Note that this may not affect the use of Color Emoji glyphs that are automatically used in some OSes but that behavior does vary across the range of operating systems that Mudlet can be run on.
  • scalingFactor - a floating point number between 0.50 and 2.00 which modifies the size of the symbols somewhat though the extremes are likely to be unsatisfactory because some of the particular symbols may be too small (and be less visible at smaller zoom levels) or too large (and be clipped by the edges of the room rectangle or circle).
  • or nil and an error message on failure.
As the symbol font details are stored in the (binary) map file rather than the profile then this function will not work until a map is loaded (or initialized, by activating a map window).

moveMapLabel, PR #6014 open

moveMapLabel(areaID/Name, labeID/Text, coordX/deltaX, coordY/deltaY[, coordZ/deltaZ][, absoluteNotRelativeMove])

Re-positions a map label within an area in the 2D mapper, in a similar manner as the moveRoom() function does for rooms and their custom exit lines. When moving a label to given coordinates this is the position that the top-left corner of the label will be positioned at; since the space allocated to a particular room on the map is ± 0.5 around the integer value of its x and y coordinates this means for a label which has a size of 1.0 x 1,0 (w x h) to position it centrally in the space for a single room at the coordinates (x, y, z) it should be positioned at (x - 0.5, y + 0.5, z).

See also: getMapLabels(), getMapLabel().
Mudlet VersionAvailable in Mudlet ?.??+

Note Note: pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/6014

Parameters
  • areaID/Name:
Area ID as number or AreaName as string containing the map label.
  • labelID/Text:
Label ID as number (which will be 0 or greater) or the LabelText on a text label. All labels will have a unique ID number but there may be more than one text labels with a non-empty text string; only the first matching one will be moved by this function and image labels also have no text and will match the empty string. with mo or AreaName as string containing the map label.
  • coordX/deltaX:
A floating point number for the absolute coordinate to use or the relative amount to move the label in "room coordinates" along the X-axis.
  • coordY/deltaY:
A floating point number for the absolute coordinate to use or the relative amount to move the label in "room coordinates" along the Y-axis.
  • coordZ/deltaZ:
(Optional) A floating point number for the absolute coordinate to use or the relative amount to move the label in "room coordinates" along the Z-axis, if omitted the label is not moved in the z-axis at all.
  • absoluteNotRelativeMove:
(Optional) a boolean value (defaults to false if omitted) as to whether to move the label to the absolute coordinates (true) or to move it the relative amount from its current location (false).
Returns
true on success or nil and an error message on failure, if successful it will also refresh the map display to show the result.
Example
-- move the first label in the area with the ID number of 2, three spaces to the east and four spaces to the north
moveMapLabel(0, 2, 3.0, 4.0)

-- move the first label in the area with the ID number of 2, one space to the west, note the final boolean argument is unneeded
moveMapLabel(0, 2, -1.0, 0.0, false)

-- move the second label in the area with the ID number of 2, three and a half spaces to the west, and two south **of the center of the current level it is on in the map**:
moveRoom(1, 2, -3.5, -2.0, true)

-- move the second label in the area with the ID number of 2, up three levels
moveRoom(1, 2, 0.0, 0.0, 3.0)

-- move the second label in the "Test 1" area one space to the west, note the last two arguments are unneeded
moveRoom("Test 1", 1, -1.0, 0.0, 0.0, false)

-- move the (top-left corner of the first) label with the text "Home" in the area with ID number 5 to the **center of the whole map**, note the last two arguments are required in this case:
moveRoom(5, "Home", 0.0, 0.0, 0.0, true)

-- all of the above will return the 'true'  boolean value assuming there are the indicated labels and areas

moveRoom, PR #6010 open

moveRoom(roomID, coordX/deltaX, coordY/deltaY[, coordZ/deltaZ][, absoluteNotRelativeMove])

Re-positions a room within an area, in the same manner as the "move to" context menu item for one or more rooms in the 2D mapper. Like that method this will also shift the entirety of any custom exit lines defined for the room concerned. This contrasts with the behavior of the setRoomCoordinates() which only moves the starting point of such custom exit lines so that they still emerge from the room to which they belong but otherwise remain pointing to the original place.

See also: setRoomCoordinates()
Mudlet VersionAvailable in Mudlet ?.??+

Note Note: pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/6010

Parameters
  • roomID:
Room ID number to move.
  • coordX/deltaX:
The absolute coordinate or the relative amount as a number to move the room in "room coordinates" along the X-axis.
  • coordY/deltaY:
The absolute coordinate or the relative amount as a number to move the room in "room coordinates" along the Y-axis.
  • coordZ/deltaZ:
(Optional) the absolute coordinate or the relative amount as a number to move the room in "room coordinates" along the Z-axis, if omitted the room is not moved in the z-axis at all.
  • absoluteNotRelativeMove:
(Optional) a boolean value (defaults to false if omitted) as to whether to move the room to the absolute coordinates (true) or the relative amount from its current location (false).
Returns
true on success or nil and an error message on failure, if successful it will also refresh the map display to show the result.
Example
-- move the first room one space to the east and two spaces to the north
moveRoom(1, 1, 2)

-- move the first room one space to the west, note the final boolean argument is unneeded
moveRoom(1, -1, 0, false)

-- move the first room three spaces to the west, and two south **of the center of the current level it is on in the map**:
moveRoom(1, -3, -2, true)

-- move the second room up three levels
moveRoom(2, 0, 0, 3)

-- move the second room one space to the west, note the last two arguments are unneeded
moveRoom(2, -1, 0, 0, false)

-- move the second room to the **center of the whole map**, note the last two arguments are required in this case:
moveRoom(2, 0, 0, 0, true)

-- all of the above will return the 'true'  boolean value assuming there are rooms with 1 and 2 as ID numbers

setExitWeightFilter, PR #8487 open

setExitWeightFilter(callback)
installs a custom filter that lets you adjust or block exits while Mudlet computes routes.
Use setExitWeightFilter(nil) to remove the filter and restore stored exit weights.


Note Note: setExitWeightFilter Each call clears the cached routing graph so Mudlet rebuilds it using the new logic. If your callback input is changed it might be worth setting new filter once again.


Parameters

callback one of:

  • a Lua function function(roomId, exitCommand) that Mudlet calls during pathfinding;
  • nil to clear the currently installed filter.
The callback receives:
roomId — numeric id of the room the exit begins in;
  • exitCommand — command string to take that exit (e.g. "north" or a custom command).
The callback may return:
a number to override the exit weight (lower weights are preferred);
  • false or the string "block" to prevent Mudlet from considering the exit;
  • nil to keep Mudlet’s original weight.
Returns

true on success;

nil and an error message if the pathfinding data cannot be updated (e.g. no map loaded).

Example
discourage mountain travel if your char is not dwarf, and totally avoid for elves
local race = getCharacterRaceFromFancyScript()
local mountainsEnv = 100
setExitWeightFilter(function(roomId, exitCommand)
    -- Block entirely for elves
    if race == "elf" then
       return "block" -- or false
    end
    
    -- Look up the current weight so we can base adjustments on it.
    local currentWeight = getRoomWeight(roomID) or 0
    -- Add a penalty to room for not dwarfs
    if race ~= "dwarf" and mountainsEnv == getRoomEnv(roomID) then
       return currentWeight + 25
    end
    
    -- No change: keep Mudlet's original weight.
    return nil
end)
Clearing the filter

Remove the custom logic and restore default weighting:

 setExitWeightFilter(nil)

setupMapSymbolFont, PR #4038 closed

setupMapSymbolFont(fontName[, onlyUseThisFont[, scalingFactor]])
configures the font used for symbols in the (2D) map.
See also: mapSymbolFontInfo()

Note Note: pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/4038

Parameters
  • fontName one of:
  • - a string that is the family name of the font to use;
  • - the empty string "" to reset to the default {which is "Bitstream Vera Sans Mono"};
  • - a Lua nil as a placeholder to not change this parameter but still allow a following one to be modified.
  • onlyUseThisFont (optional) one of:
  • - a Lua boolean true to require Mudlet to use graphemes (character) only from the selected font. Should a requested grapheme not be included in the selected font then the font replacement character (�) might be used instead; note that under some circumstances it is possible that the OS (or Mudlet) provided color Emoji Font may still be used but that cannot be guaranteed across all OS platforms that Mudlet might be run on;
  • - a Lua boolean false to allow Mudlet to get a different glyph for a particular grapheme from the most suitable other font found in the system should there not be a glyph for it in the requested font. This is the default unless previously changed by this function or by the corresponding checkbox in the Profile Preferences window for the profile concerned;
  • - a Lua nil as a placeholder to not change this parameter but still allow the following one to be modified.
  • scalingFactor (optional): a floating point value in the range 0.5 to 2.0 (default 1.0) that can be used to tweak the rectangular space that each different room symbol is scaled to fit inside; this might be useful should the range of characters used to make the room symbols be consistently under- or over-sized.
Returns
  • true on success
  • nil and an error message on failure. As the symbol font details are stored in the (binary) map file rather than the profile then this function will not work until a map is loaded (or initialised, by activating a map window).

getMapBackgroundColor, PR #8071 open

getMapBackgroundColor()
Gets the color and transparency of the map background.

See also: setMapBackgroundColor()

Returns
  • 4 integers - red, green, blue, transparency. Colors are 0 to 255 (0 being black), and transparency is 0 to 255 (0 being completely transparent).
Example
local r, g, b, a = getMapBackgroundColor()

setMapBackgroundColor, PR #8071 open

setMapBackgroundColor(r, g, b, [transparency])
Sets the color (and optionally transparency) for the map background. Colors are 0 to 255 (0 being black), and transparency is 0 to 255 (0 being completely transparent).

See also: getMapBackgroundColor()

Parameters
  • r:
Amount of red to use, 0 (none) to 255 (full).
  • g:
Amount of green to use, 0 (none) to 255 (full).
  • b:
Amount of red to use, 0 (none) to 255 (full).
  • transparency:
(optional) amount of transparency to use, 0 (fully transparent) to 255 (fully opaque). Defaults to 255 if omitted.
Example
-- make the map have a somewhat transparent red background
setMapBackgroundColor(255,0,0,200)

-- make the map have an opaque black background
setMapBackgroundColor(0,0,0)

setMapPerspective, PR #8147 open

setMapPerspective(distance, polarAngle, azimuthalAngle)
Sets the camera's position for the 3d map. See the wiki page on spherical coordinates for more clarification on the polar and azimuthal angles.

See also: shiftMapPerspective()

Parameters
  • distance:
Distance of the camera from the focal point. 1 distance is equivalent to the distance between 10 rooms on the 3d map.
  • polarAngle:
Angle of the camera from the z-axis, e.g. 0 (looking straight down from above), 90 (looking along the x/y plane) 180 (looking straight up from below).
  • azimuthalAngle:
Angle of the camera rotating counter-clockwise from the x-axis, e.g. 0 (looking west from the east), -90 or 270 (looking north from the south) etc.
Example
-- make the map perspective looking down from above at a 45 degree angle, with north facing forward (up) on the map, 5 rooms' distance from the focus point.
setMapPerspective(0.5, 45, 270)

shiftMapPerspective, PR #8147 open

shiftMapPerspective(verticalAngle, horizontalAngle, cameraRotation)
Shifts the camera's relative position for the 3d map. All arguments are expected in degrees. Each shift of the camera occurs in the order of the arguments, i.e. first vertical shift, then horizontal, and finally the camera is rotated.

See also: setMapPerspective()

Parameters
  • verticalAngle:
How many degrees to shift the camera vertically, with positive values moving the camera up.
  • horizontalAngle:
How many degrees to shift the camera horizontally, with positive values moving the camera to the right.
  • cameraRotation:
How many degrees to rotate the camera, with positive values rotating it clockwise.
Example
-- Move the camera 10 degrees down, 20 degrees to the right, and invert the map.
shiftMapPerspective(-10, 20, 180)

Miscellaneous Functions

Miscellaneous functions.

playSpatialSound, PR #8452 open

  • playSpatialSound(settings table)

Plays spatial audio files with 3D positioning using Qt6's SpatialAudio framework. Allows precise positioning, occlusion effects, room acoustics, and environmental audio for immersive gameplay experiences.

Required Key Purpose Default Description
Yes key <unique identifier> Unique key to identify this spatial sound source for later updates or removal.
Yes name <file name> Name of the audio file. May contain directory information (i.e. ambient/forest.ogg). May be part of the profile (i.e. getMudletHomeDir().. "/spatial/wind.wav") or on the local device (i.e. "C:/Users/YourName/Documents/sound.mp3").
No url <url> Resource location where the audio file may be downloaded. Only required if file is to be downloaded remotely.
No position {azimuth, elevation, distance} {0, 0, 1} 3D position as a table: azimuth (horizontal angle in degrees, 0-360), elevation (vertical angle in degrees, -90 to 90), distance (in meters, > 0).
No volume 1 to 100 50 Volume level relative to master spatial audio volume.
No occlusion 0.0 to 1.0 0.0 Occlusion factor simulating objects blocking the sound path.
No loops -1 or >= 1 1 Number of times to loop. -1 for infinite looping.
No room {dimensions, reverb, reflection, material} Room acoustics configuration table.

See also: updateSpatialSound(), stopSpatialSound(), removeSpatialSound(), getSpatialSounds()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- Play forest ambience behind the player
playSpatialSound({
    key = "forest_ambience",
    name = "ambient/forest_birds.ogg",
    position = {180, 0, 5}, -- behind player, 5 meters away  
    volume = 30,
    loops = -1 -- infinite loop
})

-- Play footsteps with room acoustics
playSpatialSound({
    key = "footsteps",
    name = "effects/footstep_stone.wav",
    position = {45, -10, 2}, -- front-right, slightly below, 2 meters
    volume = 60,
    room = {
        dimensions = {10, 3, 8}, -- 10m wide, 3m high, 8m deep
        reverb = 0.3,
        reflection = 0.7,
        material = "sheetrock"
    }
})

-- Download and play remote spatial sound
playSpatialSound({
    key = "wind_howl",
    name = "wind.ogg",
    url = "https://example.com/sounds/",
    position = {270, 45, 10}, -- left side, elevated, distant
    volume = 40,
    occlusion = 0.2 -- partially blocked
})

updateSpatialSound, PR #8452 open

  • updateSpatialSound(key, settings table)

Updates properties of an existing spatial audio source without stopping playback.

  • Parameters

• key: Unique identifier of the spatial sound source to update • settings table: Table containing properties to update (same format as playSpatialSound)

See also: playSpatialSound()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- Move sound to new position
updateSpatialSound("forest_ambience", {
    position = {90, 0, 3} -- move to right side, closer
})

-- Update volume and add occlusion
updateSpatialSound("footsteps", {
    volume = 80,
    occlusion = 0.5
})

-- Update multiple properties
updateSpatialSound("wind_howl", {
    position = {315, 30, 15},
    volume = 25,
    occlusion = 0.8
})

stopSpatialSound, PR #8452 open

  • stopSpatialSound(key)

Stops playback of a spatial audio source but keeps the source available for later use.

  • Parameters

• key: Unique identifier of the spatial sound source to stop

  • Returns

• boolean: true on success, false if source not found

See also: playSpatialSound(), removeSpatialSound()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- Stop the forest ambience
stopSpatialSound("forest_ambience")

-- Stop footsteps when player stops walking  
if not moving then
    stopSpatialSound("footsteps")
end

pauseSpatialSound, PR #8452 open

  • pauseSpatialSound(key)

Pauses playback of a spatial audio source, allowing it to be resumed later from the same position.

  • Parameters

• key: Unique identifier of the spatial sound source to pause

  • Returns

• boolean: true on success, false if source not found

See also: playSpatialSound(), stopSpatialSound()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- Pause ambient sound temporarily
pauseSpatialSound("forest_ambience")

-- Resume by playing again (will continue from pause position)
playSpatialSound({
    key = "forest_ambience",
    name = "ambient/forest_birds.ogg",
    position = {180, 0, 5}
})

removeSpatialSound, PR #8452 open

  • removeSpatialSound(key)

Completely removes a spatial audio source, stopping playback and freeing resources.

  • Parameters

• key: Unique identifier of the spatial sound source to remove

  • Returns

• boolean: true on success, false if source not found

See also: stopSpatialSound(), getSpatialSounds()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- Remove completed sound effect
removeSpatialSound("door_slam")

-- Clean up old ambient sounds
for _, key in ipairs({"old_wind", "old_rain", "old_birds"}) do
    removeSpatialSound(key)
end

getSpatialSounds, PR #8452 open

  • getSpatialSounds()

Returns a list of all currently active spatial audio sources.

  • Returns

• table: Indexed table containing the keys of all active spatial sound sources

See also: playSpatialSound(), removeSpatialSound()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- List all active spatial sounds
local activeSounds = getSpatialSounds()
for i, soundKey in ipairs(activeSounds) do
    echo("Active spatial sound: " .. soundKey .. "\n")
end

-- Stop all spatial sounds
for _, soundKey in ipairs(getSpatialSounds()) do
    stopSpatialSound(soundKey)
end

-- Check if specific sound is playing
local activeSounds = getSpatialSounds()
local isPlaying = table.contains(activeSounds, "forest_ambience")

setSpatialListener, PR #8452 open

  • setSpatialListener(settings table)

Sets the position and orientation of the spatial audio listener (the player's ears).

Required Key Purpose Default Description
No position {x, y, z} {0, 0, 0} 3D position of the listener in world coordinates.
No rotation {yaw, pitch, roll} {0, 0, 0} Orientation of the listener's head: yaw (left/right), pitch (up/down), roll (tilt).

See also: playSpatialSound()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- Set listener at origin, facing north
setSpatialListener({
    position = {0, 0, 0},
    rotation = {0, 0, 0}
})

-- Player moved to new room and is facing east  
setSpatialListener({
    position = {10, 0, 5},
    rotation = {90, 0, 0} -- 90 degrees yaw = facing east
})

-- Looking up at the sky
setSpatialListener({
    rotation = {0, 45, 0} -- 45 degrees pitch up
})

setSpatialMasterVolume, PR #8452 open

  • setSpatialMasterVolume(volume)

Sets the master volume for all spatial audio sources.

  • Parameters

• volume: Master volume level (0-100)

  • Returns

• boolean: true on success

See also: playSpatialSound()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- Set moderate spatial audio volume
setSpatialMasterVolume(60)

-- Mute all spatial audio
setSpatialMasterVolume(0)

-- Maximum spatial audio volume
setSpatialMasterVolume(100)

playSpatialTestTone, PR #8452 open

  • playSpatialTestTone(settings table)

Plays a generated test tone at a specific spatial position for testing and calibration purposes.

Required Key Purpose Default Description
Yes key <unique identifier> Unique key to identify this test tone source.
Yes type "white", "pink", or "sine" Type of test tone to generate.
Yes duration <seconds> Duration of the test tone in seconds.
Yes azimuth <degrees> Horizontal angle (0-360 degrees).
Yes elevation <degrees> Vertical angle (-90 to 90 degrees).
Yes distance <meters> Distance from listener in meters.
No frequency <Hz> 440 Frequency for sine wave test tones.
No volume 1 to 100 50 Volume of the test tone.
No loops -1 or >= 1 1 Number of loops (-1 for infinite).

See also: playSpatialSound(), stopSpatialSound()

Mudlet VersionAvailable in Mudlet4.??+
  • Example
-- Test speaker positions with white noise
playSpatialTestTone({
    key = "test_left",
    type = "white",
    duration = 2,
    azimuth = 270,   -- left side
    elevation = 0,
    distance = 2,
    volume = 70
})

-- Test frequency response with sine wave
playSpatialTestTone({
    key = "test_1khz", 
    type = "sine",
    frequency = 1000,
    duration = 3,
    azimuth = 0,     -- front center
    elevation = 0,
    distance = 1,
    volume = 50
})

-- Test distance with pink noise
playSpatialTestTone({
    key = "test_distant",
    type = "pink", 
    duration = 5,
    azimuth = 180,   -- behind
    elevation = 0,
    distance = 10,   -- far away
    volume = 80,
    loops = 2
})

getCustomLoginTextId, PR #3952 open

getCustomLoginTextId()

Returns the Id number of the custom login text setting from the profile's preferences. Returns 0 if the option is disabled or a number greater than that for the item in the table; note it is possible if using an old saved profile in the future that the number might be higher than expected. As a design policy decision it is not permitted for a script to change the setting, this function is intended to allow a script or package to check that the setting is what it expects.

Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined doLogin() function, a replacement for which is shown below.

See also: getCharacterName(), sendCharacterName(), sendCustomLoginText(), sendPassword().

Note Note: Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952

Only one custom login text has been defined initially:

Predefined custom login texts
Id Custom text Introduced in Mudlet version
1 "connect {character name} {password}" TBD

The addition of further texts would be subject to negotiation with the Mudlet Makers.

Example
-- A replacement for the default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
function doLogin()
  if getCustomLoginTextId() ~= 1 then
    -- We need this particular option but it is not permitted for a script to change the setting, it can only check what it is
    echo("\nUnable to login - please select the 'connect {character name} {password}` custom login option in the profile preferences.\n")
  else
    tempTime(2.0, [[sendCustomLoginText()]], 1)
  end
end

sendCharacterName, PR #3952 open

sendCharacterName()

Sends the name entered into the "Character name" field on the Connection Preferences form directly to the game server. Returns true unless there is nothing set in that entry in which case a nil and an error message will be returned instead.

Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined doLogin() function that may be replaced for more sophisticated requirements.

See also: getCharacterName(), sendCharacterPassword(), sendCustomLoginText(), getCustomLoginTextId().

Note Note: Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952

sendCharacterPassword, PR #3952 open

sendCharacterPassword()

Sends the password entered into the "Password" field on the Connection Preferences form directly to the game server. Returns true unless there is nothing set in that entry or it is too long after (or before) a connection was successfully made in which case a nil and an error message will be returned instead.

Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined doLogin() function, reproduced below, that may be replaced for more sophisticated requirements.

See also: getCharacterName(), sendCustomLoginText(), getCustomLoginTextId(), sendCharacterName().

Note Note: Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952

Example
-- The default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
function doLogin()
  if getCharacterName() ~= "" then
    tempTime(2.0, [[sendCharacterName()]], 1)
    tempTime(3.0, [[sendCharacterPassword()]], 1)
  end
end

sendCustomLoginText, PR #3952 open

sendCustomLoginText()

Sends the custom login text (which does NOT depend on the user's choice of GUI language) selected in the preferences for this profile. The {password} (and {character name} if present) fields will be replaced with the values entered into the "Password" and "Character name" fields on the Connection Preferences form and then sent directly to the game server. Returns true unless there is nothing set in either of those entries (though only if required for the character name) or it is too long after (or before) a connection was successfully made or if the custom login feature is disabled, in which case a nil and an error message will be returned instead.

Introduced along with four other functions to enable game server log-in to be scripted with the simultaneous movement of that functionality from the Mudlet application core code to a predefined doLogin() function, a replacement for which is shown below.

See also: getCharacterName(), sendCharacterName(), sendPassword(), getCustomLoginTextId().

Note Note: Not available yet. See https://github.com/Mudlet/Mudlet/pull/3952

Only one custom login text has been defined initially:

Predefined custom login texts
Id Custom text Introduced in Mudlet version
1 "connect {character name} {password}" TBD

The addition of further texts would be subject to negotiation with the Mudlet Makers.

Example
-- A replacement for the default function placed into LuaGlobal.lua to reproduce the previous behavior of the Mudlet application:
function doLogin()
  if getCustomLoginTextId() ~= 1 then
    -- We need this particular option but it is not permitted for a script to change the setting, it can only check what it is
    echo("\nUnable to login - please select the 'connect {character name} {password}` custom login option in the profile preferences.\n")
  else
    tempTime(2.0, [[sendCustomLoginText()]], 1)
  end
end

Mudlet Object Functions

A collection of functions that manipulate Mudlet's scripting objects - triggers, aliases, and so forth.

createComposer PR #8114 open

ok = createComposer(title, text, callbackFunction)

Creates a Composer dialog window with the given title and initial text, and registers a Lua function to handle the result. When the user clicks **Save** or **Cancel**, the Composer closes and your callback function is invoked with two arguments: the resulting text and a boolean indicating whether the user saved (true) or canceled editing (false).

See also
getComposerText(), setComposerText(), getComposerTitle(), setComposerTitle()
Mudlet VersionAvailable in Mudlet4.20+
Parameters
  • title:
The title of the Composer window.
  • text:
The initial text content in the Composer. You can use \n to start a new line, \t for tabulators, etc.
  • callbackFunction:
A Lua function to call when the Composer closes. It will receive two parameters:
  • A string with the text the user entered.
  • A boolean value – `true` if the user clicked **Save**, `false` if they clicked **Cancel**.
Returns
  • Boolean `true` if the Composer was successfully created, otherwise nil + error (for example, if another Composer is already open).
Example
-- Create a Composer window for editing a note
createComposer("Edit Note", "Default text", function(editedText, isSaved)
    if isSaved then
        echo(f"Saved text: {editedText}\n")
    else
        echo("Edit was canceled.\n")
    end
end)

getComposerText PR #8114 open

text = getComposerText()

Returns the current text from the Composer window, if it is open.

See also
createComposer(), setComposerText()
Mudlet VersionAvailable in Mudlet4.20+
Parameters
  • (none)
Returns
  • The text currently displayed in the Composer, or nil + error if the Composer is not open.
Example
-- Retrieve and print the current text from the Composer
local currentText = getComposerText()
if currentText then
    echo(f"Current text in Composer: {currentText}\n")
else
    echo("No Composer is open.\n")
end


getComposerTitle PR #8114 open

title = getComposerTitle()

Returns the current title from the Composer window, if it is open.

See also
createComposer(), setComposerTitle()
Mudlet VersionAvailable in Mudlet4.20+
Parameters
  • (none)
Returns
  • The current title of the Composer, or nil + error if the Composer is not open.
Example
-- Print the Composer title
local currentTitle = getComposerTitle()
if currentTitle then
    echo(f"Composer title: {currentTitle}\n")
else
    echo("No Composer is open.\n")
end

getKeyCode PR#8435 open

keyCode, keyModifers = getKeyCode(keyID/keyName)
Returns numbers representing the key and any modifiers for a key-binding.
See also
enableKey(...), killKey(...), tempKey(...), findItems(...),

Note Note: If a name is given and it is used by more than one key then only the first one found will be considered by this function.

Note Note: Modifiers vary between different operating systems and not all of them will be present or have the names given below for all users on all systems.

Parameters
  • mandatoryParameter:
either the ID (number) e.g. as returned by the permKey(...) or tempKey(...) functions; or the "name" (string) of a key-binding.
Returns
  • Returns two values on success: the key code as used in the functions to create a key-binding; and any modifiers as a sum of the following (including as powers of two).
Modifiers table
Modifier Value (hex) Value (dec) 2n
Shift 0x02000000 33,554,432 21
Control 0x04000000 67,108,864 22
Alt 0x08000000 134,217,728 23
Keypad 0x10000000 268,435,456 24
GroupSwitch 0x20000000 536,870,912 25

The list of key codes is rather long to include here, instead view the original code in the Mudlet GitHub repository [[1]].

  • Returns two values on failure: a Lua nil and an error message,
Example
--[[Temporarily make Shift+Alt+T put something on the main console - and remember the ID for the key-binding
so it can be removed afterwards {as a temporary one it won't show up in the Editor!}]]-- 
testKey = tempKey(mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"], mudlet.key["T"], [[echo("You pressed Shift+Alt+T didn't you!\n"]])

----Try the combination and prove that it works, then use the function to check it:
usedKey, usedModifiers = getKeyCode(testKey)
if usedKey == mudlet.T and usedModifiers == (mudlet.keymodifier.Shift + mudlet.keymodifier.Alt) then
  echo("It seems that the testKey (with ID = " .. testKey .. ") IS using the 'T' key and the 'Shift' and 'Alt' modifiers.\n")
end
----AFTER testing this, do the following to remove all the traces:
killKey(testKey)
testKey = nil
usedKey = nil
usedModifiers = nil

--Now do the same with a permanent key-binding
permKey("TestKey", "", mudlet.keymodifier["Shift"] + mudlet.keymodifier["Control"], mudlet.key["T"], [[echo("You pressed Shift+Cntl+T didn't you!\n"]])

----Try the combination and prove that it works, then use the function to check it:
usedKey, usedModifiers = getKeyCode("TestKey")
if usedKey == mudlet.T and usedModifiers == (mudlet.keymodifier.Shift + mudlet.keymodifier.Alt) then
  echo("It seems that the testKey (with name = \"TestKey\" IS using the 'T' key and the 'Shift' and 'Control' modifiers.\n")
end

----AFTER testing this, do the following to remove all the traces:
usedKey = nil
usedModifiers = nil
----AND also look for the top level "Test Key" in the "Keys" view in the editor, select it, and click the "Delete" button to remove it.

--[[Lastly, check to see if there is already a key binding for <Shift>+<Ctrl>+R
For reuse let's make it a general function - which can be copied into the code for a profile]]--
function isKeyUsed(soughtKey, soughtModifiers)
  --first get the IDs of all the current key-bindings
  local allKeys = findItems("", "keybinding", false)

  --then scan through them looking for matches for the one we want
  for _, keyID in pairs(allKeys) do
    local key, modifiers = getKeyCode(keyID)
    if key == soughtKey and modifiers == soughtModifiers then
      --got one!
      return true
    end
  end

  return false
end

----Now lets try it out - assuming that Alt+Shift+R hasn't been used so far
if isKeyUsed(mudlet.key["R"], mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"]) then
  echo "The Alt+Shift+R is already used!"
else
  echo "The Alt+Shift+R key-binding is available..."
end

----[[Let's define it temporarily to send "rent" to the game server (and mention it on screen)
remembering the ID so we can delete the key-binding after use and then forget the ID]]----
rentKey = tempKey(mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"], mudlet.key["R"], [[send("rent", true) killKey(]] .. rentKey .. [[) rentKey = nil]])

----Now we can check for it (before we use it!)
if isKeyUsed(mudlet.key["R"], mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"]) then
  echo "The Alt+Shift+R is now used!"
else
  echo "The Alt+Shift+R isn't used now..."
end

----[[It is left to the reader/user to press this combination at a suitable point - either whilst connected to
a MUD to which they want to save and presumable disconnect from - or whilst disconnected to just see the
text on screen]]----

--Finally some of the error messages
----in this case an invalid keyID
local ok, err = getKeyCode(-1)
if not ok then
  debugc(f"Error: {err}\n")
  return
end

----and here providing the arguments as a table instead of an ID number or name string and a modifier:
local ok, err = getKeyCode({mudlet.key["R"], mudlet.keymodifier["Shift"] + mudlet.keymodifier["Alt"]})
if not ok then
  debugc(f"Error: {err}\n")
  return
end
Additional development notes

setComposerText PR #8114 open

setComposerText(newText)

Sets the text content of the Composer window, if it is open.

See also
createComposer(), getComposerText()
Mudlet VersionAvailable in Mudlet4.20+
Parameters
  • newText:
The text to display in the Composer. You can use \n to start a new line, \t for tabulators, etc.
Returns
  • Boolean `true` if the Title was successfully set, or nil + error if no Composer is open.
Example
-- Change the Composer text dynamically
setComposerText("Updated text for the Composer")

setComposerTitle PR #8114 open

setComposerTitle(newTitle)

Sets the title of the Composer window, if it is open.

See also
createComposer(), getComposerTitle()
Mudlet VersionAvailable in Mudlet4.20+
Parameters
  • newTitle:
The title to display in the Composer.
Returns
  • Boolean `true` if the Title was successfully set, or nil + error if no Composer is open.
Example
-- Change the Composer title dynamically
setComposerTitle("Declaration of Independence")

Networking Functions

A collection of functions for managing networking.

getTelnetOptionsStatus PR #8962, open

getTelnetOptionsStatus()
Returns the current status of telnet options that have been negotiated between Mudlet and the game server. This function is useful for debugging telnet protocol issues and understanding which features are currently enabled in your connection. The values returned are the same as those that would be reported back to the Server if it requested them via the telnet option number 5 (STATUS).
The function returns a table where each key is a telnet option number (0-255), and the value is a sub-table containing the option details. Only options that have been negotiated so far during the telnet session are included in the results. As nearly all options are handled separately in the two directions each numbered option has two statuses to report,
See also: Telnet Protocols
Mudlet VersionAvailable in Mudlet4.21+
Returns
  • A table with telnet option numbers as keys, each containing:
    • Name: A string with the human-readable name of the telnet option (e.g., "ECHO (1)", "NAWS (31)", "MCCP2 (86)")
    • Server: (optional) Boolean indicating if the server (who sent the <IAC><WILL><OPTION> to which Mudlet replied<IAC><DO><OPTION> to agree or <IAC><DONT><OPTION> to disagree to it) has this option enabled (true) or disabled (false). Only present if the server requested this option.
    • Mudlet: (optional) Boolean indicating if Mudlet (who sent the <IAC><WILL><OPTION> to which the Server replied <IAC><DO><OPTION> to agree or <IAC><DONT><OPTION> to disagree to it) has this option enabled (true) or disabled (false). Only present if Mudlet requested this option.
Example
-- Display all negotiated telnet options
local options = getTelnetOptionsStatus()

cecho("<cyan>Current Telnet Options Status:\n")
for optionNumber, details in pairs(options) do
  cecho(string.format("<white>Option %d: <yellow>%s<reset>\n", optionNumber, details.Name))
  
  if details.Server ~= nil then
    if details.Server then
      cecho("  <white>Server: <green>enabled<reset>\n")
    else
      cecho("  <white>Server: <red>disabled<reset>\n")
    end
  end
  
  if details.Mudlet ~= nil then
    if details.Mudlet ~= nil then
      cecho("  <white>Mudlet: <green>enabled<reset>\n")
    else
      cecho("  <white>Mudlet: <red>disabled<reset>\n")
    end
  end
end
-- Check if compression (MCCP2) is enabled
local options = getTelnetOptionsStatus()

-- Option 86 is MCCP2 (Mud Client Compression Protocol 2)
if options[86] and options[86].Server then
  cecho("<green>Compression is enabled!\n")
else
  cecho("<red>Compression is not active.\n")
end
-- Monitor telnet negotiation on connect
function checkTelnetFeatures()
  local options = getTelnetOptionsStatus()
  
  -- Check for common features
  local features = {
    [1] = "Echo",
    [3] = "Suppress Go Ahead", 
    [24] = "Terminal Type",
    [31] = "Negotiate Window Size (NAWS)",
    [69] = "MSDP",
    [86] = "MCCP2 Compression",
    [201] = "GMCP"
  }
  
  cecho("<cyan>Enabled Features:\n")
  for optNum, name in pairs(features) do
    if options[optNum] then
      local status = "announced"
      if options[optNum].Server and options[optNum].Mudlet then
        status = "fully enabled"
      elseif options[optNum].Server then
        status = "server enabled"
      elseif options[optNum].Mudlet then
        status = "client enabled"
      end
      cecho(string.format("<white>%s: <green>%s\n", name, status))
    end
  end
end

registerAnonymousEventHandler("sysConnectionEvent", "checkTelnetFeatures")

Note Note: This function is primarily intended for debugging telnet protocol issues. Most users won't need to use it in normal scripts, as Mudlet handles telnet negotiation automatically. At the time of introduction there is a suspicion that the status of some options were not being correctly handled and this function was created to provide a means to monitor them.

Note Note: pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/8962

String Functions

These functions are used to manipulate strings.

Table Functions

These functions are used to manipulate tables. Through them you can add to tables, remove values, check if a value is present in the table, check the size of a table, and more.

Text to Speech Functions

These functions are used to create sound from written words. Check out our Text-To-Speech Manual for more detail on how this all works together.

UI Functions

These functions are used to construct custom user GUIs. They deal mainly with miniconsole/label/gauge creation and manipulation as well as displaying or formatting information on the screen.

createTextEdit, PR #8986

createTextEdit([windowName,] name, x, y, width, height)
Creates a new multi-line text editor widget. The text edit can be placed inside the main window or a user window. It supports word wrap, custom

fonts, stylesheets, placeholder text, and read-only mode. Use deleteTextEdit() to remove it.

Standard window functions (moveWindow(), resizeWindow(),

showWindow(), hideWindow(), raiseWindow(), lowerWindow(), setWindow()) all work with text edit widgets. windowType() returns "textedit" for these widgets.

See also: deleteTextEdit(), getTextEditText(), setTextEditText()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • windowName:
(optional) The name of the parent user window. Defaults to the main window if omitted.
  • name:
The name of the text edit to create.
  • x:
The x-coordinate of the text edit.
  • y:
The y-coordinate of the text edit.
  • width:
The width of the text edit.
  • height:
The height of the text edit.
Returns
  • true on success, or raises an error if the text edit could not be created.
Example
-- create a text edit on the main window
createTextEdit("myEditor", 10, 10, 400, 200)

-- create a text edit inside a user window
createTextEdit("myUserWindow", "myEditor", 10, 10, 400, 200)

-- Geyser usage
local editor = Geyser.TextEdit:new({
name = "myEditor",
x = 10, y = 10,
width = 400, height = 200,
})

-- set some text and a placeholder
editor:setText("Hello world!")
editor:setPlaceholder("Type here...")

deleteTextEdit, PR #8986

deleteTextEdit(name)
Deletes a text edit widget. Raises the sysTextEditDeleted event with the text edit name as an

argument.

See also: createTextEdit()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit to delete.
Returns
  • true on success, or false and an error message if the text edit was not found.
Example
deleteTextEdit("myEditor")

getTextEditText, PR #8986

getTextEditText(name)
Returns the current plain text content of a text edit widget.
See also: setTextEditText(), clearTextEdit()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit to get the text from.
Returns
  • The text content as a string, or raises an error if the text edit was not found.
Example
local text = getTextEditText("myEditor")
echo("Editor contains: " .. text .. "\n")

-- Geyser usage
local text = myEditor:getText()

setTextEditText, PR #8986

setTextEditText(name, text)
Sets the plain text content of a text edit widget, replacing any existing content.
See also: getTextEditText(), clearTextEdit()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit.
  • text:
The text to set.
Returns
  • true on success, or raises an error if the text edit was not found.
Example
setTextEditText("myEditor", "Hello world!")

-- Geyser usage
myEditor:setText("Hello world!")

clearTextEdit, PR #8986

clearTextEdit(name)
Clears all text from a text edit widget.
See also: setTextEditText(), getTextEditText()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit to clear.
Returns
  • true on success, or raises an error if the text edit was not found.
Example
clearTextEdit("myEditor")

-- Geyser usage
myEditor:clear()

setTextEditReadOnly, PR #8986

setTextEditReadOnly(name, state)
Sets whether a text edit widget is read-only. When read-only, the user cannot edit the text but can still select and copy it.
See also: createTextEdit()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit.
  • state:
true to make the text edit read-only, false to make it editable.
Returns
  • true on success, or raises an error if the text edit was not found.
Example
-- make it read-only to display content
setTextEditReadOnly("myEditor", true)

-- make it editable again
setTextEditReadOnly("myEditor", false)

-- Geyser usage
myEditor:setReadOnly(true)

setTextEditPlaceholder, PR #8986

setTextEditPlaceholder(name, text)
Sets the placeholder text displayed when the text edit is empty. The placeholder text is shown in a lighter color and disappears when the user

starts typing.

See also: createTextEdit()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit.
  • text:
The placeholder text to display.
Returns
  • true on success, or raises an error if the text edit was not found.
Example
setTextEditPlaceholder("myEditor", "Write your message here...")

-- Geyser usage
myEditor:setPlaceholder("Write your message here...")

setTextEditStyleSheet, PR #8986

setTextEditStyleSheet(name, css)
Applies a Qt stylesheet to a text edit widget for custom visual styling, such as colors, borders, and padding.
See also: createTextEdit()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit.
  • css:
A Qt stylesheet string.
Returns
  • true on success, or raises an error if the text edit was not found.
Example
setTextEditStyleSheet("myEditor", [[
QPlainTextEdit {
background-color: #1a1a2e;
color: #e0e0e0;
border: 1px solid #444;
padding: 5px;
}
]])

-- Geyser usage
myEditor:setStyleSheet([[
QPlainTextEdit {
background-color: #1a1a2e;
color: #e0e0e0;
border: 1px solid #444;
padding: 5px;
}
]])

setTextEditFont, PR #8986

setTextEditFont(name, fontName)
Sets the font family of a text edit widget.
See also: setTextEditFontSize()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit.
  • fontName:
The name of the font family to use (e.g. "Ubuntu Mono", "Courier New").
Returns
  • true on success, or raises an error if the text edit was not found.
Example
setTextEditFont("myEditor", "Ubuntu Mono")

-- Geyser usage
myEditor:setFont("Ubuntu Mono")

setTextEditFontSize, PR #8986

setTextEditFontSize(name, size)
Sets the font size of a text edit widget in points.
See also: setTextEditFont()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit.
  • size:
The font size in points.
Returns
  • true on success, or raises an error if the text edit was not found.
Example
setTextEditFontSize("myEditor", 14)

-- Geyser usage
myEditor:setFontSize(14)

setTextEditTabMovesFocus, PR #8986

setTextEditTabMovesFocus(name, state)
Controls whether pressing Tab in the text edit inserts a tab character or moves focus to the next widget. By default, Tab inserts a tab

character.

See also: createTextEdit()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • name:
The name of the text edit.
  • state:
true to have Tab move focus to the next widget, false to have Tab insert a tab character (default behavior).
Returns
  • true on success, or raises an error if the text edit was not found.
Example
-- make Tab move focus instead of inserting a tab
setTextEditTabMovesFocus("myEditor", true)

-- Geyser usage
myEditor:setTabMovesFocus(true)

--- And here's the event documentation that should be added to the Events section (if one exists on Area 51), or noted alongside the functions:

sysTextEditDeleted, PR #8986

Raised when a text edit widget is deleted via deleteTextEdit() or when the Geyser wrapper calls its type_delete method.
Arguments
  • arg1: "sysTextEditDeleted"
  • arg2: The name of the deleted text edit.
Example
function onTextEditDeleted(event, name)
echo("Text edit deleted: " .. name .. "\n")
end
registerAnonymousEventHandler("sysTextEditDeleted", onTextEditDeleted)


setBackgroundImage (updated), PR #8935

Note Note: As of Mudlet 4.21, setBackgroundImage() supports SVG files in addition to raster images (PNG, JPG, etc). Simply pass a path to an .svg file. SVG backgrounds can then be transformed using setSvgRotation(), setSvgShear(), and reset with resetSvgTransform(). SVG images are rendered at full resolution regardless of HiDPI scaling.

Example
-- set an SVG background on a label
setBackgroundImage("myLabel", getMudletHomeDir() .. "/compass.svg", 4)

-- rotate it 45 degrees
setSvgRotation("myLabel", 45)

-- Geyser usage
myLabel:setBackgroundImage(getMudletHomeDir() .. "/compass.svg")
myLabel:setSvgRotation(45)

setSvgRotation, PR #8935

setSvgRotation(labelName, angle)
Sets the rotation angle for a label's SVG background image. The SVG is rotated around its center; label text and background color are unaffected. Requires the label to have an
SVG background set via setBackgroundImage().
See also: resetSvgRotation(), setSvgShear(), resetSvgTransform()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • labelName:
The name of the label to rotate the SVG background for.
  • angle:
Rotation angle in degrees (positive = clockwise).
Returns
  • true on success, or nil and an error message if the label is not found.
Example
-- rotate the SVG background 45 degrees clockwise
setSvgRotation("myLabel", 45)

-- rotate it upside down
setSvgRotation("myLabel", 180)

-- Geyser usage
myLabel:setSvgRotation(45)

resetSvgRotation, PR #8935

resetSvgRotation(labelName)
Resets the SVG background image rotation to 0 degrees.
See also: setSvgRotation(), resetSvgTransform()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • labelName:
The name of the label to reset the SVG rotation for.
Returns
  • true on success, or nil and an error message if the label is not found.
Example
resetSvgRotation("myLabel")

-- Geyser usage
myLabel:resetSvgRotation()

setSvgShear, PR #8935

setSvgShear(labelName, shearX, shearY)
Sets the shear (skew) for a label's SVG background image. The SVG is sheared around its center; label text and background color are unaffected. Requires the label to have an

SVG background set via setBackgroundImage().

See also: resetSvgShear(), setSvgRotation(), resetSvgTransform()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • labelName:
The name of the label to shear the SVG background for.
  • shearX:
Horizontal shear factor.
  • shearY:
Vertical shear factor.
Returns
  • true on success, or nil and an error message if the label is not found.
Example
-- apply a horizontal skew to the SVG background
setSvgShear("myLabel", 0.3, 0)

-- apply both horizontal and vertical skew
setSvgShear("myLabel", 0.2, 0.1)

-- Geyser usage
myLabel:setSvgShear(0.3, 0)

resetSvgShear, PR #8935

resetSvgShear(labelName)
Resets the SVG background image shear to (0, 0).
See also: setSvgShear(), resetSvgTransform()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • labelName:
The name of the label to reset the SVG shear for.
Returns
  • true on success, or nil and an error message if the label is not found.
Example
resetSvgShear("myLabel")

-- Geyser usage
myLabel:resetSvgShear()

resetSvgTransform, PR #8935

resetSvgTransform(labelName)
Resets all SVG transforms (rotation and shear) back to defaults, but preserves any SVG tint. This is a convenience function equivalent to calling both

resetSvgRotation() and resetSvgShear().

See also: setSvgRotation(), setSvgShear(), resetSvgRotation(), resetSvgShear()
Mudlet VersionAvailable in Mudlet4.21+
Parameters
  • labelName:
The name of the label to reset all SVG transforms for.
Returns
  • true on success, or nil and an error message if the label is not found.
Example
-- reset all transforms at once
resetSvgTransform("myLabel")

-- Geyser usage
myLabel:resetSvgTransform()

getBorderColor, PR #8688

getBorderColor()
Returns the RGB values of the main window border color (the area outside the main console where the mapper, buttons, and other UI elements are placed).
See also: setBorderColor(), getBorderSizes(), getBackgroundColor()
Example
-- get the current border color
local r, g, b = getBorderColor()
echo(string.format("Border color is RGB(%d, %d, %d)\n", r, g, b))

-- check if border is using default black color
local r, g, b = getBorderColor()
if r == 0 and g == 0 and b == 0 then
  echo("Border is black - consider customizing it!\n")
end

-- store current color before changing it
local oldR, oldG, oldB = getBorderColor()
setBorderColor(50, 50, 50)
-- later, restore the original color
setBorderColor(oldR, oldG, oldB)


insertPopup, revised in PR #6925

insertPopup([windowName], text, {commands}, {hints}[{, tool-tips}][, useCurrentFormatElseDefault])
Creates text with a left-clickable link, and a right-click menu for more options at the end of the current line, like echo. The added text, upon being left-clicked, will do the first command in the list. Upon being right-clicked, it'll display a menu with all possible commands. The menu will be populated with hints, one for each line; if a tool-tips table is not provided the same hints will also be listed one-per-line as a tool-tip but if a matching number of tool-tips are provided they will be concatenated to provide a tool-tip when the text is hovered over by the pointer - these tool-tips can be rich-text to produce information formatted with additional content in the same manner as labels.
Parameters
  • windowName:
(optional) name of the window as a string to echo to. Use either main or omit for the main window, or the miniconsole's or user-window's name otherwise.
  • text:
the text string to display.
  • {commands}:
a table of lua code to do, in text strings or as functions (since Mudlet 4.11), i.e. {[[send("hello")]], function() echo("hi!") end}.
  • {hints}:
a table of strings which will be shown on the right-click menu (and popup if no {tool-tips} table is provided). If a particular position in both the commands and hints table are both the empty string "" but there is something in the tool-tips table, no entry for that position will be made in the context menu but the tool-tip can still display something which can include images or text.
  • {tool-tips}:
(optional) a table of possibly rich-text strings which will be shown on the popup if provided.
  • useCurrentFormatElseDefault:
(optional) a boolean value for using either the current formatting options (color, underline, italic and other effects) if true or the link default (blue underline) if false, if omitted the default format is used.

Note Note: Mudlet will distinguish between the optional tool-tips and the flag to switch between the standard link and the current text format by examining the type of the argument, as such this pair of arguments can be in either order.

Example
-- Create some text as a clickable with a popup menu, a left click will ''send "sleep"'':
insertPopup("activities to do", {function() send "sleep" end, function() send "sit" end, function() send "stand" end}, {"sleep", "sit", "stand"})

-- alternatively, put commands as text (in [[ and ]] to use quotation marks inside)
insertPopup("activities to do", {[[send "sleep"]], [[send "sit"]], [[send "stand"]]}, {"sleep", "sit", "stand"})

-- one can also provide helpful information

-- todo: an example with rich-text in the tool-tips(s)

selectAll, PR #8971

selectAll(str, func)
Selects every instance of a string on the cursor's current line and executes a provided function for each one. Useful for applying formatting or other operations to repeated occurrences of a word or phrase.
See also: selectString()
Parameters
  • str:
The string to select every instance of.
  • func:
The function to run for each selected instance of the string.
Example
-- bold every instance of "dragon" on the current line
selectAll("dragon", function()
  setBold(true)
end)
deselect()
resetFormat()

Discord Functions

All functions to customize the information Mudlet displays in Discord's rich presence interface. For an overview on how all of these functions tie in together, see our Discord scripting overview.

Mud Client Media Protocol

All GMCP functions to send sound and music events. For an overview on how all of these functions tie in together, see our MUD Client Media Protocol scripting overview.

Client.Media.Spatial, PR #8452 open

The Client.Media.Spatial family of GMCP packages extends the Client.Media protocol to provide 3D positional audio capabilities. These packages allow games to create immersive spatial soundscapes with positioned audio sources and listener orientation.

Mudlet VersionAvailable in Mudlet4.20+

Enabling Spatial Audio

Spatial audio requires the same settings as regular Client.Media:

  1. The "Enable GMCP" box in the Miscellaneous section must be checked.
  2. The "Allow server to download and play media" box in the Game protocols section must be checked.

Coordinate System

The spatial audio system uses a 3D coordinate system where:

  • Azimuth: Horizontal angle in degrees (0° = front, 90° = right, 180° = back, 270° = left)
  • Elevation: Vertical angle in degrees (-90° = below, 0° = level, 90° = above)
  • Distance: Distance from listener in arbitrary units (1.0 = close, higher values = farther)

For listener positioning, a Cartesian coordinate system is used:

  • X: Left/right position
  • Y: Forward/back position
  • Z: Up/down position

Playing Spatial Media

Send Client.Media.Spatial.Play GMCP events to play positioned sound sources in 3D space.

Required Parameter Value Default Description
Yes "key" <string> Unique identifier for this spatial audio source. Used for updates and stopping.
Yes "name" <file name> Name of the media file. May contain directory information (i.e. ambient/wind.wav).
Maybe "url" <url> Resource location where the media file may be downloaded. Only required if not using Client.Media.Default URL or if file is not cached.
No "volume" 1 to 100 80 Volume level relative to the master spatial audio volume.
No "loops" -1, or >= 1 1 Number of times to loop the sound. -1 for infinite looping.
No "position" <array or object> 3D position of the sound source. See position formats below.
No "occlusion" 0.0 to 1.0 0.0 Occlusion factor (0.0 = no occlusion, 1.0 = fully occluded/muffled).
No "room" <object> Room acoustics parameters. See room acoustics below.

Position Formats

Position can be specified as an array [azimuth, elevation, distance] or as an object:

// Array format
Client.Media.Spatial.Play {
  "key": "footsteps_player",
  "name": "footsteps.wav",
  "position": [45, 0, 2.5]
}

// Object format  
Client.Media.Spatial.Play {
  "key": "footsteps_player", 
  "name": "footsteps.wav",
  "position": {
    "azimuth": 45,
    "elevation": 0,
    "distance": 2.5
  }
}

Room Acoustics

Room acoustics can enhance spatial realism by simulating reverb and reflections:

Client.Media.Spatial.Play {
  "key": "cave_drip",
  "name": "water_drop.wav",
  "position": [0, -45, 8],
  "room": {
    "dimensions": [20, 30, 5],
    "reverb": 2.5,
    "reflection": 1.8,
    "material": "sheetrock"
  }
}

Updating Spatial Media

Send Client.Media.Spatial.Update GMCP events to modify properties of already playing spatial audio sources.

Required Parameter Value Description
Yes "key" <string> Unique identifier of the spatial audio source to update.
No "position" <array or object> New 3D position for the sound source.
No "volume" 1 to 100 New volume level.
No "occlusion" 0.0 to 1.0 New occlusion factor.

Example of moving a sound source:

Client.Media.Spatial.Update {
  "key": "footsteps_player",
  "position": [90, 0, 3.0],
  "volume": 60
}

Stopping Spatial Media

Send Client.Media.Spatial.Stop GMCP events to stop spatial audio sources.

Required Parameter Value Description
No "key" <string> Unique identifier of the spatial audio source to stop. If omitted, stops all spatial audio.

Stop a specific source:

Client.Media.Spatial.Stop {
  "key": "footsteps_player"
}

Stop all spatial audio:

Client.Media.Spatial.Stop {}

Listener Control

Send Client.Media.Spatial.Listener GMCP events to control the listener's position and orientation in 3D space.

Required Parameter Value Description
No "position" <array or object> Listener position in 3D space [x, y, z] or {x, y, z}.
No "rotation" <array or object> Listener rotation [yaw, pitch, roll] or {yaw, pitch, roll} in degrees.

Listener Position

Position uses Cartesian coordinates:

// Array format: [x, y, z]
Client.Media.Spatial.Listener {
  "position": [5.0, -2.0, 1.5]
}

// Object format
Client.Media.Spatial.Listener {
  "position": {
    "x": 5.0,
    "y": -2.0, 
    "z": 1.5
  }
}

Listener Rotation

Rotation controls where the listener is facing:

// Array format: [yaw, pitch, roll]
Client.Media.Spatial.Listener {
  "rotation": [180, -10, 0]
}

// Object format
Client.Media.Spatial.Listener {
  "rotation": {
    "yaw": 180,
    "pitch": -10,
    "roll": 0
  }
}

Usage Examples

Basic Positioned Sound

Client.Media.Spatial.Play {
  "key": "sword_clash",
  "name": "combat/sword_hit.wav",
  "position": [30, 0, 2],
  "volume": 85
}

Moving Ambient Sound

// Start a moving creature sound
Client.Media.Spatial.Play {
  "key": "wolf_howl",
  "name": "creatures/wolf_howl.wav", 
  "position": [-90, 10, 5],
  "loops": 3
}

// Update its position as it moves
Client.Media.Spatial.Update {
  "key": "wolf_howl",
  "position": [-45, 5, 3]
}

Environmental Audio with Room Acoustics

Client.Media.Spatial.Play {
  "key": "cathedral_organ",
  "name": "music/organ_chord.wav",
  "position": [0, 15, 20],
  "volume": 70,
  "room": {
    "dimensions": [40, 80, 15],
    "reverb": 3.0,
    "reflection": 2.2,
    "material": "sheetrock"
  }
}

Dynamic Listener Movement

// Player turns to face north and moves forward
Client.Media.Spatial.Listener {
  "position": [0, 5, 0],
  "rotation": [0, 0, 0]
}

// Player turns to look northeast and up slightly
Client.Media.Spatial.Listener {
  "rotation": [45, 15, 0]
}

Note Note: Spatial audio provides the most immersive experience when used with headphones or properly positioned stereo speakers. The 3D positioning effects may be less apparent with poor audio hardware.

GMCP Spatial Audio Capability Detection

Mudlet provides three GMCP messages for server developers to detect and query spatial audio capabilities. These allow servers to adapt their audio content based on the client's actual capabilities and current settings.

Client.Media.Spatial.Capabilities

Query the client's spatial audio capabilities to determine what features and formats are supported.

Server sends:

Client.Media.Spatial.Capabilities {}

Client responds with:

Client.Media.Spatial.Capabilities {
  "version": "1.0",
  "formats": ["wav", "mp3", "ogg", "flac", "aac", "m4a"],
  "output_modes": ["stereo", "surround", "headphone"],
  "room_materials": ["brick", "concrete", "wood", "metal", "glass", ...],
  "max_sources": 32,
  "distance_model": "inverse",
  "coordinate_system": "spherical",
  "features": {
    "positioning": true,
    "room_acoustics": true,
    "occlusion": true,
    "listener_control": true,
    "test_tones": true,
    "volume_control": true,
    "loops": true
  }
}

Response Fields:

  • version: Protocol version (currently "1.0")
  • formats: Array of supported audio file formats (detected at runtime based on Qt6 multimedia backend)
  • output_modes: Available audio output configurations
  • room_materials: Supported acoustic materials for room simulation
  • max_sources: Maximum number of simultaneous spatial audio sources
  • distance_model: Audio attenuation model used ("inverse")
  • coordinate_system: Position coordinate system ("spherical" with azimuth/elevation/distance)
  • features: Boolean flags indicating supported capabilities
Room Materials

The room materials are baed on this list from Qt QAudioRoom's Material enum. Mudlet is accepting the list of aliases as well.

Material Aliases Description
transparent air The side of the room is open and won't contribute to reflections or reverb.
acousticceilingtiles acoustictiles Acoustic tiles that suppress most reflections and reverb.
brickbare brick Bare brick wall.
brickpainted Painted brick wall.
concreteblockcoarse concrete Raw concrete wall
concreteblockpainted concretepainted Painted concrete wall
curtainheavy curtain, fabric Heavy curtain. Will mostly reflect low frequencies
fiberglassinsulation fiberglass, carpet Fiber glass insulation. Only reflects very low frequencies
glassthin glass Thin glass wall
glassthick Thick glass wall
grass Grass
linoleumonconcrete linoleum Linoleum floor
marble Marble floor
metal Metal
parquetonconcrete parquet, parquetonfiberboard Parquet wooden floor on concrete
plasterrough plaster Rough plaster
plastersmooth Smooth plaster
plywoodpanel plywood Plywood panel
polishedconcreteortile tile, polishedconcrete Polished concrete or tiles
sheetrock stone Rock
wateroricesurface water, ice, wateroriceereflector Water or ice
woodceiling Wooden ceiling
woodpanel wood Wooden panel
uniformmaterial uniform Artificial material giving uniform reflections on all frequencies

Client.Media.Spatial.Settings

Query the client's current spatial audio configuration and user settings.

Server sends:

Client.Media.Spatial.Settings {}

Client responds with:

Client.Media.Spatial.Settings {
  "master_volume": 80,
  "listener": {
    "position": [0, 0, 0],
    "rotation": [0, 0, 0]
  },
  "room": {
    "dimensions": [10, 10, 4],
    "reverb_gain": 0.3,
    "reflection_gain": 0.5,
    "reverb_time": 1.0,
    "reverb_brightness": 0.0
  }
}

Response Fields:

  • master_volume: Current master volume (0-100)
  • listener.position: 3D listener position [x, y, z] in Cartesian coordinates
  • listener.rotation: Listener orientation [yaw, pitch, roll] in degrees
  • room.dimensions: Room size [width, height, depth] in meters
  • room.reverb_gain: Reverberation intensity (0.0-5.0)
  • room.reflection_gain: Early reflection intensity (0.0-5.0)
  • room.reverb_time: Reverberation decay time in seconds (0.0-20.0)
  • room.reverb_brightness: Reverb frequency bias (-1.0 to 1.0)

Client.Media.Spatial.Status

Query the current status of active spatial audio sources managed by the server.

Server sends:

Client.Media.Spatial.Status {}

Client responds with:

Client.Media.Spatial.Status {
  "engine_initialized": true,
  "source_count": 2,
  "max_sources": 32,
  "active_sources": [
    {
      "key": "ambient_forest",
      "status": "playing",
      "position": [45, 0, 5],
      "volume": 60,
      "occlusion": 0.0,
      "size": 1.0,
      "loops": -1
    },
    {
      "key": "footsteps",
      "status": "paused",
      "position": [-90, -10, 2],
      "volume": 80,
      "occlusion": 0.5,
      "size": 0.5,
      "loops": 1
    }
  ]
}

Response Fields:

  • engine_initialized: Whether the spatial audio engine is ready
  • source_count: Number of currently active sources
  • max_sources: Maximum supported sources
  • active_sources: Array of source objects with current state
    • key: Server-assigned source identifier
    • status: Current playback state ("playing", "paused", "stopped")
    • position: Source position [azimuth, elevation, distance] in spherical coordinates
    • volume: Current volume level (0-100)
    • occlusion: Occlusion/obstruction level (0.0-4.0)
    • size: Source spatial size (0.0+, affects audio spread)
    • loops: Loop count (-1 for infinite, 0 for stopped, >0 for remaining loops)

Supported Protocols

MXP FRAME and DEST Tags, PR #8577 4.21

MXP FRAME and DEST tags allow MUD servers to create multi-window layouts, directing game output to separate panels within Mudlet. This enables rich interfaces with dedicated areas for chat, inventory, status, and more.

Mudlet VersionAvailable in Mudlet4.21+

Overview

FRAME creates a new window panel that can display game content.

DEST (destination) redirects subsequent text to a specific frame.

FRAME Tag

Creates a named frame where content can be directed.

Basic Syntax

<FRAME name="frameName" title="Frame Title" align="left" width="25%" height="100%">

Attributes

Attribute Required Description Default
NAME Yes Unique identifier for the frame -
TITLE No Display title shown in the frame's tab Same as NAME
INTERNAL No Frame appears inside the main window Yes (default)
EXTERNAL No Frame appears as a separate floating window No
FLOATING No Borderless frame without title bar No
ALIGN No Position: left, right, top, bottom left
LEFT No Absolute horizontal position (pixels, %, or 'c' suffix) -
TOP No Absolute vertical position (pixels, %, or 'c' suffix) -
WIDTH No Frame width (pixels, %, or characters with 'c' suffix) 25%
HEIGHT No Frame height (pixels, %, or characters with 'c' suffix) 25%
SCROLLING No Enable scrolling (YES/NO) YES
ACTION No open (show), close (hide), or focus open

Size Units

  • Pixels: 300px or 300
  • Percentage: 25% of available space
  • Characters: 40c for 40 characters width/height

CMUD Extension: DOCK

Note: The DOCK attribute is a CMUD extension, not part of the official MXP 1.0 specification.
<FRAME name="tab2" INTERNAL align="client" DOCK="parentFrame">

When used with align="client", the DOCK attribute creates a tabbed frame inside an existing frame.

Examples

Create a left-aligned chat panel:

<FRAME name="chat" title="Chat" align="left" width="30%">

Create a status bar at the bottom:

<FRAME name="status" align="bottom" height="50">

Create a borderless floating frame:

<FRAME name="minimap" FLOATING width="200" height="200" LEFT="10" TOP="10">

Show an existing frame:

<FRAME name="chat" action="open">

Close a frame:

<FRAME name="chat" action="close">

DEST Tag

Redirects text output to a named frame.

Syntax

<DEST name="frameName">Text goes here</DEST>

Or as a self-closing tag to set destination for all following text:

<DEST name="frameName">

Attributes

Attribute Required Description
NAME Yes Target frame name (empty string returns to main window)
EOF No If present, clears all content in the frame before writing
EOL No If present, clears the current line before writing

Examples

Send text to a chat frame:

<DEST name="chat">Player says: Hello!</DEST>

Clear frame and write new content:

<DEST name="status" EOF>HP: 100/100  MP: 50/50</DEST>

Return output to main window:

<DEST name="">

Complete Example

A typical MXP sequence to set up a multi-panel interface:

<!-- Create the frames -->
<FRAME name="chat" title="Chat" align="left" width="25%">
<FRAME name="status" title="Status" align="bottom" height="3c">

<!-- Send content to chat frame -->
<DEST name="chat">
[Guild] Bob: Anyone want to group?
[Guild] Alice: Sure!
</DEST>

<!-- Send content to status frame, clearing previous content -->
<DEST name="status" EOF>HP: 100/100 | MP: 75/100 | XP: 45%</DEST>

<!-- Return to main window for regular game output -->
<DEST name="">
You are standing in the town square.

Behavior Notes

  • Frames persist until explicitly closed with action="close"
  • Re-opening an existing frame shows it without changing its size or position (respects user customization)
  • Frame names are case-sensitive
  • Content sent via DEST inherits the formatting of the destination frame
  • Frames reset on reconnect (don't persist between sessions)

See Also

Events

New or revised events that Mudlet can raise to inform a profile about changes. See Mudlet-raised events for the existing ones.

UI Functions

All functions that help you construct custom GUIs. They deal mainly with miniconsole/label/gauge creation and manipulation as well as displaying or formatting information on the screen.

setTextFormat, PR #8983, open

setTextFormat(windowName, r1, g1, b1, r2, g2, b2, bold, underline, italics, [strikeout], [overline], [reverse], [blink])
Sets current text format of selected window. This is a more convenient means to set all the individual features at once compared to using setFgColor(windowName, r,g,b), setBold(windowName, true), setItalics(windowName, true), setUnderline(windowName, true), setStrikeOut(windowName, true).
See Also: getTextFormat()
Parameters
  • windowName
Specify name of selected window. If empty string "" or "main" format will be applied to the main console
  • r1,g1,b1
To color text background, give number values in RBG style
  • r2,g2,b2
To color text foreground, give number values in RBG style
  • bold
To format text bold, set to 1 or true, otherwise 0 or false
  • underline
To underline text, set to 1 or true, otherwise 0 or false
  • italics
To format text italic, set to 1 or true, otherwise 0 or false
  • strikeout
(optional) To strike text out, set to 1 or true, otherwise 0 or false or simply no argument
  • overline
(optional) To use overline, set to 1 or true, otherwise 0 or false or simply no argument
  • reverse
(optional) To swap foreground and background colors, set to 1 or true, otherwise 0 or false or simply no argument
  • blink
(optional) To make text blink, use "slow", "fast", or "none" (default). Requires "Enable blinking text" in Settings → Accessibility.
Example
--This script would create a mini text console and write with bold, struck-out, yellow foreground color and blue background color "This is a test".
createMiniConsole( "con1", 0,0,300,100);
setTextFormat("con1",0,0,255,255,255,0,true,0,false,1);
echo("con1","This is a test")

Note Note: In versions prior to 3.7.0 the error messages and this wiki were wrong in that they had the foreground color parameters as r1, g1 and b1 and the background ones as r2, g2 and b2.

MudMaster Chat Protocol (MMCP)

MMCP is a peer-to-peer protocol enabling out of band data to be sent to connected peers in the form of public or private chats, or general data.
See MMCP protocol documentation at: https://tintin.mudhalla.net/protocols/mmcp/
And at: https://mudstandards.org/mud/mmcp/
See also https://wiki.mudlet.org/w/Notes_on_MMCP
Mudlet VersionAvailable in Mudlet ?.??+

Note Note: pending, not yet available. See https://github.com/Mudlet/Mudlet/pull/7765

Lua functions

  • Note for all functions using target as an argument, the argument can be the client chatname or ID of the client as seen in mmcp.displayClientList()

accept

mmcp.accept(target)
Accepts an incoming connection request.
Parameters
  • target:
  • Incoming client name or ID.

Note Note: pending, not yet available in initial MMCP release.

allowSnoop

mmcp.allowSnoop(target)
Toggles the Allow Snoop flag for a client, allowing them to initiate a snoop request which will forward them text you see from your game.
Parameters
  • target:
  • Client name or ID.

call

mmcp.call(host[, port])
Initiate an outgoing connection to another client.
Parameters
  • host:
  • IPv4 address or fully qualified domain name.
  • port:
  • (optional) Port to connect to. Default 4050.
Example
local host = "1.2.3.4"
local port = 4050

mmcp.call(host, port)
You should see the following message
[ CHAT ]  - Connecting to 1.2.3.4:4050...
[ CHAT ]  - Waiting for response from 1.2.3.4:4050...
[ CHAT ]  - Connection to ChatClient at 1.2.3.4:4050 accepted.

chatAll

mmcp.chatAll(message)
Sends a message to all connected clients.
Parameters
  • message:
  • The message to send.

This message will have the format of: <Name> chats to everybody, '<message>'

You will see the message: You chat to everybody, '<message>'

Example
-- Alias: ChatAll
-- Alias Pattern: ^chatAll (.*)

mmcp.chatAll(matches[2])

chatGroup

mmcp.chatGroup(group, message)
Sends a message to all clients in the specified group.
Parameters
  • group:
  • The group to send the message to.
  • message:
  • The message to send.

The message will have the format of: <Name> chats to the group, '<message>'

You will see the message: You chat to <<group>>, '<message>'

Example
-- Alias: ChatGroup
-- Alias Pattern: ^chatGroup ([a-zA-Z0-9]+) (.*)

mmcp.chatGroup(matches[2], matches[3])

chatName

mmcp.chatName([name])
Sets or gets your current chat name visible to other clients.
Parameters
  • name:
  • (optional) The new chat name to use.
Returns
  • If no name is specified, this function will return your current chat name.
Example
-- Alias: ChatName
-- Alias Pattern: ^chatName (\S+)

mmcp.chatNAme(matches[2])

chatTo

mmcp.chatTo(target, message)
Sends a message to a specific client.
Parameters
  • target:
  • Client name or ID.
  • message:
  • The message to send.

The target client will see the message: <Name> chats to you, '<message>'

You will see the message: You chat to <target>, '<message>'

Example
-- Alias: ChatTo
-- Alias Pattern: ^chatTo (.*?) (.*)

mmcp.chatTo(matches[2], matches[3])

deny

mmcp.deny(target)
Denies an incoming connection request.
Parameters
  • target:
  • Client name or ID.

Note Note: pending, not yet available in initial MMCP release.

disconnect

mmcp.disconnect(target)
Disconnects a connected client.
Parameters
  • target:
  • Client name or ID

displayClientList

mmcp.displayClientList()
Displays a table showing information about connected and pending clients.
Example
mmcp.displayClientList()
You should see the following table
Id   Name                 Address              Port  Group           Flags    ChatClient
==== ==================== ==================== ===== =============== ======== ================
   1 ChatClient           1.2.3.4              4050                           Mudlet
==== ==================== ==================== ===== =============== ======== ================
Color Key: Connected  Pending
Flags:  F - Firewall,       I - Ignored,  P - Private,  S - Serving
        n - Allow Snooping, N - Being Snooped
  • You may then use the mmcp lua commands referencing the client by their ID (1) or name (ChatClient)

emoteAll

mmcp.emoteAll(message)
Sends an emote message to all connected clients.
Parameters
  • message:
  • The message to send.

Clients will see the message: <Name> <message>

If you have enabled the "Prefix emote messages" option, you will see: You emote to everyone: '<Name> <message>'

Otherwise you will see: <Name> <message>

Example
-- Alias: EmoteAll
-- Alias Pattern: ^emoteAll (.*)

local emoteStr = "says, '" .. matches[2] .. "'"

mmcp.emoteAll(emoteStr)

getClientFlags

mmcp.getClientFlags(target)
Returns a string containing the client flags of a connected client.
Parameters
  • target:
  • Client name or ID.
Returns

This string is an 8 character string where letters in the following positions have meaning: "12345678"

  • 1: Reserved, blank
  • 2: Reserved, blank
  • 3: P if the connection is Private, otherwise blank
  • 4: I if the connection is Ignored, otherwise blank
  • 5: S if the client is being served, otherwise blank
  • 6: F if the client is firewalled, otherwise blank
  • 7: N if the client is snooping us, n if the client can snoop us, otherwise blank
  • 8: Reserved, blank

getClientList

clientInfo = mmcp.getClientList()
Returns a lua table containing the following information for each connected client.
Returns
  • id: The ID of the client
  • name: The chat name of the client.
  • host: The hostname or IP address of the client.
  • port: The port the client (check if this is the reported port or port they connected from)
  • version: The MUD client and version of the client
Example
local clientList = mmcp.getClientList()
The variable clientList will then contain
{ {
    host = "1.2.3.4",
    id = 1,
    name = "ChatClient",
    port = 4050,
    version = "Mudlet"
  } }

ignore

mmcp.ignore(target)
Toggles ignoring a client. You will not see chat messages from an ignored client.
Parameters
  • target:
  • Client name or ID.

peek

mmcp.peek(target)
Sends a request to the target client to peek at their connection list.
Parameters
  • target:
  • Client name or ID.

ping

mmcp.ping(target)
Sends a ping request to a client.
Parameters
  • target:
  • Client name or ID.

request

mmcp.request(target)
Sends a request to the target client to request and connect to their public connections.
Mudlet will attempt to connect to each of the hosts returned by this command.
Parameters
  • target:
  • Client name or ID.

sendSideChannel

mmcp.sendSideChannel(channel, message)
Sends an OOB (Out of band) message to all connected clients.
Parameters
  • channel:
  • The channel to send the message on.
  • message:
  • The message to send.

Note Note: This will only send to other Mudlet clients. Upon receipt of this message Mudlet will raise a sysMMCPSideChannelMessage containing the channel and message data.

Example
-- myStats populated by prompt trigger
local outStr = string.format("%s,%d,%d,%d,%d,%s",
  mmcp.chatName(), myStats.hp, myStats.maxHp, myStats.mana, myStats.maxMana, myStats.buffs)

mmcp.sendSideChannel("stats", outStr)

-- Example event handling
function handleStatsData(statsTable)
  -- this should match the outStr format sent by mmcp.sendSideChannel
  local name, hp, maxHp, mana, maxMana, buffs = string.match(statsTable, "(%S+),(%d+),(%d+),(%d+),(%d+),(.*)")

  -- do things with this data
end

function VStats.eventHandler(event, ...)
  if event == "sysMMCPSideChannelMessage" then
    if arg[2] == "stats" then -- check if its actually for us, arg[2] should match "stats" provided to mmcp.sendSideChannel
      handleStatsData(arg[3])
    end
  end
end

registerAnonymousEventHandler("sysMMCPSideChannelMessage", "VStats.eventHandler")

serve

mmcp.serve(target)
Toggles the serve flag for a client, this clients chat messages will be sent to all other connected clients.
Parameters
  • target:
  • Client name or ID.

setDoNotDisturb

mmcp.setDoNotDisturb(target)
Toggles the Do Not Disturb flag, any incoming connections will be automatically denied.

Note Note: pending, not yet available in initial MMCP release.

setGroup

mmcp.setGroup(target, group)
Assigns a client to a chat group.
Parameters
  • target:
  • Client name or ID.
  • group:
  • The group name.

Note Note: The group name is only visible to you.

Example
-- Alias: SetGroup
-- Alias Pattern: ^setGroup ([a-zA-Z0-9]+) ?(.*)

mmcp.setGroup(matches[2], matches[3])

setPrivate

mmcp.setPrivate(target)
Toggles the private flag for a client. Any clients set as private will not be listed in peek or connection requests.
Parameters
  • target:
  • Client name or ID.

snoop

mmcp.snoop(target)
Starts snooping a client. The target may first need to enable snooping on their client.
Parameters
  • target:
  • Client name or ID.
Example
-- Alias: ChatSnoop
-- Alias Pattern: ^chatSnoop (.*)

mmcp.snoop(matches[2])

startServer

mmcp.startServer([port])
Starts accepting connections from clients.
Parameters
  • port:
  • (optional) Port to listen for incoming connections. Default 4050.

Note Note: pending, not yet available in initial MMCP release.

stopServer

mmcp.stopServer()
Stops accepting connections from clients.

Note Note: pending, not yet available in initial MMCP release.

Events

sysMMCPChatMessage

Raised when Mudlet receives an MMCP chat message from a client
Arguments
  • peerName:
  • Peer Name of the client
  • message:
  • Message content
Example putting MMCP messages into an EMCO window
function mmcpEventHandler(event, ...)
    -- trim whitespace
    local trimmedStr = arg[1]:match("^%s*(.-)%s*$")

    myEmcoWindow:decho("MMCP", ansi2decho(trimmedStr) .. "\n", false)
end

registerNamedEventHandler(getProfileName(), "MMCP", "sysMMCPChatMessage", "mmcpEventHandler")

sysMMCPSideChannelMessage

Raised when an MMCP side channel message has been received
Arguments
  • peerName:
  • Peer Name of the client
  • channel:
  • Channel identifier string
  • message:
  • Message content
Example
function VFrame.eventHandler(event, ...)
  if event == "gmcp.Char.Vitals" then

    VFrame.updateVitals()

  elseif event == "sysMMCPSideChannelMessage" then
    --display("event: " .. event .. " from: " .. arg[1] .. " channel: " .. arg[2] .. " message: " .. arg[3])
    if arg[2] == "stats" and myVFrame then -- check if its actually for us
      myVFrame:playerData(arg[3])
    end
  end
   
end

VFrame.registeredEvents = {
  registerAnonymousEventHandler("gmcp.Char.Vitals", "VFrame.eventHandler"),
  registerAnonymousEventHandler("sysMMCPSideChannelMessage", "VFrame.eventHandler"),
}

sysMMCPIncomingSnoopMessage

Raised when an MMCP client whom you are snooping has sent new snoop data
Arguments
  • peerName:
  • Peer Name of the client
  • message
  • Snoop content

sysMMCPPeerUpdateEvent

Raised when an MMCP client has been connected or disconnected
Arguments
  • peerName:
  • Chat name of the client

Security