237 lines
5.7 KiB
Lua
237 lines
5.7 KiB
Lua
-- Path of Building
|
|
--
|
|
-- Module: Mod Tools
|
|
-- Various functions for dealing with modifiers
|
|
--
|
|
local pairs = pairs
|
|
local ipairs = ipairs
|
|
local select = select
|
|
local type = type
|
|
local t_insert = table.insert
|
|
local t_sort = table.sort
|
|
local m_floor = math.floor
|
|
local m_abs = math.abs
|
|
local s_format = string.format
|
|
local band = bit.band
|
|
local bor = bit.bor
|
|
|
|
modLib = { }
|
|
|
|
function modLib.createMod(modName, modType, modVal, ...)
|
|
local flags = 0
|
|
local keywordFlags = 0
|
|
local tagStart = 1
|
|
local source
|
|
if select('#', ...) >= 1 and type(select(1, ...)) == "string" then
|
|
source = select(1, ...)
|
|
tagStart = 2
|
|
end
|
|
if select('#', ...) >= 2 and type(select(2, ...)) == "number" then
|
|
flags = select(2, ...)
|
|
tagStart = 3
|
|
end
|
|
if select('#', ...) >= 3 and type(select(3, ...)) == "number" then
|
|
keywordFlags = select(3, ...)
|
|
tagStart = 4
|
|
end
|
|
return {
|
|
name = modName,
|
|
type = modType,
|
|
value = modVal,
|
|
flags = flags,
|
|
keywordFlags = keywordFlags,
|
|
source = source,
|
|
select(tagStart, ...)
|
|
}
|
|
end
|
|
|
|
modLib.parseMod, modLib.parseModCache = LoadModule("Modules/ModParser", launch)
|
|
|
|
function modLib.parseTags(line)
|
|
if not line or line == "-" then
|
|
return {}
|
|
end
|
|
local Tags = {}
|
|
for tagGroup in line:gmatch("([^,]*),?") do
|
|
if tagGroup ~= "" then
|
|
local tagSet = {}
|
|
for tag in tagGroup:gmatch("([^/]*)/?") do
|
|
if tag ~= "" then
|
|
local tagName, tagValue = tag:match("^(%a+)=(.+)")
|
|
if tagName then
|
|
-- list of all the tag parts that should be numbers
|
|
if ({threshold = true})[tagName] then
|
|
tagValue = tonumber(tagValue)
|
|
end
|
|
tagSet[tagName] = tagValue == "true" and true or tagValue
|
|
else
|
|
ConPrintf("Error tag invalid: "..tag)
|
|
end
|
|
end
|
|
end
|
|
t_insert(Tags, tagSet)
|
|
end
|
|
end
|
|
return Tags
|
|
end
|
|
|
|
function modLib.parseFormattedSourceMod(line)
|
|
local modStrings = {}
|
|
for line2 in line:gmatch("([^|]*)|?") do
|
|
t_insert(modStrings, line2)
|
|
end
|
|
if #modStrings >= 4 then
|
|
local mod = {
|
|
value = (modStrings[1] == "true" and true) or tonumber(modStrings[1]) or 0,
|
|
source = modStrings[2],
|
|
name = modStrings[3],
|
|
type = modStrings[4],
|
|
flags = ModFlag[modStrings[5]] or 0,
|
|
keywordFlags = KeywordFlag[modStrings[6]] or 0,
|
|
}
|
|
for _, tag in ipairs(modLib.parseTags(modStrings[7])) do
|
|
t_insert(mod, tag)
|
|
end
|
|
return mod
|
|
end
|
|
end
|
|
|
|
function modLib.compareModParams(modA, modB)
|
|
if modA.name ~= modB.name or modA.type ~= modB.type or modA.flags ~= modB.flags or modA.keywordFlags ~= modB.keywordFlags or #modA ~= #modB then
|
|
return false
|
|
end
|
|
for i, tag in ipairs(modA) do
|
|
if tag.type ~= modB[i].type then
|
|
return false
|
|
end
|
|
if modLib.formatTag(tag) ~= modLib.formatTag(modB[i]) then
|
|
return false
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
function modLib.formatFlags(flags, src)
|
|
local flagNames = { }
|
|
for name, val in pairs(src) do
|
|
if band(flags, val) == val then
|
|
t_insert(flagNames, name)
|
|
end
|
|
end
|
|
t_sort(flagNames)
|
|
local ret
|
|
for i, name in ipairs(flagNames) do
|
|
ret = (ret and ret.."," or "") .. name
|
|
end
|
|
return ret or "-"
|
|
end
|
|
|
|
function modLib.formatTag(tag)
|
|
local paramNames = { }
|
|
local haveType
|
|
for name, val in pairs(tag) do
|
|
if name == "type" then
|
|
haveType = true
|
|
else
|
|
t_insert(paramNames, name)
|
|
end
|
|
end
|
|
t_sort(paramNames)
|
|
if haveType then
|
|
t_insert(paramNames, 1, "type")
|
|
end
|
|
local str = ""
|
|
for i, paramName in ipairs(paramNames) do
|
|
if i > 1 then
|
|
str = str .. "/"
|
|
end
|
|
local val = tag[paramName]
|
|
if type(val) == "table" then
|
|
if val[1] then
|
|
if type(val[1]) == "table" then
|
|
val = modLib.formatTags(val)
|
|
else
|
|
val = table.concat(val, ",")
|
|
end
|
|
else
|
|
val = modLib.formatTag(tag[paramName])
|
|
end
|
|
val = "{"..val.."}"
|
|
end
|
|
str = str .. s_format("%s=%s", paramName, tostring(val))
|
|
end
|
|
return str
|
|
end
|
|
|
|
function modLib.formatTags(tagList)
|
|
local ret
|
|
for _, tag in ipairs(tagList) do
|
|
ret = (ret and ret.."," or "") .. modLib.formatTag(tag)
|
|
end
|
|
return ret or "-"
|
|
end
|
|
|
|
function modLib.formatValue(value)
|
|
if type(value) ~= "table" then
|
|
return tostring(value)
|
|
end
|
|
local paramNames = { }
|
|
local haveType
|
|
for name, val in pairs(value) do
|
|
if name == "type" then
|
|
haveType = true
|
|
else
|
|
t_insert(paramNames, name)
|
|
end
|
|
end
|
|
t_sort(paramNames)
|
|
if haveType then
|
|
t_insert(paramNames, 1, "type")
|
|
end
|
|
local ret = ""
|
|
for i, paramName in ipairs(paramNames) do
|
|
if i > 1 then
|
|
ret = ret .. "/"
|
|
end
|
|
if paramName == "mod" then
|
|
ret = ret .. s_format("%s=[%s]", paramName, modLib.formatMod(value[paramName]))
|
|
else
|
|
ret = ret .. s_format("%s=%s", paramName, modLib.formatValue(value[paramName]))
|
|
end
|
|
end
|
|
return "{"..ret.."}"
|
|
end
|
|
|
|
function modLib.formatModParams(mod)
|
|
return s_format("%s|%s|%s|%s|%s", mod.name, mod.type, modLib.formatFlags(mod.flags, ModFlag), modLib.formatFlags(mod.keywordFlags, KeywordFlag), modLib.formatTags(mod))
|
|
end
|
|
|
|
function modLib.formatMod(mod)
|
|
return modLib.formatValue(mod.value) .. " = " .. modLib.formatModParams(mod)
|
|
end
|
|
|
|
function modLib.formatSourceMod(mod)
|
|
return s_format("%s|%s|%s", modLib.formatValue(mod.value), mod.source, modLib.formatModParams(mod))
|
|
end
|
|
|
|
function modLib.setSource(mod, source)
|
|
mod.source = source
|
|
if type(mod.value) == "table" and mod.value.mod then
|
|
mod.value.mod.source = source
|
|
end
|
|
return mod
|
|
end
|
|
|
|
-- Merge keystone modifiers
|
|
function modLib.mergeKeystones(env, modDB)
|
|
env.keystonesAdded = env.keystonesAdded or { }
|
|
for _, modObj in ipairs(modDB:Tabulate("LIST", nil, "Keystone")) do
|
|
if not env.keystonesAdded[modObj.value] and env.spec.tree.keystoneMap[modObj.value] then
|
|
env.keystonesAdded[modObj.value] = true
|
|
local fromTree = modObj.mod.source and not modObj.mod.source:lower():match("tree")
|
|
for _, mod in ipairs(env.spec.tree.keystoneMap[modObj.value].modList) do
|
|
modDB:AddMod(fromTree and modLib.setSource(mod, modObj.mod.source) or mod)
|
|
end
|
|
end
|
|
end
|
|
end |