Module:Item lists
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Item lists/doc
local p = {}
local cfg = require('Module:Config')
function p.fetchItemsOfTypeAndRarity(itemType, itemRarity)
local cargo = mw.ext.cargo
if itemRarity ~= "" then
local items = cargo.query(
'items',
'Item_Name, Item_Level_Requirement, Item_Tier, Item_Weapon_Class, Item_Type, Item_Lore',
{ where = "Item_Type = '" .. itemType .. "' and Item_Rarity = '" .. itemRarity .. "' and Item_Hidden = 'No'", orderBy = 'Item_Level_Requirement', 'Item_Name'}
)
return items
else
local items = cargo.query(
'items',
'Item_Name, Item_Level_Requirement, Item_Tier, Item_Weapon_Class, Item_Type, Item_Lore',
{ where = "Item_Type = '" .. itemType .. "'", orderBy = 'Item_Level_Requirement', 'Item_Name'}
)
return items
end
end
-- Fetch statistics for a given item
function p.fetchItemStats(itemName)
local cargo = mw.ext.cargo
local where = string.format("Item_Name = '%s'", p.encodeName(itemName))
local stats = cargo.query(
'item_stats',
'Item_Name, Stat_ID, Spell_Name, Class_Name, Min_Value1, Max_Value1, Min_Value2, Max_Value2, Min_Value3, Max_Value3, Stat_Order',
{ where = where, orderBy = 'Stat_Order ASC' }
)
return stats
end
-- Fetch formatting details for all stats
function p.fetchFormatDetails()
local cargo = mw.ext.cargo
local formatDetails = cargo.query(
'stat_format',
'Stat_ID, Stat_Display, Stat_Type, Stat_Color',
{}
)
local formatMap = {}
for _, detail in ipairs(formatDetails) do
formatMap[detail.Stat_ID] = detail
end
return formatMap
end
function p.formatStatLine(stat, formatDetails)
local statDetail = formatDetails[stat.Stat_ID]
local formattedStat = statDetail.Stat_Display or stat.Stat_ID
if stat.Min_Value1 and stat.Min_Value1 ~= "" and tonumber(stat.Min_Value1) >= 0 then formattedStat = formattedStat:gsub("value1", p.formatRange(stat.Min_Value1, stat.Max_Value1)) end
if stat.Min_Value1 and stat.Min_Value1 ~= "" and tonumber(stat.Min_Value1) < 0 then formattedStat = formattedStat:gsub("+value1", p.formatRange(stat.Min_Value1, stat.Max_Value1)) end
if stat.Min_Value2 and stat.Min_Value2 ~= "" then formattedStat = formattedStat:gsub("value2", p.formatRange(stat.Min_Value2, stat.Max_Value2)) end
if stat.Min_Value3 and stat.Min_Value3 ~= "" then formattedStat = formattedStat:gsub("value3", p.formatRange(stat.Min_Value3, stat.Max_Value3)) end
if stat.Spell_Name and stat.Spell_Name ~= "" then
formattedStat = formattedStat:gsub("spellvalue", string.format('<span class="item-stat-spell-link">[[%s|[%s]]]</span>', stat.Spell_Name, stat.Spell_Name))
end
if statDetail and statDetail.Stat_Type == "none" then formattedStat = string.format("[[%s]]", formattedStat) end
local class = "stat-" .. (statDetail.Stat_Color or "default")
return string.format('<p class="%s">%s</p>', class, formattedStat)
end
function p.formatRange(min, max)
if max and max ~= '' and max ~= min then
return "[" .. min .. "-" .. max .. "]"
else
return min
end
end
function p.getTableHeader(itemType)
if p.isArmorType(itemType) and itemType ~= 'Shield' then
return "<tr><th>Item</th><th data-sort-type='number'>Tier</th><th data-sort-type='number' class='nomobile'>Level</th><th data-sort-type='number' class='nomobile'>Defense</th><th class='unsortable'>Stats</th></tr>"
elseif itemType == 'Shield' then
return "<tr><th>Item</th><th data-sort-type='number'>Tier</th><th data-sort-type='number' class='nomobile'>Level</th><th data-sort-type='number' class='nomobile'>Defense</th><th data-sort-type='number' class='nomobile'>Block</th><th class='unsortable'>Stats</th></tr>"
elseif p.isWeaponType(itemType) then
return "<tr><th>Item</th><th data-sort-type='number'>Tier</th><th data-sort-type='number' class='nomobile'>Level</th><th data-sort-type='number' class='nomobile'>Damage</th><th data-sort-type='number' class='nomobile'>APS</th><th data-sort-type='number' class='nomobile'>DPS</th><th class='unsortable'>Stats</th></tr>"
elseif p.isRingOrAmulet(itemType) then
return "<tr><th>Item</th><th data-sort-type='number'>Tier</th><th data-sort-type='number' class='nomobile'>Level</th><th class='unsortable'>Stats</th></tr>"
else
return "<tr><th>Item</th><th data-sort-type='number'>Tier</th><th data-sort-type='number' class='nomobile'>Level</th><th class='unsortable'>Stats</th></tr>"
end
end
-- Display all staff items with their stats in a formatted table
function p.displayItemType(frame)
local itemType = frame.args[1]
local itemRarity = frame.args[2] or '';
--local header
--if itemRarity and itemRarity ~= '' then
--header = itemRarity
--else
--header = itemType
--end
--local itemType = "Shield"
--local itemRarity = "Satanic"
local items = p.fetchItemsOfTypeAndRarity(itemType, itemRarity)
local formatMap = p.fetchFormatDetails()
local output = {}
local headerSet = false
local tierSortOrder = p.getTiers()
if #items == 0 then
return ""
end
for _, item in ipairs(items) do
if not headerSet then
--table.insert(output, string.format("\n== %ss ==\n", header))
table.insert(output, "<table class='wikitable sortable'>" .. p.getTableHeader(item.Item_Type))
headerSet = true
end
local tierValue = tierSortOrder[item.Item_Tier] or 0
local stats = p.fetchItemStats(item.Item_Name)
local statLines = {}
local defense, block, damage, aps, dps = 'N/A', 'N/A', 'N/A', 'N/A', 'N/A'
local minRangeAS, maxRangeAS, medianAS, minRangeED, maxRangeED, medianED, minRangeDPS, maxRangeDPS, medianDPS, minDamage, maxDamage, minAttackSpeed, maxAttackSpeed = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
for _, stat in ipairs(stats) do
if stat.Stat_ID == 'enhanced_defense_percent' or stat.Stat_ID == "enhanced_defense_based_on_level_percent" or stat.Stat_ID == 'enhanced_dmg_percent' or stat.Stat_ID == "enhanced_dmg_based_on_level_percent" then
minRangeED = tonumber(stat.Min_Value1) + minRangeED
maxRangeED = tonumber(stat.Max_Value1) or tonumber(stat.Min_Value1) + maxRangeED
elseif stat.Stat_ID == 'attack_speed_percent' then
minRangeAS = tonumber(stat.Min_Value1)
maxRangeAS = tonumber(stat.Max_Value1) or tonumber(stat.Min_Value1)
end
end
table.insert(statLines, '<div class="item-list item-stats">')
for _, stat in ipairs(stats) do
if stat.Stat_ID == 'attack_dmg_base' or stat.Stat_ID == 'attacks_per_second_base' or stat.Stat_ID == 'defense_base' or stat.Stat_ID == 'block_chance_base' then
if stat.Stat_ID == 'defense_base' and stat.Max_Value1 ~= nil then
local minDefense = tonumber(stat.Min_Value1) * (1 + minRangeED/100)
local maxDefense = tonumber(stat.Max_Value1) * (1 + maxRangeED/100)
medianDefense = (minDefense + maxDefense) / 2 -- Calculate the median value.
defense = string.format('<span style="display:none;">%.2f</span>%s-%s', medianDefense, math.ceil(minDefense), math.ceil(maxDefense))
elseif stat.Stat_ID == 'defense_base' and stat.Max_Value1 == nil then
local minDefense = tonumber(stat.Min_Value1) * (1 + minRangeED/100)
local maxDefense = tonumber(stat.Min_Value1) * (1 + maxRangeED/100)
medianDefense = (minDefense + maxDefense) / 2 -- Calculate the median value.
defense = string.format('<span style="display:none;">%.2f</span>%s-%s', medianDefense, math.ceil(minDefense), math.ceil(maxDefense))
elseif stat.Stat_ID == 'block_chance_base' then
block = string.format('%s', stat.Min_Value1)
end
if stat.Stat_ID == 'attack_dmg_base' then
minDamage = tonumber(stat.Min_Value1) * (1 + minRangeED/100)
maxDamage = tonumber(stat.Max_Value1) * (1 + maxRangeED/100)
medianDamage = (minDamage + maxDamage) / 2 -- Calculate the median value.
damage = string.format('<span style="display:none;">%.2f</span>%s-%s', medianDamage, math.ceil(minDamage), math.ceil(maxDamage))
elseif stat.Stat_ID == 'attacks_per_second_base' then
minAttackSpeed = (tonumber(stat.Min_Value1) * (1 + minRangeAS/100)) * 100
minAttackSpeed = math.floor(minAttackSpeed)
minAttackSpeed = minAttackSpeed / 100
maxAttackSpeed = (tonumber(stat.Min_Value1) * (1 + maxRangeAS/100)) * 100
maxAttackSpeed = math.floor(maxAttackSpeed)
maxAttackSpeed = maxAttackSpeed / 100
medianAttackSpeed = (minAttackSpeed + maxAttackSpeed) / 2 -- Calculate the median value.
if minAttackSpeed == maxAttackSpeed then
aps = string.format('<span style="display:none;">%.2f</span>%s', medianAttackSpeed, minAttackSpeed)
else
aps = string.format('<span style="display:none;">%.2f</span>%s-%s', medianAttackSpeed, minAttackSpeed, maxAttackSpeed)
end
end
elseif stat.Stat_ID == 'socketed_flat' then
if stat.Max_Value1 and stat.Max_Value1 ~= "" then
table.insert(statLines, string.format('<p class="stat-default">Socketed (%s-%s)</p>', stat.Min_Value1, stat.Max_Value1))
else
table.insert(statLines, string.format('<p class="stat-default">Socketed (%s)</p>', stat.Min_Value1))
end
else
table.insert(statLines, p.formatStatLine(stat, formatMap))
end
end
if aps ~= 'N/A' and damage ~= 'N/A' then
minRangeDPS = math.ceil(minDamage * minAttackSpeed)
maxRangeDPS = math.ceil(maxDamage * maxAttackSpeed)
medianDPS = (minRangeDPS + maxRangeDPS) / 2
dps = string.format('<span style="display:none;">%.2f</span>%s-%s', medianDPS, minRangeDPS, maxRangeDPS)
end
if item.Item_Type == "Potion" then table.insert(statLines, string.format('<p class="item-lore">%s</p>', item.Item_Lore)) end
table.insert(statLines, '</div>')
if p.isArmorType(item.Item_Type) and item.Item_Type ~= 'Shield' then
table.insert(output, string.format("<tr><td style='width:150px'><div class='item-col %s'>[[%s]][[File:%s|link=%s]]</div></td><td style='width: 75px; text-align:center' class='tier-%s' data-sort-value='%d'>%s</td><td style='width: 75px;text-align:center' class='nomobile'>%s</td><td style='width:100px;text-align:center' class='nomobile'>%s</td><td style='width:400px;text-align:center'>%s</td></tr>",
itemRarity,
item.Item_Name,
cfg.imageFormat(item.Item_Type, item.Item_Name),
item.Item_Name,
item.Item_Tier,
tierValue,
item.Item_Tier,
item.Item_Level_Requirement,
defense,
table.concat(statLines)))
elseif item.Item_Type == 'Shield' then
table.insert(output, string.format("<tr><td style='width:150px'><div class='item-col %s'>[[%s]][[File:%s|link=%s]]</div></td><td style='width: 75px; text-align:center' class='tier-%s' data-sort-value='%d'>%s</td><td style='width: 75px;text-align:center' class='nomobile'>%s</td><td style='width:100px;text-align:center' class='nomobile'>%s</td><td style='width:100px;text-align:center' class='nomobile'>%s</td><td style='width:400px;text-align:center'>%s</td></tr>",
itemRarity,
item.Item_Name,
cfg.imageFormat(item.Item_Type, item.Item_Name),
item.Item_Name,
item.Item_Tier,
tierValue,
item.Item_Tier,
item.Item_Level_Requirement,
defense,
block,
table.concat(statLines)))
elseif p.isWeaponType(item.Item_Type) then
table.insert(output, string.format("<tr><td style='width:150px'><div class='item-col %s'>[[%s]][[File:%s|link=%s]]</div></td><td style='width: 75px; text-align:center' class='tier-%s' data-sort-value='%d'>%s</td><td style='width: 75px;text-align:center' class='nomobile'>%s</td><td style='width:100px;text-align:center' class='nomobile'>%s</td><td style='width:100px;text-align:center' class='nomobile'>%s</td><td style='width:100px;text-align:center' class='nomobile'>%s</td><td style='width:400px;text-align:center'>%s</td></tr>",
itemRarity,
item.Item_Name,
cfg.imageFormat(item.Item_Type, item.Item_Name),
item.Item_Name,
item.Item_Tier,
tierValue or "",
item.Item_Tier or "",
item.Item_Level_Requirement or "",
damage or "",
aps or "",
dps or "",
table.concat(statLines)))
elseif p.isRingOrAmulet(item.Item_Type) then
table.insert(output, string.format("<tr><td style='width:150px'><div class='item-col %s'>[[%s]][[File:%s|link=%s]]</div></td><td style='width: 75px; text-align:center' class='tier-%s' data-sort-value='%d'>%s</td><td style='width: 75px;text-align:center' class='nomobile'>%s</td><td style='width:400px;text-align:center'>%s</td></tr>",
itemRarity,
item.Item_Name,
cfg.imageFormat(item.Item_Type, item.Item_Name),
item.Item_Name,
item.Item_Tier,
tierValue or "",
item.Item_Tier or "",
item.Item_Level_Requirement or "",
table.concat(statLines)))
elseif item.Item_Type == "Charm" or item.Item_Type == "Rune" or item.Item_Type == "Jewel" or item.Item_Type == "Gem" then
table.insert(output, string.format("<tr><td style='width:150px'><div class='item-col %s'>[[%s]][[File:%s|link=%s]]</div></td><td style='width: 75px; text-align:center' class='tier-%s' data-sort-value='%d'>%s</td><td style='width: 75px;text-align:center' class='nomobile'>%s</td><td style='width:400px;text-align:center'>%s</td></tr>",
itemRarity,
item.Item_Name,
cfg.imageFormat(item.Item_Type, item.Item_Name),
item.Item_Name,
item.Item_Tier,
tierValue or "",
item.Item_Tier or "",
item.Item_Level_Requirement or "",
table.concat(statLines)))
elseif item.Item_Type == "Potion" then
table.insert(output, string.format("<tr><td style='width:150px'><div class='item-col %s'>[[%s]][[File:%s|link=%s]]</div></td><td style='width: 75px; text-align:center' class='tier-%s' data-sort-value='%d'>%s</td><td style='width: 75px;text-align:center' class='nomobile'>%s</td><td style='width:400px;text-align:center'>%s</td></tr>",
itemRarity,
item.Item_Name,
cfg.imageFormat(item.Item_Type, item.Item_Name),
item.Item_Name,
item.Item_Tier,
tierValue or "",
item.Item_Tier or "",
item.Item_Level_Requirement or "",
table.concat(statLines)))
end
end
table.insert(output, "</table>")
return table.concat(output)
end
function p.extractRange(range)
local minRange, maxRange = string.match(range, "(%d+)-(%d+)")
minRange = tonumber(minRange)
maxRange = tonumber(maxRange)
return minRange, maxRange
end
function p.getTiers()
local tierSortOrder = {
SS = 6,
S = 5,
A = 4,
B = 3,
C = 2,
D = 1
}
return tierSortOrder
end
function p.decodeHTML(itemName)
itemName = itemName:gsub("'", "'")
itemName = itemName:gsub("'", "'")
itemName = itemName:gsub("&", "&")
return itemName
end
function p.encodeName(itemName)
local decoded = p.decodeHTML(itemName)
local encodedItemName = decoded:gsub("'", "''")
return encodedItemName
end
function p.isWeaponType(itemType)
local weaponTypes = {
Sword = true,
Dagger = true,
Mace = true,
Axe = true,
Claw = true,
Polearm = true,
Chainsaw = true,
Staff = true,
Cane = true,
Wand = true,
Book = true,
Spellblade = true,
Bow = true,
Gun = true,
Flask = true,
["Throwing Weapon"] = true }
return weaponTypes[itemType] or false
end
function p.isArmorType(itemType)
local armorTypes = {
Helmet = true,
["Body Armor"] = true,
Gloves = true,
Belt = true,
Boots = true,
Shield = true,
}
return armorTypes[itemType] or false
end
function p.isRingOrAmulet(itemType)
local ringOrAmulet = {
Amulet = true,
Ring = true,
}
return ringOrAmulet[itemType] or false
end
function p.isCharmOrRune(itemType)
local isCharmOrRune = {
Charm = true,
Rune = true
}
return isCharmOrRune[itemType] or false
end
function p.isMiscType(itemType)
local miscTypes = {
Consumable = true,
Potion = true,
Key = true,
Material = true,
Collectible = true
}
return miscTypes[itemType] or false
end
return p