256 lines
10 KiB
Lua
256 lines
10 KiB
Lua
--- Self Updating Gauge, extends <a href="https://www.mudlet.org/geyser/files/geyser/GeyserGauge.html">Geyser.Gauge</a>
|
|
-- @classmod SUG
|
|
-- @author Damian Monogue <demonnic@gmail.com>
|
|
-- @copyright 2020 Damian Monogue
|
|
-- @license MIT, see LICENSE.lua
|
|
local SUG = {
|
|
name = "SelfUpdatingGaugeClass",
|
|
active = true,
|
|
updateTime = 333,
|
|
currentVariable = "",
|
|
maxVariable = "",
|
|
defaultCurrent = 50,
|
|
defaultMax = 100,
|
|
textTemplate = " |c/|m |p%",
|
|
strict = true,
|
|
}
|
|
|
|
-- Internal function, used to turn a string variable name into a value
|
|
local function getValueAt(accessString)
|
|
local ok, err = pcall(loadstring("return " .. tostring(accessString)))
|
|
if ok then return err end
|
|
return nil, err
|
|
end
|
|
|
|
-- ========== End section copied from demontools.lua
|
|
|
|
--- Creates a new Self Updating Gauge.
|
|
-- @tparam table cons table of options which control the Gauge's behaviour. In addition to all valid contraints for Geyser.Gauge, SUG adds:
|
|
-- <br>
|
|
-- <table class="tg">
|
|
-- <tr>
|
|
-- <th>name</th>
|
|
-- <th>description</th>
|
|
-- <th>default</th>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-1">active</td>
|
|
-- <td class="tg-1">boolean, if true starts the timer updating</td>
|
|
-- <td class="tg-1">true</td>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-2">updateTime</td>
|
|
-- <td class="tg-2">How often should the gauge autoupdate? Milliseconds. 0 to disable the timer but still allow event updates</td>
|
|
-- <td class="tg-2">333</td>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-1">currentVariable</td>
|
|
-- <td class="tg-1">What variable will hold the 'current' value of the gauge? Pass the name as a string, IE "currentHP" or "gmcp.Char.Vitals.hp"</td>
|
|
-- <td class="tg-1">""</td>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-2">maxVariable</td>
|
|
-- <td class="tg-2">What variable will hold the 'current' value of the gauge? Pass the name as a string, IE "maxHP" or "gmcp.Char.Vitals.maxhp"</td>
|
|
-- <td class="tg-2">""</td>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-1">textTemplate</td>
|
|
-- <td class="tg-1">Template to use for the text on the gauge. "|c" replaced with current value, "|m" replaced with max value, "|p" replaced with the % full the gauge should be</td>
|
|
-- <td class="tg-1">" |c/|m |p%"</td>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-2">defaultCurrent</td>
|
|
-- <td class="tg-2">What value to use if the currentVariable points to nil or something which cannot be made a number?</td>
|
|
-- <td class="tg-2">50</td>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-1">defaultMax</td>
|
|
-- <td class="tg-1">What value to use if the maxVariable points to nil or something which cannot be made a number?</td>
|
|
-- <td class="tg-1">100</td>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-2">updateEvent</td>
|
|
-- <td class="tg-2">The name of an event to listen for to perform an update. Can be run alongside or instead of the timer updates. Empty string to turn off</td>
|
|
-- <td class="tg-2">""</td>
|
|
-- </tr>
|
|
-- <tr>
|
|
-- <td class="tg-1">updateHook</td>
|
|
-- <td class="tg-1">A function which is run each time the gauge updates. Should take 3 arguments, the gauge itself, current value, and max value. You can return new current and max values to be used, for example `return 34, 120` would cause the gauge to use 34 for current and 120 for max regardless of what the variables it reads say.</td>
|
|
-- <td class="tg-1"></td>
|
|
-- </tr>
|
|
-- </table>
|
|
-- @param container The Geyser container for this gauge
|
|
-- @usage
|
|
-- local SUG = require("MDK.sug") --the following will watch "gmcp.Char.Vitals.hp" and "gmcp.Char.Vitals.maxhp" and update itself every 333 milliseconds
|
|
-- myGauge = SUG:new({
|
|
-- name = "myGauge",
|
|
-- currentVariable = "gmcp.Char.Vitals.hp", --if this is nil, it will use the defaultCurrent of 50
|
|
-- maxVariable = "gmcp.Char.Vitals.maxhp", --if this is nil, it will use the defaultMax of 100.
|
|
-- height = 50,
|
|
-- })
|
|
function SUG:new(cons, container)
|
|
local funcName = "SUG:new(cons, container)"
|
|
cons = cons or {}
|
|
local consType = type(cons)
|
|
assert(consType == "table", string.format("%s: cons as table expected, got %s", funcName, consType))
|
|
local me = SUG.parent:new(cons, container)
|
|
setmetatable(me, self)
|
|
self.__index = self
|
|
-- apply any styling requested
|
|
if me.cssFront then
|
|
if not me.cssBack then
|
|
me.cssBack = me.cssFront .. "background-color: black;"
|
|
end
|
|
me:setStyleSheet(me.cssFront, me.cssBack, me.cssText)
|
|
end
|
|
if me.active then
|
|
me:start()
|
|
end
|
|
me:update()
|
|
return me
|
|
end
|
|
|
|
--- Set how often to update the gauge on a timer
|
|
-- @tparam number time time in milliseconds. 0 to disable the timer
|
|
function SUG:setUpdateTime(time)
|
|
if type(time) ~= "number" then
|
|
debugc("SUG:setUpdateTime(time) time as number expected, got " .. type(time))
|
|
return
|
|
end
|
|
self.updateTime = time
|
|
if self.active then self:start() end
|
|
end
|
|
|
|
--- Set the event to listen for to update the gauge
|
|
-- @tparam string event the name of the event to listen for, use "" to disable events without stopping any existing timers
|
|
function SUG:setUpdateEvent(event)
|
|
if type(event) ~= string then
|
|
debugc("SUG:setUpdateEvent(event) event name as string expected, got " .. type(event))
|
|
return
|
|
end
|
|
self.updateEvent = event
|
|
if self.active then self:start() end
|
|
end
|
|
|
|
--- Set the name of the variable the Self Updating Gauge watches for the 'current' value of the gauge
|
|
-- @tparam string variableName The name of the variable to get the current value for the gauge. For instance "currentHP", "gmcp.Char.Vitals.hp" etc
|
|
function SUG:setCurrentVariable(variableName)
|
|
local nameType = type(variableName)
|
|
local funcName = "SUG:setCurrentVariable(variableName)"
|
|
assert(nameType == "string", string.format("%s: variableName as string expected, got: %s", funcName, nameType))
|
|
local val = getValueAt(variableName)
|
|
local valType = type(tonumber(val))
|
|
assert(valType == "number",
|
|
string.format("%s: variableName must point to a variable which is a number or coercable into one. %s points to a %s", funcName, variableName,
|
|
type(val)))
|
|
self.currentVariable = variableName
|
|
self:update()
|
|
end
|
|
|
|
--- Set the name of the variable the Self Updating Gauge watches for the 'max' value of the gauge
|
|
-- @tparam string variableName The name of the variable to get the max value for the gauge. For instance "maxHP", "gmcp.Char.Vitals.maxhp" etc. Set to "" to only check the current value
|
|
function SUG:setMaxVariable(variableName)
|
|
if variableName == "" then
|
|
self.maxVariable = variableName
|
|
self:update()
|
|
return
|
|
end
|
|
local nameType = type(variableName)
|
|
local funcName = "SUG:setMaxVariable(variableName)"
|
|
assert(nameType == "string", string.format("%s: variableName as string expected, got: %s", funcName, nameType))
|
|
local val = getValueAt(variableName)
|
|
local valType = type(tonumber(val))
|
|
assert(valType == "number",
|
|
string.format("%s: variableName must point to a variable which is a number or coercable into one. %s points to a %s", funcName, variableName,
|
|
type(val)))
|
|
self.maxVariable = variableName
|
|
self:update()
|
|
end
|
|
|
|
--- Set the template for the Self Updating Gauge to set the text with. "|c" is replaced by the current value, "|m" is replaced by the max value, and "|p" is replaced by the percentage current/max
|
|
-- @tparam string template The template to use for the text on the gauge. If the max value is 200 and current is 68, then |c will be replace by 68, |m replaced by 200, and |p replaced by 34.
|
|
function SUG:setTextTemplate(template)
|
|
local templateType = type(template)
|
|
local funcName = "SUG:setTextTemplate(template)"
|
|
assert(templateType == "string", string.format("%s: template as string expected, got %s", funcName, templateType))
|
|
self.textTemplate = template
|
|
self:update()
|
|
end
|
|
|
|
--- Set the updateHook function which is run just prior to the gauge updating
|
|
-- @tparam function func The function which will be called when the gauge updates. It should take 3 arguments, the gauge itself, the current value, and the max value. If you wish to override the current or max values used for the gauge, you can return new current and max values, like `return newCurrent newMax`
|
|
function SUG:setUpdateHook(func)
|
|
local funcType = type(func)
|
|
if funcType ~= "function" then
|
|
return nil, "setUpdateHook only takes functions, no strings or anything like that. You passed in: " .. funcType
|
|
end
|
|
self.updateHook = func
|
|
end
|
|
|
|
--- Stops the Self Updating Gauge from updating
|
|
function SUG:stop()
|
|
self.active = false
|
|
if self.timer then
|
|
killTimer(self.timer)
|
|
self.timer = nil
|
|
end
|
|
if self.eventHandler then
|
|
killAnonymousEventHandler(self.eventHandler)
|
|
self.eventHandler = nil
|
|
end
|
|
end
|
|
|
|
--- Starts the Self Updating Gauge updating. If it is already updating, it will restart it.
|
|
function SUG:start()
|
|
self:stop()
|
|
self.active = true
|
|
local update = function() self:update() end
|
|
if self.updateTime > 0 then
|
|
self.timer = tempTimer(self.updateTime / 1000, update, true)
|
|
end
|
|
local updateEvent = self.updateEvent
|
|
if updateEvent and updateEvent ~= "" and updateEvent ~= "*" then
|
|
self.eventHandler = registerAnonymousEventHandler(self.updateEvent, update)
|
|
end
|
|
end
|
|
|
|
--- Reads the values from currentVariable and maxVariable, and updates the gauge's value and text.
|
|
function SUG:update()
|
|
local current = getValueAt(self.currentVariable)
|
|
local max = getValueAt(self.maxVariable)
|
|
current = tonumber(current)
|
|
max = tonumber(max)
|
|
if current == nil then
|
|
current = self.defaultCurrent
|
|
debugc(string.format(
|
|
"Self Updating Gauge named %s is trying to update with an invalid current value. Using the defaultCurrent instead. currentVariable: '%s' maxVariable: '%s'",
|
|
self.name, self.currentVariable, self.maxVariable))
|
|
end
|
|
if max == nil then
|
|
max = self.defaultMax
|
|
if self.maxVariable ~= "" then
|
|
debugc(string.format(
|
|
"Self Updating Gauge named %s is trying to update with an invalid max value. Using the defaultCurrent instead. currentVariable: '%s' maxVariable: '%s'",
|
|
self.name, self.currentVariable, self.maxVariable))
|
|
end
|
|
end
|
|
if self.updateHook and type(self.updateHook) == "function" then
|
|
local ok, newcur, newmax = pcall(self.updateHook, self, current, max)
|
|
if ok and newcur then
|
|
current = newcur
|
|
max = newmax and newmax or self.defaultMax
|
|
end
|
|
end
|
|
local text = self.textTemplate
|
|
local percent = math.floor((current / max * 100) + 0.5)
|
|
text = text:gsub("|c", current)
|
|
text = text:gsub("|m", max)
|
|
text = text:gsub("|p", percent)
|
|
self:setValue(current, max, text)
|
|
end
|
|
|
|
SUG.parent = Geyser.Gauge
|
|
setmetatable(SUG, Geyser.Gauge)
|
|
|
|
return SUG
|