Difference between revisions of "Module:Monsters stats table"
Jump to navigation
Jump to search
m |
(Fix crit reduction value and spelling of affinities) |
||
(12 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
local findId = require("Module:FindId") | local findId = require("Module:FindId") | ||
local img = require("Module:Img") | local img = require("Module:Img") | ||
+ | local dataModuleNames = { | ||
+ | normal = "Module:Monsters stats normal/data", | ||
+ | dungeon = "Module:Monsters stats dungeon/data", | ||
+ | } | ||
− | |||
local defaultAffinities = { | local defaultAffinities = { | ||
− | {Melee = 1}, | + | { Melee = 1 }, |
− | {Magic = 1}, | + | { Magic = 1 }, |
− | {Range = 1}, | + | { Range = 1 }, |
− | {Piercing = 1}, | + | { Piercing = 1 }, |
− | {Blunt = 1}, | + | { Blunt = 1 }, |
− | {Slashing = 1}, | + | { Slashing = 1 }, |
− | {Fire = 1}, | + | { Fire = 1 }, |
− | {Ice = 1}, | + | { Ice = 1 }, |
− | {Nature = 1}, | + | { Nature = 1 }, |
− | {Chaos = 1}, | + | { Chaos = 1 }, |
− | {Posion = 1}, | + | { Posion = 1 }, |
− | {Lightning = 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) | -- Convert from CSV string to table (converts a single line of a CSV file) | ||
Line 92: | Line 111: | ||
local armorThreatFinal = (targetArmorRating + monster.defense * 10) * armorThreat | local armorThreatFinal = (targetArmorRating + monster.defense * 10) * armorThreat | ||
local baseThreat = (potentialDamageThreatFinal + weaponThreatFinal) * attackSpeedThreatFinal + armorThreatFinal | local baseThreat = (potentialDamageThreatFinal + weaponThreatFinal) * attackSpeedThreatFinal + armorThreatFinal | ||
− | return baseThreat | + | return math.floor(baseThreat) |
end | end | ||
− | local function genDefensiveTable(monsters) | + | local function genDefensiveTable(monsters, collapsed) |
− | local | + | local defensiveAffinities = {} |
− | local s = "{|class=\"wikitable sortable | + | 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 colspan=2|Monster\n" | ||
s = s .. "!rowspan=2|Base<br/>Threat\n" | s = s .. "!rowspan=2|Base<br/>Threat\n" | ||
Line 121: | Line 141: | ||
for affinity, affinityValue in pairs(value) do | for affinity, affinityValue in pairs(value) do | ||
if monster.defensiveDamageAffinity[affinity] then | if monster.defensiveDamageAffinity[affinity] then | ||
− | + | defensiveAffinities[index] = { affinity = monster.defensiveDamageAffinity[affinity] } | |
else | else | ||
− | + | defensiveAffinities[index] = { affinity = affinityValue } | |
end | end | ||
end | end | ||
end | end | ||
− | s = s .. "|" .. img._img({monster["name"], | + | s = s .. "|" .. img._img({ monster["name"], 60 }) .. "\n" |
− | s = s .. "|[[" .. monster["name"] .. "]]\n" | + | s = s .. "|style=\"text-align:left\"|[[" .. monster["name"] .. "]]\n" |
s = s .. "| " .. calcThreat(monster) .. "\n" | s = s .. "| " .. calcThreat(monster) .. "\n" | ||
s = s .. "|" .. tostring(monster.defensiveCritical.chance * 100) .. "%\n" | s = s .. "|" .. tostring(monster.defensiveCritical.chance * 100) .. "%\n" | ||
− | s = s .. "|" .. tostring(monster.defensiveCritical.damageMultiplier * 100) .. "%\n" | + | s = s .. "|" .. tostring(100 - (monster.defensiveCritical.damageMultiplier * 100)) .. "%\n" |
− | for _, value in pairsByKeys( | + | 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 | 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 | if affinityValue > 1 then | ||
s = s .. "|<span style=\"color:#4caf50\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n" | s = s .. "|<span style=\"color:#4caf50\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n" | ||
elseif affinityValue == 1 then | elseif affinityValue == 1 then | ||
− | s =s .. "|" .. tonumber((affinityValue - 1) * 100) .. "%\n" | + | s = s .. "|" .. tonumber((affinityValue - 1) * 100) .. "%\n" |
else | else | ||
s = s .. "|<span style=\"color:#f44336\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n" | s = s .. "|<span style=\"color:#f44336\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n" | ||
Line 149: | Line 222: | ||
end | end | ||
− | local function | + | local function genCombinedTable(monsters, collapsed) |
− | local | + | local offensiveAffinities = {} |
− | local s = "{|class=\"wikitable sortable | + | 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 colspan=2|Monster\n" | ||
s = s .. "!rowspan=2|Crit<br/>Chance\n" | s = s .. "!rowspan=2|Crit<br/>Chance\n" | ||
s = s .. "!rowspan=2|Crit<br/>Multiplier\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 .. "!colspan=12 style=\"text-align:center\"|Affinities\n" | ||
s = s .. "|-\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:Melee splash.png|20px|link=Combat#Affinities]]\n" | ||
s = s .. "![[File:Magic splash.png|20px|link=Combat#Affinities]]\n" | s = s .. "![[File:Magic splash.png|20px|link=Combat#Affinities]]\n" | ||
Line 174: | Line 266: | ||
for affinity, affinityValue in pairs(value) do | for affinity, affinityValue in pairs(value) do | ||
if monster.offensiveDamageAffinity[affinity] then | 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 | else | ||
− | + | defensiveAffinities[index] = { affinity = affinityValue } | |
end | end | ||
end | end | ||
end | end | ||
− | s = s .. "|" .. img._img({monster["name"], | + | s = s .. "|" .. img._img({ monster["name"], 60 }) .. "\n" |
− | s = s .. "|[[" .. monster["name"] .. "]]\n" | + | s = s .. "|style=\"text-align:left\"|[[" .. monster["name"] .. "]]\n" |
s = s .. "|" .. tostring(monster.offensiveCritical.chance * 100) .. "%\n" | s = s .. "|" .. tostring(monster.offensiveCritical.chance * 100) .. "%\n" | ||
s = s .. "|" .. tostring(monster.offensiveCritical.damageMultiplier * 100) .. "%\n" | s = s .. "|" .. tostring(monster.offensiveCritical.damageMultiplier * 100) .. "%\n" | ||
− | for _, value in pairsByKeys( | + | for _, value in pairsByKeys(offensiveAffinities) do |
− | for | + | 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 | if affinityValue > 1 then | ||
s = s .. "|<span style=\"color:#4caf50\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n" | s = s .. "|<span style=\"color:#4caf50\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n" | ||
elseif affinityValue == 1 then | elseif affinityValue == 1 then | ||
− | s =s .. "|" .. tonumber((affinityValue - 1) * 100) .. "%\n" | + | s = s .. "|" .. tonumber((affinityValue - 1) * 100) .. "%\n" |
else | else | ||
s = s .. "|<span style=\"color:#f44336\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n" | s = s .. "|<span style=\"color:#f44336\">" .. tonumber((affinityValue - 1) * 100) .. "%<span/>\n" | ||
Line 209: | Line 320: | ||
local monsters = {} | local monsters = {} | ||
local style = _args[2] | local style = _args[2] | ||
+ | local collapsed | ||
local s = "" | local s = "" | ||
+ | if _args["collapsed"] then | ||
+ | collapsed = "mw-collapsed" | ||
+ | else | ||
+ | collapsed = "" | ||
+ | end | ||
for _, value in ipairs(monstersName) do | for _, value in ipairs(monstersName) do | ||
− | table.insert(monsters, | + | 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 | end | ||
if style == "defensive" then | if style == "defensive" then | ||
− | return genDefensiveTable(monsters) | + | return genDefensiveTable(monsters, collapsed) |
elseif style == "offensive" then | elseif style == "offensive" then | ||
− | return genOffensiveTable(monsters) | + | return genOffensiveTable(monsters, collapsed) |
+ | elseif style == "combined" then | ||
+ | return genCombinedTable(monsters, collapsed) | ||
else | else | ||
return "wrong style" | return "wrong style" |
Latest revision as of 02:54, 5 December 2024
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