Module:Slottable
Jump to navigation
Jump to search
local p = {}
local itemsData = mw.loadData("Module:Items/data")
local enchantmentsData = mw.loadData("Module:Enchantment/data")
local img = require("Module:Img")
local affinities = {"Melee", "Magic", "Range", "Piercing", "Blunt", "Slashing", "Fire", "Ice", "Nature", "Chaos", "Posion", "Lightning"}
local weaponBonuses = {"strength", "intellect", "dexterity"}
local armorBonuses = {"protection", "resistance", "agility", "stamina"}
local affinitiesIcon = {
"[[File:Melee splash.png|20px|link=Combat#Affinities]]",
"[[File:Magic splash.png|20px|link=Combat#Affinities]]",
"[[File:Range splash.png|20px|link=Combat#Affinities]]",
"[[File:Stab splash.png|20px|link=Combat#Affinities]]",
"[[File:Crush splash.png|20px|link=Combat#Affinities]]",
"[[File:Slash splash.png|20px|link=Combat#Affinities]]",
"[[File:Fire_splash.png|20px|link=Combat#Affinities]]",
"[[File:Ice_splash.png|20px|link=Combat#Affinities]]",
"[[File:Nature_splash.png|20px|link=Combat#Affinities]]",
"[[File:Chaos_splash.png|20px|link=Combat#Affinities]]",
"[[File:Poison_splash.png|20px|link=Combat#Affinities]]",
"[[File:Lightning_splash.png|20px|link=Combat#Affinities]]",
}
local weaponBonusesIcon = {"Str.", "Int.", "Dex."}
local armorBonusesIcon = {"Prot.", "Res.", "Agi.", "Sta."}
local skills = {
"mining",
"foraging",
"fishing",
"farming",
"enchanting",
"runecrafting",
"smithing",
"cooking",
"crafting",
"constitution",
"attack",
"defense",
"strength",
"magic",
"range",
}
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 shallowcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in pairs(orig) do
copy[orig_key] = orig_value
end
else -- number, string, boolean, etc
copy = orig
end
return copy
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
---commentedText
---@param itemData table
---@return integer
local function getItemHigherRequiredlevel(itemData)
local highestRequiredLevel = 0
if itemData.requiredLevel then
-- Highest level of the required skills
for _, level in pairs(itemData.requiredLevel) do
if level > highestRequiredLevel then
highestRequiredLevel = level
end
end
end
return highestRequiredLevel
end
local function tierCheck(d1, d2)
if d1.tier > d2.tier then
return false
elseif d1.tier < d2.tier then
return true
elseif d1.tier == d2.tier then
if getItemHigherRequiredlevel(d1) > getItemHigherRequiredlevel(d2) then
return false
elseif getItemHigherRequiredlevel(d1) < getItemHigherRequiredlevel(d2) then
return true
elseif getItemHigherRequiredlevel(d1) == getItemHigherRequiredlevel(d2) then
if d1.id > d2.id then
return false
elseif d1.id < d2.id then
return true
end
end
end
end
---mw.html th table
---@param s string
---@param cs string|number?
---@param rs string|number?
local function th(s, cs, rs)
local c = mw.html.create('th')
:attr('colspan', cs)
:attr('rowspan', rs)
:wikitext(s)
:done()
return c
end
---mw.html td table
---@param s string
---@param bColor string|number?
local function td(s, bColor)
local c = mw.html.create('td')
:css('background-color ', bColor)
:wikitext(s)
:done()
return c
end
---commentedText
---@param id number|string
---@return table|string
local function getEnchantment(id)
local e = enchantmentsData[tostring(id)]
if e then
return e
else
return "update Module:Enchantments/data"
end
end
local function getItemTier(itemData)
local highestRequiredLevel = getItemHigherRequiredlevel(itemData)
local hRL
if highestRequiredLevel == 0 then
hRL = nil
else
hRL= tonumber(string.format("%.1f", highestRequiredLevel / 10))
end
local itemTier = itemData.overrideItemTier or hRL or itemData.enchantmentTier or 1
return itemTier
end
local function getSlotItems(slot)
local t = {}
for id, data in pairsByKeys(itemsData) do
if data.equipmentStats and data.equipmentStats.slot == slot then
table.insert(t,{
id = data.id,
name = data.name,
enchantmentTier = data.enchantmentTier,
overrideItemTier = data.overrideItemTier,
tier = getItemTier(data),
itemImage = data.itemImage,
itemIcon = data.itemIcon or nil,
requiredLevel = data.requiredLevel,
equipmentStats = {
offensiveAccuracyAffinityRating = shallowcopy(data.equipmentStats.offensiveAccuracyAffinityRating),
offensiveDamageAffinity = shallowcopy(data.equipmentStats.offensiveDamageAffinity),
weaponBonus = shallowcopy(data.equipmentStats.weaponBonus),
armorBonus = shallowcopy(data.equipmentStats.armorBonus),
defensiveDamageAffinity = shallowcopy(data.equipmentStats.defensiveDamageAffinity),
itemSet = shallowcopy(data.equipmentStats.itemSet)
},
tags = data.tags,
})
end
end
return t
end
local function getStyleItems(items, style)
local t = {}
for id, data in ipairs(items) do
local _melee = false
local _range = false
local _magic = false
local _gathering = false
local _processing = false
local _cosmetic = false
for _, value in ipairs(data.tags) do
if value == "melee" then
_melee = true
elseif value == "range" then
_range = true
elseif value == "magic" then
_magic = true
elseif value == "mining" then
_gathering = true
elseif value == "foraging" then
_gathering = true
elseif value == "fishing" then
_gathering = true
elseif value == "smithing" then
_processing = true
elseif value == "runecrafting" then
_processing = true
elseif value == "cooking" then
_processing = true
elseif value == "cosmetic" then
_cosmetic =true
end
end
if style == "melee" and _melee and not _cosmetic then
table.insert(t, data)
elseif style == "range" and _range and not _cosmetic then
table.insert(t, data)
elseif style == "magic" and _magic and not _cosmetic then
table.insert(t, data)
elseif style == "gathering" and _gathering and not _cosmetic then
table.insert(t, data)
elseif style == "processing" and _processing and not _cosmetic then
table.insert(t, data)
end
end
return t
end
local function getNeededColums(items)
local offStat = {}
local offAff = {}
local acc = {}
local defStat = {}
local defAff = {}
local skill= {}
local setBonus = {}
for _, data in pairsByKeys(items) do
for i, v in ipairs(weaponBonuses) do
if data.equipmentStats.weaponBonus and data.equipmentStats.weaponBonus[v] then
if not offStat[i] then
offStat[i] = v
end
end
end
for i, v in ipairs(affinities) do
if data.equipmentStats.offensiveDamageAffinity and data.equipmentStats.offensiveDamageAffinity[v] then
if not offAff[i] then
offAff[i] = v
end
end
end
for i, v in ipairs(affinities) do
if data.equipmentStats.offensiveAccuracyAffinityRating and data.equipmentStats.offensiveAccuracyAffinityRating[v] then
if not acc[i] then
acc[i] = v
end
end
end
for i, v in ipairs(armorBonuses) do
if data.equipmentStats.armorBonus and data.equipmentStats.armorBonus[v] and data.equipmentStats.armorBonus[v] ~= 0 then
if not defStat[i] then
defStat[i] = v
end
end
end
for i, v in ipairs(affinities) do
if data.equipmentStats.defensiveDamageAffinity and data.equipmentStats.defensiveDamageAffinity[v] and data.equipmentStats.defensiveDamageAffinity[v] ~= 1 then
if not defAff[i] then
defAff[i] = v
end
end
end
for i, v in ipairs(skills) do
if data.requiredLevel and data.requiredLevel[v] then
if not skill[i] then
skill[i] = v
end
end
end
if data.equipmentStats.itemSet then
setBonus[1] = 1
end
end
local t = {offStat = offStat, offAff = offAff, acc = acc, defStat = defStat, defAff = defAff, skill =skill, setBonus = setBonus}
for key, value in pairs(t) do
if tablelength(value) == 0 then
t[key] = nil
end
end
return t
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 genImgCell(data)
local url = ""
if data.itemIcon then
url = data.itemIcon
elseif data.itemImage then
url = data.itemImage
end
local c = mw.html.create('td')
:css('text-align', 'center')
:tag('img')
:attr('src', fullUrl(url))
:attr('alt', capitalize(data.name))
:attr('width', "40px")
:done()
return c
end
local function genNameCell(name)
local c = mw.html.create('td')
:css('text-align', 'left')
:wikitext("[[" .. capitalize(name) .. "]]")
:done()
return c
end
local function genTierCell(data)
local c = mw.html.create('td')
:wikitext(tostring(data.tier))
:done()
return c
end
local function genRecLvlCells(tr, data, skill)
for _, v in pairs(skill) do
local s = ""
if data.requiredLevel and data.requiredLevel[v] then
s = tostring(data.requiredLevel[v])
else
s = "0"
end
tr:node(td(s))
end
return tr
end
local function genWeaponBonusCells(tr, data, offStat)
for _, v in pairsByKeys(offStat) do
local s = ""
local bc = ""
if data.equipmentStats.weaponBonus and data.equipmentStats.weaponBonus[v] then
if data.equipmentStats.weaponBonus[v] > 0 then
s = "+" .. tostring(data.equipmentStats.weaponBonus[v])
bc = "#2e5e05"
elseif data.equipmentStats.weaponBonus[v] < 0 then
s = tostring(data.equipmentStats.weaponBonus[v])
bc = "#801c13"
else
s = "+" .. tostring(data.equipmentStats.weaponBonus[v])
end
else
s = "0"
end
tr:node(td(s, bc))
end
return tr
end
local function genOffensiveDamageAffinityCells(tr, data, offAff)
for _, v in pairsByKeys(offAff) do
local s = ""
local bc = ""
if data.equipmentStats.offensiveDamageAffinity and data.equipmentStats.offensiveDamageAffinity[v] then
if data.equipmentStats.offensiveDamageAffinity[v] > 1 then
s = "+" .. tostring((data.equipmentStats.offensiveDamageAffinity[v] -1) * 10) .. "%"
bc = "#2e5e05"
elseif data.equipmentStats.offensiveDamageAffinity[v] < 1 then
s = "-" .. tostring((1 - data.equipmentStats.offensiveDamageAffinity[v]) * 100) .. "%"
bc = "#801c13"
else
s = "+0"
end
else
s = "+0"
end
tr:node(td(s, bc))
end
return tr
end
local function genAccuracyOffensiveDamageAffinityCells(tr, data, acc)
for _, v in pairsByKeys(acc) do
local s = ""
local bc = ""
if data.equipmentStats.offensiveAccuracyAffinityRating and data.equipmentStats.offensiveAccuracyAffinityRating[v] then
if data.equipmentStats.offensiveAccuracyAffinityRating[v] > 1 then
s = "+" .. tostring(data.equipmentStats.offensiveAccuracyAffinityRating[v])
bc = "#2e5e05"
elseif data.equipmentStats.offensiveAccuracyAffinityRating[v] < 1 then
s = tostring(data.equipmentStats.offensiveAccuracyAffinityRating[v])
bc = "#801c13"
else
s = "+0"
end
else
s = "+0"
end
tr:node(td(s, bc))
end
return tr
end
local function genArmorBonusCells(tr, data, defStat)
for _, v in pairsByKeys(defStat) do
local s = ""
local bc = ""
if data.equipmentStats.armorBonus and data.equipmentStats.armorBonus[v] then
if data.equipmentStats.armorBonus[v] > 0 then
s = "+" .. tostring(data.equipmentStats.armorBonus[v])
bc = "#2e5e05"
elseif data.equipmentStats.armorBonus[v] < 0 then
s = tostring(data.equipmentStats.armorBonus[v])
bc = "#801c13"
else
s = "+" .. tostring(data.equipmentStats.armorBonus[v])
end
else
s = "0"
end
tr:node(td(s, bc))
end
return tr
end
local function genDefensiveDamageAffinityCells(tr, data, defAff)
for _, v in pairsByKeys(defAff) do
local s = ""
local bc = ""
if data.equipmentStats.defensiveDamageAffinity and data.equipmentStats.defensiveDamageAffinity[v] then
if data.equipmentStats.defensiveDamageAffinity[v] > 1 then
s = "+" .. tostring((data.equipmentStats.defensiveDamageAffinity[v] -1) * 10) .. "%"
bc = "#2e5e05"
elseif data.equipmentStats.defensiveDamageAffinity[v] < 1 then
s = "-" .. tostring((1 - data.equipmentStats.defensiveDamageAffinity[v]) * 100) .. "%"
bc = "#801c13"
else
s = "+0"
end
else
s = "+0"
end
tr:node(td(s, bc))
end
return tr
end
local function genSetBonusCell(data)
local setBonus = data.equipmentStats.itemSet
local s = ""
if setBonus then
for i, v in ipairs(setBonus) do
local e = getEnchantment(v)
s = s .. "[[" .. e.name .. "]]"
if i < tablelength(setBonus) then
s = s ..", "
end
end
end
local c = mw.html.create('td')
:css('text-align', 'center')
:wikitext(s)
:done()
return c
end
local function genTHead(t, cols)
local tr = t:tag('tr')
:node(th("", 2))
:node(th(""))
if cols.skill then
tr:node(th("Req. lvl.", tablelength(cols.skill)))
end
if cols.offStat then
if tablelength(cols.offStat) <= 2 then
tr:node(th("Off. Sta.", tablelength(cols.offStat)))
else
tr:node(th("Offensive Stats", tablelength(cols.offStat)))
end
end
if cols.offAff then
if tablelength(cols.offAff) <= 2 then
tr:node(th("Off. Aff.", tablelength(cols.offAff)))
else
tr:node(th("Offensive Affinities", tablelength(cols.offAff)))
end
end
if cols.acc then
if tablelength(cols.acc) <= 2 then
tr:node(th("Acc.", tablelength(cols.acc)))
else
tr:node(th("Accuracies", tablelength(cols.acc)))
end
end
if cols.defStat then
if tablelength(cols.defStat) <= 2 then
tr:node(th("Def. Sta.", tablelength(cols.defStat)))
else
tr:node(th("Defensive Stats", tablelength(cols.defStat)))
end
end
if cols.defAff then
if tablelength(cols.defAff) <= 2 then
tr:node(th("Def. Aff.", tablelength(cols.defAff)))
else
tr:node(th("Defensive Affinities", tablelength(cols.defAff)))
end
end
if cols.setBonus then
tr:node(th("Set Bonus", 1, 2))
end
tr:done()
local tr2 = t:tag('tr')
:node(th("Image"))
:node(th("Name"))
:node(th("Tier"))
if cols.skill then
for i in pairsByKeys(cols.skill) do
tr2:node(th(img._img({skills[i], 20})))
end
end
if cols.offStat then
for i in pairsByKeys(cols.offStat) do
tr2:node(th(weaponBonusesIcon[i]))
end
end
if cols.offAff then
for i in pairsByKeys(cols.offAff) do
tr2:node(th(affinitiesIcon[i]))
end
end
if cols.acc then
for i in pairsByKeys(cols.acc) do
tr2:node(th(affinitiesIcon[i]))
end
end
if cols.defStat then
for i in pairsByKeys(cols.defStat) do
tr2:node(th(armorBonusesIcon[i]))
end
end
if cols.defAff then
for i in pairsByKeys(cols.defAff) do
tr2:node(th(affinitiesIcon[i]))
end
end
tr2:done()
return t
end
local function genTBody(t, items, cols)
for id, data in pairsByKeys(items) do
local tr = t:tag('tr')
:node(genImgCell(data))
:node(genNameCell(data.name))
:node(genTierCell(data))
if cols.skill then
tr = genRecLvlCells(tr, data, cols.skill)
end
if cols.offStat then
tr = genWeaponBonusCells(tr, data, cols.offStat)
end
if cols.offAff then
tr = genOffensiveDamageAffinityCells(tr, data, cols.offAff)
end
if cols.acc then
tr = genAccuracyOffensiveDamageAffinityCells(tr, data, cols.acc)
end
if cols.defStat then
tr = genArmorBonusCells(tr, data, cols.defStat)
end
if cols.defAff then
tr = genDefensiveDamageAffinityCells(tr, data, cols.defAff)
end
if cols.setBonus then
tr:node(genSetBonusCell(data))
end
tr:done()
end
return t
end
local function genTable(items)
local cols = getNeededColums(items)
local t = mw.html.create('table')
:addClass("wikitable sortable jquery-tablesorter")
:css('text-align', 'right')
t = genTHead(t, cols)
t = genTBody(t, items, cols)
return t
end
function p.slotTable(frame)
return p._slotTable(frame:getParent().args)
end
function p._slotTable(_args)
local slot = _args[1]
local style = _args[2]
local items = getStyleItems(getSlotItems(slot), style)
table.sort(items, tierCheck)
local t = genTable(items)
return t
end
return p