Input line alias/trigger scripts.

Share your scripts and packages with other Mudlet users.
Post Reply
Buck
Posts: 19
Joined: Tue Aug 30, 2016 8:11 pm

Input line alias/trigger scripts.

Post by Buck »

As per request, some details about my alias/trigger scripts.

In order to make Mudlet more accessible to both newbies and mushclient players, I added the ability to set aliases and mushclient like triggers via the input line. This makes it easier for people to use simple aliases and triggers without having to learn the Mudlet interface, which is overwhelming to a lot of non-technical players.

The aliases and triggers support custom variables (set with /set), which adds a layer of flexibility. There are no regular expressions involved. The name of the alias has to be a single word, and each alias has to be prefixed with a slash (/) when called. This to differentiate between client side and server side aliases. Aliases aren't added as Mudlet aliases, but instead stored separately in a hash.

The usage of the alias engine is fairly straightforward:

Code: Select all

/alias [name] [actions]

A local alias command separate from the server. This allows for using
variables and local commands in your aliases not available from the server.

/alias will show the currently set aliases

/alias equipbow /getbag bow; wield bow; /getbag arrow; hold arrow would create an
alias called 'equipbow', which would execute the following commands when called:
/getbag bow
wield bow
/getbag arrow
hold arrow

You can reference arguments the same way as the server side alias,
using $* for all arguments or $1 $2 $3 $etc for individual arguments.

Giving only the alias name without actions will clear an alias.
For instance:

/alias equipbow will clear the alias called 'equipbow'

It is also possible to limit aliases to specific zones or rooms by using
/zonealias and /roomalias respectfully.
Triggers were a little more difficult. I couldn't get around creating actual Mudlet triggers, and I had to create a special Trigger folder for them.

Code: Select all

/trigger '<pattern>' <actions>

The pattern must be enclosed with single quotes. Currently, the pattern
cannot contain a single quote. If this is a problem, let me know.

The pattern system is fairly simple. It matches the text you give
it (it is case sensitive), and executes the actions you specified.
The actions are parsed clientside, so you can call other plugin
commands. You can separate multiple commands with a semi-colon (;).

For example:

/trigger '* has arrived.' say hello %1!

Would create a trigger that says hello to anyone arriving in the room.

/trigger without arguments shows you your current triggers:

mt_1: '* has arrived' -> 'say hello %1!'

You can remove triggers with /removetrigger <id>, for example:

/removetrigger mt_1
I used percentage (%) instead of dollar signs ($) here because that's what mushclient uses, and this command was created specifically for mushclient players.

What this command does internally, is translate the pattern to a proper regular expression, creates a Mudlet trigger with it, and adds that to a special "Generated Triggers" trigger folder. Deleting triggers from lua is impossible as far as I can tell, so when a trigger is removed, it is actually just disabled.

For example, the command:

Code: Select all

/trigger '* has arrived.' say hi %1!; hug %1
Will generate the following trigger:

Image

The trigger IDs and original patterns are stored in a separate hash. If someone deletes an entry manually from the Generated Triggers folder, it will also be removed from the hash. This hash is only used for people to keep track of the triggers they've made:

Image

As you can see, the triggers aren't sorted. It's on the todo list :D

Creating a large number of triggers this way might cause performance issues, but I've found I'm often adding triggers this way instead of proper Mudlet triggers because of convenience.

User avatar
Vadi
Posts: 5035
Joined: Sat Mar 14, 2009 3:13 pm

Re: Input line alias/trigger scripts.

Post by Vadi »

Thanks for writing this up! I think this is a good idea - a command-line interface to creating simple aliases/triggers like this does fill a need. Something for us to consider for the future.

User avatar
Vadi
Posts: 5035
Joined: Sat Mar 14, 2009 3:13 pm

Re: Input line alias/trigger scripts.

Post by Vadi »

Is the script for this available? I'm not seeing it in the post.

Jor'Mox
Posts: 1142
Joined: Wed Apr 03, 2013 2:19 am

Re: Input line alias/trigger scripts.

Post by Jor'Mox »

So, I saw this, and figured I would try my hand at making a script to do what this supposedly does, since code doesn't yet appear to be forthcoming. I have something that is nominally working, but is still somewhat untested.

The syntax for both the alias and the trigger aliases is as follows:
/alias pattern >> commands to send
/trigger pattern >> commands to send

Hopefully the block of comments at the very beginning of the script cover the rest well enough so as to make it useable. At this point, aliases and triggers should persist between sessions, and you can list or delete the aliases or triggers it is responsible for. Note that all aliases and triggers that it creates are TEMP objects, so won't show up on the GUI.
Code: [show] | [select all] lua
-- Command Line Simple Triggers and Aliases Script
-- 
-- use * to indicate an argument that must be provided
-- use ? to indicate an argument that is optional
-- use %# to indicate the appropriately numbered argument
-- use wait # to wait that many seconds, including decimal seconds, before continuing to the next command
--
-- use /alias or /trigger to show a list of all aliases or triggers managed by this script
-- use /delete alias # or /delete trigger # to delete that alias or trigger, using the number matching that shown on the list
-- 

cmd_line = cmd_line or {data = {}}
cmd_line.data.triggers = cmd_line.triggers or {}
cmd_line.data.aliases = cmd_line.aliases or {}
local script_aliases = script_aliases or {}

local runQueue
function runQueue(fnc,tbl)
    local info = table.remove(tbl,1)
    if info then
        local run = function()
                fnc(info[2])
                runQueue(fnc,tbl)
            end
        if info[1] ~= 0 then
            tempTimer(info[1], run)
        else
            run()
        end
    end
end

local function doQueue(fnc,...)
    local tbl = {}
    local args = arg
    if type(arg[1]) == "table" then args = arg[1] end
    for k,v in ipairs(args) do
        if k % 2 == 1 and type(v) ~= "number" then
            table.insert(args,k,0)
        end
    end
    for k = 1,#args,2 do
        tbl[(k + 1) / 2] = {args[k],args[k+1]}
    end
    runQueue(fnc,tbl)
end

function sendQueue(...)
    doQueue(send,...)
end

function expandQueue(...)
    doQueue(expandAlias,...)
end

local function parse_pattern(ptrn)
    ptrn = string.gsub(ptrn,"([^/])%*","%1(.*)")
    ptrn = string.gsub(ptrn,"^%*","(.*)")
    ptrn = string.gsub(ptrn,"([^/])%?","%1\\s*(.*)")
    ptrn = string.gsub(ptrn,"^%?%s*","(.-)\s*")
    ptrn = string.gsub(ptrn,"%s+\\s%*","\\s*")
    ptrn = "^" .. ptrn .. "$"
    return ptrn
end

local function parse_cmds(cmds)
    cmds = string.split(cmds,"%s*;%s*")
    local str = "expandQueue("
    local start, match, stop, tmp
		local comma = ""
    for k,v in ipairs(cmds) do
        if string.match(v,"wait [%d%.]+") then
            str = str .. comma .. string.match(v,"^wait ([%d%.]+)$")
        elseif string.match(v,"%%%d+") then
            tmp = ""
			for start, match, stop in string.gmatch(v,"(.-)%%(%d+)([^%%]*)") do
                tmp = tmp .. string.format([[%s" .. matches[%s] .. "%s]], start, match + 1, stop)
            end
            str = str .. comma .. [["]] .. tmp .. [["]]
        else
            str = str .. comma .. [["]] .. v .. [["]]
        end
		comma = ","
    end
    str = str .. ")"
    return str
end

local function save_cmd()
    table.save(getMudletHomeDir().."/mycmd_data.lua", cmd_line.data)
end

local function check_duplicate(ptrn, is_trigger)
    local tbl
    local func
    if is_trigger then
        tbl = cmd_line.data.triggers
        func = killTrigger
    else
        tbl = cmd_line.data.aliases
        func = killAlias
    end
    
    for i,v in ipairs(tbl) do
        if v[2] == ptrn then
            func(v[1])
            print(string.format("Existing %s with identical pattern has been replaced.",is_trigger and "trigger" or "alias"))
            table.remove(tbl,i)
            break
        end
    end
end

local function make_item(ptrn, cmds, is_trigger, is_config)
    local pattern = parse_pattern(ptrn)
    local commands = parse_cmds(cmds)
    if not is_config then
        check_duplicate(ptrn,is_trigger)
    end
    if is_trigger then
        table.insert(cmd_line.data.triggers,{tempRegexTrigger(pattern,commands),ptrn,cmds})
    else
        table.insert(cmd_line.data.aliases,{tempAlias(pattern,commands),ptrn,cmds})
    end
    if not is_config then
        save_cmd()
        print(string.format("New %s with pattern %s has been created.",is_trigger and "trigger" or "alias",ptrn))
    end
end

local function show_items(triggers)
    local tbl
    if triggers then
        tbl = cmd_line.data.triggers
    else
        tbl = cmd_line.data.aliases
    end
    for i,v in ipairs(tbl) do
        print(string.format("%3s: %s  >>  %s",i,v[2],v[3]))
    end
end

local function delete_item(number, is_trigger)
    local info, func
    if is_trigger then
        info = table.remove(cmd_line.data.triggers,number)
        func = killTrigger
    else
        info = table.remove(cmd_line.data.aliases,number)
        func = killAlias
    end
    if info then
        func(info[1])
        save_cmd()
        print(string.format("%s number %s has been deleted.",is_trigger and "Trigger" or "Alias",number))
    end
end

local function load_cmd()
    local file = getMudletHomeDir().."/mycmd_data.lua"
	local tmp = {}
	cmd_line.data = {aliases = {}, triggers = {}}
    if io.exists(file) then
        table.load(file, tmp)
		for i,v in ipairs(tmp.triggers) do
        	make_item(v[2],v[3],true,true)
    	end
    	for i,v in ipairs(tmp.aliases) do
        	make_item(v[2],v[3],false,true)
    	end
    end
end

local function config()
    for i,v in ipairs(cmd_line.data.triggers) do
        killTrigger(v[1])
    end
    for i,v in ipairs(cmd_line.data.aliases) do
        killAlias(v[1])
    end
    for i,v in ipairs(script_aliases) do
        killAlias(v)
    end
    load_cmd()
    
    script_aliases = {}
    table.insert(script_aliases,tempAlias([[^/(alias|trigger) (.*) >> (.*)$]],[[raiseEvent("cmdMakeItem",matches[2],matches[3],matches[4])]]))
    table.insert(script_aliases,tempAlias([[^/(alias|trigger)$]],[[raiseEvent("cmdShowList",matches[2])]]))
    table.insert(script_aliases,tempAlias([[^/delete (alias|trigger) (\d+)$]],[[raiseEvent("cmdDeleteItem",matches[2],matches[3])]]))
end

function cmd_line.event_handler(event,...)
    if event == "sysConnectionEvent" or event == "sysInstall" then
        config()
    elseif event == "cmdMakeItem" then
        make_item(arg[2],arg[3],arg[1] == "trigger")
    elseif event == "cmdShowList" then
        show_items(arg[1] == "trigger")
    elseif event == "cmdDeleteItem" then
        delete_item(arg[2], arg[1] == "trigger")
    end
end

registerAnonymousEventHandler("sysConnectionEvent", "cmd_line.event_handler")
registerAnonymousEventHandler("sysInstall", "cmd_line.event_handler")
registerAnonymousEventHandler("cmdMakeItem", "cmd_line.event_handler")
registerAnonymousEventHandler("cmdShowList", "cmd_line.event_handler")
registerAnonymousEventHandler("cmdDeleteItem", "cmd_line.event_handler")
Edit: Note that in order to make use of the "wait" functionality, this script includes two public functions, sendQueue and expandQueue. They are both essentially identical, except that one uses "send" and the other uses "expandAlias" to execute commands. They act similarly to sendAll, except that any arguments of the "number" type are treated as wait commands, so the script waits that many seconds before continuing. Also, unlike sendAll, these commands are not all sent at one time, even if there are no wait commands included. There is effectively a zero second wait between each command.

Edit: Updated to include additions and revisions.

User avatar
Vadi
Posts: 5035
Joined: Sat Mar 14, 2009 3:13 pm

Re: Input line alias/trigger scripts.

Post by Vadi »

Do you think you could make this a package? I've pasted it in but /alias wasn't doing much.

Jor'Mox
Posts: 1142
Joined: Wed Apr 03, 2013 2:19 am

Re: Input line alias/trigger scripts.

Post by Jor'Mox »

I certainly can, but I'd like to make sure all the kinks are worked out first. There is just the single script, with no aliases or such to include, so it would be a fairly simple package as far as it goes. As for the /alias command not working, the most likely cause is that it needs to catch the sysConnectionEvent to set itself up. For some reason, I found it only really did that for the first connect of a session if the script was checked, though other scripts with a similar event handler setup haven't typically had that issue. Regardless, you can always raise the event yourself, or just reconnect in session, and it should go through the appropriate steps.

Post Reply