diff options
author | chai <chaifix@163.com> | 2021-11-15 13:53:59 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-11-15 13:53:59 +0800 |
commit | 942a030afd348ab2e02eac8054b43e3c3a72ea48 (patch) | |
tree | a13459f39a3d2f1b533fbd1b5ab523d7a621f673 /Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/Modes.lua | |
parent | e307051a56a54c27f10438fd2025edf61d0dfeed (diff) |
*rename
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/Modes.lua')
-rw-r--r-- | Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/Modes.lua | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/Modes.lua b/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/Modes.lua new file mode 100644 index 0000000..4e01890 --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/Modes.lua @@ -0,0 +1,457 @@ +------------------------------------------------------------------------------------------------------------------- +-- This include library allows use of specially-designed tables for tracking +-- certain types of modes and state. +-- +-- Usage: include('Modes.lua') +-- +-- Construction syntax: +-- +-- 1) Create a new list of mode values. The first value will always be the default. +-- MeleeMode = M{'Normal', 'Acc', 'Att'} -- Construct as a basic table, using braces. +-- MeleeMode = M('Normal', 'Acc', 'Att') -- Pass in a list of strings, using parentheses. +-- +-- Optional: If constructed as a basic table, and the table contains a key value +-- of 'description', that description will be saved for future reference. +-- If a simple list of strings is passed in, no description will be set. +-- +-- MeleeMode = M{['description']='Melee Mode', 'Normal', 'Acc', 'Att'} +-- +-- +-- 2) Create a boolean mode with a specified default value (note parentheses): +-- UseLuzafRing = M(true) +-- UseLuzafRing = M(false) +-- +-- Optional: A string may be provided that will be used as the mode description: +-- UseLuzafRing = M(false, 'description') +-- UseLuzafRing = M(true, 'description') +-- +-- +-- 3) Create a string mode with a specified default value. Construct with a table: +-- CombatWeapon = M{['description']='Melee Mode', ['string']='Dagger'} +-- CombatWeapon = M{['description']='Melee Mode', ['string']=''} +-- +-- +-- +-- Public information fields (all are case-insensitive): +-- +-- 1) m.description -- Get a text description of the mode table, if it's been set. +-- 2) m.current -- Gets the current mode text value. Booleans will return the strings "on" or "off". +-- 3) m.value -- Gets the current mode value. Booleans will return the boolean values of true or false. +-- 3) m.index -- Gets the current index value, or true/false for booleans. +-- +-- Typically use m.current when using the mode to create a set name, and m.value when +-- testing the mode value in conditional rules. +-- +-- Public class functions: +-- +-- 1) m:describe(str) -- Sets the description for the mode table to the provided string value. +-- 2) m:options(options) -- Redefine the options for a list mode table. Cannot be used on a boolean table. +-- +-- +-- Public mode manipulation functions: +-- +-- 1) m:cycle() -- Cycles through the list going forwards. Acts as a toggle on boolean mode vars. +-- 2) m:cycleback() -- Cycles through the list going backwards. Acts as a toggle on boolean mode vars. +-- 3) m:toggle() -- Toggles a boolean Mode between true and false. +-- 4) m:set(n) -- Sets the current mode value to n. +-- Note: If m is boolean, n can be boolean true/false, or string of on/off/true/false. +-- Note: If m is boolean and no n is given, this forces m to true. +-- 5) m:unset() -- Sets a boolean mode var to false. +-- 6) m:reset() -- Returns the mode var to its default state. +-- 7) m:default() -- Same as reset() +-- +-- All public functions return the current value after completion. +-- +-- +-- Example usage: +-- +-- sets.MeleeMode.Normal = {} +-- sets.MeleeMode.Acc = {} +-- sets.MeleeMode.Att = {} +-- +-- MeleeMode = M{'Normal', 'Acc', 'Att', ['description']='Melee Mode'} +-- MeleeMode:cycle() +-- equip(sets.engaged[MeleeMode.current]) +-- MeleeMode:options('Normal', 'LowAcc', 'HighAcc') +-- >> Changes the option list, but the description stays 'Melee Mode' +-- +-- +-- sets.LuzafRing.on = {ring2="Luzaf's Ring"} +-- sets.LuzafRing.off = {} +-- +-- UseLuzafRing = M(false) +-- UseLuzafRing:toggle() +-- equip(sets.precast['Phantom Roll'], sets.LuzafRing[UseLuzafRing.value]) +------------------------------------------------------------------------------------------------------------------- + + +_meta = _meta or {} +_meta.M = {} +_meta.M.__class = 'mode' +_meta.M.__methods = {} + + +-- Default constructor for mode tables +-- M{'a', 'b', etc, ['description']='a'} -- defines a mode list, description 'a' +-- M('a', 'b', etc) -- defines a mode list, no description +-- M('a') -- defines a mode list, default 'a' +-- M{['description']='a'} -- defines a mode list, default 'Normal', description 'a' +-- M{} -- defines a mode list, default 'Normal', no description +-- M(false) -- defines a mode boolean, default false, no description +-- M(true) -- defines a mode boolean, default true, no description +-- M(false, 'a') -- defines a mode boolean, default false, description 'a' +-- M(true, 'a') -- defines a mode boolean, default true, description 'a' +-- M() -- defines a mode boolean, default false, no description +function M(t, ...) + local m = {} + m._track = {} + m._track._class = 'mode' + + -- If we're passed a list of strings (that is, the first element is a string), + -- convert them to a table + local args = {...} + if type(t) == 'string' then + t = {[1] = t} + + for ind, val in ipairs(args) do + t[ind+1] = val + end + end + + -- Construct the table that we'll be adding the metadata to + + -- If we have a table of values, it's either a list or a string + if type(t) == 'table' then + -- Save the description, if provided + if t['description'] then + m._track._description = t['description'] + end + + -- If we were given an explicit 'string' field, construct a string mode class. + if t.string and type(t.string) == 'string' then + m._track._type = 'string' + m._track._count = 1 + m._track._default = 'defaultstring' + + if t.string then + m['string'] = t.string + m['defaultstring'] = t.string + end + -- Otherwise put together a standard list mode class. + else + m._track._type = 'list' + m._track._invert = {} + m._track._count = 0 + m._track._default = 1 + + -- Only copy numerically indexed values + for ind, val in ipairs(t) do + m[ind] = val + m._track._invert[val] = ind + m._track._count = ind + end + + if m._track._count == 0 then + m[1] = 'Normal' + m._track._invert['Normal'] = 1 + m._track._count = 1 + end + end + -- If the first argument is a bool, construct a boolean mode class. + elseif type(t) == 'boolean' or t == nil then + m._track._type = 'boolean' + m._track._count = 2 + m._track._default = t or false + m._track._description = args[1] + -- Text lookups for bool values + m[true] = 'on' + m[false] = 'off' + else + -- Construction failure + error("Unable to construct a mode table with the provided parameters.", 2) + end + + -- Initialize current value to the default. + m._track._current = m._track._default + + return setmetatable(m, _meta.M) +end + +-------------------------------------------------------------------------- +-- Metamethods +-- Functions that will be used as metamethods for the class +-------------------------------------------------------------------------- + +-- Handler for __index when trying to access the current mode value. +-- Handles indexing 'current' or 'value' keys. +_meta.M.__index = function(m, k) + if type(k) == 'string' then + local lk = k:lower() + if lk == 'current' then + return m[m._track._current] + elseif lk == 'value' then + if m._track._type == 'boolean' then + return m._track._current + else + return m[m._track._current] + end + elseif lk == 'has_value' then + return _meta.M.__methods.f_has_value(m) + elseif lk == 'default' then + if m._track._type == 'boolean' then + return m._track._default + else + return m[m._track._default] + end + elseif lk == 'description' then + return m._track._description + elseif lk == 'index' then + return m._track._current + elseif m._track[lk] then + return m._track[lk] + elseif m._track['_'..lk] then + return m._track['_'..lk] + else + return _meta.M.__methods[lk] + end + end +end + +-- Tostring handler for printing out the table and its current state. +_meta.M.__tostring = function(m) + local res = '' + if m._track._description then + res = res .. m._track._description .. ': ' + end + + if m._track._type == 'list' then + res = res .. '{' + for k,v in ipairs(m) do + res = res..tostring(v) + if m[k+1] ~= nil then + res = res..', ' + end + end + res = res..'}' + elseif m._track._type == 'string' then + res = res .. 'String' + else + res = res .. 'Boolean' + end + + res = res .. ' ('..tostring(m.Current).. ')' + + -- Debug addition + --res = res .. ' [' .. m._track._type .. '/' .. tostring(m._track._current) .. ']' + + return res +end + +-- Length handler for the # value lookup. +_meta.M.__len = function(m) + return m._track._count +end + + +-------------------------------------------------------------------------- +-- Public methods +-- Functions that can be used as public methods for manipulating the class. +-------------------------------------------------------------------------- + +-- Function to set the table's description. +_meta.M.__methods['describe'] = function(m, str) + if type(str) == 'string' then + m._track._description = str + else + error("Invalid argument type: " .. type(str), 2) + end +end + +-- Function to change the list of options available. +-- Leaves the description intact. +-- Cannot be used on boolean classes. +_meta.M.__methods['options'] = function(m, ...) + if m._track._type ~= 'list' then + error("Can only revise the options list for a list mode class.", 2) + end + + local options = {...} + -- Always include a default option if nothing else is given. + if #options == 0 then + options = {'Normal'} + end + + -- Zero-out existing values and clear the tracked inverted list + -- and member count. + for key,val in ipairs(m) do + m[key] = nil + end + m._track._invert = {} + m._track._count = 0 + + -- Insert in new data. + for key,val in ipairs(options) do + m[key] = val + m._track._invert[val] = key + m._track._count = key + end + + m._track._current = m._track._default +end + + +-- Function to test whether the list table contains the specified value. +_meta.M.__methods['contains'] = function(m, str) + if m._track._invert then + if type(str) == 'string' then + return (m._track._invert[str] ~= nil) + else + error("Invalid argument type: " .. type(str), 2) + end + else + error("Cannot test for containment on a " .. m._track._type .. " mode class.", 2) + end +end + + +-------------------------------------------------------------------------- +-- Public methods +-- Functions that will be used as public methods for manipulating state. +-------------------------------------------------------------------------- + +-- Cycle forwards through the list +_meta.M.__methods['cycle'] = function(m) + if m._track._type == 'list' then + m._track._current = (m._track._current % m._track._count) + 1 + elseif m._track._type == 'boolean' then + m:toggle() + end + + return m.Current +end + +-- Cycle backwards through the list +_meta.M.__methods['cycleback'] = function(m) + if m._track._type == 'list' then + m._track._current = m._track._current - 1 + if m._track._current < 1 then + m._track._current = m._track._count + end + elseif m._track._type == 'boolean' then + m:toggle() + end + + return m.Current +end + +-- Toggle a boolean value +_meta.M.__methods['toggle'] = function(m) + if m._track._type == 'boolean' then + m._track._current = not m._track._current + else + error("Can only toggle a boolean mode.", 2) + end + + return m.Current +end + + +-- Set the current value +_meta.M.__methods['set'] = function(m, val) + if m._track._type == 'boolean' then + if val == nil then + m._track._current = true + elseif type(val) == 'boolean' then + m._track._current = val + elseif type(val) == 'string' then + val = val:lower() + if val == 'on' or val == 'true' then + m._track._current = true + elseif val == 'off' or val == 'false' then + m._track._current = false + else + error("Unrecognized value: "..tostring(val), 2) + end + else + error("Unrecognized value type: "..type(val), 2) + end + elseif m._track._type == 'list' then + if not val then + error("List variable cannot be set to nil.", 2) + end + if m._track._invert[val] then + m._track._current = m._track._invert[val] + else + local found = false + for v, ind in pairs(m._track._invert) do + if val:lower() == v:lower() then + m._track._current = ind + found = true + break + end + end + + if not found then + error("Unknown mode value: " .. tostring(val), 2) + end + end + elseif m._track._type == 'string' then + if type(val) == 'string' then + m._track._current = 'string' + m.string = val + else + error("Unrecognized value type: "..type(val), 2) + end + end + + return m.Current +end + + +-- Forces a boolean mode to false, or a string to an empty string. +_meta.M.__methods['unset'] = function(m) + if m._track._type == 'boolean' then + m._track._current = false + elseif m._track._type == 'string' then + m._track._current = 'string' + m.string = '' + else + error("Cannot unset a list mode class.", 2) + end + + return m.Current +end + + +-- Reset to the default value +_meta.M.__methods['reset'] = function(m) + m._track._current = m._track._default + + return m.Current +end + + +-- Check to be sure that the mode var has a valid (for its type) value. +-- String vars must be non-empty. +-- List vars must not be empty strings, or the word 'none'. +-- Boolean are always considered valid (can only be true or false). +_meta.M.__methods['f_has_value'] = function(m) + local cur = m.value + if m._track._type == 'string' then + if cur and cur ~= '' then + return true + else + return false + end + elseif m._track._type == 'boolean' then + return true + else + if not cur or cur == '' or cur:lower() == 'none' then + return false + else + return true + end + end +end + + |