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