Files
PathOfBuilding/Modules/ModTools.lua
Openarl bae83782f4 Major update; nearing release
Changes:
 - Literally everything
 - Everything else too
2016-08-29 21:52:56 +10:00

222 lines
6.0 KiB
Lua

-- Path of Building
--
-- Module: Mod Tools
-- Various functions for dealing with modifier lists and databases.
--
local t_insert = table.insert
local m_floor = math.floor
local m_abs = math.abs
modLib = { }
modLib.parseMod = LoadModule("Modules/ModParser")
-- Break modifier name into namespace and mod name
local spaceLookup = { }
function modLib.getSpaceName(modName)
if not spaceLookup[modName] then
local spaceName, mod = modName:match("^([^_]+)_(.+)$")
if not spaceName then
spaceName = "global"
mod = modName
end
spaceLookup[modName] = { spaceName, mod }
return spaceName, mod
end
return unpack(spaceLookup[modName])
end
-- Extract condition name from modifier name
local condLookup = { }
function modLib.getCondName(modName)
if not condLookup[modName] then
local isNot, condName, mod = modName:match("^(n?o?t?)(%w+)_(.+)$")
isNot = (isNot == "not")
condLookup[modName] = { isNot, condName, mod }
return isNot, condName, mod
end
return unpack(condLookup[modName])
end
-- Magic table to check modifier type:
-- "MORE" = multiplicative (contains 'More' in the modifier name)
-- "INC" = additive (contains 'Inc' in the modifier name)
modLib.getModType = { }
modLib.getModType.__index = function(t, modName)
local val
if modName:match("More$") then
val = "MORE"
elseif modName:match("Inc$") then
val = "INC"
else
val = "BASE"
end
t[modName] = val
return val
end
setmetatable(modLib.getModType, modLib.getModType)
-- Merge modifier with existing mod list, respecting additivity/multiplicativity
function modLib.listMerge(modList, modName, modVal)
if modList[modName] then
if type(modVal) == "boolean" then
modList[modName] = modList[modName] or modVal
elseif type(modVal) == "function" then
local orig = modList[modName]
modList[modName] = function(...) orig(...) modVal(...) end
elseif modLib.getModType[modName] == "MORE" then
modList[modName] = modList[modName] * modVal
else
modList[modName] = modList[modName] + modVal
end
else
modList[modName] = modVal
end
end
-- Scale and merge modifier with existing mod list
function modLib.listScaleMerge(modList, modName, modVal, scale)
if type(modVal) == "number" then
local type = modLib.getModType[modName]
if type == "MORE" then
modLib.listMerge(modList, modName, 1 + m_floor((modVal - 1) * scale * 100) / 100)
elseif type == "INC" or m_abs(modVal) == modVal then -- Yes, there's a nasty hack there, move along
modLib.listMerge(modList, modName, m_floor(modVal * scale))
else
modLib.listMerge(modList, modName, modVal * scale)
end
else
modLib.listMerge(modList, modName, modVal)
end
end
-- Unmerge modifier from existing mod list, respecting additivity/multiplicativity
function modLib.listUnmerge(modList, modName, modVal)
if type(modVal) == "boolean" then
if modVal == true then
modList[modName] = false
end
elseif type(modVal) == "string" then
modList[modName] = nil
elseif modLib.getModType[modName] == "MORE" then
if modVal == 0 then
modList[modName] = 1
else
modList[modName] = (modList[modName] or 1) / modVal
end
else
modList[modName] = (modList[modName] or 0) - modVal
end
end
-- Merge modifier with mod database
function modLib.dbMerge(modDB, spaceName, modName, modVal)
if not spaceName then
spaceName, modName = modLib.getSpaceName(modName)
elseif spaceName == "" then
spaceName = "global"
end
if not modDB[spaceName] then
modDB[spaceName] = { }
end
modLib.listMerge(modDB[spaceName], modName, modVal)
end
-- Scale and merge modifier with mod database
function modLib.dbScaleMerge(modDB, spaceName, modName, modVal, scale)
if not spaceName then
spaceName, modName = modLib.getSpaceName(modName)
elseif spaceName == "" then
spaceName = "global"
end
if not modDB[spaceName] then
modDB[spaceName] = { }
end
modLib.listScaleMerge(modDB[spaceName], modName, modVal, scale)
end
-- Scale and merge modifier list with mod database
function modLib.dbScaleMergeList(modDB, modList, scale)
if scale and scale ~= 1 then
for k, modVal in pairs(modList) do
local spaceName, modName = modLib.getSpaceName(k)
if not modDB[spaceName] then
modDB[spaceName] = { }
end
modLib.listScaleMerge(modDB[spaceName], modName, modVal, scale)
end
else
modLib.dbMergeList(modDB, modList)
end
end
-- Unmerge modifier from mod database
function modLib.dbUnmerge(modDB, spaceName, modName, modVal)
if not spaceName then
spaceName, modName = modLib.getSpaceName(modName)
elseif spaceName == "" then
spaceName = "global"
end
if not modDB[spaceName] then
modDB[spaceName] = { }
end
modLib.listUnmerge(modDB[spaceName], modName, modVal)
end
-- Merge modifier list with mod database
function modLib.dbMergeList(modDB, modList)
for k, modVal in pairs(modList) do
local spaceName, modName = modLib.getSpaceName(k)
if not modDB[spaceName] then
modDB[spaceName] = { }
end
modLib.listMerge(modDB[spaceName], modName, modVal)
end
end
-- Unmerge modifier list from mod database
function modLib.dbUnmergeList(modDB, modList)
for k, modVal in pairs(modList) do
local spaceName, modName = modLib.getSpaceName(k)
if not modDB[spaceName] then
modDB[spaceName] = { }
end
modLib.listUnmerge(modDB[spaceName], modName, modVal)
end
end
-- Print modifier list to the console
function modLib.listPrint(modList, tab)
local names = { }
for k in pairs(modList) do
if type(k) == "string" then
t_insert(names, k)
end
end
table.sort(names)
for _, name in pairs(names) do
ConPrintf("%s%s = %s", string.rep("\t", tab or 0), name, modList[name])
end
end
-- Print modifier database to the console
function modLib.dbPrint(modDB)
local spaceNames = { }
for k in pairs(modDB) do
t_insert(spaceNames, k)
end
table.sort(spaceNames)
for _, spaceName in pairs(spaceNames) do
if type(modDB[spaceName]) ~= "table" then
ConPrintf("%s = %s", spaceName, modDB[spaceName])
elseif next(modDB[spaceName]) then
ConPrintf("%s = {", spaceName)
modLib.listPrint(modDB[spaceName], 1)
ConPrintf("},")
else
ConPrintf("%s = { },", spaceName)
end
end
end