Adding comlink package and subcommand handler utility

This commit is contained in:
Matt Wagner 2021-09-30 09:01:29 -07:00
parent f119dfb5a1
commit 5e35d48216
11 changed files with 379 additions and 62 deletions

View File

@ -0,0 +1,7 @@
[
{
"name": "comlinks",
"regex": "^comlinks( ?.*)$",
"script": "lotj.comlinkInfo.command(matches[2])"
}
]

View File

@ -1,3 +1,5 @@
-- Based on AutoResearch script by @ZakattackLOTJ
lotj = lotj or {} lotj = lotj or {}
lotj.autoResearch = lotj.autoResearch or {} lotj.autoResearch = lotj.autoResearch or {}
@ -8,10 +10,9 @@ function lotj.autoResearch.log(text, precedingNewline)
cecho("[<cyan>LOTJ AutoResearch<reset>] "..text.."\n") cecho("[<cyan>LOTJ AutoResearch<reset>] "..text.."\n")
end end
function lotj.autoResearch.command(args) local subcommands = {{
argList = splitargs(args) args = {"start"},
action = function()
if #argList == 1 and argList[1] == "start" then
lotj.autoResearch.enabled = true lotj.autoResearch.enabled = true
lotj.autoResearch.researchList = {} lotj.autoResearch.researchList = {}
lotj.autoResearch.log("Research list cleared.") lotj.autoResearch.log("Research list cleared.")
@ -19,8 +20,11 @@ function lotj.autoResearch.command(args)
enableTrigger("autoresearch.grabSkills") enableTrigger("autoresearch.grabSkills")
lotj.autoResearch.log("Retrieving research list...") lotj.autoResearch.log("Retrieving research list...")
send("practice", false) send("practice", false)
end,
elseif #argList == 1 and argList[1] == "next" then helpText = "Get the practice list and automatically begin researching anything eligible for it. Must be in a library."
},{
args = {"next"},
action = function()
if #(lotj.autoResearch.researchList or {}) == 0 then if #(lotj.autoResearch.researchList or {}) == 0 then
lotj.autoResearch.log("Research list empty.") lotj.autoResearch.log("Research list empty.")
lotj.autoResearch.enabled = false lotj.autoResearch.enabled = false
@ -29,8 +33,11 @@ function lotj.autoResearch.command(args)
table.remove(lotj.autoResearch.researchList, 1) table.remove(lotj.autoResearch.researchList, 1)
expandAlias("autoresearch continue", false) expandAlias("autoresearch continue", false)
end,
elseif #argList == 1 and argList[1] == "continue" then helpText = "Resume researching the first skill in the current autoresearch list."
},{
args = {"continue"},
action = function()
if #(lotj.autoResearch.researchList or {}) == 0 then if #(lotj.autoResearch.researchList or {}) == 0 then
lotj.autoResearch.log("Research list empty.") lotj.autoResearch.log("Research list empty.")
lotj.autoResearch.enabled = false lotj.autoResearch.enabled = false
@ -40,30 +47,18 @@ function lotj.autoResearch.command(args)
local current = lotj.autoResearch.initialCount - #lotj.autoResearch.researchList + 1 local current = lotj.autoResearch.initialCount - #lotj.autoResearch.researchList + 1
lotj.autoResearch.log(current.."/"..lotj.autoResearch.initialCount..": Researching "..lotj.autoResearch.researchList[1].."...") lotj.autoResearch.log(current.."/"..lotj.autoResearch.initialCount..": Researching "..lotj.autoResearch.researchList[1].."...")
send("research "..lotj.autoResearch.researchList[1], false) send("research "..lotj.autoResearch.researchList[1], false)
end,
elseif #argList == 1 and argList[1] == "stop" then helpText = "Skip to the next skill in the autoresearch list and begin researching it."
},{
args = {"stop"},
action = function()
lotj.autoResearch.enabled = false lotj.autoResearch.enabled = false
lotj.autoResearch.researchList = {} lotj.autoResearch.researchList = {}
lotj.autoResearch.log("Research list cleared.") lotj.autoResearch.log("Research list cleared.")
end,
helpText = "Clear the autoresearch list and disable triggers for continuing automatically."
}}
else function lotj.autoResearch.command(args)
lotj.autoResearch.log("AutoResearch Command List\n") processCommand("autoresearch", subcommands, args)
cecho([[
<yellow>autoresearch start<reset>
Get the practice list and automatically begin researching anything eligible for it. Must be in a library.
<yellow>autoresearch continue<reset>
Resume researching the first skill in the current autoresearch list.
<yellow>autoresearch next<reset>
Skip to the next skill in the autoresearch list and begin researching it.
<yellow>autoresearch stop<reset>
Clear the autoresearch list and disable triggers for continuing automatically.
]])
end
end end

View File

@ -0,0 +1,133 @@
-- Comlink info script by Johnson
-- Translated to Mudlet by Kbug
lotj = lotj or {}
lotj.comlinkInfo = lotj.comlinkInfo or {}
function lotj.comlinkInfo.setup()
lotj.comlinkInfo.loadForChar()
lotj.setup.registerEventHandler("gmcp.Char.Info", lotj.comlinkInfo.loadForChar)
end
function lotj.comlinkInfo.log(text, precedingNewline)
if precedingNewline then
echo("\n")
end
cecho("[<cyan>LOTJ Comlinks<reset>] "..text.."\n")
end
function lotj.comlinkInfo.loadForChar()
local charName = gmcpVarByPath("Char.Info.name")
if charName and io.exists(getMudletHomeDir() .. "/comlinkdata_" .. charName .. ".lua") then
table.load(getMudletHomeDir() .. "/comlinkdata_" .. charName .. ".lua", lotj.comlinkInfo.comlinks)
if lotj.comlinkInfo.comlinks then
local comlinkCount = 0
for _, _ in pairs(lotj.comlinkInfo.comlinks) do
comlinkCount = comlinkCount+1
end
lotj.comlinkInfo.log("Loaded data for "..comlinkCount.." comlinks.")
end
end
if not lotj.comlinkInfo.comlinks then
lotj.comlinkInfo.comlinks = {}
end
end
function lotj.comlinkInfo.saveForChar()
local charName = gmcpVarByPath("Char.Info.name")
if charName then
table.save(getMudletHomeDir() .. "/comlinkdata_" .. charName .. ".lua", lotj.comlinkInfo.comlinks)
else
lotj.comlinkInfo.log("No character name detected for saving comlink data.")
end
end
function lotj.comlinkInfo.cleanupComlinkName(line)
line = line:gsub("%(Humming%)", '')
line = string.trim(line:gsub("%(%d+%)", ''))
line = line:gsub('"', '')
line = line:gsub("'", '')
return line
end
function lotj.comlinkInfo.registerComlink(comlinkName, channel, encryption)
local name = lotj.comlinkInfo.cleanupComlinkName(comlinkName)
local comlink = { channel = 0, encryption = 0 }
comlink = lotj.comlinkInfo.comlinks[name] or comlink -- load an existing comlink or make a new one
if channel ~= nil then -- got a channel
if comlink.channel ~= channel then -- new channel is different than existing channel
comlink.channel = tonumber(channel) or 0
end
end
if encryption ~= nil then -- got an encryption
if comlink.encryption ~= encryption then -- new encryption is different than existing
comlink.encryption = tonumber(encryption) or 0
end
end
lotj.comlinkInfo.comlinks[name] = comlink -- rip out quotation marks
lotj.comlinkInfo.saveForChar()
end
local subcommands = {{
args = {"reset"},
action = function()
lotj.comlinkInfo.comlinks = {}
lotj.comlinkInfo.log("Stored comlink data erased.")
lotj.comlinkInfo.saveForChar()
end,
helpText = "Deletes the stored comlink list."
},{
args = {"delete", "comlink:string"},
action = function(name)
for i, v in pairs(lotj.comlinkInfo.comlinks) do
-- search by comlink keyword or note keyword
if string.find(i:lower(), name:lower(), 0, true) or (v.note and (string.find(v.note:lower(), name:lower(), 0, true))) then
lotj.comlinkInfo.log("Comlink '" .. i .. "' removed from stored comlinks.")
lotj.comlinkInfo.comlinks[i] = nil
lotj.comlinkInfo.saveForChar()
return
end
end
lotj.comlinkInfo.log("Comlink '" .. name .. "' not found in comlinks.")
end,
helpText = "Deletes the first comlink matching the specified keyword from the comlink list.\n"..
"Notice: Will match either the comlink description or the note attached to that comlink."
},{
args = {"notes"},
action = function()
lotj.comlinkInfo.log("Listing all stored comlinks with notes:")
for i, v in pairs(lotj.comlinkInfo.comlinks) do
if v.note then
cecho(" <dim_gray>" .. i .. " <yellow>-> <dim_gray>(Note:<red>" .. v.note .. "<dim_gray>)\n")
end
end
end,
helpText = "Prints a list of every comlink that has a note."
},{
args = {"note", "comlink:string", "note:string?"},
action = function(com, note)
for i, v in pairs(lotj.comlinkInfo.comlinks) do
if string.find(i:lower(), com:lower(), 0, true) or (v.note and (string.find(v.note:lower(), com:lower(), 0, true))) then -- search by comlink keyword or note keyword
if note == "" or note == nil then
lotj.comlinkInfo.log("Removed '"..v.note.."' as note from comlink '"..i.."'.")
v.note = nil
else
v.note = note
lotj.comlinkInfo.log("Added '"..v.note.."' as note to comlink '"..i.."'.")
end
lotj.comlinkInfo.saveForChar()
return
end
end
lotj.comlinkInfo.log("Comlink '"..com.."' note found in comlinks.")
end,
helpText = "Adds a note to the first comlink matching the specified keyword.\n"..
"Notice: Will match either the comlink description or the note attached to that comlink.\n"..
"Use quotes around multi-word notes, as in: comlink note newbtech \"Secret channel for Anakin\""
}}
function lotj.comlinkInfo.command(args)
processCommand("comlinks", subcommands, args)
end

View File

@ -0,0 +1,5 @@
[
{
"name": "comlink-info"
}
]

View File

@ -52,18 +52,6 @@ local function styleGaugeText(gauge, fontSize)
gauge:setFontSize(fontSize) gauge:setFontSize(fontSize)
end end
local function gmcpVarByPath(varPath)
local temp = gmcp
for varStep in varPath:gmatch("([^\\.]+)") do
if temp and temp[varStep] then
temp = temp[varStep]
else
return nil
end
end
return temp
end
-- Wires up GMCP subscriptions for a gauge. -- Wires up GMCP subscriptions for a gauge.
-- statName is the short version of the stat name to show after the value (mv, hp, etc) -- statName is the short version of the stat name to show after the value (mv, hp, etc)
local function wireGaugeUpdate(gauge, valueVarName, maxVarName, statName, eventName) local function wireGaugeUpdate(gauge, valueVarName, maxVarName, statName, eventName)

View File

@ -1,5 +1,8 @@
[ [
{ {
"name": "setup" "name": "setup"
},
{
"name": "util"
} }
] ]

View File

@ -24,6 +24,7 @@ local function setup()
lotj.infoPanel.setup() lotj.infoPanel.setup()
lotj.mapper.setup() lotj.mapper.setup()
lotj.systemMap.setup() lotj.systemMap.setup()
lotj.comlinkInfo.setup()
-- Then set our UI default view -- Then set our UI default view
lotj.layout.selectTab(lotj.layout.upperRightTabData, "map") lotj.layout.selectTab(lotj.layout.upperRightTabData, "map")
@ -73,23 +74,3 @@ lotj.setup.registerEventHandler("sysProtocolEnabled", function(_, protocol)
sendGMCP("Core.Supports.Set", "[\"Ship 1\"]") sendGMCP("Core.Supports.Set", "[\"Ship 1\"]")
end end
end) end)
function splitargs(args)
local retval = {}
local spat, epat, buf, quoted = [=[^(['"])]=], [=[(['"])$]=]
for str in args:gmatch("%S+") do
local squoted = str:match(spat)
local equoted = str:match(epat)
local escaped = str:match([=[(\*)['"]$]=])
if squoted and not quoted and not equoted then
buf, quoted = str, squoted
elseif buf and equoted == quoted and #escaped % 2 == 0 then
str, buf, quoted = buf .. ' ' .. str, nil, nil
elseif buf then
buf = buf .. ' ' .. str
end
if not buf then table.insert(retval, (str:gsub(spat,""):gsub(epat,""))) end
end
if buf then error("Missing matching quote for "..buf) end
return retval
end

139
src/scripts/setup/util.lua Normal file
View File

@ -0,0 +1,139 @@
function splitargs(args)
local retval = {}
local spat, epat, buf, quoted = [=[^(['"])]=], [=[(['"])$]=]
for str in args:gmatch("%S+") do
local squoted = str:match(spat)
local equoted = str:match(epat)
local escaped = str:match([=[(\*)['"]$]=])
if squoted and not quoted and not equoted then
buf, quoted = str, squoted
elseif buf and equoted == quoted and #escaped % 2 == 0 then
str, buf, quoted = buf .. ' ' .. str, nil, nil
elseif buf then
buf = buf .. ' ' .. str
end
if not buf then table.insert(retval, (str:gsub(spat,""):gsub(epat,""))) end
end
if buf then error("Missing matching quote for "..buf) end
return retval
end
function gmcpVarByPath(varPath)
local temp = gmcp
for varStep in varPath:gmatch("([^\\.]+)") do
if temp and temp[varStep] then
temp = temp[varStep]
else
return nil
end
end
return temp
end
-- Handles matching argument text to a list of subcommands.
-- Each subcommand should be an object with the following properties:
-- args: List of elements to match input against, each matching:
-- a string to match exactly for the argument in this position
-- a token indicating a type of variable argument in this position, one of:
-- argName:string - any string
-- argName:string? - any string, optional
-- argName:number - any number
-- argName:number? - any number, optional
-- all optional arguments must appear after all non-optional arguments.
-- action: A function, taking each variable argument as an argument.
-- helpText: Description of what this subcommand does.
--
-- If
-- For example:
-- local subcommands = {{
-- "args": {"list"},
-- "action": function() ...do stuff... end,
-- "helpText": "List the things."
-- },{
-- "args": {"show", "<thingName:string>"},
-- "action": function(thingName) ...do stuff... end,
-- "helpText": "Find a given thing by name and show it"
-- }}
--
-- This would match against the second subcommand, effectively calling your function
-- with "testName" as the argument.
-- processCommand("shopkeeper", subcommands, "show testName")
--
-- Calling this with "help" or any nonmatching argument will print out the list of
-- subcommands and descriptions, using the commandName argument as the overall command
-- name for documentation.
function processCommand(commandName, subcommands, input)
inputArgs = splitargs(input)
for _, subcommand in pairs(subcommands) do
local match = true
local matchArgs = {}
local foundOptArg = false
-- Go through each subcommand arg to look for non-matches. Innocent until proven guilty.
for i, arg in ipairs(subcommand.args) do
local startIdx, _, argName, varType, argOpt = arg:find("([^:]+):?([^?]*)([?]?)")
if not startIdx then
error("Invalid subcommand argument specifier: "..arg)
elseif foundOptArg and argOpt ~= "?" then
error("Found non-optional argument ("..arg..") after optional argument.")
end
if varType == "" then
-- Exact match for subcommand name
if inputArgs[i] ~= argName then
match = false
end
else
-- Variable. Check type and optional state
local rawValue = inputArgs[i]
if varType == "number" then
rawValue = tonumber(rawValue)
if not rawValue then
match = false
end
end
-- Check that optional arguments are given values, or no match
if argOpt == "?" then
foundOptArg = true
elseif not rawValue or rawValue == "" then
match = false
end
table.insert(matchArgs, rawValue)
end
end
-- Got too many arguments, fail
if #inputArgs > #subcommand.args then
match = false
end
if match then
subcommand.action(unpack(matchArgs))
return
end
end
if not (#inputArgs == 1 and inputArgs[1] == "help") then
cecho("<red>Invalid syntax.<reset>\n\n")
end
cecho("<white>Available options for "..commandName.." command:<reset>")
for _, subcommand in pairs(subcommands) do
cecho("\n\n<yellow>"..commandName)
for _, arg in ipairs(subcommand.args) do
local _, _, argName, varType, argOpt = arg:find("([^:]+):?([^?]*)([?]?)")
if varType == "" then
cecho(" <yellow>"..argName)
elseif argOpt == "?" then
cecho(" <yellow>[<ansi_light_black>"..argName.."<yellow>]")
else
cecho(" <yellow><<light_gray>"..argName.."<yellow>>")
end
end
cecho("<reset>\n\n"..subcommand.helpText)
end
echo("\n\n")
end

View File

@ -0,0 +1,11 @@
if not lotj.comlinkInfo.comlinks then
return
end
local line = lotj.comlinkInfo.cleanupComlinkName(matches[1])
local comlink = lotj.comlinkInfo.comlinks[line]
if comlink ~= nil then -- found a comlink with stored data
cecho(" <yellow>-> <gray>(Chan:<red>" .. comlink.channel .. "<gray> Enc:<red>" .. comlink.encryption .. "<gray>" .. ((comlink.note and " Note:") or "") .. "<red>" .. ((comlink.note and comlink.note) or "") .. "<gray>)")
end
setTriggerStayOpen("inventory-comlinks", 1)

View File

@ -0,0 +1,5 @@
lotj.comlinkInfo.registerComlink(matches.comlink, matches.channel, matches.encryption)
echo("\n")
lotj.comlinkInfo.log("Stored comlink: "..matches.comlink)
lotj.comlinkInfo.log("Stored channel: "..matches.channel)
lotj.comlinkInfo.log("Stored encryption: "..matches.encryption)

View File

@ -0,0 +1,50 @@
[
{
"name": "store-comlink",
"patterns": [
{
"pattern": "^You tune (?<comlink>.*) to channel (?<channel>.*)\\.$",
"type": "regex"
},
{
"pattern": "^You set (?P<comlink>.*) to encryption code (?P<encryption>.*)\\.$",
"type": "regex"
},
{
"pattern": "^(Current comlink now\\:)?(?P<comlink>.*) Frequency\\:(?P<channel>.*) Encryption\\:(?P<encryption>.*)$",
"type": "regex"
}
]
},
{
"name": "inventory-comlinks",
"fireLength": 1,
"patterns": [
{
"pattern": "^You are carrying\\:$",
"type": "regex"
}
],
"children": [
{
"name": "inv-comlink-info",
"patterns": [
{
"pattern": "^ (.*)$",
"type": "regex"
}
]
}
]
},
{
"name": "equipment-comlink",
"patterns": [
{
"pattern": "^\\<(.*)\\> +(?P<comlink>.*) \\(Channel\\: (?P<channel>.*?)\\)( \\(Code\\: (?P<encryption>.*?)\\))?$",
"type": "regex"
}
],
"script": "lotj.comlinkInfo.registerComlink(matches.comlink, matches.channel, matches.encryption)"
}
]