Module:Monsters stats table
Jump to navigation
Jump to search
local p = {}
local findId = require("Module:FindId")
local img = require("Module:Img")
local dataModuleNames = {
normal = "Module:Monsters stats normal/data",
dungeon = "Module:Monsters stats dungeon/data",
}
local defaultAffinities = {
{ Melee = 1 },
{ Magic = 1 },
{ Range = 1 },
{ Piercing = 1 },
{ Blunt = 1 },
{ Slashing = 1 },
{ Fire = 1 },
{ Ice = 1 },
{ Nature = 1 },
{ Chaos = 1 },
{ Posion = 1 },
{ Lightning = 1 }
}
local loadedDataModules = {}
--
-- Loads data modules
--
-- @param dataType {string}
-- @return {data table}
--
function p.loadData(dataType)
local moduleName = dataModuleNames[dataType]
if loadedDataModules[moduleName] == nil then
loadedDataModules[moduleName] = mw.loadData(moduleName)
end
return loadedDataModules[moduleName]
end
-- Convert from CSV string to table (converts a single line of a CSV file)
local function fromCSV(s)
s = s .. ',' -- ending comma
local t = {} -- table to collect fields
local fieldstart = 1
repeat
local nexti = string.find(s, ',', fieldstart)
table.insert(t, string.sub(s, fieldstart, nexti - 1))
fieldstart = nexti + 1
until fieldstart > string.len(s)
return t
end
local function pairsByKeys(t, f)
local a = {}
local orgi_key_type
local orgi_key_numbered
for n in pairs(t) do
if tonumber(n) == nil then
table.insert(a, n)
orgi_key_type = "word"
elseif type(n) == "number" then
table.insert(a, n)
orgi_key_type = "int"
elseif type(n) == "string" and type(tonumber(n) == "number") then
orgi_key_type = "number"
table.insert(a, tonumber(n))
end
end
table.sort(a, f)
local key
local value
local i = 0 -- iterator variable
local iter = function() -- iterator function
i = i + 1
if a[i] == nil then
return nil
elseif orgi_key_type == "word" or orgi_key_type == "int" then
key = a[i]
value = t[a[i]]
elseif orgi_key_type == "number" then
key = tostring(a[i])
value = t[tostring(a[i])]
end
return key, value
end
return iter
end
local function calcThreat(monster)
local damageThreat = 2
local weaponThreat = 3
local armorThreat = 5
local attackSpeedThreat = 3
local attackSpeedThreatLevel = 2.4 / monster.attackSpeed
local attackSpeedThreatFinal = attackSpeedThreatLevel * attackSpeedThreat
local potentialDamageThreatFinal =
(monster.attack +
monster.strength +
monster.magic +
monster.range) *
damageThreat
local weaponThreatFinal =
(monster.weapon.dexterity +
monster.weapon.intellect +
monster.weapon.strength) *
weaponThreat
local targetArmorRating =
monster.armor.protection +
monster.armor.resistance +
monster.armor.agility * 1.5
local armorThreatFinal = (targetArmorRating + monster.defense * 10) * armorThreat
local baseThreat = (potentialDamageThreatFinal + weaponThreatFinal) * attackSpeedThreatFinal + armorThreatFinal
return math.floor(baseThreat)
end
local function genDefensiveTable(monsters, collapsed)
local defensiveAffinities = {}
local s = "{|class=\"wikitable sortable mw-collapsible " .. collapsed .. "\" style=\"text-align:center;width:100%\"\n"
s = s .. "|+ style=\"white-space:nowrap\" |Defensive Affinities\n"
s = s .. "!rowspan=2 colspan=2|Monster\n"
s = s .. "!rowspan=2|Base<br/>Threat\n"
s = s .. "!rowspan=2|Crit<br/>Avoidance\n"
s = s .. "!rowspan=2|Crit<br/>Reduction\n"
s = s .. "!colspan=12 style=\"text-align:center\"|Affinities\n"
s = s .. "|-\n"
s = s .. "![[File:Melee splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Magic splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Range splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Stab splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Crush splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Slash splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Fire_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Ice_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Nature_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Chaos_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Poison_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Lightning_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "|-\n"
for _, monster in ipairs(monsters) do
for index, value in pairsByKeys(defaultAffinities) do
for affinity, affinityValue in pairs(value) do
if monster.defensiveDamageAffinity[affinity] then
defensiveAffinities[index] = { affinity = monster.defensiveDamageAffinity[affinity] }
else
defensiveAffinities[index] = { affinity = affinityValue }
end
end
end
s = s .. "|" .. img._img({ monster["name"], 60 }) .. "\n"
s = s .. "|style=\"text-align:left\"|[[" .. monster["name"] .. "]]\n"
s = s .. "| " .. calcThreat(monster) .. "\n"
s = s .. "|" .. tostring(monster.defensiveCritical.chance * 100) .. "%\n"
s = s .. "|" .. tostring(100 - (monster.defensiveCritical.damageMultiplier * 100)) .. "%\n"
for _, value in pairsByKeys(defensiveAffinities) do
for _, affinityValue in pairs(value) do
if affinityValue > 1 then
s = s .. "|<span style=\"color:#4caf50\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n"
elseif affinityValue == 1 then
s = s .. "|" .. tonumber((affinityValue - 1) * 100) .. "%\n"
else
s = s .. "|<span style=\"color:#f44336\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n"
end
end
end
s = s .. "|-\n"
end
s = s .. "|}"
return s
end
local function genOffensiveTable(monsters, collapsed)
local offensiveAffinities = {}
local s = "{|class=\"wikitable sortable mw-collapsible " .. collapsed .. "\" style=\"text-align:center;width:100%\"\n"
s = s .. "|+ style=\"white-space:nowrap\" |Offensive Affinities\n"
s = s .. "!rowspan=2 colspan=2|Monster\n"
s = s .. "!rowspan=2|Crit<br/>Chance\n"
s = s .. "!rowspan=2|Crit<br/>Multiplier\n"
s = s .. "!colspan=12 style=\"text-align:center\"|Affinities\n"
s = s .. "|-\n"
s = s .. "![[File:Melee splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Magic splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Range splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Stab splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Crush splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Slash splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Fire_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Ice_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Nature_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Chaos_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Poison_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Lightning_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "|-\n"
for _, monster in ipairs(monsters) do
for index, value in pairsByKeys(defaultAffinities) do
for affinity, affinityValue in pairs(value) do
if monster.offensiveDamageAffinity[affinity] then
offensiveAffinities[index] = { affinity = monster.offensiveDamageAffinity[affinity] }
else
offensiveAffinities[index] = { affinity = affinityValue }
end
end
end
s = s .. "|" .. img._img({ monster["name"], 60 }) .. "\n"
s = s .. "|style=\"text-align:left\"|[[" .. monster["name"] .. "]]\n"
s = s .. "|" .. tostring(monster.offensiveCritical.chance * 100) .. "%\n"
s = s .. "|" .. tostring(monster.offensiveCritical.damageMultiplier * 100) .. "%\n"
for _, value in pairsByKeys(offensiveAffinities) do
for _, affinityValue in pairs(value) do
if affinityValue > 1 then
s = s .. "|<span style=\"color:#4caf50\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n"
elseif affinityValue == 1 then
s = s .. "|" .. tonumber((affinityValue - 1) * 100) .. "%\n"
else
s = s .. "|<span style=\"color:#f44336\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n"
end
end
end
s = s .. "|-\n"
end
s = s .. "|}"
return s
end
local function genCombinedTable(monsters, collapsed)
local offensiveAffinities = {}
local defensiveAffinities = {}
local s = "{|class=\"wikitable sortable mw-collapsible " .. collapsed .. "\" style=\"text-align:center;width:100%\"\n"
s = s .. "|+ style=\"white-space:nowrap\" |Affinities\n"
s = s .. "!rowspan=2 colspan=2|Monster\n"
s = s .. "!rowspan=2|Crit<br/>Chance\n"
s = s .. "!rowspan=2|Crit<br/>Multiplier\n"
s = s .. "!colspan=12 style=\"text-align:center\"|Affinities\n"
s = s .. "!rowspan=2|Base<br/>Threat\n"
s = s .. "!rowspan=2|Crit<br/>Avoidance\n"
s = s .. "!rowspan=2|Crit<br/>Reduction\n"
s = s .. "!colspan=12 style=\"text-align:center\"|Affinities\n"
s = s .. "|-\n"
s = s .. "![[File:Melee splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Magic splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Range splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Stab splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Crush splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Slash splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Fire_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Ice_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Nature_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Chaos_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Poison_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Lightning_splash.png|20px|link=Combat#Affinities]]\n"
-- sep
s = s .. "![[File:Melee splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Magic splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Range splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Stab splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Crush splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Slash splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Fire_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Ice_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Nature_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Chaos_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Poison_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "![[File:Lightning_splash.png|20px|link=Combat#Affinities]]\n"
s = s .. "|-\n"
for _, monster in ipairs(monsters) do
for index, value in pairsByKeys(defaultAffinities) do
for affinity, affinityValue in pairs(value) do
if monster.offensiveDamageAffinity[affinity] then
offensiveAffinities[index] = { affinity = monster.offensiveDamageAffinity[affinity] }
else
offensiveAffinities[index] = { affinity = affinityValue }
end
if monster.defensiveDamageAffinity[affinity] then
defensiveAffinities[index] = { affinity = monster.defensiveDamageAffinity[affinity] }
else
defensiveAffinities[index] = { affinity = affinityValue }
end
end
end
s = s .. "|" .. img._img({ monster["name"], 60 }) .. "\n"
s = s .. "|style=\"text-align:left\"|[[" .. monster["name"] .. "]]\n"
s = s .. "|" .. tostring(monster.offensiveCritical.chance * 100) .. "%\n"
s = s .. "|" .. tostring(monster.offensiveCritical.damageMultiplier * 100) .. "%\n"
for _, value in pairsByKeys(offensiveAffinities) do
for _, affinityValue in pairs(value) do
if affinityValue > 1 then
s = s .. "|<span style=\"color:#4caf50\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n"
elseif affinityValue == 1 then
s = s .. "|" .. tonumber((affinityValue - 1) * 100) .. "%\n"
else
s = s .. "|<span style=\"color:#f44336\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n"
end
end
end
s = s .. "| " .. calcThreat(monster) .. "\n"
s = s .. "|" .. tostring(monster.defensiveCritical.chance * 100) .. "%\n"
s = s .. "|" .. tostring(100 - (monster.defensiveCritical.damageMultiplier * 100)) .. "%\n"
for _, value in pairsByKeys(defensiveAffinities) do
for _, affinityValue in pairs(value) do
if affinityValue > 1 then
s = s .. "|<span style=\"color:#4caf50\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n"
elseif affinityValue == 1 then
s = s .. "|" .. tonumber((affinityValue - 1) * 100) .. "%\n"
else
s = s .. "|<span style=\"color:#f44336\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n"
end
end
end
s = s .. "|-\n"
end
s = s .. "|}"
return s
end
function p.monsters_stats_table(frame)
return p._monsters_stats_table(frame:getParent().args)
end
function p._monsters_stats_table(_args)
local monstersName = fromCSV(_args[1])
local monsters = {}
local style = _args[2]
local collapsed
local s = ""
if _args["collapsed"] then
collapsed = "mw-collapsed"
else
collapsed = ""
end
for _, value in ipairs(monstersName) do
table.insert(monsters, p.loadData("normal")[tostring(findId._findId({ value, "monster" }))])
table.insert(monsters, p.loadData("dungeon")[tostring(findId._findId({ value, "monster" }))])
end
if monsters == nil then
return "no monster match"
end
if style == "defensive" then
return genDefensiveTable(monsters, collapsed)
elseif style == "offensive" then
return genOffensiveTable(monsters, collapsed)
elseif style == "combined" then
return genCombinedTable(monsters, collapsed)
else
return "wrong style"
end
end
return p