Difference between revisions of "Manual:Supported Protocols"

From Mudlet
Jump to navigation Jump to search
 
(24 intermediate revisions by 3 users not shown)
Line 6: Line 6:
  
 
* [[Manual:Supported_Protocols#CHARSET (Encoding) | CHARSET]] Telnet Option
 
* [[Manual:Supported_Protocols#CHARSET (Encoding) | CHARSET]] Telnet Option
 +
* [[Manual:Supported_Protocols#ECHO (Password Masking) | ECHO]] Telnet Option
 
* [[Manual:Supported_Protocols#GMCP | GMCP]] - Generic Mud Communication Protocol
 
* [[Manual:Supported_Protocols#GMCP | GMCP]] - Generic Mud Communication Protocol
 
* [[Manual:Supported_Protocols#MNES | MNES]] - Mud New-Environ Standard
 
* [[Manual:Supported_Protocols#MNES | MNES]] - Mud New-Environ Standard
Line 15: Line 16:
 
* [[Manual:Supported Protocols#NAWS|NAWS]] - Negotiate About Window Size
 
* [[Manual:Supported Protocols#NAWS|NAWS]] - Negotiate About Window Size
 
* [[Manual:Supported_Protocols#NEW-ENVIRON | NEW-ENVIRON]] Telnet Option
 
* [[Manual:Supported_Protocols#NEW-ENVIRON | NEW-ENVIRON]] Telnet Option
 +
* [[Manual:Supported_Protocols#OSC_8:_Hyperlink_Protocol | OSC 8]] - Hyperlink Protocol via Operating System Command 8
 
* [[Manual:Supported_Protocols#TLS (Secure Connections) | TLS]] Transport Layer Security
 
* [[Manual:Supported_Protocols#TLS (Secure Connections) | TLS]] Transport Layer Security
  
 
'''Default Protocol Settings'''
 
'''Default Protocol Settings'''
  
[[Manual:Supported_Protocols#CHARSET (Encoding) | CHARSET]], [[Manual:Supported_Protocols#GMCP | GMCP]], [[Manual:Supported_Protocols#MSP | MSP]], [[Manual:Supported_Protocols#MSSP | MSSP]], [[Manual:Supported_Protocols#MTTS | MTTS]], [[Manual:Supported_Protocols#MXP | MXP]],  [[Manual:Supported Protocols#NAWS|NAWS]], and [[Manual:Supported_Protocols#NEW-ENVIRON | NEW-ENVIRON]] are enabled by default. [[Manual:Supported_Protocols#MSDP | MSDP]] and [[Manual:Supported_Protocols#MNES | MNES]] may be enabled in the Settings menu. [[Manual:Supported_Protocols#TLS (Secure Connections) | TLS]] is enabled from the Connections dialog for supported games.
+
[[Manual:Supported_Protocols#CHARSET (Encoding) | CHARSET]], [[Manual:Supported_Protocols#GMCP | GMCP]], [[Manual:Supported_Protocols#MSP | MSP]], [[Manual:Supported_Protocols#MSSP | MSSP]], [[Manual:Supported_Protocols#MTTS | MTTS]], [[Manual:Supported_Protocols#MXP | MXP]],  [[Manual:Supported Protocols#NAWS|NAWS]], and [[Manual:Supported_Protocols#NEW-ENVIRON | NEW-ENVIRON]] are enabled by default. [[Manual:Supported_Protocols#MSDP | MSDP]] and [[Manual:Supported_Protocols#MNES | MNES]] may be enabled in the Settings menu. [[Manual:Supported_Protocols#OSC_8:_Hyperlink_Protocol | OSC 8]] is enabled by default. [[Manual:Supported_Protocols#TLS (Secure Connections) | TLS]] is enabled from the Connections dialog for supported games.
  
 
[[File:Screenshot 2025-10-18 at 8.05.37 AM.png|alt=Game protocols drop-down list on the General tab of Settings|frameless|620x290px]]
 
[[File:Screenshot 2025-10-18 at 8.05.37 AM.png|alt=Game protocols drop-down list on the General tab of Settings|frameless|620x290px]]
Line 73: Line 75:
 
CHARSET negotiation is available in Mudlet 4.10+.
 
CHARSET negotiation is available in Mudlet 4.10+.
  
==GMCP==
+
== ECHO (Password Masking) ==
Generic Mud Communication Protocol, or GMCP, is a protocol for game servers to communicate information with game clients in a separate channel from the one which carries all of the text that makes up the game itself. Enabling the Debug window will show you GMCP events as they are coming in, and to get an idea of what information is currently stored, hit the Statistics button.
 
  
When working with GMCP on IRE games, this [https://github.com/keneanung/GMCPAdditions GMCP reference] is a useful tool.
+
The ECHO telnet option enables automatic password masking in Mudlet, hiding sensitive input from the screen with asterisks (****) during password entry.
  
===Using GMCP===
+
=== For Game Server Administrators ===
====Receiving GMCP data====
 
To "trigger" on GMCP messages, you'll need to create [[Manual:Technical_Manual#Event_System|an event handler]] - Mudlet will call it for you whenever relevant GMCP data is received.
 
  
As an example, create a new script and give it a name of the function you'd like to be called when the relevant GMCP message is received. Then, add the GMCP event you'd like the function to fire on under the registered event handlers left. Lastly, define the function - either in this or any other script - and you'll be done. The GMCP data received will be stored in the corresponding field of the ''gmcp'' table, which your function will read from.
+
==== How It Works ====
  
Example:
+
When your game needs a password from a player:
  
:[[File:using_gmcp.png|border|center]]
+
# Send '''IAC WILL ECHO''' - This tells Mudlet "I will handle echoing characters"
 +
# The player's typed password is masked with asterisks automatically
 +
# After password entry, send '''IAC WONT ECHO''' - This tells Mudlet "I won't handle echoing anymore"
 +
# Normal text echoing resumes
  
The ''test_gmcp()'' function will be called whenever ''Char.Vitals'' is received from the game, and it'll echo the latest data on the screen.
+
==== Implementation ====
  
====Sending GMCP data====
+
'''When to send ECHO:'''
Certain modules will only send data when a request is made by your client. In Mudlet, you can make such a request using the command '''sendGMCP("command")'''. Read your game's relevant documentation, such as the [http://nexus.ironrealms.com/GMCP IRE document on GMCP], for information about specific modules.
+
* At login prompts
 +
* When creating new passwords
 +
* During password change sequences
 +
* Any time you ask for sensitive input
  
:See Also: [[Manual:Networking Functions#sendGMCP | sendGMCP]]
+
'''Basic sequence:'''
  
===Managing GMCP modules===
+
{| class="wikitable"
While some GMCP modules are enabled by Mudlet by default when you connect with a GMCP enabled game, others may not be 'standard' modules and are instead specific to the game itself. In order to provide a way to manage GMCP modules without scripts causing modules in use by other scripts to be disabled.
+
! Server Action !! Telnet Sequence !! Effect
 +
|-
 +
| Ask for password || IAC WILL ECHO || Mudlet starts masking input
 +
|-
 +
| Player types password || (player input masked) || Shows ******* on screen
 +
|-
 +
| Password received || IAC WONT ECHO || Mudlet stops masking, normal display resumes
 +
|}
  
====Registering user====
+
==== Example Implementation ====
While this step is no longer strictly required, you can register your 'user' with gmod using
 
<syntaxhighlight lang="lua">
 
gmod.registerUser("MyUser")
 
</syntaxhighlight>
 
Where ''MyUser'' is your plugin/addon/whatever name. However, your user will be automatically registered if you enable or disable any modules using it. Which leads us to...
 
  
====Enabling modules====
+
'''Pseudocode for login:'''
Enabling a GMCP module is as easy as:
+
<syntaxhighlight lang="python">
<syntaxhighlight lang="lua">
+
# At login prompt
gmod.enableModule("MyUser", "Module.Name")
+
send_to_client("Password: ")
</syntaxhighlight>
+
send_telnet_option(IAC, WILL, ECHO) # Start masking
  
If MyUser has not been registered previously, then they will be automatically registered when you call this function. An example of a module which would need to be enabled this way is the IRE.Rift module provided by IRE MUDs.
+
# Read password (Mudlet displays asterisks)
<syntaxhighlight lang="lua">
+
password = read_input_from_client()
-- add this to a login trigger, or anything that will get done just once per login
 
gmod.enableModule("<character name>", "IRE.Rift")
 
</syntaxhighlight>
 
  
Another example would be the Combat module in Lithmeria, which isn't enabled by default:
+
# Password received
<syntaxhighlight lang="lua">
+
send_telnet_option(IAC, WONT, ECHO)  # Stop masking
-- add this to a login trigger, or anything that will get done just once per login
+
send_to_client("\n")
gmod.enableModule("<character name>", "Combat")
 
</syntaxhighlight>
 
  
====Disabling modules====
+
# Verify password and continue...
Disabling a GMCP module is just as easy as enabling it:
 
<syntaxhighlight lang="lua">
 
gmod.disableModule("MyUser", "Module.Name")
 
 
</syntaxhighlight>
 
</syntaxhighlight>
The main difference being that the module will be turned on as soon as you enable it if it is not already enabled. If you disable it, it will not be disabled with the server until every user of that module has disabled it. This prevents script A from disabling modules that script B may still be using.
 
  
===Thorough GMCP tutorial===
+
==== Important Notes ====
A good GMCP tutorial that walks you through receiving and sending GMCP data is [http://www.mudlet.org/wp-content/uploads/2013/02/GMCPtutorial.pdf available here] - take a read!
 
  
==MSDP==
+
* '''Always turn ECHO off''' after password entry - forgetting this will mask all subsequent player input
MSDP (Mud Server Data Protocol) is a protocol for game servers to communicate information with game clients in a separate channel from the one which carries all of the text that makes up the game itself. Mudlet can be configured to use MSDP by clicking on the Settings button (or Options->Preferences in the menu, or <alt>p). The option is on the General tab.
+
* '''Use for passwords only''' - don't leave ECHO on for normal gameplay
 +
* '''Test thoroughly''' - ensure ECHO toggles work at all password prompts
 +
* '''Handle reconnects''' - reset ECHO state when players reconnect or timeout
  
Once MSDP is enabled, you will need to reconnect to the game so that Mudlet can inform the server it is ready to receive MSDP information. Please note that some servers don't both send MSDP and GMCP at the same time, so even if you enable both in Mudlet, the server will choose to send only one of them.
+
==== Telnet Byte Values ====
  
Enabling the Debug window will show you MSDP events as they are coming in, and to get an idea of what information is currently stored, hit the Statistics button. Also see [http://tintin.sourceforge.net/protocols/msdp/ MSDP reference] for some of the commands and values your server might support.
+
For low-level implementation:
  
===Using MSDP===
+
{| class="wikitable"
====Receiving MSDP data====
+
! Command !! Decimal !! Hexadecimal
To "trigger" on MSDP messages, you'll need to create [[Manual:Technical_Manual#Event_System|an event handler]] - Mudlet will call it for you whenever relevant MSDP data is received.
+
|-
 +
| IAC (Interpret As Command) || 255 || 0xFF
 +
|-
 +
| WILL || 251 || 0xFB
 +
|-
 +
| WONT || 252 || 0xFC
 +
|-
 +
| ECHO || 1 || 0x01
 +
|}
  
As an example, lets create a script that'll track whenever we move - that is, the room number changes. To begin with, we need to ask the game to be sending us updates whenever we move - so do:
+
'''Byte sequence to start masking:''' <code>255 251 1</code> (IAC WILL ECHO)
  
<code>
+
'''Byte sequence to stop masking:''' <code>255 252 1</code> (IAC WONT ECHO)
lua sendMSDP("REPORT", "ROOM_VNUM")
 
</code>
 
  
in the command-line first to enable reporting of the room number and name. Then, create a new script and give it a name of the function you'd like to be called when the relevant MSDP message is received. Add the MSDP event you'd like the function to fire on under the registered event handlers - in our case, '''msdp.ROOM_VNUM'''. Lastly, define the function - either in this or any other script - and you'll be done. The MSDP data received will be stored in the corresponding field of the ''msdp'' table, which your function will read from.
+
==== Testing ====
  
Example:
+
To verify ECHO works correctly:
  
:[[File:Using_msdp.png|border|center]]
+
# Connect to your game with Mudlet 4.20+
 +
# Reach a password prompt
 +
# Type characters - you should see asterisks (*) instead of your text
 +
# After entering the password, normal echoing should resume
  
The ''test_msdp()'' function will be called whenever ''ROOM_VNUM'' is received from the game, and it'll echo the latest data on the screen.
+
If masking doesn't work, check:
 +
* Is your server sending IAC WILL ECHO before the password prompt?
 +
* Is your server sending IAC WONT ECHO after receiving the password?
 +
* Are the telnet bytes correct (255 251 1 and 255 252 1)?
  
====Sending MSDP data====
+
==== User Settings ====
You can use [[Manual:Networking Functions#sendMSDP | sendMSDP]] to send information via MSDP back to the game. The first parameter to the function is the MSDP variable, and all the subsequent ones are values. See the [https://mudhalla.net/tintin/protocols/msdp/ MSDP documentation] for some examples of data that you can send:
 
  
<syntaxhighlight lang="lua">
+
Players can disable password masking if desired via '''Settings → Special Options → Disable password masking'''. However, proper ECHO implementation still benefits players who keep masking enabled (the default).
-- ask the server to report your health changes to you. Result will be stored in msdp.HEALTH in Mudlet
 
sendMSDP("REPORT", "HEALTH")
 
  
-- client - IAC SB MSDP MSDP_VAR "SEND" MSDP_VAL "AREA NAME" MSDP_VAL "ROOM NAME" IAC SE in the documentation translates to the following in Mudlet:
+
==== See Also ====
sendMSDP("SEND", "AREA NAME", "ROOM NAME")
 
</syntaxhighlight>
 
  
:See Also: [[Manual:Networking Functions#sendMSDP | sendMSDP]]
+
* [[Security#Password_Masking_Feature|Password Masking in Mudlet]]
 +
* [https://www.rfc-editor.org/rfc/rfc857.html RFC 857 - Telnet ECHO Option]
  
==MSP==
+
==GMCP==
 +
Generic Mud Communication Protocol, or GMCP, is a protocol for game servers to communicate information with game clients in a separate channel from the one which carries all of the text that makes up the game itself. Enabling the Debug window will show you GMCP events as they are coming in, and to get an idea of what information is currently stored, hit the Statistics button.
  
Want to add accessibility and excitement into your game? How about implementing sound and music triggers?
+
When working with GMCP on IRE games, this [https://github.com/keneanung/GMCPAdditions GMCP reference] is a useful tool.
  
'''Mud Sound Protocol''', or MSP, provides a way for games to send sound and music triggers to clients. Clients have the option to implement a framework where the corresponding triggers play. MSP triggers are sent in one direction to game clients and not to game servers. Sounds may be downloaded manually or automatically if conditions are met.
+
===Using GMCP===
 +
====Receiving GMCP data====
 +
To "trigger" on GMCP messages, you'll need to create [[Manual:Technical_Manual#Event_System|an event handler]] - Mudlet will call it for you whenever relevant GMCP data is received.
  
Games could use telnet option negotiation to signal clients support for MSP (''WILL'', ''WONT''), and toggling MSP processing on and off (''DO'', ''DONT''). This is communicated using TELOPT 90, which is reserved (unofficially) for the MSP protocol by our community. Games that do not support telnet option negotiation for MSP should provide a means for their players to toggle this feature on and off.
+
As an example, create a new script and give it a name of the function you'd like to be called when the relevant GMCP message is received. Then, add the GMCP event you'd like the function to fire on under the registered event handlers left. Lastly, define the function - either in this or any other script - and you'll be done. The GMCP data received will be stored in the corresponding field of the ''gmcp'' table, which your function will read from.
  
The latest specification for MSP is located [https://www.zuggsoft.com/zmud/msp.htm here] and available in PDF [[:File:MUD Sound Protocol.pdf|here]].
+
Example:
  
===MSP in Mudlet===
+
:[[File:using_gmcp.png|border|center]]
  
Mudlet processes MSP sound and music triggers in three ways:
+
The ''test_gmcp()'' function will be called whenever ''Char.Vitals'' is received from the game, and it'll echo the latest data on the screen.
  
#'''MSP over OOB''' - Mudlet is capable of receiving hidden, out-of-band telnet sound and music triggers from game servers via messaging with TELOPT 90.
+
====Sending GMCP data====
#'''MSP for Lua''' - Mudlet triggers may capture and invoke the [[Manual:Lua Functions#receiveMSP | receiveMSP]] function available through the Lua interpreter of Mudlet to process MSP.
+
Certain modules will only send data when a request is made by your client. In Mudlet, you can make such a request using the command '''sendGMCP("command")'''. Read your game's relevant documentation, such as the [http://nexus.ironrealms.com/GMCP IRE document on GMCP], for information about specific modules.
#'''MSP over GMCP''' - Mudlet may receive GMCP events from game servers sent with the [[Manual:Scripting#MUD_Client_Media_Protocol | Client.Media]] package.
 
  
Sound or music triggers that contain a media file name will be searched for in the '''media''' folder of the corresponding Mudlet profile that matches the host for the game. If the ''media'' folder and the file are found by Mudlet, it will be played, given the host's operating system supports playing that type of media file. If the file is not found, Mudlet could initiate a download of the media file when provided a URL to find the file. Alternatively, game administrators may instruct players on other ways to transfer media files by 1) creating a ''media'' folder in their game's Mudlet profile and 2) copying files or extracting them from an archive (zip).
+
:See Also: [[Manual:Networking Functions#sendGMCP | sendGMCP]]
  
MSP is available in Mudlet 4.4+
+
===Managing GMCP modules===
 +
While some GMCP modules are enabled by Mudlet by default when you connect with a GMCP enabled game, others may not be 'standard' modules and are instead specific to the game itself. In order to provide a way to manage GMCP modules without scripts causing modules in use by other scripts to be disabled.
  
===Receiving MSP Data ===
+
====Registering user====
 +
While this step is no longer strictly required, you can register your 'user' with gmod using
 +
<syntaxhighlight lang="lua">
 +
gmod.registerUser("MyUser")
 +
</syntaxhighlight>
 +
Where ''MyUser'' is your plugin/addon/whatever name. However, your user will be automatically registered if you enable or disable any modules using it. Which leads us to...
  
Processing of MSP is enabled by default on new game profiles. Control whether the processing is on or off through the Settings menu in Mudlet.
+
====Enabling modules====
 +
Enabling a GMCP module is as easy as:
 +
<syntaxhighlight lang="lua">
 +
gmod.enableModule("MyUser", "Module.Name")
 +
</syntaxhighlight>
  
====MSP over OOB====
+
If MyUser has not been registered previously, then they will be automatically registered when you call this function. An example of a module which would need to be enabled this way is the IRE.Rift module provided by IRE MUDs.
 +
<syntaxhighlight lang="lua">
 +
-- add this to a login trigger, or anything that will get done just once per login
 +
gmod.enableModule("<character name>", "IRE.Rift")
 +
</syntaxhighlight>
  
Game administrators may send sound and music triggers over the out-of-bounds (hidden) telnet channel encoded with TELOPT 90 after performing telnet negotiation with Mudlet. The advantage to this is that all of the communication is behind the scenes with no additional trigger requirements for the player (see ''MSP over Lua'').  Games will send the bytes of out-of-band messages to Mudlet in a format like this: <pre>IAC SB TELOPT_MSP !!SOUND(cow.wav L=2 V=100) IAC SE</pre>
+
Another example would be the Combat module in Lithmeria, which isn't enabled by default:
 +
<syntaxhighlight lang="lua">
 +
-- add this to a login trigger, or anything that will get done just once per login
 +
gmod.enableModule("<character name>", "Combat")
 +
</syntaxhighlight>
  
{{note}} Game admins: This option does require a TELOPT 90 WILL message.
+
====Disabling modules====
 +
Disabling a GMCP module is just as easy as enabling it:
 +
<syntaxhighlight lang="lua">
 +
gmod.disableModule("MyUser", "Module.Name")
 +
</syntaxhighlight>
 +
The main difference being that the module will be turned on as soon as you enable it if it is not already enabled. If you disable it, it will not be disabled with the server until every user of that module has disabled it. This prevents script A from disabling modules that script B may still be using.
 +
 
 +
===Thorough GMCP tutorial===
 +
A good GMCP tutorial that walks you through receiving and sending GMCP data is [http://www.mudlet.org/wp-content/uploads/2013/02/GMCPtutorial.pdf available here] - take a read!
  
==== MSP for Lua ====
+
==MSDP==
 +
MSDP (Mud Server Data Protocol) is a protocol for game servers to communicate information with game clients in a separate channel from the one which carries all of the text that makes up the game itself. Mudlet can be configured to use MSDP by clicking on the Settings button (or Options->Preferences in the menu, or <alt>p). The option is on the General tab.
  
Check for MSP support with your game and enable any options that allow sound and music triggers to be sent to your screen.
+
Once MSDP is enabled, you will need to reconnect to the game so that Mudlet can inform the server it is ready to receive MSDP information. Please note that some servers don't both send MSDP and GMCP at the same time, so even if you enable both in Mudlet, the server will choose to send only one of them.
  
You can download the package from [[Media:MSP.zip]] or follow the instructions below.
+
Enabling the Debug window will show you MSDP events as they are coming in, and to get an idea of what information is currently stored, hit the Statistics button. Also see [http://tintin.sourceforge.net/protocols/msdp/ MSDP reference] for some of the commands and values your server might support.
  
Create a sound trigger to invoke the Lua interpreter:
+
===Using MSDP===
 +
====Receiving MSDP data====
 +
To "trigger" on MSDP messages, you'll need to create [[Manual:Technical_Manual#Event_System|an event handler]] - Mudlet will call it for you whenever relevant MSDP data is received.
  
{| class="wikitable"
+
As an example, lets create a script that'll track whenever we move - that is, the room number changes. To begin with, we need to ask the game to be sending us updates whenever we move - so do:
!Name
+
 
!Text
+
<code>
!Type
+
lua sendMSDP("REPORT", "ROOM_VNUM")
!Script
+
</code>
|-
+
 
| style="text-align:center;" |Sound Trigger
+
in the command-line first to enable reporting of the room number and name. Then, create a new script and give it a name of the function you'd like to be called when the relevant MSDP message is received. Add the MSDP event you'd like the function to fire on under the registered event handlers - in our case, '''msdp.ROOM_VNUM'''. Lastly, define the function - either in this or any other script - and you'll be done. The MSDP data received will be stored in the corresponding field of the ''msdp'' table, which your function will read from.
|^!!SOUND\((\S+?)(?: (.+))?\)$
+
 
|perl regex
+
Example:
| style="text-align:left;" |
 
*deleteLine()
 
*[[Manual:Lua Functions#receiveMSP | receiveMSP]](matches[1])
 
|-
 
|}
 
  
Create a music trigger to invoke the Lua interpreter:
+
:[[File:Using_msdp.png|border|center]]
  
{| class="wikitable"
+
The ''test_msdp()'' function will be called whenever ''ROOM_VNUM'' is received from the game, and it'll echo the latest data on the screen.
!Name
 
!Text
 
!Type
 
!Script
 
|-
 
| style="text-align:center;" |Music Trigger
 
|^!!MUSIC\((\S+?)(?: (.+))?\)$
 
|perl regex
 
| style="text-align:left;" |
 
*deleteLine()
 
*[[Manual:Lua Functions#receiveMSP | receiveMSP]](matches[1])
 
|-
 
|}
 
  
{{note}} Game admins: Best practice is to implement a TELOPT 90 WILL message as a signal to the client that MSP is supported. This is not required.  
+
====Sending MSDP data====
 +
You can use [[Manual:Networking Functions#sendMSDP | sendMSDP]] to send information via MSDP back to the game. The first parameter to the function is the MSDP variable, and all the subsequent ones are values. See the [https://mudhalla.net/tintin/protocols/msdp/ MSDP documentation] for some examples of data that you can send:
  
If your game does not negotiate MSP, you can download [[Media:MSP-Alternate.zip]] or you can use this script in your trigger instead of receiveMSP for MSP Sound:
 
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
deleteLine()
+
-- ask the server to report your health changes to you. Result will be stored in msdp.HEALTH in Mudlet
local mspFile = nil
+
sendMSDP("REPORT", "HEALTH")
local mspVolume = 100
+
 
local mspLength = 1
+
-- client - IAC SB MSDP MSDP_VAR "SEND" MSDP_VAL "AREA NAME" MSDP_VAL "ROOM NAME" IAC SE in the documentation translates to the following in Mudlet:
local mspPriority = 50
+
sendMSDP("SEND", "AREA NAME", "ROOM NAME")
local mspType = nil
+
</syntaxhighlight>
local mspURL = nil
+
 
-- Strip !!SOUND() from the line
+
:See Also: [[Manual:Networking Functions#sendMSDP | sendMSDP]]
local line = matches[1]:sub(9, -2)
+
 
-- Break up the line into tokens
+
==MSP==
local tokens = line:split(" ")
+
 
-- Iterate through the tokens to discover MSP values
+
Want to add accessibility and excitement into your game? How about implementing sound and music triggers?
for index, value in ipairs(tokens) do
+
 
  if index == 1 then
+
'''Mud Sound Protocol''', or MSP, provides a way for games to send sound and music triggers to clients. Clients have the option to implement a framework where the corresponding triggers play. MSP triggers are sent in one direction to game clients and not to game servers. Sounds may be downloaded manually or automatically if conditions are met.
    mspFile = value
+
 
  elseif value:find("V=", 1, true) == 1 or value:find("v=", 1, true) == 1 then
+
Games could use telnet option negotiation to signal clients support for MSP (''WILL'', ''WONT''), and toggling MSP processing on and off (''DO'', ''DONT''). This is communicated using TELOPT 90, which is reserved (unofficially) for the MSP protocol by our community. Games that do not support telnet option negotiation for MSP should provide a means for their players to toggle this feature on and off.
    mspVolume = tonumber(value:sub(3))
+
 
  elseif value:find("L=", 1, true) == 1 or value:find("l=", 1, true) == 1 then
+
The latest specification for MSP is located [https://www.zuggsoft.com/zmud/msp.htm here] and available in PDF [[:File:MUD Sound Protocol.pdf|here]].
    mspLength = tonumber(value:sub(3))
+
 
  elseif value:find("P=", 1, true) == 1 or value:find("p=", 1, true) == 1 then
+
===MSP in Mudlet===
    mspPriority = tonumber(value:sub(3))
+
 
  elseif value:find("T=", 1, true) == 1 or value:find("t=", 1, true) == 1 then
+
Mudlet processes MSP sound and music triggers in three ways:
    mspType = value:sub(3)
 
  elseif value:find("U=", 1, true) == 1 or value:find("u=", 1, true) == 1 then
 
    mspURL = value:sub(3)
 
  end
 
end
 
if mspFile == "Off" and mspURL == nil then
 
  stopSounds()
 
else
 
  playSoundFile(
 
    {
 
      name = mspFile,
 
      volume = mspVolume,
 
      loops = mspLength,
 
      priority = mspPriority,
 
      tag = mspType,
 
      url = mspURL,
 
    }
 
  )
 
end
 
</syntaxhighlight>
 
  
If your game does not negotiate MSP, you can use this script in your trigger instead of receiveMSP for MSP Music:
+
#'''MSP over OOB''' - Mudlet is capable of receiving hidden, out-of-band telnet sound and music triggers from game servers via messaging with TELOPT 90.
<syntaxhighlight lang="lua">
+
#'''MSP for Lua''' - Mudlet triggers may capture and invoke the [[Manual:Lua Functions#receiveMSP | receiveMSP]] function available through the Lua interpreter of Mudlet to process MSP.
deleteLine()
+
#'''MSP over GMCP''' - Mudlet may receive GMCP events from game servers sent with the [[Manual:Scripting#MUD_Client_Media_Protocol | Client.Media]] package.
local mspFile = nil
+
 
local mspVolume = 100
+
Sound or music triggers that contain a media file name will be searched for in the '''media''' folder of the corresponding Mudlet profile that matches the host for the game. If the ''media'' folder and the file are found by Mudlet, it will be played, given the host's operating system supports playing that type of media file. If the file is not found, Mudlet could initiate a download of the media file when provided a URL to find the file. Alternatively, game administrators may instruct players on other ways to transfer media files by 1) creating a ''media'' folder in their game's Mudlet profile and 2) copying files or extracting them from an archive (zip).
local mspLength = 1
+
 
local mspContinue = true
+
MSP is available in Mudlet 4.4+
local mspType = nil
+
 
local mspURL = nil
+
===Receiving MSP Data ===
-- Strip !!MUSIC() from the line
+
 
local line = matches[1]:sub(9, -2)
+
Processing of MSP is enabled by default on new game profiles. Control whether the processing is on or off through the Settings menu in Mudlet.
-- Break up the line into tokens
+
 
local tokens = line:split(" ")
+
====MSP over OOB====
-- Iterate through the tokens to discover MSP values
+
 
for index, value in ipairs(tokens) do
+
Game administrators may send sound and music triggers over the out-of-bounds (hidden) telnet channel encoded with TELOPT 90 after performing telnet negotiation with Mudlet. The advantage to this is that all of the communication is behind the scenes with no additional trigger requirements for the player (see ''MSP over Lua'').  Games will send the bytes of out-of-band messages to Mudlet in a format like this: <pre>IAC SB TELOPT_MSP !!SOUND(cow.wav L=2 V=100) IAC SE</pre>
  if index == 1 then
+
 
    mspFile = value
+
{{note}} Game admins: This option does require a TELOPT 90 WILL message.
  elseif value:find("V=", 1, true) == 1 or value:find("v=", 1, true) == 1 then
+
 
    mspVolume = tonumber(value:sub(3))
+
==== MSP for Lua ====
  elseif value:find("L=", 1, true) == 1 or value:find("l=", 1, true) == 1 then
+
 
    mspLength = tonumber(value:sub(3))
+
Check for MSP support with your game and enable any options that allow sound and music triggers to be sent to your screen.
  elseif value:find("C=", 1, true) == 1 or value:find("c=", 1, true) == 1 then
+
 
    if tonumber(value:sub(3)) == 0 then
+
You can download the package from [[Media:MSP.zip]] or follow the instructions below.
      mspContinue = false
+
 
    else
+
Create a sound trigger to invoke the Lua interpreter:
      mspContinue = true
+
 
    end
+
{| class="wikitable"
  elseif value:find("T=", 1, true) == 1 or value:find("t=", 1, true) == 1 then
+
!Name
    mspType = value:sub(3)
+
!Text
  elseif value:find("U=", 1, true) == 1 or value:find("u=", 1, true) == 1 then
+
!Type
    mspURL = value:sub(3)
+
!Script
  end
+
|-
end
+
| style="text-align:center;" |Sound Trigger
if mspFile == "Off" and mspURL == nil then
+
|^!!SOUND\((\S+?)(?: (.+))?\)$
  stopMusic()
+
|perl regex
else
+
| style="text-align:left;" |
  playMusicFile(
+
*deleteLine()
    {
+
*[[Manual:Lua Functions#receiveMSP | receiveMSP]](matches[1])
      name = mspFile,
+
|-
      volume = mspVolume,
+
|}
      loops = mspLength,
 
      continue = mspContinue,
 
      tag = mspType,
 
      url = mspURL,
 
    }
 
  )
 
end
 
</syntaxhighlight>
 
  
====MSP over GMCP====
+
Create a music trigger to invoke the Lua interpreter:
  
Reference Mudlet's [[Manual:Scripting#MUD_Client_Media_Protocol | documentation]] on the [[Standards:MUD_Client_Media_Protocol | MUD Client Media Protocol]] specification for more information.
+
{| class="wikitable"
 +
!Name
 +
!Text
 +
!Type
 +
!Script
 +
|-
 +
| style="text-align:center;" |Music Trigger
 +
|^!!MUSIC\((\S+?)(?: (.+))?\)$
 +
|perl regex
 +
| style="text-align:left;" |
 +
*deleteLine()
 +
*[[Manual:Lua Functions#receiveMSP | receiveMSP]](matches[1])
 +
|-
 +
|}
  
{{note}} Game admins: Do not implement a TELOPT 90 WILL message exchange when exclusively using this option.
+
{{note}} Game admins: Best practice is to implement a TELOPT 90 WILL message as a signal to the client that MSP is supported. This is not required.  
  
===MSP Troubleshooting ===
+
If your game does not negotiate MSP, you can download [[Media:MSP-Alternate.zip]] or you can use this script in your trigger instead of receiveMSP for MSP Sound:
 
+
<syntaxhighlight lang="lua">
*Wildcards ''?'' or ''*'' within the file name do not trigger automatic sound or music downloads. Ensure the sound was downloaded previously prior to using a wildcard.
+
deleteLine()
*Mudlet < 4.11 would not play the MSP sound if it had unknown elements, Mudlet 4.12+ will ignore the unknown elements and do the best it can to play the sound.
+
local mspFile = nil
 
+
local mspVolume = 100
===MSP Specification===
+
local mspLength = 1
For more insight into the syntax of sound and music triggers, please reference the [https://www.zuggsoft.com/zmud/msp.htm specification].
+
local mspPriority = 50
 
+
local mspType = nil
===Sound packs===
+
local mspURL = nil
As most games have been around for a long time, they often use Mud Sound Protocol (MSP) to play sounds.  We often find that the game administrators have documented a downloadable soundpack on their website, or that a 3rd party has made one.  In Mudlet, a profile is created for each game, and you can manually create a media folder inside of it and drop in the media files (sound, music).  For games using MSP, you can create simple triggers to play them which are [[#MSP_for_Lua|documented above]].
+
-- Strip !!SOUND() from the line
== MSSP ==
+
local line = matches[1]:sub(9, -2)
'''Mud Server Status Protocol''', or MSSP, provides a way for game crawlers (i.e. [https://tintin.sourceforge.io/protocols/mssp/mudlist.html MSSP Mud Crawler]) and game listing sites (search for Listings [https://www.reddit.com/r/MUD/ here]) to gather detailed information about a game, including dynamic information like boot time and the current amount of online players. It also makes submitting a new game entry very simple on game listing sites. A player or administrator is only required to fill in the hostname and port and other information is gathered from behind the scenes.
+
-- Break up the line into tokens
 
+
local tokens = line:split(" ")
===MSSP in Mudlet===
+
-- Iterate through the tokens to discover MSP values
The MSSP data presented in Mudlet will enable MSSP standard data fields to be made accessible for scripting.  Some useful fields include the game name, number of players, uptime, game hostname, game port, codebase, admin contact, Discord invite URL, year created, link to an icon, ip address, primary language, game location, website and several others may be available. It is up to the game in question to populate the data, so don't expect all fields to be filled in.
+
for index, value in ipairs(tokens) do
 
+
  if index == 1 then
MSSP is available in Mudlet 4.1+.
+
    mspFile = value
 
+
  elseif value:find("V=", 1, true) == 1 or value:find("v=", 1, true) == 1 then
===Receiving MSSP Data ===
+
    mspVolume = tonumber(value:sub(3))
To receive MSSP data in Mudlet, these conditions must be met:
+
  elseif value:find("L=", 1, true) == 1 or value:find("l=", 1, true) == 1 then
 
+
    mspLength = tonumber(value:sub(3))
#The ''Enable MSSP'' box in the Settings window of Mudlet must be checked (default on).
+
  elseif value:find("P=", 1, true) == 1 or value:find("p=", 1, true) == 1 then
# The game must negotiate MSSP with clients like Mudlet at its login screen.  Details [https://tintin.sourceforge.io/protocols/mssp/ here].
+
    mspPriority = tonumber(value:sub(3))
 
+
  elseif value:find("T=", 1, true) == 1 or value:find("t=", 1, true) == 1 then
To see whether your game supports MSSP, after connecting, type ''lua mssp''. If the game does not support MSSP, you will see an empty table ''mssp = {}''.  If it does you will see information similar to the example below. The data may be accessed in a similar way to the instructions for GMCP listed above. Typically, MSSP data is only sent once per connection.
+
    mspType = value:sub(3)
 +
  elseif value:find("U=", 1, true) == 1 or value:find("u=", 1, true) == 1 then
 +
    mspURL = value:sub(3)
 +
  end
 +
end
 +
if mspFile == "Off" and mspURL == nil then
 +
  stopSounds()
 +
else
 +
  playSoundFile(
 +
    {
 +
      name = mspFile,
 +
      volume = mspVolume,
 +
      loops = mspLength,
 +
      priority = mspPriority,
 +
      tag = mspType,
 +
      url = mspURL,
 +
    }
 +
  )
 +
end
 +
</syntaxhighlight>
  
 +
If your game does not negotiate MSP, you can use this script in your trigger instead of receiveMSP for MSP Music:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
mssp = {
+
deleteLine()
  HOSTNAME = "stickmud.com",
+
local mspFile = nil
  VT100 = "1",
+
local mspVolume = 100
  UPTIME = "1565657220",
+
local mspLength = 1
  MSDP = "0",
+
local mspContinue = true
  MCP = "0",
+
local mspType = nil
  GMCP = "1",
+
local mspURL = nil
  PORT = "7680",
+
-- Strip !!MUSIC() from the line
  ["MINIMUM AGE"] = "13",
+
local line = matches[1]:sub(9, -2)
   PUEBLO = "0",
+
-- Break up the line into tokens
  INTERMUD = "-1",
+
local tokens = line:split(" ")
  SKILLS = "100",
+
-- Iterate through the tokens to discover MSP values
   ["HIRING BUILDERS"] = "0",
+
for index, value in ipairs(tokens) do
  PLAYERS = "6",
+
   if index == 1 then
  CONTACT = "[email protected]",
+
    mspFile = value
  CODEBASE = "LDMud 3.5.0 (3.5.1)",
+
   elseif value:find("V=", 1, true) == 1 or value:find("v=", 1, true) == 1 then
   ["HIRING CODERS"] = "0",
+
    mspVolume = tonumber(value:sub(3))
  ["PAY FOR PERKS"] = "0",
+
   elseif value:find("L=", 1, true) == 1 or value:find("l=", 1, true) == 1 then
  LOCATION = "Canada",
+
    mspLength = tonumber(value:sub(3))
   GAMESYSTEM = "Custom",
+
   elseif value:find("C=", 1, true) == 1 or value:find("c=", 1, true) == 1 then
  MCCP = "0",
+
    if tonumber(value:sub(3)) == 0 then
  SUBGENRE = "Medieval Fantasy",
+
      mspContinue = false
  ROOMS = "10000",
+
    else
  STATUS = "Live",
+
      mspContinue = true
  FAMILY = "LPMud",
+
    end
  LEVELS = "150",
+
   elseif value:find("T=", 1, true) == 1 or value:find("t=", 1, true) == 1 then
  CREATED = "1991",
+
    mspType = value:sub(3)
   ["PAY TO PLAY"] = "0",
+
   elseif value:find("U=", 1, true) == 1 or value:find("u=", 1, true) == 1 then
  IP = "24.138.28.11",
+
    mspURL = value:sub(3)
  MOBILES = "-1",
+
   end
  GAMEPLAY = "Hack and Slash",
+
end
   CLASSES = "8",
+
if mspFile == "Off" and mspURL == nil then
  NAME = "StickMUD",
+
   stopMusic()
  SSL = "7670", -- legacy key, use TLS now please!
+
else
  TLS = "7670",
+
   playMusicFile(
  ANSI = "1",
+
    {
  ICON = "https://www.stickmud.com/favicon.ico",
+
      name = mspFile,
   RACES = "12",
+
      volume = mspVolume,
   UTF-8 = "0",
+
      loops = mspLength,
   AREAS = "-1",
+
      continue = mspContinue,
  MXP = "0",
+
      tag = mspType,
  HELPFILES = "-1",
+
      url = mspURL,
  ["XTERM 256 COLORS"] = "0",
+
    }
  MSP = "1",
+
   )
  OBJECTS = "9780",
+
end
  WEBSITE = "https://www.stickmud.com",
 
  GENRE = "Fantasy",
 
  DISCORD = "https://discord.gg/erBBxt",
 
   LANGUAGE = "English"
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==MTTS==
+
====MSP over GMCP====
MUD servers frequently seek information about the capabilities of a MUD Client. Despite the availability of various methods, achieving consistency and reliability in this endeavor has proven challenging. The Mud Terminal Type Standard ([https://tintin.mudhalla.net/protocols/mtts/ MTTS]) aims to alleviate these issues by introducing a transparent and straightforward standard for MUD Clients to communicate their terminal capabilities. This standard builds upon and formalizes [https://datatracker.ietf.org/doc/html/rfc1091 RFC 1091], which outlines the Telnet Terminal-Type Option.
 
  
===MTTS in Mudlet===
+
Reference Mudlet's [[Manual:Scripting#MUD_Client_Media_Protocol | documentation]] on the [[Standards:MUD_Client_Media_Protocol | MUD Client Media Protocol]] specification for more information.
By incorporating the Mud Terminal-Type Standard (MTTS), Mudlet will communicate with interested servers that it possesses the following capabilities:  
 
  
*'''Support for ANSI Color Codes:''' The client supports all common ANSI color codes.
+
{{note}} Game admins: Do not implement a TELOPT 90 WILL message exchange when exclusively using this option.
*'''UTF-8 Character Encoding:''' The client utilizes UTF-8 character encoding.
 
* '''Support for 256 Color Codes:''' Mudlet is equipped to handle all 256 color codes.
 
* '''OSC Color Palette:''' Mudlet acknowledges support for the OSC color palette.
 
*'''Screen Reader Support:''' Mudlet offers support for screen readers, with opt-in functionality (not advertised by default).
 
*'''Truecolor Codes:''' Mudlet supports truecolor codes using semicolon notation.
 
*'''Mud New Environment Standard (MNES) Support:''' The client adheres to the Mud New Environment Standard for information exchange.
 
*'''TLS Encryption:''' The client supports Transport Layer Security for data encryption.
 
  
====Screen Reader Opt-In ====
+
===MSP Troubleshooting ===
Users can find on the Accessibility tab under the Settings menu a checkbox identified as "Advertise screen reader use via protocols supporting this notice" which when checked will notify interested game servers. This information may be used to optimize the gaming experience.
+
 
 +
*Wildcards ''?'' or ''*'' within the file name do not trigger automatic sound or music downloads. Ensure the sound was downloaded previously prior to using a wildcard.
 +
*Mudlet < 4.11 would not play the MSP sound if it had unknown elements, Mudlet 4.12+ will ignore the unknown elements and do the best it can to play the sound.
 +
 
 +
===MSP Specification===
 +
For more insight into the syntax of sound and music triggers, please reference the [https://www.zuggsoft.com/zmud/msp.htm specification].
  
[[File:Screenshot_2024-01-01_at_2.35.07_PM.png|alt=Image displaying the Advertise screen reader checkbox|619x619px]]
+
===Sound packs===
 +
As most games have been around for a long time, they often use Mud Sound Protocol (MSP) to play sounds.  We often find that the game administrators have documented a downloadable soundpack on their website, or that a 3rd party has made one.  In Mudlet, a profile is created for each game, and you can manually create a media folder inside of it and drop in the media files (sound, music).  For games using MSP, you can create simple triggers to play them which are [[#MSP_for_Lua|documented above]].
 +
== MSSP ==
 +
'''Mud Server Status Protocol''', or MSSP, provides a way for game crawlers (i.e. [https://tintin.sourceforge.io/protocols/mssp/mudlist.html MSSP Mud Crawler]) and game listing sites (search for Listings [https://www.reddit.com/r/MUD/ here]) to gather detailed information about a game, including dynamic information like boot time and the current amount of online players. It also makes submitting a new game entry very simple on game listing sites. A player or administrator is only required to fill in the hostname and port and other information is gathered from behind the scenes.
  
====Available MTTS Information====
+
===MSSP in Mudlet===
Through a Telnet TERMINAL-TYPE Option negotiation, Mudlet transfers a bitvector to game servers, (i.e., <code>2349</code>) for processing.  A bitvector, also known as a bitmap, is a data structure that represents a fixed-size sequence of binary digits or bits. In a bitvector, each bit corresponds to a specific position or index in the sequence, and its value can be either 0 or 1. The MTTS bitvector represents is a set of flags and boolean values, where each bit can represent the state of a particular boolean condition or flag. For example, if the third bit is set to <code>1</code>, it indicates that the client is using UTF-8 character encoding. A <code>0</code> indicator would indicate that UTF-8 was not supported.
+
The MSSP data presented in Mudlet will enable MSSP standard data fields to be made accessible for scripting.  Some useful fields include the game name, number of players, uptime, game hostname, game port, codebase, admin contact, Discord invite URL, year created, link to an icon, ip address, primary language, game location, website and several others may be available. It is up to the game in question to populate the data, so don't expect all fields to be filled in.
{| class="wikitable"
+
 
|+MTTS Bitvector
+
MSSP is available in Mudlet 4.1+.
!Bit
+
 
!Property
+
===Receiving MSSP Data ===
!Meaning
+
To receive MSSP data in Mudlet, these conditions must be met:
|-
+
 
|1
+
#The ''Enable MSSP'' box in the Settings window of Mudlet must be checked (default on).
|ANSI
+
# The game must negotiate MSSP with clients like Mudlet at its login screen.  Details [https://tintin.sourceforge.io/protocols/mssp/ here].
|Client supports all common ANSI color codes.
+
 
|-
+
To see whether your game supports MSSP, after connecting, type ''lua mssp''. If the game does not support MSSP, you will see an empty table ''mssp = {}''.  If it does you will see information similar to the example below. The data may be accessed in a similar way to the instructions for GMCP listed above. Typically, MSSP data is only sent once per connection.
|2
+
 
|VT100
+
<syntaxhighlight lang="lua">
|Client supports all common VT100 codes.
+
mssp = {
|-
+
  HOSTNAME = "stickmud.com",
|4
+
  VT100 = "1",
|UTF-8
+
  UPTIME = "1565657220",
|Client is using UTF-8 character encoding.
+
  MSDP = "0",
|-
+
  MCP = "0",
|8
+
  GMCP = "1",
|256 COLORS
+
  PORT = "7680",
| Client supports all 256 color codes.
+
  ["MINIMUM AGE"] = "13",
|-
+
  PUEBLO = "0",
|16
+
  INTERMUD = "-1",
|MOUSE TRACKING
+
  SKILLS = "100",
|Client supports xterm mouse tracking.
+
  ["HIRING BUILDERS"] = "0",
|-
+
  PLAYERS = "6",
| 32
+
  CONTACT = "[email protected]",
| OSC COLOR PALETTE
+
  CODEBASE = "LDMud 3.5.0 (3.5.1)",
|Client supports OSC and the OSC color palette.
+
  ["HIRING CODERS"] = "0",
|-
+
  ["PAY FOR PERKS"] = "0",
|64
+
  LOCATION = "Canada",
|SCREEN READER
+
  GAMESYSTEM = "Custom",
|Client is using a screen reader.
+
  MCCP = "0",
|-
+
  SUBGENRE = "Medieval Fantasy",
|128
+
  ROOMS = "10000",
|PROXY
+
  STATUS = "Live",
|Client is a proxy allowing different users to connect from the same IP address.
+
  FAMILY = "LPMud",
|-
+
  LEVELS = "150",
|256
+
  CREATED = "1991",
|TRUECOLOR
+
  ["PAY TO PLAY"] = "0",
|Client supports truecolor codes using semicolon notation.
+
  IP = "24.138.28.11",
|-
+
  MOBILES = "-1",
|512
+
  GAMEPLAY = "Hack and Slash",
|MNES
+
  CLASSES = "8",
|Client supports the Mud New Environment Standard for information exchange.
+
  NAME = "StickMUD",
|-
+
  SSL = "7670", -- legacy key, use TLS now please!
|1024
+
  TLS = "7670",
|MSLP
+
  ANSI = "1",
|Client supports the Mud Server Link Protocol for clickable link handling.
+
  ICON = "https://www.stickmud.com/favicon.ico",
|-
+
  RACES = "12",
| 2048
+
  UTF-8 = "0",
|TLS
+
  AREAS = "-1",
|Client supports Transport Layer Security for data encryption.
+
  MXP = "0",
|}
+
  HELPFILES = "-1",
 
+
  ["XTERM 256 COLORS"] = "0",
====Negotiating MTTS====
+
  MSP = "1",
Per the MTTS guidance, game servers should initiate up to 4 TTYPE requests to complete the TTYPE cycling routine within a given connection. If the connection is reset, negotiate TTYPE again. Reference the [https://tintin.mudhalla.net/protocols/mtts/ MTTS website] for more information.
+
  OBJECTS = "9780",
{| class="wikitable"
+
  WEBSITE = "https://www.stickmud.com",
! Server
+
  GENRE = "Fantasy",
!Mudlet
+
  DISCORD = "https://discord.gg/erBBxt",
|-
+
  LANGUAGE = "English"
| IAC DO TTYPE (24) IAC SE
+
}
| IAC WILL TTYPE (24) IAC SE
+
</syntaxhighlight>
|-
+
 
| IAC SB TTYPE (24) SEND (1) IAC SE
+
==MTTS==
|IAC SB TTYPE (24) IS (0) ''MUDLET'' IAC SE
+
MUD servers frequently seek information about the capabilities of a MUD Client. Despite the availability of various methods, achieving consistency and reliability in this endeavor has proven challenging. The Mud Terminal Type Standard ([https://tintin.mudhalla.net/protocols/mtts/ MTTS]) aims to alleviate these issues by introducing a transparent and straightforward standard for MUD Clients to communicate their terminal capabilities. This standard builds upon and formalizes [https://datatracker.ietf.org/doc/html/rfc1091 RFC 1091], which outlines the Telnet Terminal-Type Option.
|-
 
|IAC SB TTYPE (24) SEND (1) IAC SE
 
| IAC SB TTYPE (24) IS (0) ''ANSI-TRUECOLOR'' IAC SE
 
|-
 
| IAC SB TTYPE (24) SEND (1) IAC SE
 
|IAC SB TTYPE (24) IS (0) ''MTTS 2349'' IAC SE
 
|-
 
| IAC SB TTYPE (24) SEND (1) IAC SE
 
|IAC SB TTYPE (24) IS (0) ''MTTS 2349'' IAC SE
 
|-
 
|}
 
  
If a Mudlet user does not want to enable Mud Terminal Type Standard, they may choose the Settings, General menu item in Mudlet and toggle off the "Enable MTTS" checkbox.
+
===MTTS in Mudlet===
 +
By incorporating the Mud Terminal-Type Standard (MTTS), Mudlet will communicate with interested servers that it possesses the following capabilities:
  
MTTS is available in Mudlet 4.18+.
+
*'''Support for ANSI Color Codes:''' The client supports all common ANSI color codes.
 +
*'''UTF-8 Character Encoding:''' The client utilizes UTF-8 character encoding.
 +
* '''Support for 256 Color Codes:''' Mudlet is equipped to handle all 256 color codes.
 +
* '''OSC Color Palette:''' Mudlet acknowledges support for the OSC color palette.
 +
*'''Screen Reader Support:''' Mudlet offers support for screen readers, with opt-in functionality (not advertised by default).
 +
*'''Truecolor Codes:''' Mudlet supports truecolor codes using semicolon notation.
 +
*'''Mud New Environment Standard (MNES) Support:''' The client adheres to the Mud New Environment Standard for information exchange.
 +
*'''TLS Encryption:''' The client supports Transport Layer Security for data encryption.
  
==MXP==
+
====Screen Reader Opt-In ====
MXP is based loosely on the HTML and XML standards supported by modern web browsers.  It is only "loosely" based upon these standards because games require dynamic, streaming text, rather than the page-oriented view of web browsers. Also, the existing standards are needlessly verbose for use on a game where text efficiency is important.
+
Users can find on the Accessibility tab under the Settings menu a checkbox identified as "Advertise screen reader use via protocols supporting this notice" which when checked will notify interested game servers. This information may be used to optimize the gaming experience.
  
In addition, there are additional security concerns to worry about with MXP. While support for HTML tags within a line is desired, players on a game can exploit this power and cause problems. Certain HTML functions need to be restricted so that players cannot abuse them. For example, while it might be desirable to allow players to change the font or color of their chat messages, you would not want to allow them to display a large graphics image, or execute script commands on the client of other users.  MXP handles this by grouping the various tags and commands into secure and open categories, and preventing the secure tags from being used by players.
+
[[File:Screenshot_2024-01-01_at_2.35.07_PM.png|alt=Image displaying the Advertise screen reader checkbox|619x619px]]
  
Mudlet implements a subset of MXP features - the most popular ones that are actually in use. Mudlet supports MXP links (including send to prompt and open in browser in Mudlet 3.17+), pop-up menus, creation of custom elements, and line modes. As a game admin, you can ask what features are supported with the <code><SUPPORT></code> command.
+
====Available MTTS Information====
 
+
Through a Telnet TERMINAL-TYPE Option negotiation, Mudlet transfers a bitvector to game servers, (i.e., <code>2349</code>) for processing.  A bitvector, also known as a bitmap, is a data structure that represents a fixed-size sequence of binary digits or bits. In a bitvector, each bit corresponds to a specific position or index in the sequence, and its value can be either 0 or 1. The MTTS bitvector represents is a set of flags and boolean values, where each bit can represent the state of a particular boolean condition or flag. For example, if the third bit is set to <code>1</code>, it indicates that the client is using UTF-8 character encoding. A <code>0</code> indicator would indicate that UTF-8 was not supported.
===MXP in Mudlet===
+
{| class="wikitable"
Just like GMCP, MXP data is available in the <code>mxp.</code> namespace and events are raised. To see all MXP events, turn on Debug mode.
+
|+MTTS Bitvector
 
+
!Bit
[[File:MXP data.png]]
+
!Property
 
+
!Meaning
<syntaxhighlight lang="lua">
+
|-
function testmxpsend()
+
|1
  print("Text for the link is: ".. mxp.send.href)
+
|ANSI
  print("Commands to do are: ")
+
|Client supports all common ANSI color codes.
  display(mxp.send.actions)
+
|-
  print("\n")
+
|2
end
+
|VT100
 
+
|Client supports all common VT100 codes.
registerAnonymousEventHandler("mxp.send", "testmxpsend")
+
|-
</syntaxhighlight>
+
|4
 
+
|UTF-8
{{Note}} Available in Mudlet 4.8+
+
|Client is using UTF-8 character encoding.
 
+
|-
Since Mudlet 4.20+ you can also display a different text to the player with the <code>mxp.send.text</code> variable.
+
|8
 
+
|256 COLORS
e.g. in a shop you might like a click to purchase interface
+
| Client supports all 256 color codes.
 
+
|-
<syntaxhighlight lang="lua>
+
|16
 
+
|MOUSE TRACKING
mxp.send = {
+
|Client supports xterm mouse tracking.
actions = { "send([[buy apple]])" },
+
|-
href = "buy apple", -- command sent when clicked
+
| 32
text = "a big apple", -- text shown to the player
+
| OSC COLOR PALETTE
}
+
|Client supports OSC and the OSC color palette.
 
+
|-
</syntaxhighlight>
+
|64
 
+
|SCREEN READER
===Receiving MXP Data ===
+
|Client is using a screen reader.
[[File:Mudlet MXP example.gif|alt=shows how MXP can be used to BUY an item at a shop, then within the inventory they can select what to do with their items. i.e. Drop, Eat, Wear, Drink...|thumb|MXP example in Mudlet]]
+
|-
Processing of MXP is enabled by default on new game profiles. Control whether the processing is on or off through the Settings menu in Mudlet.
+
|128
 
+
|PROXY
====Simple example of receiving MXP Data (Server owners)====
+
|Client is a proxy allowing different users to connect from the same IP address.
<syntaxhighlight lang="html">
+
|-
<SEND href=\"&text;\">  go north...  </SEND>"
+
|256
</syntaxhighlight>This creates a clickable link that will enable the player to navigate without typing the directions into Mudlet. MXP sends the data immediately when clicked.  
+
|TRUECOLOR
 +
|Client supports truecolor codes using semicolon notation.
 +
|-
 +
|512
 +
|MNES
 +
|Client supports the Mud New Environment Standard for information exchange.
 +
|-
 +
|1024
 +
|MSLP
 +
|Client supports the Mud Server Link Protocol for clickable link handling.
 +
|-
 +
| 2048
 +
|TLS
 +
|Client supports Transport Layer Security for data encryption.
 +
|}
  
====Advanced example of receiving MXP Data (Server owners)====
+
====Negotiating MTTS====
<syntaxhighlight lang="html">
+
Per the MTTS guidance, game servers should initiate up to 4 TTYPE requests to complete the TTYPE cycling routine within a given connection. If the connection is reset, negotiate TTYPE again. Reference the [https://tintin.mudhalla.net/protocols/mtts/ MTTS website] for more information.
<send href='examine &#34;&name;&#34;|get &#34;&name;&#34;' hint='Right mouse click to act on this item|Get &desc;|Examine &desc;|Look in &desc;' expire=get>\" ATT='name desc'>
+
{| class="wikitable"
</syntaxhighlight>This creates a clickable link that will 'examine' an item. It also enables a right-click function wherein the player can select to either examine or get the item (in this case &name; is the item and &desc; is the item's description ).
+
! Server
 +
!Mudlet
 +
|-
 +
| IAC DO TTYPE (24) IAC SE
 +
| IAC WILL TTYPE (24) IAC SE
 +
|-
 +
| IAC SB TTYPE (24) SEND (1) IAC SE
 +
|IAC SB TTYPE (24) IS (0) ''MUDLET'' IAC SE
 +
|-
 +
|IAC SB TTYPE (24) SEND (1) IAC SE
 +
| IAC SB TTYPE (24) IS (0) ''ANSI-TRUECOLOR'' IAC SE
 +
|-
 +
| IAC SB TTYPE (24) SEND (1) IAC SE
 +
|IAC SB TTYPE (24) IS (0) ''MTTS 2349'' IAC SE
 +
|-
 +
| IAC SB TTYPE (24) SEND (1) IAC SE
 +
|IAC SB TTYPE (24) IS (0) ''MTTS 2349'' IAC SE
 +
|-
 +
|}
  
===MXP Specification===
+
If a Mudlet user does not want to enable Mud Terminal Type Standard, they may choose the Settings, General menu item in Mudlet and toggle off the "Enable MTTS" checkbox.
MXP was originally developed and supported by the Zuggsoft team. For more insight into the syntax, reference the [https://www.zuggsoft.com/zmud/mxp.htm specification] or the PDF [[:File:MUD eXtension Protocol.pdf|here]]. Mudlet has a partial implementation version 1.0 of the MXP spec - to see what is supported, ask Mudlet with the [https://www.zuggsoft.com/zmud/mxp.htm#Version%20Control <SUPPORT>] tag.
 
  
==NEW-ENVIRON==
+
MTTS is available in Mudlet 4.18+.
To enhance the player experience through sharing more client-supported details, the Telnet New-Environ Option may be used to transfer client environment variables from Mudlet to game servers. Sharing supporting information on information such as encoding, terminal emulation, and accessibility options aims to improve initial player setup and increase the retention rate for new gaming community members.
 
  
===NEW-ENVIRON in Mudlet===
+
==MXP==
Mudlet supports two methods of information exchange via NEW-ENVIRON, the first via [https://datatracker.ietf.org/doc/html/rfc1572 RFC 1572]: '''Telnet New-Environ Option''' (on by default), and the second is [https://tintin.mudhalla.net/protocols/mnes/ MNES]: '''Mud New-Environ Standard''' (off by default), which shares a standardized set of client information across multiple clients.  
+
MXP is based loosely on the HTML and XML standards supported by modern web browsers.  It is only "loosely" based upon these standards because games require dynamic, streaming text, rather than the page-oriented view of web browsers.  Also, the existing standards are needlessly verbose for use on a game where text efficiency is important.
 +
 
 +
In addition, there are additional security concerns to worry about with MXP.  While support for HTML tags within a line is desired, players on a game can exploit this power and cause problems. Certain HTML functions need to be restricted so that players cannot abuse them. For example, while it might be desirable to allow players to change the font or color of their chat messages, you would not want to allow them to display a large graphics image, or execute script commands on the client of other users.  MXP handles this by grouping the various tags and commands into secure and open categories, and preventing the secure tags from being used by players.
 +
 
 +
Mudlet implements a subset of MXP features - the most popular ones that are actually in use. Mudlet supports MXP links (including send to prompt and open in browser in Mudlet 3.17+), pop-up menus, creation of custom elements, and line modes. As a game admin, you can ask what features are supported with the <code><SUPPORT></code> command.
  
====Client Environment Variable Updates====
+
===MXP in Mudlet===
Mudlet provides a user-friendly interface for managing environmental variables through its Settings menu. For certain environmental variables, manual selections made in the Settings menus can dynamically notify servers that have expressed interest in the client's environmental variables through the negotiation of the NEW-ENVIRON option. For instance, when a Mudlet user updates the data encoding for a server profile by navigating to Settings, General, and choosing a specific data encoding from the drop-down menu, this information becomes available for transmission via both the RFC (default) and MNES (requires user enabling) options.
+
Just like GMCP, MXP data is available in the <code>mxp.</code> namespace and events are raised. To see all MXP events, turn on Debug mode.
==== Screen Reader Opt-In====
 
Users can find on the Accessibility tab under the Settings menu a checkbox identified as "Advertise screen reader use via protocols supporting this notice" which when checked will notify interested game servers. This information may be used to optimize the gaming experience.
 
  
[[File:Screenshot_2024-01-01_at_2.35.07_PM.png|alt=Image displaying the Advertise screen reader checkbox|619x619px]]
+
[[File:MXP data.png]]
====Available Client Environment Variables [https://datatracker.ietf.org/doc/html/rfc1572 RFC 1572]====
 
Two types of variables are used per RFC 152, well-known variables defined with VAR (0) and for less common variables, USERVAR (3). Currently, per the RFC, Mudlet shares its variables via the USERVAR (3) type.
 
  
Some client variables updates may be reported ad-hoc with an INFO (2) message. If there is no value for a defined variable, a VAL (1) will be sent without a value following it.
+
<syntaxhighlight lang="lua">
{| class="wikitable"
+
function testmxpsend()
!Type
+
  print("Text for the link is: ".. mxp.send.href)
!Variable
+
  print("Commands to do are: ")
!Example Values
+
  display(mxp.send.actions)
!Mudlet Default
+
  print("\n")
!OPT-IN
+
end
!INFO
+
 
!Purpose
+
registerAnonymousEventHandler("mxp.send", "testmxpsend")
!Available
+
</syntaxhighlight>
|-
+
 
|USERVAR
+
{{Note}} Available in Mudlet 4.8+
|'''256_COLORS'''
+
 
|1, 0
+
Since Mudlet 4.20+ you can also display a different text to the player with the <code>mxp.send.text</code> variable.
|1
+
 
|
+
e.g. in a shop you might like a click to purchase interface
|
+
 
|Client supports all 256 color codes. 1 = Yes/True/ACK.
+
<syntaxhighlight lang="lua>
|4.18
+
 
|-
+
mxp.send = {
|USERVAR
+
actions = { "send([[buy apple]])" },
|'''ANSI'''
+
href = "buy apple", -- command sent when clicked
|1, 0
+
text = "a big apple", -- text shown to the player
|1
+
}
|
+
 
|
+
</syntaxhighlight>
|Client supports all common ANSI color codes. 1 = Yes/True/ACK.
+
 
|4.18
+
===Receiving MXP Data ===
|-
+
[[File:Mudlet MXP example.gif|alt=shows how MXP can be used to BUY an item at a shop, then within the inventory they can select what to do with their items. i.e. Drop, Eat, Wear, Drink...|thumb|MXP example in Mudlet]]
|USERVAR
+
Processing of MXP is enabled by default on new game profiles. Control whether the processing is on or off through the Settings menu in Mudlet.
|'''BOLD_IS_BRIGHT'''
+
 
|2, 1, 0
+
====Simple example of receiving MXP Data (Server owners)====
|
+
<syntaxhighlight lang="html">
|
+
<SEND href=\"&text;\">  go north... </SEND>"
|Yes
+
</syntaxhighlight>This creates a clickable link that will enable the player to navigate without typing the directions into Mudlet. MXP sends the data immediately when clicked.
|Use bright colors always (2), sometimes (1), or never (0).
+
 
|future
+
====Advanced example of receiving MXP Data (Server owners)====
|-
+
<syntaxhighlight lang="html">
|USERVAR
+
<send href='examine &#34;&name;&#34;|get &#34;&name;&#34;' hint='Right mouse click to act on this item|Get &desc;|Examine &desc;|Look in &desc;' expire=get>\" ATT='name desc'>
|'''CHARSET'''
+
</syntaxhighlight>This creates a clickable link that will 'examine' an item. It also enables a right-click function wherein the player can select to either examine or get the item (in this case &name; is the item and &desc; is the item's description ).
|UTF-8, ASCII
+
 
|
+
===MXP Specification===
|
+
MXP was originally developed and supported by the Zuggsoft team. For more insight into the syntax, reference the [https://www.zuggsoft.com/zmud/mxp.htm specification] or the PDF [[:File:MUD eXtension Protocol.pdf|here]]. Mudlet has a partial implementation version 1.0 of the MXP spec - to see what is supported, ask Mudlet with the [https://www.zuggsoft.com/zmud/mxp.htm#Version%20Control <SUPPORT>] tag.
|Yes
+
 
| Encoding set in the client
+
==NEW-ENVIRON==
|4.18
+
To enhance the player experience through sharing more client-supported details, the Telnet New-Environ Option may be used to transfer client environment variables from Mudlet to game servers. Sharing supporting information on information such as encoding, terminal emulation, and accessibility options aims to improve initial player setup and increase the retention rate for new gaming community members.
|-
+
 
|USERVAR
+
===NEW-ENVIRON in Mudlet===
|'''CLIENT_NAME'''
+
Mudlet supports two methods of information exchange via NEW-ENVIRON, the first via [https://datatracker.ietf.org/doc/html/rfc1572 RFC 1572]: '''Telnet New-Environ Option''' (on by default), and the second is [https://tintin.mudhalla.net/protocols/mnes/ MNES]: '''Mud New-Environ Standard''' (off by default), which shares a standardized set of client information across multiple clients.
|MUDLET
+
 
|MUDLET
+
====Client Environment Variable Updates====
|
+
Mudlet provides a user-friendly interface for managing environmental variables through its Settings menu. For certain environmental variables, manual selections made in the Settings menus can dynamically notify servers that have expressed interest in the client's environmental variables through the negotiation of the NEW-ENVIRON option. For instance, when a Mudlet user updates the data encoding for a server profile by navigating to Settings, General, and choosing a specific data encoding from the drop-down menu, this information becomes available for transmission via both the RFC (default) and MNES (requires user enabling) options.  
|
+
==== Screen Reader Opt-In====
|Name of the client.
+
Users can find on the Accessibility tab under the Settings menu a checkbox identified as "Advertise screen reader use via protocols supporting this notice" which when checked will notify interested game servers. This information may be used to optimize the gaming experience.
|4.18
+
 
|-
+
[[File:Screenshot_2024-01-01_at_2.35.07_PM.png|alt=Image displaying the Advertise screen reader checkbox|619x619px]]
|USERVAR
+
====Available Client Environment Variables [https://datatracker.ietf.org/doc/html/rfc1572 RFC 1572]====
|'''CLIENT_VERSION'''
+
Two types of variables are used per RFC 152, well-known variables defined with VAR (0) and for less common variables, USERVAR (3). Currently, per the RFC, Mudlet shares its variables via the USERVAR (3) type.
|4/18, 4/17/2-DEV
+
 
|
+
Some client variables updates may be reported ad-hoc with an INFO (2) message. If there is no value for a defined variable, a VAL (1) will be sent without a value following it.
 +
{| class="wikitable"
 +
!Type
 +
!Variable
 +
!Example Values
 +
!Mudlet Default
 +
!OPT-IN
 +
!INFO
 +
!Purpose
 +
!Available
 +
|-
 +
|USERVAR
 +
|'''256_COLORS'''
 +
|1, 0
 +
|1
 
|
 
|
 
|
 
|
| Version of the client.
+
|Client supports all 256 color codes. 1 = Yes/True/ACK.
 
|4.18
 
|4.18
 
|-
 
|-
 
|USERVAR
 
|USERVAR
|'''MTTS'''
+
|'''ANSI'''
|2349
+
|1, 0
 +
|1
 
|
 
|
 
|
 
|
|Yes
+
|Client supports all common ANSI color codes. 1 = Yes/True/ACK.
|Bitvector defined in the Mud Terminal Type Standard ([https://tintin.mudhalla.net/protocols/mtts/ MTTS]).
+
|4.18
| 4.18
 
 
|-
 
|-
| USERVAR
+
|USERVAR
|'''OSC_COLOR_PALETTE'''
+
|'''BOLD_IS_BRIGHT'''
|1, 0
+
|2, 1, 0
 
|
 
|
 
|
 
|
|
+
|Yes
|Client supports OSC and the OSC color palette. 1 = Yes/True/ACK.
+
|Use bright colors always (2), sometimes (1), or never (0).
| 4.18
+
|future
 
|-
 
|-
| USERVAR
+
|USERVAR
|'''OSC_HYPERLINKS'''
+
|'''CHARSET'''
|1, 0
+
|UTF-8, ASCII
|1
 
 
|
 
|
 
|
 
|
|Client supports OSC 8 hyperlinks per the [https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda standard specification] with Mudlet extensions for enhanced styling and interactivity. 1 = Yes/True/ACK.
+
|Yes
| 4.20
+
| Encoding set in the client
 +
|4.18
 
|-
 
|-
| USERVAR
+
|USERVAR
|'''OSC_HYPERLINKS_COMPACT'''
+
|'''CLIENT_NAME'''
|1, 0
+
|MUDLET
|1
+
|MUDLET
 
|
 
|
 
|
 
|
|Client supports compact/shorthand JSON syntax for OSC 8 hyperlink configuration (e.g., <code>s</code> for <code>style</code>, <code>c</code> for <code>color</code>). 1 = Yes/True/ACK.
+
|Name of the client.
| 4.21
+
|4.18
 
|-
 
|-
| USERVAR
+
|USERVAR
|'''OSC_HYPERLINKS_DISABLED'''
+
|'''CLIENT_VERSION'''
|1, 0
+
|4/18, 4/17/2-DEV
|1
+
|
 
|
 
|
 
|
 
|
|Client supports the <code>disabled</code> parameter to create non-interactive hyperlinks that block clicks and context menus while preserving tooltips. 1 = Yes/True/ACK.
+
| Version of the client.
| 4.21
+
|4.18
 
|-
 
|-
| USERVAR
+
|USERVAR
|'''OSC_HYPERLINKS_MENU'''
+
|'''MTTS'''
|1, 0
+
|2349
|1
 
 
|
 
|
 
|
 
|
|Client supports the <code>menu</code> parameter for interactive right-click context menus on OSC 8 hyperlinks. 1 = Yes/True/ACK.
+
|Yes
| 4.20
+
|Bitvector defined in the Mud Terminal Type Standard ([https://tintin.mudhalla.net/protocols/mtts/ MTTS]).
 +
| 4.18
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_PRESETS'''
+
|'''OSC_COLOR_PALETTE'''
 
|1, 0
 
|1, 0
|1
 
 
|
 
|
 
|
 
|
|Client supports the <code>preset:</code> URI scheme for defining reusable styling configurations that can be referenced by name. 1 = Yes/True/ACK.
+
|
| 4.21
+
|Client supports OSC and the OSC color palette. 1 = Yes/True/ACK.
 +
| 4.18
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_PROMPT'''
+
|'''OSC_HYPERLINKS'''
 
|1, 0
 
|1, 0
 
|1
 
|1
 
|
 
|
 
|
 
|
|Client supports the <code>prompt:</code> URI scheme for pre-filling the command line. 1 = Yes/True/ACK.
+
|Client supports OSC 8 hyperlinks per the [https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda standard specification] with Mudlet extensions for enhanced styling and interactivity. 1 = Yes/True/ACK.
 
| 4.20
 
| 4.20
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_SELECTION'''
+
|'''OSC_HYPERLINKS_COMPACT'''
 +
|1, 0
 +
|1
 +
|
 +
|
 +
|Client supports compact/shorthand JSON syntax for OSC 8 hyperlink configuration (e.g., <code>s</code> for <code>style</code>, <code>c</code> for <code>color</code>). 1 = Yes/True/ACK.
 +
| 4.21
 +
|-
 +
| USERVAR
 +
|'''OSC_HYPERLINKS_DISABLED'''
 
|1, 0
 
|1, 0
 
|1
 
|1
 
|
 
|
 
|
 
|
|Client supports the <code>selection</code> parameter for stateful toggle behavior with radio-button (exclusive) and checkbox (multi-select) group support, including the <code>:selected</code> pseudo-class. 1 = Yes/True/ACK.
+
|Client supports the <code>disabled</code> parameter to create non-interactive hyperlinks that block clicks and context menus while preserving tooltips. 1 = Yes/True/ACK.
 
| 4.21
 
| 4.21
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_SEND'''
+
|'''OSC_HYPERLINKS_MENU'''
 
|1, 0
 
|1, 0
 
|1
 
|1
 
|
 
|
 
|
 
|
|Client supports the <code>send:</code> URI scheme for immediately executing commands. 1 = Yes/True/ACK.
+
|Client supports the <code>menu</code> parameter for interactive right-click context menus on OSC 8 hyperlinks. 1 = Yes/True/ACK.
 
| 4.20
 
| 4.20
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_SPOILER'''
+
|'''OSC_HYPERLINKS_PRESETS'''
 
|1, 0
 
|1, 0
 
|1
 
|1
 
|
 
|
 
|
 
|
|Client supports the <code>spoiler</code> parameter for click-to-reveal hidden content with redacted display until interaction. 1 = Yes/True/ACK.
+
|Client supports the <code>preset:</code> URI scheme for defining reusable styling configurations that can be referenced by name. 1 = Yes/True/ACK.
 
| 4.21
 
| 4.21
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_STYLE_BASIC'''
+
|'''OSC_HYPERLINKS_PROMPT'''
 
|1, 0
 
|1, 0
 
|1
 
|1
 
|
 
|
 
|
 
|
|Client supports basic styling for OSC 8 hyperlinks including colors (foreground, background), text formatting (bold, italic), and simple text decorations (underline, strikeout, overline). 1 = Yes/True/ACK.
+
|Client supports the <code>prompt:</code> URI scheme for pre-filling the command line. 1 = Yes/True/ACK.
 
| 4.20
 
| 4.20
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_STYLE_STATES'''
+
|'''OSC_HYPERLINKS_SELECTION'''
 
|1, 0
 
|1, 0
 
|1
 
|1
 
|
 
|
 
|
 
|
|Client supports interactive pseudo-class states for OSC 8 hyperlinks (:hover, :active, :visited, :focus, :focus-visible, :link, :any-link, :selected, :disabled) with state-specific styling and accessibility enhancements. 1 = Yes/True/ACK.
+
|Client supports the <code>selection</code> parameter for stateful toggle behavior with radio-button (exclusive) and checkbox (multi-select) group support, including the <code>:selected</code> pseudo-class. 1 = Yes/True/ACK.
 
| 4.21
 
| 4.21
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_TOOLTIP'''
+
|'''OSC_HYPERLINKS_SEND'''
 
|1, 0
 
|1, 0
 
|1
 
|1
 
|
 
|
 
|
 
|
|Client supports the <code>tooltip</code> parameter for displaying contextual help text when hovering over OSC 8 hyperlinks. 1 = Yes/True/ACK.
+
|Client supports the <code>send:</code> URI scheme for immediately executing commands. 1 = Yes/True/ACK.
 
| 4.20
 
| 4.20
 
|-
 
|-
 
| USERVAR
 
| USERVAR
|'''OSC_HYPERLINKS_VISIBILITY'''
+
|'''OSC_HYPERLINKS_SPOILER'''
 
|1, 0
 
|1, 0
 
|1
 
|1
 
|
 
|
 
|
 
|
|Client supports the <code>visibility</code> parameter for automatic hide/reveal behavior including timed concealment, expiration triggers, and delayed reveal. 1 = Yes/True/ACK.
+
|Client supports the <code>spoiler</code> parameter for click-to-reveal hidden content with redacted display until interaction. 1 = Yes/True/ACK.
 
| 4.21
 
| 4.21
 
|-
 
|-
|USERVAR
+
| USERVAR
|'''SCREEN_READER'''
+
|'''OSC_HYPERLINKS_STYLE_BASIC'''
 
|1, 0
 
|1, 0
|0
+
|1
|Yes
 
|Yes
 
|Client is using a screen reader. 1 = Yes/True/ACK.
 
|4.18
 
|-
 
|USERVAR
 
|'''TERMINAL_TYPE'''
 
|ANSI-TRUECOLOR, ANSI-256COLOR, ANSI, XTERM, VT100, DUMB
 
|ANSI-TRUECOLOR
 
 
|
 
|
 
|
 
|
|Terminal type of the client
+
|Client supports basic styling for OSC 8 hyperlinks including colors (foreground, background), text formatting (bold, italic), and simple text decorations (underline, strikeout, overline). 1 = Yes/True/ACK.
|4.18
+
| 4.20
 
|-
 
|-
|USERVAR
+
| USERVAR
|'''TLS'''
+
|'''OSC_HYPERLINKS_STYLE_STATES'''
 
|1, 0
 
|1, 0
 +
|1
 
|
 
|
 
|
 
|
|
+
|Client supports interactive pseudo-class states for OSC 8 hyperlinks (:hover, :active, :visited, :focus, :focus-visible, :link, :any-link, :selected, :disabled) with state-specific styling and accessibility enhancements. 1 = Yes/True/ACK.
|Client supports Transport Layer Security for data encryption. 1 = Yes/True/ACK.
+
| 4.21
|4.18
 
 
|-
 
|-
|USERVAR
+
| USERVAR
|'''TRUECOLOR'''
+
|'''OSC_HYPERLINKS_TOOLTIP'''
 
|1, 0
 
|1, 0
 +
|1
 
|
 
|
 
|
 
|
|
+
|Client supports the <code>tooltip</code> parameter for displaying contextual help text when hovering over OSC 8 hyperlinks. 1 = Yes/True/ACK.
|Client supports truecolor codes using semicolon notation. 1 = Yes/True/ACK.
+
| 4.20
|4.18
+
|-
 +
| USERVAR
 +
|'''OSC_HYPERLINKS_VISIBILITY'''
 +
|1, 0
 +
|1
 +
|
 +
|
 +
|Client supports the <code>visibility</code> parameter for automatic hide/reveal behavior including timed concealment, expiration triggers, and delayed reveal. 1 = Yes/True/ACK.
 +
| 4.21
 
|-
 
|-
 
|USERVAR
 
|USERVAR
|'''UTF-8'''
+
|'''SCREEN_READER'''
 
|1, 0
 
|1, 0
|
+
|0
|
+
|Yes
 
|Yes
 
|Yes
|Client is using UTF-8 character encoding. 1 = Yes/True/ACK.
+
|Client is using a screen reader. 1 = Yes/True/ACK.
 
|4.18
 
|4.18
 
|-
 
|-
 
|USERVAR
 
|USERVAR
|'''VT100'''
+
|'''TERMINAL_TYPE'''
| 1, 0
+
|ANSI-TRUECOLOR, ANSI-256COLOR, ANSI, XTERM, VT100, DUMB
|0
+
|ANSI-TRUECOLOR
 
|
 
|
 
|
 
|
|Client supports all common VT100 codes. 1 = Yes/True/ACK. This is not applicable for Mudlet and while defined, is not used.
+
|Terminal type of the client
 
|4.18
 
|4.18
 
|-
 
|-
 
|USERVAR
 
|USERVAR
|'''WORD_WRAP'''
+
|'''TLS'''
|100
+
|1, 0
 
|
 
|
 
|
 
|
| Yes
+
|
|Client wraps text at this value
+
|Client supports Transport Layer Security for data encryption. 1 = Yes/True/ACK.
 
|4.18
 
|4.18
 
|-
 
|-
|}
+
|USERVAR
 
+
|'''TRUECOLOR'''
==== Negotiating NEW-ENVIRON====
+
|1, 0
Negotiating the NEW-ENVIRON Telnet option empowers game servers to request one, multiple, or all client environment variables configured within Mudlet. The process unfolds with the game server sending a Telopt DO NEW-ENVIRON (39), prompting Mudlet to respond with a WILL NEW-ENVIRON (39). Subsequently, the game server can send SB NEW-ENVIRON (39) SEND to receive all available environment variables. Mudlet responds with SB NEW-ENVIRON (39) IS (0) < VAR (0) | USERVAR (3) > "<variable>" [VAL (1)] ["<value>"] [ .. [ VAR (0) | USERVAR (3) ] "<variable>" VAL (1) "<value>"] containing the list of environmental variables.
+
|
 
+
|
Once an environmental variable is transmitted to a server within the ongoing connection, Mudlet replies with SB NEW-ENVIRON (39) INFO (2) < VAR (0) | USERVAR (3) > "<variable>" [VAL (1)] ["<value>"] messages for select variables. Importantly, no reply from the server is required in this context. If there is a need to specify a particular list of requested environmental variables to Mudlet, the format SB NEW-ENVIRON (39) SEND < VAR (0) | USERVAR (3) > "<variable>" [ .. < VAR (0) | USERVAR (3) > "<variable>" ] can be employed.
+
|
 
+
|Client supports truecolor codes using semicolon notation. 1 = Yes/True/ACK.
Success example #1 (one environmental variable):
+
|4.18
{| class="wikitable"
 
!Server
 
!Mudlet
 
 
|-
 
|-
|IAC DO NEW-ENVIRON (39) IAC SE
+
|USERVAR
|IAC WILL NEW-ENVIRON (39) IAC SE
+
|'''UTF-8'''
 +
|1, 0
 +
|
 +
|
 +
|Yes
 +
|Client is using UTF-8 character encoding. 1 = Yes/True/ACK.
 +
|4.18
 +
|-
 +
|USERVAR
 +
|'''VT100'''
 +
| 1, 0
 +
|0
 +
|
 +
|
 +
|Client supports all common VT100 codes. 1 = Yes/True/ACK. This is not applicable for Mudlet and while defined, is not used.
 +
|4.18
 
|-
 
|-
|IAC SB NEW-ENVIRON (39) SEND (1) USERVAR (3) ''CHARSET'' IAC SE
+
|USERVAR
| IAC SB NEW-ENVIRON (39) IS (0) USERVAR (3) ''CHARSET'' VAL (1) ''UTF-8'' IAC SE
+
|'''WORD_WRAP'''
 +
|100
 +
|
 +
|
 +
| Yes
 +
|Client wraps text at this value
 +
|4.18
 +
|-
 +
|}
 +
 
 +
==== Negotiating NEW-ENVIRON====
 +
Negotiating the NEW-ENVIRON Telnet option empowers game servers to request one, multiple, or all client environment variables configured within Mudlet. The process unfolds with the game server sending a Telopt DO NEW-ENVIRON (39), prompting Mudlet to respond with a WILL NEW-ENVIRON (39). Subsequently, the game server can send SB NEW-ENVIRON (39) SEND to receive all available environment variables. Mudlet responds with SB NEW-ENVIRON (39) IS (0) < VAR (0) | USERVAR (3) > "<variable>" [VAL (1)] ["<value>"] [ .. [ VAR (0) | USERVAR (3) ] "<variable>" VAL (1) "<value>"] containing the list of environmental variables.
 +
 
 +
Once an environmental variable is transmitted to a server within the ongoing connection, Mudlet replies with SB NEW-ENVIRON (39) INFO (2) < VAR (0) | USERVAR (3) > "<variable>" [VAL (1)] ["<value>"] messages for select variables. Importantly, no reply from the server is required in this context. If there is a need to specify a particular list of requested environmental variables to Mudlet, the format SB NEW-ENVIRON (39) SEND < VAR (0) | USERVAR (3) > "<variable>" [ .. < VAR (0) | USERVAR (3) > "<variable>" ] can be employed.
 +
 
 +
Success example #1 (one environmental variable):
 +
{| class="wikitable"
 +
!Server
 +
!Mudlet
 +
|-
 +
|IAC DO NEW-ENVIRON (39) IAC SE
 +
|IAC WILL NEW-ENVIRON (39) IAC SE
 +
|-
 +
|IAC SB NEW-ENVIRON (39) SEND (1) USERVAR (3) ''CHARSET'' IAC SE
 +
| IAC SB NEW-ENVIRON (39) IS (0) USERVAR (3) ''CHARSET'' VAL (1) ''UTF-8'' IAC SE
 
|-
 
|-
 
|}
 
|}
Line 1,047: Line 1,152:
 
* <nowiki>RFC 1073</nowiki> - [https://www.rfc-editor.org/rfc/rfc1073.html Telnet Window Size Option]
 
* <nowiki>RFC 1073</nowiki> - [https://www.rfc-editor.org/rfc/rfc1073.html Telnet Window Size Option]
  
==TLS (Secure Connections)==
+
==OSC 8: Hyperlink Protocol==
To connect to a game using Transport Layer Security (TLS) for more security, tick the 'Secure' box in the profile connection settings:
 
  
[[File:Secure-connection.png|center]]
+
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]].
  
Note that the game must support a secure (TLS) connection in order for this to work, and this feature is available in Mudlet 3.17+.
+
{{MudletVersion|4.20}}
  
If you are a games admin/developer, check out [https://wiki.mudlet.org/w/Sample_TLS_Configuration this] or [https://blog.oestrich.org/2018/11/nginx-tls-socket this] example on how to setup a secure connection to your game, as well as [[Manual:Technical_Manual#Receiving_MSSP_Data|MSSP data]] in order to let Mudlet know that you do have a secure connection available.
+
===Quick Start===
  
===Secure connection prompt ===
+
Want to try OSC 8 hyperlinks immediately? Send this command in Mudlet:
{{MudletVersion|4.17}}
 
To encourage enhanced data transfer protection and privacy, Mudlet will respond to the detection of the <code>TLS</code> (or <code>SSL</code> legacy) key of MSSP ([[MSSP|Mud Server Status Protocol]]) and prompt a user not on a TLS (Transport Layer Security) connection with a choice to reconnect with the advertised TLS port from MSSP.
 
  
[[File:200146744-9aa3305d-99b2-4e4b-ab48-99779d7e0f76.png|alt=Prompting for secure connection|frameless|928x928px]]
+
say !osc8-docs
 +
 
 +
 
 +
[[File:OSC 8 Hyperlinks.png|411px|frameless]]
  
If the user selects <code>Yes</code>, Mudlet automatically updates the port with the <code>TLS</code> value gathered from MSSP, check-marks the <code>Secure</code> checkbox on the connection dialog, then reconnects.  If the user selects <code>No</code>, Mudlet automatically updates a profile preference so they are not asked again for the current profile, then reconnects.  This preference may be controlled on the Settings->Connection menu.  This preference is enabled by default.
+
===Feature Overview===
  
[[File:Secure connection reminder.png|alt=Secure connection reminder|frameless|927x927px]]
+
{| 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}}
 +
|-
 +
| [[#Accessibility|Accessibility]] || Keyboard navigation, screen reader support || {{MudletVersion|4.21}}
 +
|-
 +
| [[#Compact Syntax|Compact Syntax]] || Shorthand property names || {{MudletVersion|4.21}}
 +
|-
 +
| [[#Presets|Presets]] || Reusable style templates || {{MudletVersion|4.21}}
 +
|}
  
= Supported Protocols for Specific Games=
+
----
  
Mudlet includes support for the legacy, game specific ATCP and channel 102 protocols. Please use standards based protocols in the future (i.e., GMCP) vs. requesting to add a new game specific one.
+
===Tier 1: Fundamentals===
  
==ATCP==
+
====Understanding OSC Sequences====
  
Mudlet includes support for ATCP. This is primarily available on IRE-based MUDs, but Mudlet's implementation is generic enough such that any it should work on others.
+
=====Purpose=====
  
{{Note}} ATCP has been overtaken by GMCP, prefer to use that instead.
+
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.
  
The latest ATCP data is stored in the atcp table. Whenever new data arrives, the previous is overwritten. An event is also raised for each ATCP message that arrives. To find out the available messages available in the atcp table and the event names, you can use display(atcp).
+
=====How It Works=====
  
Note that while the typical message comes in the format of Module.Submodule, ie Char.Vitals or Room.Exits, in Mudlet the dot is removed - so it becomes CharVitals and RoomExits.
+
# Server sends an escape sequence starting with <code>ESC ]</code> (escape + right bracket)
;Example
+
# The sequence contains command data (like a URL)
<syntaxhighlight lang="lua">
+
# The sequence ends with a String Terminator: <code>ESC \</code> (escape + backslash)
room_number = tonumber(atcp.RoomNum)
+
# The terminal processes the command and renders the result
echo(room_number)
+
 
</syntaxhighlight>
+
=====Key Characters=====
  
===Triggering on ATCP events===
+
{| 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
 +
|}
  
If you’d like to trigger on ATCP messages, then you need to create scripts to attach handlers to the ATCP messages. The ATCP handler names follow the same format as the atcp table - RoomNum, RoomExits, CharVitals and so on.
+
{{Note}} "Note: Mudlet requires proper termination with either ST (ESC ) Mudlet 4.20 or BEL (0x07) Mudlet 4.20+. Missing terminators cause text to buffer without displaying (with a 4096-byte safety limit)."
  
While the concept of handlers for events is to be explained elsewhere in the manual, the quick rundown is this - place the event name you’d like your script to listen to into the Add User Defined Event Handler: field and press the + button to register it. Next, because scripts in Mudlet can have multiple functions, you need to tell Mudlet which function should it call for you when your handler receives a message. You do that by setting the Script name: to the function name in the script you’d like to be called.
+
====Basic Links====
  
For example, if you’d like to listen to the RoomExits event and have it call the process_exits() function - register RoomExits as the event handler, make the script name be process_exits, and use this in the script:
+
=====Purpose=====
  
<syntaxhighlight lang="lua">
+
Create clickable text that performs actions when clicked—sending commands to the game, pre-filling input, or opening web pages.
function process_exits(event, args)
 
    echo("Called event: " .. event .. "\nWith args: " .. args)
 
end
 
</syntaxhighlight>
 
  
Feel free to experiment with this to achieve the desired results. A ATCP demo package is also available on the forums for using event handlers and parsing its messages into Lua datastructures.
+
{{MudletVersion|4.20}}
  
===Mudlet-specific ATCP===
+
=====How It Works=====
See [[Manual:ATCP_Extensions|ATCP Extensions]] for ATCP extensions that have been added to Mudlet.
 
  
==Aardwolf’s 102 subchannel ==
+
OSC 8 hyperlinks work like HTML tags with opening and closing sequences:
  
Similar to ATCP, Aardwolf includes a hidden channel of information that you can access in Mudlet. Mudlet deals with it in the same way as with ATCP, so for full usage instructions see the ATCP section. All data is stored in the channel102 table, such that you can do:
+
# '''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>
  
<syntaxhighlight lang="lua">
+
=====Structure=====
display(channel102)
+
 
</syntaxhighlight>
+
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>
  
... to see all the latest information that has been received. The event to create handlers on is titled '''channel102Message''', and you can use the [[Manual:Lua_Functions#sendTelnetChannel102|sendTelnetChannel102(msg)]] function to send text via the 102 channel back to Aardwolf.
+
=====Common Encodings=====
  
<syntaxhighlight lang="lua">
+
{| class="wikitable"
-- Function for detecting AFK status on Aardwolf mud.
+
! Character !! Encoded !! When to Encode
function amIafk()
+
|-
   for k,v in pairs(channel102) do
+
| Space || <code>%20</code> || In commands: <code>cast%20fireball</code>
       if k==100 and v==4 then
+
|-
         return true
+
| <code>"</code> || <code>%22</code> || In JSON strings
       end
+
|-
   end
+
| <code>{</code> || <code>%7B</code> || JSON object start
   return false
+
|-
end
+
| <code>}</code> || <code>%7D</code> || JSON object end
</syntaxhighlight>
+
|-
 
+
| <code>:</code> || <code>%3A</code> || JSON key-value separator
= Adding support for a telnet protocol=
+
|-
In addition to supporting ATCP, GMCP, Aardwolf's 102 and MXP, Mudlet has open telnet support - meaning that for any telnet protocol it doesn't support, it has the tools you can use to build the support for. This does not mean Mudlet supports other protocols "out of the box" - you will either have to get code that adds the support, or you could create it yourself.
+
| <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
 +
  "title": "",      // Menu header (string or {text, style})
 +
  "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
 +
|-
 +
| <code>title</code> || String/Object || Non-clickable header label above menu items
 +
|}
 +
 
 +
[[File:MenuTitle.png|frameless]]
 +
 
 +
'''Menu item format:'''
 +
<syntaxhighlight lang="json">
 +
{"Label Text": "scheme:command"}
 +
</syntaxhighlight>
 +
 
 +
'''Separator:'''
 +
<syntaxhighlight lang="json">
 +
"-"
 +
</syntaxhighlight>
 +
 
 +
'''Title (simple):'''
 +
<syntaxhighlight lang="json">
 +
{"title": "Lamb and Barley Stew", "menu": [...]}
 +
</syntaxhighlight>
 +
 
 +
{{MudletVersion|4.21}}
 +
 
 +
'''Title with styling:'''
 +
<syntaxhighlight lang="json">
 +
{
 +
  "title": {
 +
    "text": "Lamb and Barley Stew",
 +
    "style": {"color": "#5fbdaf", "bold": true}
 +
  },
 +
  "menu": [...]
 +
}
 +
</syntaxhighlight>
 +
 
 +
{{MudletVersion|4.21}}
 +
 
 +
{{Note}} For Mudlet, <code>title</code> defaults to teal (<code>#5fbdaf</code>) when no style is specified. <code>title</code> has no effect if <code>menu</code> is not configured.
 +
 
 +
=====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===
 +
 
 +
====Accessibility====
 +
 
 +
=====Purpose=====
 +
 
 +
Enable screen reader users and keyboard-only users to discover, navigate, and activate OSC 8 hyperlinks without a mouse.
 +
 
 +
{{MudletVersion|4.21}}
 +
 
 +
=====How It Works=====
 +
 
 +
# Caret mode enables keyboard navigation of game output
 +
# Tab / Shift+Tab moves between links (wraps around at buffer boundaries)
 +
# Enter or Space activates the focused link
 +
# Menu key or Shift+F10 opens context menus
 +
# Screen readers announce link tooltip, state, and available actions on focus
 +
 
 +
=====What Servers Should Know=====
 +
 
 +
Links work with keyboard and screen readers automatically—no extra configuration needed. However, a few authoring choices significantly improve the experience:
 +
 
 +
'''Write descriptive tooltips.''' The tooltip is the first thing a screen reader announces when a user navigates to a link. Without one, the raw command (e.g. <code>send:look</code>) is read aloud instead.
 +
 
 +
<syntaxhighlight lang="json">
 +
{"tooltip": "Examine the iron gate"}
 +
</syntaxhighlight>
 +
 
 +
'''Use meaningful selection group and value names.''' Group names are exposed to assistive technology. A group named <code>"combat_stance"</code> is more useful than <code>"g1"</code>.
 +
 
 +
'''Spoilers are keyboard-safe.''' The first Enter/Space reveals hidden text; a second press activates the link function. No changes needed.
 +
 
 +
'''Disabled and visited states are announced.''' Screen readers append "disabled", "visited", or "selected" to the link announcement automatically.
 +
 
 +
'''Links with menus announce "has menu."''' Users hear this cue and can press Menu or Shift+F10 to open the context menu at the caret position.
 +
 
 +
====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="8" | '''Top-level''' || style || s
 +
|-
 +
| menu || m
 +
|-
 +
| tooltip || t
 +
|-
 +
| title || ti
 +
|-
 +
| 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>d</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"}
 +
  ],
 +
  "title": "Header text",      // or {"text": "...", "style": {...}}
 +
  "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 || vi
 +
|-
 +
| visibility || v || italic || i || focus || f
 +
|-
 +
| selection || sel || underline || u || selected || sl
 +
|-
 +
| spoiler || sp || strikethrough || st || disabled || d
 +
|-
 +
| title || ti
 +
|}
 +
 
 +
====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
 +
 
 +
====== When Parameters Become Reserved ======
 +
 
 +
These parameters only need encoding when the client advertises the corresponding capabilities:
 +
 
 +
{| class="wikitable"
 +
|-
 +
! Parameter !! Reserved When Client Advertises
 +
|-
 +
| <code>config</code> || Any of: OSC_HYPERLINKS_STYLE_BASIC, OSC_HYPERLINKS_STYLE_STATES, OSC_HYPERLINKS_TOOLTIP, OSC_HYPERLINKS_MENU, OSC_HYPERLINKS_VISIBILITY, OSC_HYPERLINKS_SPOILER, OSC_HYPERLINKS_DISABLED, OSC_HYPERLINKS_SELECTION, OSC_HYPERLINKS_COMPACT
 +
|-
 +
| <code>preset</code> || OSC_HYPERLINKS_PRESETS
 +
|}
 +
 
 +
{{Note|If a client only advertises OSC_HYPERLINKS, OSC_HYPERLINKS_SEND, and OSC_HYPERLINKS_PROMPT, no URL encoding of these parameters is required.}}
 +
 
 +
====== 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.}}
 +
 
 +
For server-side convenience, the [https://github.com/Cryosphere-MUD/mudlet-url-munger Cryosphere-MUD/mudlet-url-munger] C++ library can automatically percent-encode reserved parameter names in URLs before sending them via OSC 8.
 +
 
 +
===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, TITLE, VISIBILITY, SELECTION support
 +
* Implement context menus and dynamic visibility
 +
 
 +
'''Accessibility tip:''' Descriptive <code>tooltip</code> values double as screen reader announcements. If your links lack tooltips, keyboard users hear raw commands like <code>openUrl([[https://...]])</code>. A short, human-readable tooltip costs almost nothing and dramatically improves the experience for all users.
 +
 
 +
'''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, title, visibility, selection managers
 +
 
 +
'''Level 5:''' Add shorthand expansion table
 +
 
 +
'''Level 6:''' Implement preset storage and deep merge
 +
 
 +
'''Level 7:''' Implement keyboard accessibility for links
 +
 
 +
=====Key Accessibility Notes=====
 +
 
 +
* '''Keyboard navigation:''' Tab / Shift+Tab should cycle between links with wrap-around. Override your framework's default Tab handling (Qt: <code>focusNextPrevChild</code>) to prevent it from intercepting Tab for widget focus traversal.
 +
* '''Keyboard activation:''' Enter / Space activates the focused link. Respect the spoiler flow: first activation reveals, second activates. Handle selection group state the same as mouse clicks.
 +
* '''Context menu keys:''' Menu key and Shift+F10 should open context menus at the caret position rather than the mouse position.
 +
* '''IAccessible2 text attributes:''' Expose link semantics using these attributes per character span:
 +
** <code>text-link:</code> — the link command (escape <code>;</code> <code>:</code> <code>\</code> per IAccessible2 spec)
 +
** <code>text-link-visited:true;</code> — link has been activated before
 +
** <code>text-link-disabled:true;</code> — link is non-interactive
 +
** <code>text-link-selected:true;</code> — link is in selected state
 +
** <code>text-link-group:</code> — selection group name (escaped)
 +
* '''Screen reader announcements:''' On link focus, announce: tooltip (or command fallback), then append state suffixes: ", visited", ", disabled", ", selected", ", has menu". Announce "Wrapping to first/last link" when Tab cycles past the buffer boundary.
 +
* '''Hidden link announcements:''' When the visibility manager conceals links, announce the count (debounced to batch rapid removals).
 +
 
 +
=====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
 +
 
 +
==TLS (Secure Connections)==
 +
To connect to a game using Transport Layer Security (TLS) for more security, tick the 'Secure' box in the profile connection settings:
 +
 
 +
[[File:Secure-connection.png|center]]
 +
 
 +
Note that the game must support a secure (TLS) connection in order for this to work, and this feature is available in Mudlet 3.17+.
 +
 
 +
If you are a games admin/developer, check out [https://wiki.mudlet.org/w/Sample_TLS_Configuration this] or [https://blog.oestrich.org/2018/11/nginx-tls-socket this] example on how to setup a secure connection to your game, as well as [[Manual:Technical_Manual#Receiving_MSSP_Data|MSSP data]] in order to let Mudlet know that you do have a secure connection available.
 +
 
 +
===Secure connection prompt ===
 +
{{MudletVersion|4.17}}
 +
To encourage enhanced data transfer protection and privacy, Mudlet will respond to the detection of the <code>TLS</code> (or <code>SSL</code> legacy) key of MSSP ([[MSSP|Mud Server Status Protocol]]) and prompt a user not on a TLS (Transport Layer Security) connection with a choice to reconnect with the advertised TLS port from MSSP.
 +
 
 +
[[File:200146744-9aa3305d-99b2-4e4b-ab48-99779d7e0f76.png|alt=Prompting for secure connection|frameless|928x928px]]
 +
 
 +
If the user selects <code>Yes</code>, Mudlet automatically updates the port with the <code>TLS</code> value gathered from MSSP, check-marks the <code>Secure</code> checkbox on the connection dialog, then reconnects.  If the user selects <code>No</code>, Mudlet automatically updates a profile preference so they are not asked again for the current profile, then reconnects.  This preference may be controlled on the Settings->Connection menu.  This preference is enabled by default.
 +
 
 +
[[File:Secure connection reminder.png|alt=Secure connection reminder|frameless|927x927px]]
 +
 
 +
= Supported Protocols for Specific Games=
 +
 
 +
Mudlet includes support for the legacy, game specific ATCP and channel 102 protocols. Please use standards based protocols in the future (i.e., GMCP) vs. requesting to add a new game specific one.
 +
 
 +
==ATCP==
 +
 
 +
Mudlet includes support for ATCP. This is primarily available on IRE-based MUDs, but Mudlet's implementation is generic enough such that any it should work on others.
 +
 
 +
{{Note}} ATCP has been overtaken by GMCP, prefer to use that instead.
 +
 
 +
The latest ATCP data is stored in the atcp table. Whenever new data arrives, the previous is overwritten. An event is also raised for each ATCP message that arrives. To find out the available messages available in the atcp table and the event names, you can use display(atcp).
 +
 
 +
Note that while the typical message comes in the format of Module.Submodule, ie Char.Vitals or Room.Exits, in Mudlet the dot is removed - so it becomes CharVitals and RoomExits.
 +
;Example
 +
<syntaxhighlight lang="lua">
 +
room_number = tonumber(atcp.RoomNum)
 +
echo(room_number)
 +
</syntaxhighlight>
 +
 
 +
===Triggering on ATCP events===
 +
 
 +
If you’d like to trigger on ATCP messages, then you need to create scripts to attach handlers to the ATCP messages. The ATCP handler names follow the same format as the atcp table - RoomNum, RoomExits, CharVitals and so on.
 +
 
 +
While the concept of handlers for events is to be explained elsewhere in the manual, the quick rundown is this - place the event name you’d like your script to listen to into the Add User Defined Event Handler: field and press the + button to register it. Next, because scripts in Mudlet can have multiple functions, you need to tell Mudlet which function should it call for you when your handler receives a message. You do that by setting the Script name: to the function name in the script you’d like to be called.
 +
 
 +
For example, if you’d like to listen to the RoomExits event and have it call the process_exits() function - register RoomExits as the event handler, make the script name be process_exits, and use this in the script:
 +
 
 +
<syntaxhighlight lang="lua">
 +
function process_exits(event, args)
 +
    echo("Called event: " .. event .. "\nWith args: " .. args)
 +
end
 +
</syntaxhighlight>
 +
 
 +
Feel free to experiment with this to achieve the desired results. A ATCP demo package is also available on the forums for using event handlers and parsing its messages into Lua datastructures.
 +
 
 +
===Mudlet-specific ATCP===
 +
See [[Manual:ATCP_Extensions|ATCP Extensions]] for ATCP extensions that have been added to Mudlet.
 +
 
 +
==Aardwolf’s 102 subchannel ==
 +
 
 +
Similar to ATCP, Aardwolf includes a hidden channel of information that you can access in Mudlet. Mudlet deals with it in the same way as with ATCP, so for full usage instructions see the ATCP section. All data is stored in the channel102 table, such that you can do:
 +
 
 +
<syntaxhighlight lang="lua">
 +
display(channel102)
 +
</syntaxhighlight>
 +
 
 +
... to see all the latest information that has been received. The event to create handlers on is titled '''channel102Message''', and you can use the [[Manual:Lua_Functions#sendTelnetChannel102|sendTelnetChannel102(msg)]] function to send text via the 102 channel back to Aardwolf.
 +
 
 +
<syntaxhighlight lang="lua">
 +
-- Function for detecting AFK status on Aardwolf mud.
 +
function amIafk()
 +
   for k,v in pairs(channel102) do
 +
       if k==100 and v==4 then
 +
         return true
 +
       end
 +
   end
 +
   return false
 +
end
 +
</syntaxhighlight>
 +
 
 +
= Adding support for a telnet protocol=
 +
In addition to supporting ATCP, GMCP, Aardwolf's 102 and MXP, Mudlet has open telnet support - meaning that for any telnet protocol it doesn't support, it has the tools you can use to build the support for. This does not mean Mudlet supports other protocols "out of the box" - you will either have to get code that adds the support, or you could create it yourself.
 +
 
 +
The basic tools that you need are [[Manual:Miscellaneous_Functions#addSupportedTelnetOption|addSupportedTelnetOption()]], [[Manual:Miscellaneous_Functions#sendSocket|sendSocket()]] and the [[Manual:Event_Engine#sysTelnetEvent|sysTelnetEvent]].
 +
 
 +
Create [[Manual:Event_Engine#Registering_an_event_from_a_script|an event handler]] that goes off on [[Manual:Event_Engine#sysTelnetEvent|sysTelnetEvent]] - which is raised whenever an unsupported telnet option is encountered. Your logic handling will start in this event handler. Once you decide what you'd like to send to the game, use [[Manual:Miscellaneous_Functions#sendSocket|sendSocket()]] to send raw data as-is. Finally, when your logic is done, use [[Manual:Miscellaneous_Functions#addSupportedTelnetOption|addSupportedTelnetOption()]] to register your telnet option with Mudlet, so it will respond with telnet DO on a query from the game server. See [http://www.mudbytes.net/forum/comment/63920/#c63920 this MSDP snippet] for a barebones example.
 +
 
 +
===API philosophy===
 +
Adding a support for a new telnet protocol will involve adding the user-facing API. It best for users if it was in the same style as Mudlets handling of other protocols. To see how it's done exactly, check out GMCP, ATCP or Aardwolf 102 examples - but the gist of it is provided below.
 +
 
 +
Mudlet has a built-in event system, which is used to broadcast messages in an independent way. With it, people can "trigger" on 102, ATCP or GMCP events with Lua functions that get called whenever an event they're interested in is raised. '''Use the event system to provide your users with a way to react to new protocol data'''.
 +
 
 +
Events have names, and optionally, any amount of data with them. For protocol support, Mudlet prefixes the relevant message received name with the protocol name in lowercase. For example, an ATCP Char.Vitals getting updated would raise an event titled "atcp.Char.Vitals". A GMCP Room.Info message would raise a "gmcp.Room.Info" message.
 +
 
 +
Additionally, Mudlet also allows catch-all event - in case the user wants to use one event handler for a variety of sub-events (it's not uncommon for games to use ''Main.Sub.Add'', ''Main.Sub.Remove'', ''Main.Sub.List'' to keep track of a list, for example, while conserving data). To accomplish this, it raises events for every relevant namespace - that is, a Main.Sub.Add event will raise ''protocol.Main.Sub'' and ''protocol.Main.Sub.Add events''. While it is entirely possible for one event handler to react to multiple events, this is provided for convenience.
 +
 
 +
For storing protocol data, Mudlet uses an aptly named global table - '''gmcp''' for GMCP data, '''atcp''' for ATCP data. Data is stored in the same way it is received and the event is raised for - so a Char.Vitals message's contents will be stored in gmcp.Char.Vitals, a Room.Info's contents in gmcp.Room.Info. If there were was any nested data within the message, it is stored as a table within the proper namespace - ie, a "details" JSON array of a GMCP Room.Info message would be stored in gmcp.Room.Info.details. '''Use a global table with the protocol name in lowerspace for storing permanent data''' that your users will read from.
 +
 
 +
That's it! If you'll need any Mudlet-related help, feel free to [http://forums.mudlet.org/viewforum.php?f=9 post on our forums]. Once you're done, [[Mudlet_Packages|package your work]] for distribution which you can optionally post in the [http://forums.mudlet.org/viewforum.php?f=6 finished scripts] section.
  
The basic tools that you need are [[Manual:Miscellaneous_Functions#addSupportedTelnetOption|addSupportedTelnetOption()]], [[Manual:Miscellaneous_Functions#sendSocket|sendSocket()]] and the [[Manual:Event_Engine#sysTelnetEvent|sysTelnetEvent]].
 
  
Create [[Manual:Event_Engine#Registering_an_event_from_a_script|an event handler]] that goes off on [[Manual:Event_Engine#sysTelnetEvent|sysTelnetEvent]] - which is raised whenever an unsupported telnet option is encountered. Your logic handling will start in this event handler. Once you decide what you'd like to send to the game, use [[Manual:Miscellaneous_Functions#sendSocket|sendSocket()]] to send raw data as-is. Finally, when your logic is done, use [[Manual:Miscellaneous_Functions#addSupportedTelnetOption|addSupportedTelnetOption()]] to register your telnet option with Mudlet, so it will respond with telnet DO on a query from the game server. See [http://www.mudbytes.net/forum/comment/63920/#c63920 this MSDP snippet] for a barebones example.
+
==telnet:// and telnets:// URI Schemes==
  
===API philosophy===
+
Mudlet registers as a system handler for <code>telnet://</code> and <code>telnets://</code> URI schemes on Windows, Linux, and macOS. Links follow the format <code>telnet://[user@]host[:port]</code> per [https://datatracker.ietf.org/doc/html/rfc4248 RFC 4248], with <code>telnets://</code> as the TLS-encrypted variant.
Adding a support for a new telnet protocol will involve adding the user-facing API. It best for users if it was in the same style as Mudlets handling of other protocols. To see how it's done exactly, check out GMCP, ATCP or Aardwolf 102 examples - but the gist of it is provided below.
 
  
Mudlet has a built-in event system, which is used to broadcast messages in an independent way. With it, people can "trigger" on 102, ATCP or GMCP events with Lua functions that get called whenever an event they're interested in is raised. '''Use the event system to provide your users with a way to react to new protocol data'''.
+
* Default port: 23 (<code>telnet://</code>), 992 (<code>telnets://</code>)
 +
* Optional username in the URI is stored in the profile's auto-login field
 +
* Existing profiles matching the host and port are reused automatically
  
Events have names, and optionally, any amount of data with them. For protocol support, Mudlet prefixes the relevant message received name with the protocol name in lowercase. For example, an ATCP Char.Vitals getting updated would raise an event titled "atcp.Char.Vitals". A GMCP Room.Info message would raise a "gmcp.Room.Info" message.
+
See [[Manual:Connection_Window#Connecting_via_telnet:.2F.2F_links|Connecting via telnet:// links]] for usage details.
 
 
Additionally, Mudlet also allows catch-all event - in case the user wants to use one event handler for a variety of sub-events (it's not uncommon for games to use ''Main.Sub.Add'', ''Main.Sub.Remove'', ''Main.Sub.List'' to keep track of a list, for example, while conserving data). To accomplish this, it raises events for every relevant namespace - that is, a Main.Sub.Add event will raise ''protocol.Main.Sub'' and ''protocol.Main.Sub.Add events''. While it is entirely possible for one event handler to react to multiple events, this is provided for convenience.
 
 
 
For storing protocol data, Mudlet uses an aptly named global table - '''gmcp''' for GMCP data, '''atcp''' for ATCP data. Data is stored in the same way it is received and the event is raised for - so a Char.Vitals message's contents will be stored in gmcp.Char.Vitals, a Room.Info's contents in gmcp.Room.Info. If there were was any nested data within the message, it is stored as a table within the proper namespace - ie, a "details" JSON array of a GMCP Room.Info message would be stored in gmcp.Room.Info.details. '''Use a global table with the protocol name in lowerspace for storing permanent data''' that your users will read from.
 
 
 
That's it! If you'll need any Mudlet-related help, feel free to [http://forums.mudlet.org/viewforum.php?f=9 post on our forums]. Once you're done, [[Mudlet_Packages|package your work]] for distribution which you can optionally post in the [http://forums.mudlet.org/viewforum.php?f=6 finished scripts] section.
 
  
 
[[Category:Mudlet Manual]]
 
[[Category:Mudlet Manual]]

Latest revision as of 19:37, 18 April 2026

Supported Protocols

Mudlet negotiates and supports the following telnet based protocols:

  • CHARSET Telnet Option
  • ECHO Telnet Option
  • GMCP - Generic Mud Communication Protocol
  • MNES - Mud New-Environ Standard
  • MSDP - Mud Server Data Protocol
  • MSP - Mud Sound Protocol
  • MSSP - Mud Server Status Protocol
  • MTTS - Mud Terminal-Type Standard
  • MXP - Mud eXtension Protocol
  • NAWS - Negotiate About Window Size
  • NEW-ENVIRON Telnet Option
  • OSC 8 - Hyperlink Protocol via Operating System Command 8
  • TLS Transport Layer Security

Default Protocol Settings

CHARSET, GMCP, MSP, MSSP, MTTS, MXP, NAWS, and NEW-ENVIRON are enabled by default. MSDP and MNES may be enabled in the Settings menu. OSC 8 is enabled by default. TLS is enabled from the Connections dialog for supported games.

Game protocols drop-down list on the General tab of Settings

CHARSET (Encoding)

More and more game servers are looking beyond ASCII encoding to support extended character sets, like UTF-8 encoding, to meet demand for localization of language and the use of emoji characters.

Encoding in Mudlet

Reference our manual page on Unicode for more information on Unicode updating, scripting and trigger support in Mudlet.

Manual Encoding Updates

Mudlet supports manual selection of a server data encoding. Mudlet users may update the server data encoding for a profile by choosing Settings, General and selecting a server data encoding from the corresponding drop-down menu. The server data encoding defaults to ASCII. When the setting is changed, the selected encoding saves with the user's profile information.

Automated Encoding Updates

Negotiating the CHARSET telnet option provides game servers the capability to automatically request a preferred character set with Mudlet per RFC 2066. Game servers may send a telopt WILL CHARSET (42), Mudlet responds with a DO CHARSET (42), then the game server may send SB CHARSET (42) REQUEST (1) <separator_character> <charset>. Mudlet will respond with SB CHARSET (42) ACCEPTED (2) <charset> if it supports that character set. Mudlet will respond with SB CHARSET (42) REJECTED (3) if it refuses the requested character set(s). When Mudlet accepts a requested character set, it automatically updates the server data encoding viewable in the Settings menu. It is possible to send a list of requested character sets to Mudlet by appending additional "<separator_character> <charset>" byte groups to a SB CHARSET (42) REQUEST (1).

Success example:

Server Mudlet
IAC WILL CHARSET (42) IAC DO CHARSET (42)
IAC SB CHARSET (42) REQUEST (1) <space> UTF-8 IAC SE IAC SB CHARSET (42) ACCEPTED (2) UTF-8 IAC SE

The following is an example of an attempted negotiation where the encoding was not available with Mudlet:

Server Mudlet
IAC WILL CHARSET (42) IAC DO CHARSET (42)
IAC SB CHARSET (42) REQUEST (1) <space> DEEP-6 IAC SE IAC SB CHARSET (42) REJECTED (3) IAC SE

If a Mudlet user does not want to negotiate character set, they may choose the Settings, Special Options menu item in Mudlet and enable "Force CHARSET negotiation off". The following is an example of an attempted negotiation where "Force CHARSET negotiation off" is enabled.

Server Mudlet
IAC WILL CHARSET (42) IAC DONT CHARSET (42)

CHARSET negotiation is available in Mudlet 4.10+.

ECHO (Password Masking)

The ECHO telnet option enables automatic password masking in Mudlet, hiding sensitive input from the screen with asterisks (****) during password entry.

For Game Server Administrators

How It Works

When your game needs a password from a player:

  1. Send IAC WILL ECHO - This tells Mudlet "I will handle echoing characters"
  2. The player's typed password is masked with asterisks automatically
  3. After password entry, send IAC WONT ECHO - This tells Mudlet "I won't handle echoing anymore"
  4. Normal text echoing resumes

Implementation

When to send ECHO:

  • At login prompts
  • When creating new passwords
  • During password change sequences
  • Any time you ask for sensitive input

Basic sequence:

Server Action Telnet Sequence Effect
Ask for password IAC WILL ECHO Mudlet starts masking input
Player types password (player input masked) Shows ******* on screen
Password received IAC WONT ECHO Mudlet stops masking, normal display resumes

Example Implementation

Pseudocode for login:

# At login prompt
send_to_client("Password: ")
send_telnet_option(IAC, WILL, ECHO)  # Start masking

# Read password (Mudlet displays asterisks)
password = read_input_from_client()

# Password received
send_telnet_option(IAC, WONT, ECHO)  # Stop masking
send_to_client("\n")

# Verify password and continue...

Important Notes

  • Always turn ECHO off after password entry - forgetting this will mask all subsequent player input
  • Use for passwords only - don't leave ECHO on for normal gameplay
  • Test thoroughly - ensure ECHO toggles work at all password prompts
  • Handle reconnects - reset ECHO state when players reconnect or timeout

Telnet Byte Values

For low-level implementation:

Command Decimal Hexadecimal
IAC (Interpret As Command) 255 0xFF
WILL 251 0xFB
WONT 252 0xFC
ECHO 1 0x01

Byte sequence to start masking: 255 251 1 (IAC WILL ECHO)

Byte sequence to stop masking: 255 252 1 (IAC WONT ECHO)

Testing

To verify ECHO works correctly:

  1. Connect to your game with Mudlet 4.20+
  2. Reach a password prompt
  3. Type characters - you should see asterisks (*) instead of your text
  4. After entering the password, normal echoing should resume

If masking doesn't work, check:

  • Is your server sending IAC WILL ECHO before the password prompt?
  • Is your server sending IAC WONT ECHO after receiving the password?
  • Are the telnet bytes correct (255 251 1 and 255 252 1)?

User Settings

Players can disable password masking if desired via Settings → Special Options → Disable password masking. However, proper ECHO implementation still benefits players who keep masking enabled (the default).

See Also

GMCP

Generic Mud Communication Protocol, or GMCP, is a protocol for game servers to communicate information with game clients in a separate channel from the one which carries all of the text that makes up the game itself. Enabling the Debug window will show you GMCP events as they are coming in, and to get an idea of what information is currently stored, hit the Statistics button.

When working with GMCP on IRE games, this GMCP reference is a useful tool.

Using GMCP

Receiving GMCP data

To "trigger" on GMCP messages, you'll need to create an event handler - Mudlet will call it for you whenever relevant GMCP data is received.

As an example, create a new script and give it a name of the function you'd like to be called when the relevant GMCP message is received. Then, add the GMCP event you'd like the function to fire on under the registered event handlers left. Lastly, define the function - either in this or any other script - and you'll be done. The GMCP data received will be stored in the corresponding field of the gmcp table, which your function will read from.

Example:

Using gmcp.png

The test_gmcp() function will be called whenever Char.Vitals is received from the game, and it'll echo the latest data on the screen.

Sending GMCP data

Certain modules will only send data when a request is made by your client. In Mudlet, you can make such a request using the command sendGMCP("command"). Read your game's relevant documentation, such as the IRE document on GMCP, for information about specific modules.

See Also: sendGMCP

Managing GMCP modules

While some GMCP modules are enabled by Mudlet by default when you connect with a GMCP enabled game, others may not be 'standard' modules and are instead specific to the game itself. In order to provide a way to manage GMCP modules without scripts causing modules in use by other scripts to be disabled.

Registering user

While this step is no longer strictly required, you can register your 'user' with gmod using

gmod.registerUser("MyUser")

Where MyUser is your plugin/addon/whatever name. However, your user will be automatically registered if you enable or disable any modules using it. Which leads us to...

Enabling modules

Enabling a GMCP module is as easy as:

gmod.enableModule("MyUser", "Module.Name")

If MyUser has not been registered previously, then they will be automatically registered when you call this function. An example of a module which would need to be enabled this way is the IRE.Rift module provided by IRE MUDs.

-- add this to a login trigger, or anything that will get done just once per login
gmod.enableModule("<character name>", "IRE.Rift")

Another example would be the Combat module in Lithmeria, which isn't enabled by default:

-- add this to a login trigger, or anything that will get done just once per login
gmod.enableModule("<character name>", "Combat")

Disabling modules

Disabling a GMCP module is just as easy as enabling it:

gmod.disableModule("MyUser", "Module.Name")

The main difference being that the module will be turned on as soon as you enable it if it is not already enabled. If you disable it, it will not be disabled with the server until every user of that module has disabled it. This prevents script A from disabling modules that script B may still be using.

Thorough GMCP tutorial

A good GMCP tutorial that walks you through receiving and sending GMCP data is available here - take a read!

MSDP

MSDP (Mud Server Data Protocol) is a protocol for game servers to communicate information with game clients in a separate channel from the one which carries all of the text that makes up the game itself. Mudlet can be configured to use MSDP by clicking on the Settings button (or Options->Preferences in the menu, or <alt>p). The option is on the General tab.

Once MSDP is enabled, you will need to reconnect to the game so that Mudlet can inform the server it is ready to receive MSDP information. Please note that some servers don't both send MSDP and GMCP at the same time, so even if you enable both in Mudlet, the server will choose to send only one of them.

Enabling the Debug window will show you MSDP events as they are coming in, and to get an idea of what information is currently stored, hit the Statistics button. Also see MSDP reference for some of the commands and values your server might support.

Using MSDP

Receiving MSDP data

To "trigger" on MSDP messages, you'll need to create an event handler - Mudlet will call it for you whenever relevant MSDP data is received.

As an example, lets create a script that'll track whenever we move - that is, the room number changes. To begin with, we need to ask the game to be sending us updates whenever we move - so do:

lua sendMSDP("REPORT", "ROOM_VNUM")

in the command-line first to enable reporting of the room number and name. Then, create a new script and give it a name of the function you'd like to be called when the relevant MSDP message is received. Add the MSDP event you'd like the function to fire on under the registered event handlers - in our case, msdp.ROOM_VNUM. Lastly, define the function - either in this or any other script - and you'll be done. The MSDP data received will be stored in the corresponding field of the msdp table, which your function will read from.

Example:

Using msdp.png

The test_msdp() function will be called whenever ROOM_VNUM is received from the game, and it'll echo the latest data on the screen.

Sending MSDP data

You can use sendMSDP to send information via MSDP back to the game. The first parameter to the function is the MSDP variable, and all the subsequent ones are values. See the MSDP documentation for some examples of data that you can send:

-- ask the server to report your health changes to you. Result will be stored in msdp.HEALTH in Mudlet
sendMSDP("REPORT", "HEALTH")

-- client - IAC SB MSDP MSDP_VAR "SEND" MSDP_VAL "AREA NAME" MSDP_VAL "ROOM NAME" IAC SE in the documentation translates to the following in Mudlet:
sendMSDP("SEND", "AREA NAME", "ROOM NAME")
See Also: sendMSDP

MSP

Want to add accessibility and excitement into your game? How about implementing sound and music triggers?

Mud Sound Protocol, or MSP, provides a way for games to send sound and music triggers to clients. Clients have the option to implement a framework where the corresponding triggers play. MSP triggers are sent in one direction to game clients and not to game servers. Sounds may be downloaded manually or automatically if conditions are met.

Games could use telnet option negotiation to signal clients support for MSP (WILL, WONT), and toggling MSP processing on and off (DO, DONT). This is communicated using TELOPT 90, which is reserved (unofficially) for the MSP protocol by our community. Games that do not support telnet option negotiation for MSP should provide a means for their players to toggle this feature on and off.

The latest specification for MSP is located here and available in PDF here.

MSP in Mudlet

Mudlet processes MSP sound and music triggers in three ways:

  1. MSP over OOB - Mudlet is capable of receiving hidden, out-of-band telnet sound and music triggers from game servers via messaging with TELOPT 90.
  2. MSP for Lua - Mudlet triggers may capture and invoke the receiveMSP function available through the Lua interpreter of Mudlet to process MSP.
  3. MSP over GMCP - Mudlet may receive GMCP events from game servers sent with the Client.Media package.

Sound or music triggers that contain a media file name will be searched for in the media folder of the corresponding Mudlet profile that matches the host for the game. If the media folder and the file are found by Mudlet, it will be played, given the host's operating system supports playing that type of media file. If the file is not found, Mudlet could initiate a download of the media file when provided a URL to find the file. Alternatively, game administrators may instruct players on other ways to transfer media files by 1) creating a media folder in their game's Mudlet profile and 2) copying files or extracting them from an archive (zip).

MSP is available in Mudlet 4.4+

Receiving MSP Data

Processing of MSP is enabled by default on new game profiles. Control whether the processing is on or off through the Settings menu in Mudlet.

MSP over OOB

Game administrators may send sound and music triggers over the out-of-bounds (hidden) telnet channel encoded with TELOPT 90 after performing telnet negotiation with Mudlet. The advantage to this is that all of the communication is behind the scenes with no additional trigger requirements for the player (see MSP over Lua). Games will send the bytes of out-of-band messages to Mudlet in a format like this:

IAC SB TELOPT_MSP !!SOUND(cow.wav L=2 V=100) IAC SE

Note Note: Game admins: This option does require a TELOPT 90 WILL message.

MSP for Lua

Check for MSP support with your game and enable any options that allow sound and music triggers to be sent to your screen.

You can download the package from Media:MSP.zip or follow the instructions below.

Create a sound trigger to invoke the Lua interpreter:

Name Text Type Script
Sound Trigger ^!!SOUND\((\S+?)(?: (.+))?\)$ perl regex

Create a music trigger to invoke the Lua interpreter:

Name Text Type Script
Music Trigger ^!!MUSIC\((\S+?)(?: (.+))?\)$ perl regex

Note Note: Game admins: Best practice is to implement a TELOPT 90 WILL message as a signal to the client that MSP is supported. This is not required.

If your game does not negotiate MSP, you can download Media:MSP-Alternate.zip or you can use this script in your trigger instead of receiveMSP for MSP Sound:

deleteLine()
local mspFile = nil
local mspVolume = 100
local mspLength = 1
local mspPriority = 50
local mspType = nil
local mspURL = nil
-- Strip !!SOUND() from the line
local line = matches[1]:sub(9, -2)
-- Break up the line into tokens
local tokens = line:split(" ")
-- Iterate through the tokens to discover MSP values
for index, value in ipairs(tokens) do
  if index == 1 then
    mspFile = value
  elseif value:find("V=", 1, true) == 1 or value:find("v=", 1, true) == 1 then
    mspVolume = tonumber(value:sub(3))
  elseif value:find("L=", 1, true) == 1 or value:find("l=", 1, true) == 1 then
    mspLength = tonumber(value:sub(3))
  elseif value:find("P=", 1, true) == 1 or value:find("p=", 1, true) == 1 then
    mspPriority = tonumber(value:sub(3))
  elseif value:find("T=", 1, true) == 1 or value:find("t=", 1, true) == 1 then
    mspType = value:sub(3)
  elseif value:find("U=", 1, true) == 1 or value:find("u=", 1, true) == 1 then
    mspURL = value:sub(3)
  end
end
if mspFile == "Off" and mspURL == nil then
  stopSounds()
else
  playSoundFile(
    {
      name = mspFile,
      volume = mspVolume,
      loops = mspLength,
      priority = mspPriority,
      tag = mspType,
      url = mspURL,
    }
  )
end

If your game does not negotiate MSP, you can use this script in your trigger instead of receiveMSP for MSP Music:

deleteLine()
local mspFile = nil
local mspVolume = 100
local mspLength = 1
local mspContinue = true
local mspType = nil
local mspURL = nil
-- Strip !!MUSIC() from the line
local line = matches[1]:sub(9, -2)
-- Break up the line into tokens
local tokens = line:split(" ")
-- Iterate through the tokens to discover MSP values
for index, value in ipairs(tokens) do
  if index == 1 then
    mspFile = value
  elseif value:find("V=", 1, true) == 1 or value:find("v=", 1, true) == 1 then
    mspVolume = tonumber(value:sub(3))
  elseif value:find("L=", 1, true) == 1 or value:find("l=", 1, true) == 1 then
    mspLength = tonumber(value:sub(3))
  elseif value:find("C=", 1, true) == 1 or value:find("c=", 1, true) == 1 then
    if tonumber(value:sub(3)) == 0 then
      mspContinue = false
    else
      mspContinue = true
    end
  elseif value:find("T=", 1, true) == 1 or value:find("t=", 1, true) == 1 then
    mspType = value:sub(3)
  elseif value:find("U=", 1, true) == 1 or value:find("u=", 1, true) == 1 then
    mspURL = value:sub(3)
  end
end
if mspFile == "Off" and mspURL == nil then
  stopMusic()
else
  playMusicFile(
    {
      name = mspFile,
      volume = mspVolume,
      loops = mspLength,
      continue = mspContinue,
      tag = mspType,
      url = mspURL,
    }
  )
end

MSP over GMCP

Reference Mudlet's documentation on the MUD Client Media Protocol specification for more information.

Note Note: Game admins: Do not implement a TELOPT 90 WILL message exchange when exclusively using this option.

MSP Troubleshooting

  • Wildcards ? or * within the file name do not trigger automatic sound or music downloads. Ensure the sound was downloaded previously prior to using a wildcard.
  • Mudlet < 4.11 would not play the MSP sound if it had unknown elements, Mudlet 4.12+ will ignore the unknown elements and do the best it can to play the sound.

MSP Specification

For more insight into the syntax of sound and music triggers, please reference the specification.

Sound packs

As most games have been around for a long time, they often use Mud Sound Protocol (MSP) to play sounds. We often find that the game administrators have documented a downloadable soundpack on their website, or that a 3rd party has made one. In Mudlet, a profile is created for each game, and you can manually create a media folder inside of it and drop in the media files (sound, music). For games using MSP, you can create simple triggers to play them which are documented above.

MSSP

Mud Server Status Protocol, or MSSP, provides a way for game crawlers (i.e. MSSP Mud Crawler) and game listing sites (search for Listings here) to gather detailed information about a game, including dynamic information like boot time and the current amount of online players. It also makes submitting a new game entry very simple on game listing sites. A player or administrator is only required to fill in the hostname and port and other information is gathered from behind the scenes.

MSSP in Mudlet

The MSSP data presented in Mudlet will enable MSSP standard data fields to be made accessible for scripting. Some useful fields include the game name, number of players, uptime, game hostname, game port, codebase, admin contact, Discord invite URL, year created, link to an icon, ip address, primary language, game location, website and several others may be available. It is up to the game in question to populate the data, so don't expect all fields to be filled in.

MSSP is available in Mudlet 4.1+.

Receiving MSSP Data

To receive MSSP data in Mudlet, these conditions must be met:

  1. The Enable MSSP box in the Settings window of Mudlet must be checked (default on).
  2. The game must negotiate MSSP with clients like Mudlet at its login screen. Details here.

To see whether your game supports MSSP, after connecting, type lua mssp. If the game does not support MSSP, you will see an empty table mssp = {}. If it does you will see information similar to the example below. The data may be accessed in a similar way to the instructions for GMCP listed above. Typically, MSSP data is only sent once per connection.

mssp = {
  HOSTNAME = "stickmud.com",
  VT100 = "1",
  UPTIME = "1565657220",
  MSDP = "0",
  MCP = "0",
  GMCP = "1",
  PORT = "7680",
  ["MINIMUM AGE"] = "13",
  PUEBLO = "0",
  INTERMUD = "-1",
  SKILLS = "100",
  ["HIRING BUILDERS"] = "0",
  PLAYERS = "6",
  CONTACT = "[email protected]",
  CODEBASE = "LDMud 3.5.0 (3.5.1)",
  ["HIRING CODERS"] = "0",
  ["PAY FOR PERKS"] = "0",
  LOCATION = "Canada",
  GAMESYSTEM = "Custom",
  MCCP = "0",
  SUBGENRE = "Medieval Fantasy",
  ROOMS = "10000",
  STATUS = "Live",
  FAMILY = "LPMud",
  LEVELS = "150",
  CREATED = "1991",
  ["PAY TO PLAY"] = "0",
  IP = "24.138.28.11",
  MOBILES = "-1",
  GAMEPLAY = "Hack and Slash",
  CLASSES = "8",
  NAME = "StickMUD",
  SSL = "7670", -- legacy key, use TLS now please!
  TLS = "7670",
  ANSI = "1",
  ICON = "https://www.stickmud.com/favicon.ico",
  RACES = "12",
  UTF-8 = "0",
  AREAS = "-1",
  MXP = "0",
  HELPFILES = "-1",
  ["XTERM 256 COLORS"] = "0",
  MSP = "1",
  OBJECTS = "9780",
  WEBSITE = "https://www.stickmud.com",
  GENRE = "Fantasy",
  DISCORD = "https://discord.gg/erBBxt",
  LANGUAGE = "English"
}

MTTS

MUD servers frequently seek information about the capabilities of a MUD Client. Despite the availability of various methods, achieving consistency and reliability in this endeavor has proven challenging. The Mud Terminal Type Standard (MTTS) aims to alleviate these issues by introducing a transparent and straightforward standard for MUD Clients to communicate their terminal capabilities. This standard builds upon and formalizes RFC 1091, which outlines the Telnet Terminal-Type Option.

MTTS in Mudlet

By incorporating the Mud Terminal-Type Standard (MTTS), Mudlet will communicate with interested servers that it possesses the following capabilities:

  • Support for ANSI Color Codes: The client supports all common ANSI color codes.
  • UTF-8 Character Encoding: The client utilizes UTF-8 character encoding.
  • Support for 256 Color Codes: Mudlet is equipped to handle all 256 color codes.
  • OSC Color Palette: Mudlet acknowledges support for the OSC color palette.
  • Screen Reader Support: Mudlet offers support for screen readers, with opt-in functionality (not advertised by default).
  • Truecolor Codes: Mudlet supports truecolor codes using semicolon notation.
  • Mud New Environment Standard (MNES) Support: The client adheres to the Mud New Environment Standard for information exchange.
  • TLS Encryption: The client supports Transport Layer Security for data encryption.

Screen Reader Opt-In

Users can find on the Accessibility tab under the Settings menu a checkbox identified as "Advertise screen reader use via protocols supporting this notice" which when checked will notify interested game servers. This information may be used to optimize the gaming experience.

Image displaying the Advertise screen reader checkbox

Available MTTS Information

Through a Telnet TERMINAL-TYPE Option negotiation, Mudlet transfers a bitvector to game servers, (i.e., 2349) for processing. A bitvector, also known as a bitmap, is a data structure that represents a fixed-size sequence of binary digits or bits. In a bitvector, each bit corresponds to a specific position or index in the sequence, and its value can be either 0 or 1. The MTTS bitvector represents is a set of flags and boolean values, where each bit can represent the state of a particular boolean condition or flag. For example, if the third bit is set to 1, it indicates that the client is using UTF-8 character encoding. A 0 indicator would indicate that UTF-8 was not supported.

MTTS Bitvector
Bit Property Meaning
1 ANSI Client supports all common ANSI color codes.
2 VT100 Client supports all common VT100 codes.
4 UTF-8 Client is using UTF-8 character encoding.
8 256 COLORS Client supports all 256 color codes.
16 MOUSE TRACKING Client supports xterm mouse tracking.
32 OSC COLOR PALETTE Client supports OSC and the OSC color palette.
64 SCREEN READER Client is using a screen reader.
128 PROXY Client is a proxy allowing different users to connect from the same IP address.
256 TRUECOLOR Client supports truecolor codes using semicolon notation.
512 MNES Client supports the Mud New Environment Standard for information exchange.
1024 MSLP Client supports the Mud Server Link Protocol for clickable link handling.
2048 TLS Client supports Transport Layer Security for data encryption.

Negotiating MTTS

Per the MTTS guidance, game servers should initiate up to 4 TTYPE requests to complete the TTYPE cycling routine within a given connection. If the connection is reset, negotiate TTYPE again. Reference the MTTS website for more information.

Server Mudlet
IAC DO TTYPE (24) IAC SE IAC WILL TTYPE (24) IAC SE
IAC SB TTYPE (24) SEND (1) IAC SE IAC SB TTYPE (24) IS (0) MUDLET IAC SE
IAC SB TTYPE (24) SEND (1) IAC SE IAC SB TTYPE (24) IS (0) ANSI-TRUECOLOR IAC SE
IAC SB TTYPE (24) SEND (1) IAC SE IAC SB TTYPE (24) IS (0) MTTS 2349 IAC SE
IAC SB TTYPE (24) SEND (1) IAC SE IAC SB TTYPE (24) IS (0) MTTS 2349 IAC SE

If a Mudlet user does not want to enable Mud Terminal Type Standard, they may choose the Settings, General menu item in Mudlet and toggle off the "Enable MTTS" checkbox.

MTTS is available in Mudlet 4.18+.

MXP

MXP is based loosely on the HTML and XML standards supported by modern web browsers. It is only "loosely" based upon these standards because games require dynamic, streaming text, rather than the page-oriented view of web browsers. Also, the existing standards are needlessly verbose for use on a game where text efficiency is important.

In addition, there are additional security concerns to worry about with MXP. While support for HTML tags within a line is desired, players on a game can exploit this power and cause problems. Certain HTML functions need to be restricted so that players cannot abuse them. For example, while it might be desirable to allow players to change the font or color of their chat messages, you would not want to allow them to display a large graphics image, or execute script commands on the client of other users. MXP handles this by grouping the various tags and commands into secure and open categories, and preventing the secure tags from being used by players.

Mudlet implements a subset of MXP features - the most popular ones that are actually in use. Mudlet supports MXP links (including send to prompt and open in browser in Mudlet 3.17+), pop-up menus, creation of custom elements, and line modes. As a game admin, you can ask what features are supported with the <SUPPORT> command.

MXP in Mudlet

Just like GMCP, MXP data is available in the mxp. namespace and events are raised. To see all MXP events, turn on Debug mode.

MXP data.png

function testmxpsend()
  print("Text for the link is: ".. mxp.send.href)
  print("Commands to do are: ")
  display(mxp.send.actions)
  print("\n")
end

registerAnonymousEventHandler("mxp.send", "testmxpsend")

Note Note: Available in Mudlet 4.8+

Since Mudlet 4.20+ you can also display a different text to the player with the mxp.send.text variable.

e.g. in a shop you might like a click to purchase interface

mxp.send = {
actions = { "send([[buy apple]])" },
href = "buy apple", -- command sent when clicked
text = "a big apple", -- text shown to the player
}

Receiving MXP Data

shows how MXP can be used to BUY an item at a shop, then within the inventory they can select what to do with their items. i.e. Drop, Eat, Wear, Drink...
MXP example in Mudlet

Processing of MXP is enabled by default on new game profiles. Control whether the processing is on or off through the Settings menu in Mudlet.

Simple example of receiving MXP Data (Server owners)

<SEND href=\"&text;\">  go north...  </SEND>"

This creates a clickable link that will enable the player to navigate without typing the directions into Mudlet. MXP sends the data immediately when clicked.

Advanced example of receiving MXP Data (Server owners)

<send href='examine &#34;&name;&#34;|get &#34;&name;&#34;' hint='Right mouse click to act on this item|Get &desc;|Examine &desc;|Look in &desc;' expire=get>\" ATT='name desc'>

This creates a clickable link that will 'examine' an item. It also enables a right-click function wherein the player can select to either examine or get the item (in this case &name; is the item and &desc; is the item's description ).

MXP Specification

MXP was originally developed and supported by the Zuggsoft team. For more insight into the syntax, reference the specification or the PDF here. Mudlet has a partial implementation version 1.0 of the MXP spec - to see what is supported, ask Mudlet with the <SUPPORT> tag.

NEW-ENVIRON

To enhance the player experience through sharing more client-supported details, the Telnet New-Environ Option may be used to transfer client environment variables from Mudlet to game servers. Sharing supporting information on information such as encoding, terminal emulation, and accessibility options aims to improve initial player setup and increase the retention rate for new gaming community members.

NEW-ENVIRON in Mudlet

Mudlet supports two methods of information exchange via NEW-ENVIRON, the first via RFC 1572: Telnet New-Environ Option (on by default), and the second is MNES: Mud New-Environ Standard (off by default), which shares a standardized set of client information across multiple clients.

Client Environment Variable Updates

Mudlet provides a user-friendly interface for managing environmental variables through its Settings menu. For certain environmental variables, manual selections made in the Settings menus can dynamically notify servers that have expressed interest in the client's environmental variables through the negotiation of the NEW-ENVIRON option. For instance, when a Mudlet user updates the data encoding for a server profile by navigating to Settings, General, and choosing a specific data encoding from the drop-down menu, this information becomes available for transmission via both the RFC (default) and MNES (requires user enabling) options.

Screen Reader Opt-In

Users can find on the Accessibility tab under the Settings menu a checkbox identified as "Advertise screen reader use via protocols supporting this notice" which when checked will notify interested game servers. This information may be used to optimize the gaming experience.

Image displaying the Advertise screen reader checkbox

Available Client Environment Variables RFC 1572

Two types of variables are used per RFC 152, well-known variables defined with VAR (0) and for less common variables, USERVAR (3). Currently, per the RFC, Mudlet shares its variables via the USERVAR (3) type.

Some client variables updates may be reported ad-hoc with an INFO (2) message. If there is no value for a defined variable, a VAL (1) will be sent without a value following it.

Type Variable Example Values Mudlet Default OPT-IN INFO Purpose Available
USERVAR 256_COLORS 1, 0 1 Client supports all 256 color codes. 1 = Yes/True/ACK. 4.18
USERVAR ANSI 1, 0 1 Client supports all common ANSI color codes. 1 = Yes/True/ACK. 4.18
USERVAR BOLD_IS_BRIGHT 2, 1, 0 Yes Use bright colors always (2), sometimes (1), or never (0). future
USERVAR CHARSET UTF-8, ASCII Yes Encoding set in the client 4.18
USERVAR CLIENT_NAME MUDLET MUDLET Name of the client. 4.18
USERVAR CLIENT_VERSION 4/18, 4/17/2-DEV Version of the client. 4.18
USERVAR MTTS 2349 Yes Bitvector defined in the Mud Terminal Type Standard (MTTS). 4.18
USERVAR OSC_COLOR_PALETTE 1, 0 Client supports OSC and the OSC color palette. 1 = Yes/True/ACK. 4.18
USERVAR OSC_HYPERLINKS 1, 0 1 Client supports OSC 8 hyperlinks per the standard specification with Mudlet extensions for enhanced styling and interactivity. 1 = Yes/True/ACK. 4.20
USERVAR OSC_HYPERLINKS_COMPACT 1, 0 1 Client supports compact/shorthand JSON syntax for OSC 8 hyperlink configuration (e.g., s for style, c for color). 1 = Yes/True/ACK. 4.21
USERVAR OSC_HYPERLINKS_DISABLED 1, 0 1 Client supports the disabled parameter to create non-interactive hyperlinks that block clicks and context menus while preserving tooltips. 1 = Yes/True/ACK. 4.21
USERVAR OSC_HYPERLINKS_MENU 1, 0 1 Client supports the menu parameter for interactive right-click context menus on OSC 8 hyperlinks. 1 = Yes/True/ACK. 4.20
USERVAR OSC_HYPERLINKS_PRESETS 1, 0 1 Client supports the preset: URI scheme for defining reusable styling configurations that can be referenced by name. 1 = Yes/True/ACK. 4.21
USERVAR OSC_HYPERLINKS_PROMPT 1, 0 1 Client supports the prompt: URI scheme for pre-filling the command line. 1 = Yes/True/ACK. 4.20
USERVAR OSC_HYPERLINKS_SELECTION 1, 0 1 Client supports the selection parameter for stateful toggle behavior with radio-button (exclusive) and checkbox (multi-select) group support, including the :selected pseudo-class. 1 = Yes/True/ACK. 4.21
USERVAR OSC_HYPERLINKS_SEND 1, 0 1 Client supports the send: URI scheme for immediately executing commands. 1 = Yes/True/ACK. 4.20
USERVAR OSC_HYPERLINKS_SPOILER 1, 0 1 Client supports the spoiler parameter for click-to-reveal hidden content with redacted display until interaction. 1 = Yes/True/ACK. 4.21
USERVAR OSC_HYPERLINKS_STYLE_BASIC 1, 0 1 Client supports basic styling for OSC 8 hyperlinks including colors (foreground, background), text formatting (bold, italic), and simple text decorations (underline, strikeout, overline). 1 = Yes/True/ACK. 4.20
USERVAR OSC_HYPERLINKS_STYLE_STATES 1, 0 1 Client supports interactive pseudo-class states for OSC 8 hyperlinks (:hover, :active, :visited, :focus, :focus-visible, :link, :any-link, :selected, :disabled) with state-specific styling and accessibility enhancements. 1 = Yes/True/ACK. 4.21
USERVAR OSC_HYPERLINKS_TOOLTIP 1, 0 1 Client supports the tooltip parameter for displaying contextual help text when hovering over OSC 8 hyperlinks. 1 = Yes/True/ACK. 4.20
USERVAR OSC_HYPERLINKS_VISIBILITY 1, 0 1 Client supports the visibility parameter for automatic hide/reveal behavior including timed concealment, expiration triggers, and delayed reveal. 1 = Yes/True/ACK. 4.21
USERVAR SCREEN_READER 1, 0 0 Yes Yes Client is using a screen reader. 1 = Yes/True/ACK. 4.18
USERVAR TERMINAL_TYPE ANSI-TRUECOLOR, ANSI-256COLOR, ANSI, XTERM, VT100, DUMB ANSI-TRUECOLOR Terminal type of the client 4.18
USERVAR TLS 1, 0 Client supports Transport Layer Security for data encryption. 1 = Yes/True/ACK. 4.18
USERVAR TRUECOLOR 1, 0 Client supports truecolor codes using semicolon notation. 1 = Yes/True/ACK. 4.18
USERVAR UTF-8 1, 0 Yes Client is using UTF-8 character encoding. 1 = Yes/True/ACK. 4.18
USERVAR VT100 1, 0 0 Client supports all common VT100 codes. 1 = Yes/True/ACK. This is not applicable for Mudlet and while defined, is not used. 4.18
USERVAR WORD_WRAP 100 Yes Client wraps text at this value 4.18

Negotiating NEW-ENVIRON

Negotiating the NEW-ENVIRON Telnet option empowers game servers to request one, multiple, or all client environment variables configured within Mudlet. The process unfolds with the game server sending a Telopt DO NEW-ENVIRON (39), prompting Mudlet to respond with a WILL NEW-ENVIRON (39). Subsequently, the game server can send SB NEW-ENVIRON (39) SEND to receive all available environment variables. Mudlet responds with SB NEW-ENVIRON (39) IS (0) < VAR (0) | USERVAR (3) > "<variable>" [VAL (1)] ["<value>"] [ .. [ VAR (0) | USERVAR (3) ] "<variable>" VAL (1) "<value>"] containing the list of environmental variables.

Once an environmental variable is transmitted to a server within the ongoing connection, Mudlet replies with SB NEW-ENVIRON (39) INFO (2) < VAR (0) | USERVAR (3) > "<variable>" [VAL (1)] ["<value>"] messages for select variables. Importantly, no reply from the server is required in this context. If there is a need to specify a particular list of requested environmental variables to Mudlet, the format SB NEW-ENVIRON (39) SEND < VAR (0) | USERVAR (3) > "<variable>" [ .. < VAR (0) | USERVAR (3) > "<variable>" ] can be employed.

Success example #1 (one environmental variable):

Server Mudlet
IAC DO NEW-ENVIRON (39) IAC SE IAC WILL NEW-ENVIRON (39) IAC SE
IAC SB NEW-ENVIRON (39) SEND (1) USERVAR (3) CHARSET IAC SE IAC SB NEW-ENVIRON (39) IS (0) USERVAR (3) CHARSET VAL (1) UTF-8 IAC SE

Success example #2 (all environmental variables):

Server Mudlet
IAC DO NEW-ENVIRON (39) IAC SE IAC WILL NEW-ENVIRON (39) IAC SE
IAC SB NEW-ENVIRON (39) SEND (1) IAC SE IAC SB NEW-ENVIRON (39) IS (0) USERVAR (3) 256_COLORS VAL (1) 1 USERVAR (3) ANSI VAL (1) 1 USERVAR (3) CHARSET VAL (1) UTF-8 USERVAR (3) CLIENT_NAME VAL (1) MUDLET USERVAR (3) CLIENT_VERSION VAL (1) 4/17/2-DEV USERVAR (3) USERVAR (3) MTTS VAL (1) 2349 USERVAR (3) OSC_COLOR_PALETTE VAL (1) 1 USERVAR (3) SCREEN_READER VAL (1) USERVAR (3) TERMINAL_TYPE VAL (1) ANSI-TRUECOLOR USERVAR (3) TLS VAL (1) 1 USERVAR (3) TRUECOLOR VAL (1) 1 USERVAR (3) UTF-8 VAL (1) 1 USERVAR (3) VT100 VAL (1) 0 USERVAR (3) WORD_WRAP VAL (1) 100 IAC SE
[ As updates occur in the client the following are possible... ]
IAC SB NEW-ENVIRON (39) INFO (2) USERVAR (3) CHARSET VAL (1) UTF-8 IAC SE

IAC SB NEW-ENVIRON (39) INFO (2) USERVAR (3) MTTS VAL (1) 2349 IAC SE

IAC SB NEW-ENVIRON (39) INFO (2) USERVAR (3) SCREEN_READER VAL (1) IAC SE

IAC SB NEW-ENVIRON (39) INFO (2) USERVAR (3) UTF-8 VAL (1) 1 IAC SE

IAC SB NEW-ENVIRON (39) INFO (2) USERVAR (3) WORD_WRAP VAL (1) 100 IAC SE

If a Mudlet user does not want to negotiate environmental variables, they may choose the Settings, Special Options menu item in Mudlet and enable "Force NEW_ENVIRON negotiation off". The following is an example of an attempted negotiation where "Force NEW-ENVIRON negotiation off" is enabled.

Server Mudlet
IAC DO NEW-ENVIRON (39) IAC SE IAC WONT NEW-ENVIRON (39) IAC SE

NEW-ENVIRON negotiation is available in Mudlet 4.18+.

MNES

The Mud New-Environment Standard is an alternative way to share client-supported details between Mudlet to game servers. MNES is a variant of NEW-ENVIRON, not based on the RFC.

Activating MNES

If your game supports MNES, instruct users to toggle on the `Enable MNES` menu option on the General tab in Mudlet.

Enable MNES is found on the Game protocols section of the General tab of Settings 

Mud New-Environ Standard Client Environment Variables MNES

MNES leverages VAR (0) to transfer up to five client environment variables. Some client variables updates may be reported ad-hoc with an INFO message. If there is no value for a defined variable, a VAL (1) will be sent without a value following it.

Type Variable Example Values Mudlet Default INFO Purpose
VAR CHARSET UTF-8, ASCII Yes Encoding set in the client
VAR CLIENT_NAME MUDLET MUDLET Name of the client.
VAR CLIENT_VERSION 4/18, 4/17/2-DEV Version of the client.
VAR MTTS 2349 Yes Bitvector defined in the Mud Terminal Type Standard (MTTS).
VAR TERMINAL_TYPE ANSI-TRUECOLOR, ANSI-256COLOR, ANSI, XTERM, VT100, DUMB ANSI-TRUECOLOR Terminal type of the client

Negotiating MNES

The primary differences between MNES and the out-of-the-box RFC 152 NEW-ENVIRON implementation is that MNES sends no more than 5 client environment variables ("IPADDRESS" will not be implemented in Mudlet), it uses a VAR (0) for the SEND (1), IS (0), and INFO (2) messages, and returns a multiple client variable response in multiple IS (0) messages.

Server Mudlet
IAC DO NEW-ENVIRON (39) IAC SE IAC WILL NEW-ENVIRON (39) IAC SE
IAC SB NEW-ENVIRON (39) SEND IAC SE IAC SB NEW-ENVIRON (39) IS (0) VAR (0) CHARSET VAL (1) UTF-8 IAC SE

IAC SB NEW-ENVIRON (39) IS (0) VAR (0) CLIENT_NAME VAL (1) MUDLET IAC SE

IAC SB NEW-ENVIRON (39) IS (0) VAR (0) CLIENT_VERSION VAL (1) 4/17/2-DEV IAC SE

IAC SB NEW-ENVIRON (39) IS (0) VAR (0) MTTS VAL (1) 2349 IAC SE

IAC SB NEW-ENVIRON (39) IS (0) VAR (0) TERMINAL_TYPE VAL (1) ANSI-TRUECOLOR IAC SE

[ As updates occur in the client the following are possible... ]
IAC SB NEW-ENVIRON (39) INFO (2) VAR (0) CHARSET VAL (1) ASCII IAC SE

IAC SB NEW-ENVIRON (39) INFO (2) VAR (0) MTTS VAL (1) 2345 IAC SE

MNES negotiation is available in Mudlet 4.18+.

NAWS

The NAWS (Negotiate About Window Size) protocol allows the client to inform the server of the current dimensions of the terminal window. This is useful for servers to adjust their output formatting dynamically based on the client's terminal size.

Activation

NAWS is automatically negotiated during the Telnet session if the server supports it. Mudlet will respond to the server's DO NAWS request with WILL NAWS and send the current terminal dimensions.

Negotiation

When NAWS is enabled, Mudlet sends the terminal dimensions (width and height) to the server using the following format:

IAC SB NAWS <width high byte> <width low byte> <height high byte> <height low byte> IAC SE
  • Width: The width of the terminal in characters, sent as two bytes (high byte first).
  • Height: The height of the terminal in characters, sent as two bytes (high byte first).
  • IAC: Interpret As Command (0xFF).
  • SB: Subnegotiation Begin (0xFA).
  • SE: Subnegotiation End (0xF0).

Example

If the terminal size is 80x24, Mudlet will send the following sequence:

IAC SB NAWS 0x00 0x50 0x00 0x18 IAC SE
  • 0x00 0x50 represents the width (80 in decimal).
  • 0x00 0x18 represents the height (24 in decimal).

Implementation in Mudlet

Mudlet calculates the terminal dimensions dynamically and sends updates when the window size changes.

Notes

  • NAWS is supported by most modern MUD servers.
  • Mudlet ensures compliance with the Telnet protocol by doubling any IAC bytes in the width or height values to avoid confusion with actual Telnet commands.

Troubleshooting

If NAWS does not appear to work:

  1. Ensure the server supports NAWS and requests it during the Telnet negotiation.
  2. Verify that the terminal dimensions are correctly set in Mudlet.
  3. Check for any network issues that might interfere with Telnet sub-negotiations.

References

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 MXP.

Mudlet VersionAvailable in Mudlet4.20+

Quick Start

Want to try OSC 8 hyperlinks immediately? Send this command in Mudlet:

say !osc8-docs


OSC 8 Hyperlinks.png

Feature Overview

Feature Description Version
Basic Links Send commands, pre-fill input, open URLs
Mudlet VersionAvailable in Mudlet4.20+
Visual Styling Colors, fonts, decorations
Mudlet VersionAvailable in Mudlet4.20+
Interactive States Hover, active, visited effects
Mudlet VersionAvailable in Mudlet4.20+
Tooltips Custom hover text
Mudlet VersionAvailable in Mudlet4.20+
Context Menus Right-click menus
Mudlet VersionAvailable in Mudlet4.20+
Visibility Auto-hide/reveal links
Mudlet VersionAvailable in Mudlet4.21+
Spoilers Click-to-reveal hidden text
Mudlet VersionAvailable in Mudlet4.21+
Disabled Links Non-clickable display links
Mudlet VersionAvailable in Mudlet4.21+
Selection Stateful toggle links
Mudlet VersionAvailable in Mudlet4.21+
Accessibility Keyboard navigation, screen reader support
Mudlet VersionAvailable in Mudlet4.21+
Compact Syntax Shorthand property names
Mudlet VersionAvailable in Mudlet4.21+
Presets Reusable style templates
Mudlet VersionAvailable in Mudlet4.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
  1. Server sends an escape sequence starting with ESC ] (escape + right bracket)
  2. The sequence contains command data (like a URL)
  3. The sequence ends with a String Terminator: ESC \ (escape + backslash)
  4. The terminal processes the command and renders the result
Key Characters
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: "Note: Mudlet requires proper termination with either ST (ESC ) Mudlet 4.20 or BEL (0x07) Mudlet 4.20+. Missing terminators cause text to buffer without displaying (with a 4096-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.

Mudlet VersionAvailable in Mudlet4.20+
How It Works

OSC 8 hyperlinks work like HTML tags with opening and closing sequences:

  1. Opening sequence defines the link target: ESC ] 8 ; ; URI ESC \
  2. Link text appears between sequences (can include ANSI formatting)
  3. Closing sequence ends the clickable region: ESC ] 8 ; ; ESC \
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
Scheme Action Example Capability Variable
send: Immediately sends command to game send:look OSC_HYPERLINKS_SEND
prompt: Places command in input line for editing prompt:cast fireball OSC_HYPERLINKS_PROMPT
http: / https: Opens in default web browser https://mudlet.org OSC_HYPERLINKS
ftp: Opens in default handler ftp://files.example.com 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 RFC 3986.

How It Works
  1. Special characters are replaced with %XX where XX is the hex value
  2. The entire JSON config object must be encoded
  3. Spaces in commands use %20
Common Encodings
Character Encoded When to Encode
Space %20 In commands: cast%20fireball
" %22 In JSON strings
{ %7B JSON object start
} %7D JSON object end
: %3A JSON key-value separator
, %2C JSON element separator
& %26 In web URL query strings
# %23 In web URL fragments
What to Encode

Always encode:

  • The entire JSON object in the config parameter
  • Spaces in command URIs

Never encode:

  • URI scheme (send:, https://)
  • Parameter structure (?, =, & in URL structure)
Example

Human-readable:

{"style": {"color": "red"}}

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: encodeURIComponent()
  • Python: urllib.parse.quote()
  • Lua: socket.url.escape() 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.

Mudlet VersionAvailable in Mudlet4.20+
How It Works
  1. Append ?config= to your URI
  2. Follow with percent-encoded JSON
  3. Mudlet parses the JSON and applies styling/behavior
Structure
SCHEME:COMMAND?config=PERCENT_ENCODED_JSON
Configuration Object
{
  "style": { },      // Visual appearance
  "tooltip": "",     // Hover text
  "menu": [ ],       // Right-click options
  "title": "",       // Menu header (string or {text, style})
  "visibility": { }, // Auto-hide/reveal
  "selection": { },  // Toggle state
  "spoiler": false,  // Hidden text
  "disabled": false  // Non-clickable
}

Style Properties

Purpose

Control the visual appearance of hyperlink text including colors, fonts, and decorations.

Properties
Property Type Description Example Values
color String Text foreground color "red", "#ff0000", "rgb(255,0,0)"
bg String Background color "blue", "#000080"
bold Boolean Bold weight true, false
italic Boolean Italic style true, false
underline Boolean/String Underline style true, "wavy", "dotted", "dashed"
overline Boolean/String Overline style true, "wavy", "dotted", "dashed"
strikethrough Boolean/String Strikethrough style true, "wavy", "dotted", "dashed"
text-decoration-color String Color for underline/overline/strikethrough "red", "#ff0000"

Note Note: OSC 8 links are not underlined by default (unlike traditional hyperlinks). Add "underline": true 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:

{"style": {"color": "red", "bold": true}}

Blue background with white text:

{"style": {"color": "white", "bg": "blue"}}

Wavy green underline:

{"style": {"underline": "wavy", "text-decoration-color": "green"}}
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.

Mudlet VersionAvailable in Mudlet4.20+
How It Works
  1. Define base style properties at the top level of style
  2. Add state-specific overrides as nested objects
  3. When a state activates, its properties override the base
  4. Multiple states can be active; higher priority wins
Available States
State Trigger Priority Use Case
active Mouse button pressed 1 (highest) Click feedback
hover Mouse cursor over link 2 Highlight on mouseover
focus-visible Keyboard focus indicator 3 Accessibility
focus Any focus (keyboard/mouse) 4 Focus ring
visited Link clicked previously 5 Show history
selected Selection state active 6 Toggle indicators
disabled Link is disabled 7 Unavailable options
link Unvisited link 8 Distinct unvisited style
any-link Always applies 9 (lowest) Universal styling

Note Note: The visited state resets when Mudlet restarts (session-scoped).

Examples

Hover color change:

{
  "style": {
    "color": "blue",
    "hover": {"color": "red"}
  }
}

Button-like press effect:

{
  "style": {
    "bg": "green",
    "color": "white",
    "hover": {"bg": "lightgreen"},
    "active": {"bg": "darkgreen"}
  }
}

Link vs visited states:

{
  "style": {
    "link": {"color": "blue", "underline": true},
    "visited": {"color": "purple", "strikethrough": true}
  }
}
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.

Mudlet VersionAvailable in Mudlet4.20+
How It Works
  1. Add "tooltip" property to JSON configuration
  2. Text appears when user hovers over the link
  3. Replaces default system tooltip
Configuration
Property Type Description Default
tooltip String Custom hover text Auto-generated based on link type
Examples

Simple tooltip:

{"tooltip": "Click to attack the enemy"}

Tooltip with styling:

{
  "style": {"color": "red", "bold": true},
  "tooltip": "Warning: This action cannot be undone!"
}
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.

Mudlet VersionAvailable in Mudlet4.20+

How It Works
  1. Left-click executes the primary URI action
  2. Right-click displays the context menu
  3. Each menu item can have its own command
  4. Use "-" to create visual separators
Configuration
Property Type Description
menu Array Array of menu items
title String/Object Non-clickable header label above menu items

MenuTitle.png

Menu item format:

{"Label Text": "scheme:command"}

Separator:

"-"

Title (simple):

{"title": "Lamb and Barley Stew", "menu": [...]}
Mudlet VersionAvailable in Mudlet4.21+

Title with styling:

{
  "title": {
    "text": "Lamb and Barley Stew",
    "style": {"color": "#5fbdaf", "bold": true}
  },
  "menu": [...]
}
Mudlet VersionAvailable in Mudlet4.21+

Note Note: For Mudlet, title defaults to teal (#5fbdaf) when no style is specified. title has no effect if menu is not configured.

Examples

Basic combat menu:

{
  "menu": [
    {"Attack": "send:attack"},
    {"Defend": "send:defend"},
    "-",
    {"Flee": "send:flee"}
  ]
}

Menu with tooltip:

{
  "menu": [
    {"Fireball": "send:cast fireball"},
    {"Ice Bolt": "send:cast ice bolt"},
    "-",
    {"Heal": "send:cast heal"}
  ],
  "tooltip": "Right-click for spell options"
}

Note Note: Links with menus automatically show "Right-click for menu" tooltip if no custom tooltip is provided.

Screenshot 2025-10-17 at 7.48.38 AM.png

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.

Mudlet VersionAvailable in Mudlet4.21+

How It Works

Conceal action:

  1. Link appears normally when printed
  2. User clicks the link (starts delay timer if set) OR expire trigger fires
  3. After delay/trigger, link text is replaced with spaces

Reveal action:

  1. Link text replaced with spaces when printed (starts hidden)
  2. Delay timer starts immediately OR expire trigger fires
  3. Link text becomes visible

Reveal-then-conceal:

  1. Link starts hidden
  2. Reveals via delay or expire trigger
  3. After revealed, clicking hides it
Configuration
Property Type Description Default
action String/Array Required. "conceal", "reveal", or ["reveal", "conceal"]
delay Number Milliseconds before action (1000 = 1 second)
expire Object Triggers that immediately perform the action
wholeline Boolean Conceal entire line, not just link text (primarily for deletion) false

Expire triggers:

Property Type Description Default
input Boolean Trigger when user sends any command false
prompt Boolean Trigger on GA/EOR prompt from server false
output Boolean Trigger when new output arrives after idle gap false
outputDelay Number Milliseconds of silence defining idle gap 500
Examples

Click to dismiss after delay:

{"visibility": {"action": "conceal", "delay": 500}}

Hide on next server prompt:

{"visibility": {"action": "conceal", "expire": {"prompt": true}}}

Hide when user sends a command:

{"visibility": {"action": "conceal", "expire": {"input": true}}}

Delayed hint (reveal after 5 seconds):

{"visibility": {"action": "reveal", "delay": 5000}}

Appear then click to dismiss:

{"visibility": {"action": ["reveal", "conceal"], "delay": 3000}}

Delete entire line on click:

{"visibility": {"action": "conceal", "delay": 0, "wholeline": true}}

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.

Mudlet VersionAvailable in Mudlet4.21+

How It Works
  1. Link appears with background color matching text (invisible)
  2. Automatic "Click to reveal" tooltip guides the user
  3. First click reveals the hidden text
  4. Subsequent clicks execute the link function (unless disabled)
  5. Tooltip clears after reveal
Configuration
Property Type Description Default
spoiler Boolean Enable spoiler behavior false
disabled Boolean Prevent function execution after reveal false
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

Luminance Background Generation
< 0.1 (very dark) Fixed rgb(40, 40, 40)
< 0.5 (dark) Original background lightened 140%
≥ 0.5 (light) Original background darkened 140%
Examples

Basic spoiler:

{"spoiler": true}

Reveal-only spoiler (no function execution):

{"spoiler": true, "disabled": true}

Spoiler with custom revealed styling:

{
  "spoiler": true,
  "style": {"color": "yellow", "italic": true}
}

Spoiler with menu:

{
  "spoiler": true,
  "menu": [
    {"Show Again": "send:hint"},
    {"Disable Hints": "send:hints off"}
  ]
}
Spoilers vs Visibility
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.

Mudlet VersionAvailable in Mudlet4.21+
How It Works
  1. Link displays with optional disabled styling
  2. Left-click does nothing (no function execution)
  3. Right-click menus are blocked (completely non-interactive)
  4. Can combine with spoilers for reveal-only behavior

Note Note: Disabled state is permanent. To re-enable, the server must send a new link.

Configuration
Property Type Description Default
disabled Boolean Prevent link function execution false
Styling

Use the disabled pseudo-class for visual feedback:

{
  "disabled": true,
  "style": {
    "color": "gray",
    "disabled": {
      "color": "darkgray",
      "strikethrough": true
    }
  }
}
Examples

Basic disabled link:

{"disabled": true}

Disabled with menu defined (menu blocked):

{
  "disabled": true,
  "menu": [
    {"Why locked?": "send:help locked"},
    {"Requirements": "send:requirements"}
  ],
  "tooltip": "Requires level 10 - menu blocked"
}

Note 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):

{"spoiler": true, "disabled": true}
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.

Mudlet VersionAvailable in Mudlet4.21+

How It Works
  1. Links are organized into named groups
  2. Clicking toggles the selection state
  3. Visual style updates immediately via selected pseudo-class
  4. Server receives callback with &selected=true or &selected=false
  5. In exclusive mode, selecting one deselects others in the group
Selection Modes

Radio Button Mode ("exclusive": true, 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 ("exclusive": false):

  • Multiple links per group can be selected
  • Each toggles independently
  • Use for: reactions, multi-select filters, feature toggles
Configuration
Property Type Description Default
group String Required. Group identifier for related links
value String Required. Unique identifier within group
toggle Boolean Allow deselecting by clicking again true
selected Boolean Initial selection state false
exclusive Boolean Radio (true) vs checkbox (false) mode true
disabled Boolean Prevent selection changes false

Note Note: Selection state is per-console. Different windows maintain independent states.

Server Callback

When clicked, the URI is modified to include selection state:

  • Selecting: send:react?type=like&selected=true
  • Deselecting: send:react?type=like&selected=false
Styling

Use selected and disabled pseudo-classes:

{
  "selection": {"group": "reactions", "value": "like"},
  "style": {
    "color": "gray",
    "selected": {"color": "blue", "bold": true},
    "disabled": {"color": "darkgray", "strikethrough": true},
    "hover": {"color": "lightblue"}
  }
}
Examples

Social reactions (checkbox mode):

{
  "selection": {
    "group": "post_123_reactions",
    "value": "thumbs_up",
    "exclusive": false
  },
  "style": {
    "color": "gray",
    "selected": {"color": "blue", "bold": true}
  }
}

Difficulty selection (radio mode):

{
  "selection": {
    "group": "difficulty",
    "value": "hard",
    "exclusive": true
  },
  "style": {
    "bg": "gray",
    "selected": {"bg": "red", "bold": true}
  }
}

Pre-selected option:

{
  "selection": {
    "group": "combat_mode",
    "value": "aggressive",
    "selected": true
  }
}

Non-toggleable (must select different option):

{
  "selection": {
    "group": "thread_following",
    "value": "thread_456",
    "toggle": false
  }
}

Disabled option:

{
  "selection": {
    "group": "poll",
    "value": "sold_out",
    "disabled": true
  },
  "style": {
    "disabled": {"strikethrough": true}
  }
}

link management example

Capability Detection
USERVAR OSC_HYPERLINKS_SELECTION = "1"

Tier 6: Optimization

Accessibility

Purpose

Enable screen reader users and keyboard-only users to discover, navigate, and activate OSC 8 hyperlinks without a mouse.

Mudlet VersionAvailable in Mudlet4.21+
How It Works
  1. Caret mode enables keyboard navigation of game output
  2. Tab / Shift+Tab moves between links (wraps around at buffer boundaries)
  3. Enter or Space activates the focused link
  4. Menu key or Shift+F10 opens context menus
  5. Screen readers announce link tooltip, state, and available actions on focus
What Servers Should Know

Links work with keyboard and screen readers automatically—no extra configuration needed. However, a few authoring choices significantly improve the experience:

Write descriptive tooltips. The tooltip is the first thing a screen reader announces when a user navigates to a link. Without one, the raw command (e.g. send:look) is read aloud instead.

{"tooltip": "Examine the iron gate"}

Use meaningful selection group and value names. Group names are exposed to assistive technology. A group named "combat_stance" is more useful than "g1".

Spoilers are keyboard-safe. The first Enter/Space reveals hidden text; a second press activates the link function. No changes needed.

Disabled and visited states are announced. Screen readers append "disabled", "visited", or "selected" to the link announcement automatically.

Links with menus announce "has menu." Users hear this cue and can press Menu or Shift+F10 to open the context menu at the caret position.

Compact Syntax

Purpose

Reduce JSON size by 30-80% using single-letter property abbreviations. Especially valuable when generating many styled links.

Mudlet VersionAvailable in Mudlet4.21+
How It Works
  1. Replace verbose property names with abbreviations
  2. Mudlet recognizes both forms
  3. Can mix shorthand and full names in same config
  4. No functionality difference—purely size optimization
Shorthand Mappings
Category Full Name Shorthand
Top-level style s
menu m
tooltip t
title ti
visibility v
selection sel
disabled d
spoiler sp
Style color c
bg bg
bold b
italic i
underline u
overline o
strikethrough st
text-decoration-color tdc
Pseudo-class hover h
active a
visited vi
focus f
focus-visible fv
link l
any-link al
selected sl
disabled d

Note: The disabled property appears in two categories:

  • Top-level (d): Controls interactivity. {"d":true} prevents clicks.
  • Pseudo-class (d): Controls appearance. {"s":{"d":{"c":"gray"}}}
Examples

Full syntax (91 characters):

{"style": {"color": "red", "bold": true, "hover": {"color": "yellow"}}}

Shorthand syntax (54 characters):

{"s": {"c": "red", "b": true, "h": {"c": "yellow"}}}

Mixing formats:

{"s": {"c": "red"}, "tooltip": "Full name works too"}
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.

Mudlet VersionAvailable in Mudlet4.21+
How It Works
  1. Define preset at connection time using preset: URI scheme
  2. Reference preset in links with ?preset=NAME
  3. Override preset properties with additional &config=
  4. Presets are session-scoped (cleared on disconnect)
Defining Presets
ESC ] 8 ; ; preset:NAME?config=JSON ESC \ ESC ] 8 ; ; ESC \

Note 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):

Preset Override Result
{"s":{"c":"red","b":true}} {"s":{"c":"blue"}} {"s":{"c":"blue","b":true}}
{"s":{"c":"red"}} {"t":"Tooltip"} {"s":{"c":"red"},"t":"Tooltip"}
Size Comparison
Format Example Encoded Size Reduction
Full JSON {"style":{"color":"red","bold":true}} ~141 chars Baseline
Shorthand {"s":{"c":"red","b":true}} ~88 chars 38%
Preset ?preset=danger ~17 chars 88%

Note 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

{
  "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"}
  ],
  "title": "Header text",      // or {"text": "...", "style": {...}}
  "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
}

Quick Reference: NEW-ENVIRON Variables

Tier Variable Feature
1 OSC_HYPERLINKS Basic protocol support
OSC_HYPERLINKS_SEND send: scheme
OSC_HYPERLINKS_PROMPT prompt: scheme
2 OSC_HYPERLINKS_STYLE_BASIC Colors, bold, italic, decorations
OSC_HYPERLINKS_STYLE_STATES Hover, active, visited states
3 OSC_HYPERLINKS_TOOLTIP Custom tooltips
OSC_HYPERLINKS_MENU Context menus
4 OSC_HYPERLINKS_VISIBILITY Auto-hide/reveal
OSC_HYPERLINKS_SPOILER Spoiler text
OSC_HYPERLINKS_DISABLED Non-clickable links
5 OSC_HYPERLINKS_SELECTION Stateful selection
6 OSC_HYPERLINKS_COMPACT Shorthand syntax
OSC_HYPERLINKS_PRESETS Style presets

Quick Reference: Shorthand Mappings

Full Short Full Short Full Short
style s color c hover h
menu m bg bg active a
tooltip t bold b visited vi
visibility v italic i focus f
selection sel underline u selected sl
spoiler sp strikethrough st disabled d
title ti

Security & Limitations

Trusted URI Schemes

Only these schemes are supported (others are rejected):

  • send:, prompt:
  • http:, https:, ftp:
  • preset: (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:

  • config – JSON configuration for link styling and behavior
  • preset – Named style preset reference
When Parameters Become Reserved

These parameters only need encoding when the client advertises the corresponding capabilities:

Parameter Reserved When Client Advertises
config Any of: OSC_HYPERLINKS_STYLE_BASIC, OSC_HYPERLINKS_STYLE_STATES, OSC_HYPERLINKS_TOOLTIP, OSC_HYPERLINKS_MENU, OSC_HYPERLINKS_VISIBILITY, OSC_HYPERLINKS_SPOILER, OSC_HYPERLINKS_DISABLED, OSC_HYPERLINKS_SELECTION, OSC_HYPERLINKS_COMPACT
preset OSC_HYPERLINKS_PRESETS
Note: If a client only advertises OSC_HYPERLINKS, OSC_HYPERLINKS_SEND, and OSC_HYPERLINKS_PROMPT, no URL encoding of these parameters is required.
Impact on Web URLs

If your web URL contains these parameter names, they must be percent-encoded to avoid conflicts:

Original URL Corrected URL
https://example.com/?config=value https://example.com/?%63%6F%6E%66%69%67=value
https://api.game.com/?preset=normal https://api.game.com/?%70%72%65%73%65%74=normal
Percent-Encoding Reference
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.

For server-side convenience, the Cryosphere-MUD/mudlet-url-munger C++ library can automatically percent-encode reserved parameter names in URLs before sending them via OSC 8.

Implementation Guidance

For Game Servers

Progressive Enhancement Strategy

Level 1: Basic Links

  • Detect OSC_HYPERLINKS=1
  • Use simple send:/prompt: schemes
  • Provide plain text fallbacks

Level 2: Visual Enhancement

  • Check OSC_HYPERLINKS_STYLE_BASIC=1
  • Add colors, bold, italic formatting
  • Use full JSON property names

Level 3: Interactive Features

  • Verify OSC_HYPERLINKS_STYLE_STATES=1
  • Add hover, active, visited effects

Level 4: Advanced Interactions

  • Check for MENU, TOOLTIP, TITLE, VISIBILITY, SELECTION support
  • Implement context menus and dynamic visibility

Accessibility tip: Descriptive tooltip values double as screen reader announcements. If your links lack tooltips, keyboard users hear raw commands like openUrl([[1]]). A short, human-readable tooltip costs almost nothing and dramatically improves the experience for all users.

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, title, visibility, selection managers

Level 5: Add shorthand expansion table

Level 6: Implement preset storage and deep merge

Level 7: Implement keyboard accessibility for links

Key Accessibility Notes
  • Keyboard navigation: Tab / Shift+Tab should cycle between links with wrap-around. Override your framework's default Tab handling (Qt: focusNextPrevChild) to prevent it from intercepting Tab for widget focus traversal.
  • Keyboard activation: Enter / Space activates the focused link. Respect the spoiler flow: first activation reveals, second activates. Handle selection group state the same as mouse clicks.
  • Context menu keys: Menu key and Shift+F10 should open context menus at the caret position rather than the mouse position.
  • IAccessible2 text attributes: Expose link semantics using these attributes per character span:
    • text-link: — the link command (escape ; : \ per IAccessible2 spec)
    • text-link-visited:true; — link has been activated before
    • text-link-disabled:true; — link is non-interactive
    • text-link-selected:true; — link is in selected state
    • text-link-group: — selection group name (escaped)
  • Screen reader announcements: On link focus, announce: tooltip (or command fallback), then append state suffixes: ", visited", ", disabled", ", selected", ", has menu". Announce "Wrapping to first/last link" when Tab cycles past the buffer boundary.
  • Hidden link announcements: When the visibility manager conceals links, announce the count (debounced to batch rapid removals).
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

References

TLS (Secure Connections)

To connect to a game using Transport Layer Security (TLS) for more security, tick the 'Secure' box in the profile connection settings:

Secure-connection.png

Note that the game must support a secure (TLS) connection in order for this to work, and this feature is available in Mudlet 3.17+.

If you are a games admin/developer, check out this or this example on how to setup a secure connection to your game, as well as MSSP data in order to let Mudlet know that you do have a secure connection available.

Secure connection prompt

Mudlet VersionAvailable in Mudlet4.17+

To encourage enhanced data transfer protection and privacy, Mudlet will respond to the detection of the TLS (or SSL legacy) key of MSSP (Mud Server Status Protocol) and prompt a user not on a TLS (Transport Layer Security) connection with a choice to reconnect with the advertised TLS port from MSSP.

Prompting for secure connection

If the user selects Yes, Mudlet automatically updates the port with the TLS value gathered from MSSP, check-marks the Secure checkbox on the connection dialog, then reconnects.  If the user selects No, Mudlet automatically updates a profile preference so they are not asked again for the current profile, then reconnects.  This preference may be controlled on the Settings->Connection menu.  This preference is enabled by default.

Secure connection reminder

Supported Protocols for Specific Games

Mudlet includes support for the legacy, game specific ATCP and channel 102 protocols. Please use standards based protocols in the future (i.e., GMCP) vs. requesting to add a new game specific one.

ATCP

Mudlet includes support for ATCP. This is primarily available on IRE-based MUDs, but Mudlet's implementation is generic enough such that any it should work on others.

Note Note: ATCP has been overtaken by GMCP, prefer to use that instead.

The latest ATCP data is stored in the atcp table. Whenever new data arrives, the previous is overwritten. An event is also raised for each ATCP message that arrives. To find out the available messages available in the atcp table and the event names, you can use display(atcp).

Note that while the typical message comes in the format of Module.Submodule, ie Char.Vitals or Room.Exits, in Mudlet the dot is removed - so it becomes CharVitals and RoomExits.

Example
room_number = tonumber(atcp.RoomNum)
echo(room_number)

Triggering on ATCP events

If you’d like to trigger on ATCP messages, then you need to create scripts to attach handlers to the ATCP messages. The ATCP handler names follow the same format as the atcp table - RoomNum, RoomExits, CharVitals and so on.

While the concept of handlers for events is to be explained elsewhere in the manual, the quick rundown is this - place the event name you’d like your script to listen to into the Add User Defined Event Handler: field and press the + button to register it. Next, because scripts in Mudlet can have multiple functions, you need to tell Mudlet which function should it call for you when your handler receives a message. You do that by setting the Script name: to the function name in the script you’d like to be called.

For example, if you’d like to listen to the RoomExits event and have it call the process_exits() function - register RoomExits as the event handler, make the script name be process_exits, and use this in the script:

function process_exits(event, args)
    echo("Called event: " .. event .. "\nWith args: " .. args)
end

Feel free to experiment with this to achieve the desired results. A ATCP demo package is also available on the forums for using event handlers and parsing its messages into Lua datastructures.

Mudlet-specific ATCP

See ATCP Extensions for ATCP extensions that have been added to Mudlet.

Aardwolf’s 102 subchannel

Similar to ATCP, Aardwolf includes a hidden channel of information that you can access in Mudlet. Mudlet deals with it in the same way as with ATCP, so for full usage instructions see the ATCP section. All data is stored in the channel102 table, such that you can do:

display(channel102)

... to see all the latest information that has been received. The event to create handlers on is titled channel102Message, and you can use the sendTelnetChannel102(msg) function to send text via the 102 channel back to Aardwolf.

-- Function for detecting AFK status on Aardwolf mud.
function amIafk()
   for k,v in pairs(channel102) do
      if k==100 and v==4 then
         return true
      end
   end
   return false
end

Adding support for a telnet protocol

In addition to supporting ATCP, GMCP, Aardwolf's 102 and MXP, Mudlet has open telnet support - meaning that for any telnet protocol it doesn't support, it has the tools you can use to build the support for. This does not mean Mudlet supports other protocols "out of the box" - you will either have to get code that adds the support, or you could create it yourself.

The basic tools that you need are addSupportedTelnetOption(), sendSocket() and the sysTelnetEvent.

Create an event handler that goes off on sysTelnetEvent - which is raised whenever an unsupported telnet option is encountered. Your logic handling will start in this event handler. Once you decide what you'd like to send to the game, use sendSocket() to send raw data as-is. Finally, when your logic is done, use addSupportedTelnetOption() to register your telnet option with Mudlet, so it will respond with telnet DO on a query from the game server. See this MSDP snippet for a barebones example.

API philosophy

Adding a support for a new telnet protocol will involve adding the user-facing API. It best for users if it was in the same style as Mudlets handling of other protocols. To see how it's done exactly, check out GMCP, ATCP or Aardwolf 102 examples - but the gist of it is provided below.

Mudlet has a built-in event system, which is used to broadcast messages in an independent way. With it, people can "trigger" on 102, ATCP or GMCP events with Lua functions that get called whenever an event they're interested in is raised. Use the event system to provide your users with a way to react to new protocol data.

Events have names, and optionally, any amount of data with them. For protocol support, Mudlet prefixes the relevant message received name with the protocol name in lowercase. For example, an ATCP Char.Vitals getting updated would raise an event titled "atcp.Char.Vitals". A GMCP Room.Info message would raise a "gmcp.Room.Info" message.

Additionally, Mudlet also allows catch-all event - in case the user wants to use one event handler for a variety of sub-events (it's not uncommon for games to use Main.Sub.Add, Main.Sub.Remove, Main.Sub.List to keep track of a list, for example, while conserving data). To accomplish this, it raises events for every relevant namespace - that is, a Main.Sub.Add event will raise protocol.Main.Sub and protocol.Main.Sub.Add events. While it is entirely possible for one event handler to react to multiple events, this is provided for convenience.

For storing protocol data, Mudlet uses an aptly named global table - gmcp for GMCP data, atcp for ATCP data. Data is stored in the same way it is received and the event is raised for - so a Char.Vitals message's contents will be stored in gmcp.Char.Vitals, a Room.Info's contents in gmcp.Room.Info. If there were was any nested data within the message, it is stored as a table within the proper namespace - ie, a "details" JSON array of a GMCP Room.Info message would be stored in gmcp.Room.Info.details. Use a global table with the protocol name in lowerspace for storing permanent data that your users will read from.

That's it! If you'll need any Mudlet-related help, feel free to post on our forums. Once you're done, package your work for distribution which you can optionally post in the finished scripts section.


telnet:// and telnets:// URI Schemes

Mudlet registers as a system handler for telnet:// and telnets:// URI schemes on Windows, Linux, and macOS. Links follow the format telnet://[user@]host[:port] per RFC 4248, with telnets:// as the TLS-encrypted variant.

  • Default port: 23 (telnet://), 992 (telnets://)
  • Optional username in the URI is stored in the profile's auto-login field
  • Existing profiles matching the host and port are reused automatically

See Connecting via telnet:// links for usage details.