Module:Infobox Monster
Jump to navigation
Jump to search
local p ={}
local findId = require("Module:FindId")
local infoboxModule = require('Module:Infobox')
local monstersData = mw.loadData("Module:Monsters/data")
local normalMonsters = mw.loadData("Module:Monsters stats normal/data")
local dungeonMonsters = mw.loadData("Module:Monsters stats dungeon/data")
local headerCount = 1
local labelCount = 1
local dataCount = 1
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 affinitiesIcon = {
[1] = "[[File:Melee splash.png|20px|link=Combat#Affinities]]",
[2] = "[[File:Magic splash.png|20px|link=Combat#Affinities]]",
[3] = "[[File:Range splash.png|20px|link=Combat#Affinities]]",
[4] = "[[File:Stab splash.png|20px|link=Combat#Affinities]]",
[5] = "[[File:Crush splash.png|20px|link=Combat#Affinities]]",
[6] = "[[File:Slash splash.png|20px|link=Combat#Affinities]]",
[7] = "[[File:Fire_splash.png|20px|link=Combat#Affinities]]",
[8] = "[[File:Ice_splash.png|20px|link=Combat#Affinities]]",
[9] = "[[File:Nature_splash.png|20px|link=Combat#Affinities]]",
[10] = "[[File:Chaos_splash.png|20px|link=Combat#Affinities]]",
[11] = "[[File:Poison_splash.png|20px|link=Combat#Affinities]]",
[12] = "[[File:Lightning_splash.png|20px|link=Combat#Affinities]]",
}
-- 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 tchelper(first, rest)
return first:upper()..rest:lower()
end
local function capitalize(s)
s = s:gsub("(%a)([%w_']*)", tchelper):gsub(" Of "," of "):gsub(" The "," the "):gsub("Ii","II")
return s
end
local function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
local function h()
local s = "header" .. headerCount
headerCount = headerCount + 1
labelCount = headerCount
dataCount = headerCount
return s
end
local function sbreak()
local s = "sbreak" .. headerCount
headerCount = headerCount + 1
labelCount = headerCount
dataCount = headerCount
return s
end
local function l()
local s = "label" .. labelCount
dataCount = labelCount
labelCount = labelCount + 1
headerCount = labelCount
return s
end
local function d()
local s = "data" .. dataCount
dataCount = dataCount + 1
headerCount = dataCount
labelCount = dataCount
return s
end
local function sl()
local s = "s" .. l{}
return s
end
local function sd()
local s = "s" .. d{}
return s
end
local function rc()
local s = "rowclass" .. labelCount
return s
end
---fetches an monster object from monsters/data module
---@param id number
---@return table|nil
local function getMonster(id)
local mosnter = monstersData[tostring(id)]
if mosnter then
return mosnter
end
return nil
end
local function getMonsterStats(id)
local mosnterStats = normalMonsters[tostring(id)]
if not mosnterStats then
mosnterStats = dungeonMonsters[tostring(id)]
if not mosnterStats then
return nil
end
end
return mosnterStats
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 fullUrl(url)
local newUrl = url
if url:sub(1,5) == "https" then
return newUrl
end
if url:sub(1,1) ~= "/" then
newUrl = "/" .. newUrl
end
newUrl = "https://www.play.idlescape.com" .. newUrl
return newUrl
end
local function createImgTag(monster)
local url = fullUrl(monster.image)
local attrs = {
src = fullUrl(monster.image),
alt = monster.name,
width = "150px"
}
local img = mw.html.create('img'):attr(attrs)
return tostring(img)
end
local function createOffAffinity(args, monsterStats)
for index, value in pairsByKeys(defaultAffinities) do
for affinity, affinityValue in pairs(value) do
if monsterStats.offensiveDamageAffinity[affinity] then
affinityValue = monsterStats.offensiveDamageAffinity[affinity]
args[sl()] = affinitiesIcon[index]
if affinityValue > 1 then
args[sd()] = "<span style=\"color:#4caf50\">" .. (affinityValue - 1) * 100 .. "%<span/>"
elseif affinityValue < 1 then
args[sd()] = "<span style=\"color:#f44336\">" .. (affinityValue - 1) * 100 .. "%<span/>"
else
args[sd()] = (affinityValue - 1) * 100 .. "%"
end
else
args[sl()] = affinitiesIcon[index]
args[sd()] = (affinityValue - 1) * 100 .. "%"
end
if index % 3 == 0 then
args["bodyclass"] = "equal-space"
args[sbreak()] ="yes"
end
end
end
return args
end
local function createDeffAffinity(args, monsterStats)
for index, value in pairsByKeys(defaultAffinities) do
for affinity, affinityValue in pairs(value) do
if monsterStats.defensiveDamageAffinity[affinity] then
affinityValue = monsterStats.defensiveDamageAffinity[affinity]
args[sl()] = affinitiesIcon[index]
if affinityValue > 1 then
args[sd()] = "<span style=\"color:#4caf50\">" .. (affinityValue - 1) * 100 .. "%<span/>"
elseif affinityValue < 1 then
args[sd()] = "<span style=\"color:#f44336\">" .. (affinityValue - 1) * 100 .. "%<span/>"
else
args[sd()] = (affinityValue - 1) * 100 .. "%"
end
else
args[sl()] = affinitiesIcon[index]
args[sd()] = (affinityValue - 1) * 100 .. "%"
end
if index % 3 == 0 then
args["bodyclass"] = "equal-space"
args[sbreak()] ="yes"
end
end
end
return args
end
local function getZonesLink(zones)
local s = ""
if zones then
for index, value in ipairs(zones) do
s = s .. "[[" .. capitalize(value) .. "]]"
if tablelength(zones) > index then
s = s .. ", "
end
end
end
return s
end
local function createInfobox(monster, monsterStats, zones, dps)
local args = {}
args.autoheaders = "y"
args.subbox = "no"
args.bodystyle = " "
args.title = monster.name
args.image = createImgTag(monster)
args[l()] = "Zones"
args[d()] = getZonesLink(zones)
args[h()] = "Offensive Stats"
args[sl()] = "Attack Speed"
args[sd()] = tostring(monsterStats.attackSpeed)
args[sl()] = "DPS"
args[sd()] = tostring(dps)
args[sl()] = "Crit Chance"
args[sd()] = tostring(monsterStats.offensiveCritical.chance * 100) .. "%"
args[sl()] = "Crit Multiplier"
args[sd()] = tostring(monsterStats.offensiveCritical.damageMultiplier * 100) .. "%"
args[h()] = "Offensive Affinities"
createOffAffinity(args, monsterStats)
args[h()] = "Defensive Stats"
args[sl()] = "Threat"
args[sd()] = calcThreat(monsterStats)
args[sl()] = "Crit Avoidance"
args[sd()] = tostring(monsterStats.defensiveCritical.chance * 100) .. "%"
args[sl()] = "Crit Reduction"
args[sd()] = tostring(monsterStats.defensiveCritical.damageMultiplier * 100) .. "%"
args[h()] = "Defensive Affinities"
createDeffAffinity(args, monsterStats)
for key, data in pairs(args) do
if string.find(key, "data") then
args[key] = tostring(data)
end
end
return infoboxModule.infobox(args)
end
function p.infoboxMonster(frame)
local args = frame:getParent().args
return p._infoboxMonster(args)
end
function p._infoboxMonster(_args)
local zones = fromCSV(_args["zones"])
local dps = _args["DPS"]
local name
local id
local monster
local monsterStats
local infobox
if _args[1] then
name = _args[1]
else
name = mw.title.getCurrentTitle().text
end
id = findId._findId({name, "monster"})
if not id then
return "<div style=\"color:red\"> No monster named '" .. name .. "'</div>. The Module:Monsters Ids/data maybe outdated."
end
monster = getMonster(id)
if not monster then
return "<div style=\"color:red\"> No monster named '" .. name .. "'</div>. The Module:Monsters/data maybe outdated."
end
monsterStats = getMonsterStats(id)
if not monsterStats then
return "<div style=\"color:red\"> No monster named '" .. name .. "'</div>. Module:Monsters stats normal/data and Module:Monsters stats dungeon/data maybe outdated."
end
infobox = createInfobox(monster, monsterStats, zones, dps)
return infobox
end
return p