Module:Sandbox/Sorbasi
Intended for use by #invoke'ing inside Template:Item.
Automatic generation of standard parts of an Item page based on api data.
Defaults to the invoking page's Title as the item name, which can be overridden with the named parameter `source` in either the invoking template or the direct invocation.
Exposed functions are:
`ItemPage` - Attempts to do everything. Has the additional params skip_lore, skip_desc, manual_lore, manual_desc, manual_navbox, obtaining, usage, skins, trivia, see_also.
`InfoBox` - Populates and invokes Template:Item/InfoBox using json data looked up based on api name.
`ItemPageCategories` - Generates page categories for an item page. If passed the named parameter `test` outputs a comma separated list instead of category links. If passed the named parameters `source` or `source2` will override/merge item values. Will automatically add effects from the highest masterwork level of an item when it differs, if source2 is not supplied.
`ItemPageIntro` - Outputs the combined results of `getLoreStyled` and/or `getItemDesc`
`getLore` - Returns the item's lore, if any, unformatted.
`getLoreStyled` - Returns the result of Template:ItemLore with the item's lore, if any.
`getItemDesc` - Returns the result of Template:ItemDesc populate with the item's api data. Supports overrides via the named parameters `desc_name`/`desc_plural`/ `desc_proper`.
Depends on item stats converting data at [[./Tables]], and conditionally upon consumable effects data at [[./Effects]] and masterworking cost data at [[./Masterworking]]
Pulls data from itemized pages living under Monumenta_Wiki:API/Items. These are intended to be parsed and uploaded automatically by a bot from the official api json.
local p = {}
local DATA_BASE = 'Monumenta_Wiki:API/Items/'
local MAX_MASTERWORK = 4
local tables = mw.loadData('Module:Sandbox/Sorbasi/tables')
local data
local effects
local mwdata
function maybeLoadEffects()
if not effects then
effects = mw.loadData('Module:Sandbox/Sorbasi/Effects')
end
end
function maybeLoadMasterworking()
if not mwdata then
mwdata = mw.loadData('Module:Sandbox/Sorbasi/Masterworking')
end
end
function is_singleton_enchantment(v)
if tables.enchantment_singletons[string.lower(v)] then
return true
end
return false
end
function loadSourceByItemName(n)
data = mw.loadJsonData(DATA_BASE .. n)
end
function loadSourceByFrameContent(frame)
local frameParent = frame:getParent()
loadSourceByItemName(frame.args.source or frameParent.args.source or frameParent:getTitle())
end
function p.getLore(frame)
local frameParent = frame:getParent()
loadSourceByFrameContent(frame)
return data.lore
end
function p.getLoreStyled(frame)
local lore = p.getLore(frame)
return lore and "<p>" .. frame:expandTemplate{ title = 'ItemLore', args = {lore} } .. "</p>" or ""
end
function p.getItemDesc(frame)
local frameParent = frame:getParent()
loadSourceByFrameContent(frame)
local source2 = frame.args.source2 or frameParent.args.source2 or nil
local nameOverride = frame.args.desc_name or frameParent.args.desc_name or data.name or nil
local plural = frame.args.desc_plural or frameParent.args.desc_plural or nil
local proper = frame.args.desc_proper or frameParent.args.desc_proper or nil
local typeOverride = data.type
local wand = false
local typeSecond = nil
local articleSecond = "a"
if source2 then
local dd = mw.loadJsonData(DATA_BASE .. source2)
typeSecond = dd.type
if string.sub(typeSecond, 1, 1) == "O" then articleSecond = "an" end
if typeSecond == "Wand" then
wand = true
if dd.base_item == "Shield" then
typeSecond = "Mainhand Shield"
elseif string.find(dd.base_item, "Sword", 1, true) then
typeSecond = "Mainhand Sword"
elseif string.find(dd.base_item, "Axe", 1, true) then
typeSecond = "Axe"
end
end
end
if typeOverride == "Wand" then
wand = true
if data.base_item == "Shield" then
typeOverride = "Mainhand Shield"
elseif string.find(data.base_item, "Sword", 1, true) then
typeOverride = "Mainhand Sword"
elseif string.find(data.base_item, "Axe", 1, true) then
typeOverride = "Axe"
end
end
--{{ItemDesc|item_type|tier|location|name|plural|proper_noun}}
local desc = frame:expandTemplate{ title = 'ItemDesc', args = {typeOverride or nil, data.tier or nil, data.region or nil, nameOverride or nil, plural or nil, proper or "true"} }
if wand and source2 and typeSecond ~= typeOverride then
return desc .. " It can also function as ".. articleSecond .." [[" .. typeSecond .. "s|" .. string.lower(typeSecond) .. "]] and a [[Wands|wand]]."
elseif source2 and typeSecond ~= typeOverride then
return desc .. " It can also function as ".. articleSecond .." [[" .. typeSecond .. "s|" .. string.lower(typeSecond) .. "]]."
elseif wand and typeOverride ~= "Wand" then
return desc .. " It can also function as a [[Wands|wand]]."
else
return desc
end
end
-- this uppercasing logic is premised on stackoverflow answers at https://stackoverflow.com/questions/2421695/first-character-uppercase-lua
function statToNiceName(s)
local t = {}
for ss in string.gmatch(s, "([^_ ]+)") do
-- gsub actually returns an expanded value list, so parens pretend only the first value exists
table.insert(t, (string.gsub(ss, "^%l", string.upper)))
end
return table.concat(t, " ")
end
function numToSigned(n)
if n > 0 then return "+" .. tostring(n) end
return tostring(n)
end
function numToSignedPercent(n)
if n < 0 then
return tostring(n * 100) .. "%"
else
return "+" .. tostring(n * 100) .. "%"
end
end
function romanNumeral(n, frame)
return frame:expandTemplate{ title = 'RomanNumeral', args = {n} }
end
-- this function is evidence of the damage writing lua has done to my mind
function ticksToHuman(x)
if not x or x == 1 then
return ""
elseif x == -1 then
return "∞"
else
local seconds = x / 20
local minutes = math.floor(seconds / 60)
local hours = tostring(math.floor(minutes / 60))
seconds = string.format("%02d", seconds % 60)
if hours ~= "0" then
return hours .. ":" .. string.format("%02d", minutes) .. ":" .. seconds
elseif minutes then
return tostring(minutes) .. ":" .. seconds
end
end
end
function getName()
return tostring(data.name) or tostring(data.base_item) or 'Unknown Item'
end
function getBaseItem()
return tostring(data.base_item) or ''
end
--assuming this and tier and region lookups remain needed, should probably split into helper modules for readability and simplified maintenance
function locationNameFromShort(r)
return tables.locationShortToLong[string.lower(r)] or r
end
function regionNameFromShort(r)
return tables.regionShortToLong[string.lower(r)] or "Unknown Region"
end
function getRegion()
return regionNameFromShort(tostring(data.region) or '')
end
function getTier()
return tostring(data.tier) or 'Unknown'
end
--api gives dummy item groups for items that dont actually have one
function getLocation()
return data.location and data.location ~= '' and not tables.regionLongToShort[data.location] and tostring(data.location) or nil
end
-- these are currently unsafe. need to validate for html insertion
function getTierStyled()
local tier = getTier()
return '<span class="tier_' .. string.lower(tier) .. '">' .. tier .. '</span>'
end
function getLocationStyled()
local loc = getLocation()
return '<span class="loc_' .. string.lower(loc) .. '">' .. locationNameFromShort(loc) .. '</span>'
end
function getSlotFromType(t)
return tostring(tables.equipSlotFromType[t or data.type]) or 'Misc'
end
function getWearString(t)
return tostring(tables.usageStringFromSlot[getSlotFromType(t or nil)]) or "When properly contemplated:"
end
function p.ItemPageIntro(frame)
return p.getLoreStyled(frame) .. "<p>" .. p.getItemDesc(frame) .. "</p>"
end
function p.ItemPageCategories(frame)
local frameParent = frame:getParent()
if frameParent.args.catname then loadSourceByItemName(frameParent.args.catname)
else loadSourceByFrameContent(frame) end
local c = {}
table.insert(c, "Items")
local source2 = frame.args.source2 or frameParent.args.source2 or nil
local source2_type = nil
local source2_consumable = nil
local source2_wand = nil
-- this specifically breaks on its own for something like truest north where the base rank doesnt have a disambig but later ranks do
if source2 == nil and data.masterwork and data.masterwork ~= MAX_MASTERWORK then source2 = data.name .. "-" .. tostring(MAX_MASTERWORK) end
-- we accidentally shadowed the global effects table here but it doesnt matter since it's not directly used in this function
local effects = nil
local stats = nil
if data.effects then
effects = {}
for k,v in pairs(data.effects) do effects[getEffectName(v)] = true end
end
if data.stats then
stats = {}
for k,v in pairs(data.stats) do stats[k] = true end
end
if source2 then
local dd = mw.loadJsonData(DATA_BASE .. source2)
source2_type = dd.type
if source2_type == "Wand" then
source2_wand = true
if string.find(dd.base_item, "sword") then source2_type = "Mainhand Sword"
elseif string.find(dd.base_item, "shield") then source2_type = "Mainhand Shield"
elseif string.find(dd.base_item, "axe") then source2_type = "Axe"
end
end
if dd.effects then
source2_consumable = true
if effects == nil then effects = {} end
for k,v in pairs(dd.effects) do effects[getEffectName(v)] = true end
end
if dd.stats then
if stats == nil then stats = {} end
for k,v in pairs(dd.stats) do stats[k] = true end
end
end
if data.type == "Consumable" or effects or source2_consumable then table.insert(c, "Consumable Items") end
if effects then
for k,v in pairs(effects) do
table.insert(c, "Consumable Items with " .. k)
end
end
if data.class_name then table.insert(c, tostring(data.class_name) .. " Charms") end
if getLocation() then table.insert(c, locationNameFromShort(getLocation()) .. " Items") end
if data.power then table.insert(c, tostring(data.power) .. " Power Charms") end
if data.region then
table.insert(c, getRegion() .. " Items")
if data.tier then
table.insert(c, getRegion() .. " " .. getTier() .. " Items")
end
local slot = getSlotFromType()
local base = string.lower(tostring(data.base_item))
local special = ""
if data.type == "Wand" then
if string.find(base, "sword") then special = "Sword"
elseif string.find(base, "shield") then special = "Shield"
elseif string.find(base, "axe") then special = "Axe"
end
end
if effects and data.type ~= "Consumable" then
table.insert(c, getRegion() .. " Consumable Items")
end
table.insert(c, getRegion() .. " " .. tostring(data.type) .. " Items")
if data.type ~= "Wand" and source2_wand then
table.insert(c, getRegion() .. " Wand Items")
end
if data.type ~= "Charm" and (special ~= "" or source2_type) then
if special == "Axe" or source2_type == "Axe" then table.insert(c, getRegion() .. " Axe Items") end
if special ~= "Axe" then table.insert(c, getRegion() .. " " .. slot .. " " .. special .. " Items") end
if source2_type and source2_type ~= "Axe" then table.insert(c, getRegion() .. " " .. source2_type .. " Items") end
end
end
if data.type ~= "Charm" then
for k,v in pairs(stats) do
local p = string.find(k, "_flat") or string.find(k, "_percent") or string.find(k, "_base")
local name = string.sub(k, 1, (p or #k + 1) - 1)
local op = string.sub(k, (p or #k) + 1)
if op ~= "base" then
table.insert(c, "Items with " .. statToNiceName(name))
elseif name == "throw_rate" then
table.insert(c, "Thrown Items")
end
end
end
if frame.args.test or frameParent.args.test then return table.concat(c, ",")
else return "[[Category:" .. table.concat(c, "]][[Category:") .. "]]" end
end
function getEffectName(v)
maybeLoadEffects()
local effectFormat = effects.effects[string.lower(v.EffectType)] or {l=v.EffectType, t=""}
local name = effectFormat.l
return name
end
function getEffectDisplay(v, frame)
maybeLoadEffects()
local effectFormat = effects.effects[string.lower(v.EffectType)] or {l=v.EffectType, t=""}
local nameLink = effectFormat.l
local nameDisplay = nameLink
local style = nil
local strength = tonumber(v.EffectStrength)
local strengthDisplay = ""
local durationDisplay = ticksToHuman(v.EffectDuration)
if durationDisplay then
durationDisplay = " (" .. durationDisplay .. ")"
end
if effects.mirror[string.lower(v.EffectType)] then
strength = strength * -1
nameLink = effectFormat.l
nameDisplay = effects.mirror[string.lower(v.EffectType)]
style = "<span class=\"malus\" style=\"color:#b94e48;\">"
else
nameDisplay = effectFormat.l
end
if effectFormat.t == "single" then
--strengthDisplay = ""
elseif effectFormat.t == "percent" or (tonumber(v.EffectStrength) ~= math.floor(tonumber(v.EffectStrength)) and (effectFormat.t == "" or not effectFormat.t)) then
strengthDisplay = numToSignedPercent(strength) .. " "
else
--strengthDisplay = ""
nameDisplay = nameDisplay .. " " .. romanNumeral(v.EffectStrength, frame)
end
return (style or "") .. strengthDisplay .. "[[" .. nameLink .. "|" .. nameDisplay .. "]]" .. durationDisplay .. (style and "</span>" or "")
end
function InfoBoxEffects(frame)
if not data.effects then
return nil
end
local result = {}
for k,v in pairs(data.effects) do
table.insert(result, getEffectDisplay(v, frame))
end
return #table and table.concat(result, "<br>") or nil;
end
function InfoBoxRegion()
-- awkwardly complex preprocessing for the "region" block per ingame
-- misleading name describes way more than the region
local result = {}
if data.tier then
table.insert(result, getRegion() .. ' : ' .. getTierStyled())
end
if tostring(data.type) == "Charm" then
table.insert(result, "Charm Power : " .. string.rep("★", data.power) .. " " .. tostring(data.class_name) )
end
if data.masterwork then
table.insert(result, "Masterwork : " .. mwstars(data.masterwork))
end
if getLocation() then
table.insert(result, getLocationStyled())
end
return table.concat(result, "<br>\n")
end
-- key, value, positionOfOperandSplit
function DescribeAttribute(k, v, p)
local name = string.sub(k, 1, p - 1)
local operand = string.sub(k, p + 1)
local nicename = statToNiceName(name)
if operand == "percent" then
return numToSigned(v) .. "% " .. nicename
elseif operand == "base" then
if k == "spell_power_base" then
return tostring(v) .. "% " .. nicename
else
return tostring(v) .. " " .. nicename
end
else
return numToSigned(v) .. " " .. nicename
end
end
--unsmush into cursed duplicate code for items that have multiple valid slots
function SecondaryAttributes(name)
local dd = mw.loadJsonData(DATA_BASE .. name)
-- heckin truest north
if dd.type == data.type then return "" end
-- *inhales*
local description = {}
table.insert(description, getWearString(dd.type))
local actuallyHasAttributes = false
for k,v in pairs(dd.stats) do
-- can this be a single find? first attempt to silently failed
local is_attribute = string.find(k, "_flat") or string.find(k, "_percent") or string.find(k, "_base")
if k == "armor" or k == "agility" then
is_attribute = #k + 1
end
if is_attribute ~= nil then
actuallyHasAttributes = true
table.insert(description, DescribeAttribute(k, v, is_attribute))
end
end
return table.concat(description, '<br>')
end
--smush these into a single for loop
function InfoBoxStats(frame)
local frameParent = frame:getParent()
local describeEnchantments = {}
local describeAttributes = {}
local secondary = ""
if frame.args.source2 or frameParent.args.source2 then
secondary = SecondaryAttributes(frame.args.source2 or frameParent.args.source2)
end
-- why are lua tables so jank
local actuallyHasAttributes = false
table.insert(describeAttributes, getWearString())
for k,v in pairs(data.stats) do
-- can this be a single find? first attempt to silently failed
local is_attribute = string.find(k, "_flat") or string.find(k, "_percent") or string.find(k, "_base")
if k == "armor" or k == "agility" then
is_attribute = #k + 1
end
if is_attribute == nil then
local n = statToNiceName(k)
if is_singleton_enchantment(n) then
table.insert(describeEnchantments, "[[" .. n .. "]]")
else
table.insert(describeEnchantments, "[[" .. n .. "|" .. n .. " " .. romanNumeral(v, frame) .. "]]")
end
else
actuallyHasAttributes = true
table.insert(describeAttributes, DescribeAttribute(k, v, is_attribute))
end
end
local attr = ""
if actuallyHasAttributes and #secondary > 1 then
attr = table.concat(describeAttributes, '<br>') .. "<br>" .. secondary
elseif actuallyHasAttributes then
attr = table.concat(describeAttributes, '<br>')
elseif #secondary > 1 then
attr = secondary
end
return table.concat(describeEnchantments, '<br>'), attr
end
function mwcost(frame, t, i)
maybeLoadMasterworking()
-- why was unpack only giving us nil values it had one job
local location = mwdata.locations[string.lower(t)] or {}
local ctype, mat, anim, abbrev = location[1], location[2], location[3], location[4]
ctype = ctype or t
local tier = (mwdata.costs[ctype] and mwdata.costs[ctype][i]) or {}
local mats, har, pdia = tier[1], tier[2], tier[3]
if frame.args.test2 then
return tostring(mats) .. " " .. (mat or "nil") .. " + " .. tostring(har) .. " HAR" .. ((pdia and " + " .. tostring(pdia) .. " P. Dia") or "")
end
return tostring(mats) .. " " .. frame:expandTemplate{ title = 'Mini', args = {mat, anim or nil, abbrev or nil} } .. " + " .. tostring(har) .. " " .. frame:expandTemplate{ title = 'Mini', args = {"Hyperchromatic Archos Ring", nil, "HAR"} } .. (pdia and (" + " .. tostring(pdia) .. " " .. frame:expandTemplate{ title = 'Mini', args = {"Pulsating Diamond", nil, "P. Dia"} }) or "")
end
function mwstars(x)
-- TODO remove explicit color when wiki stylesheets get values
return "<span class=\"mwbright\" style=\"color:#EF9E23;\">" .. string.rep("★", x) .. "</span><span class=\"mwdull\" style=\"color:#7A7A7A;\">" .. string.rep("☆", MAX_MASTERWORK - x) .. "</span>"
end
--this can be made inline as seen elsewhere in the script i just didnt know how at the time
--use pcall to suppress load errors so we dont need to be explicitly told anything
--if this causes issues rework to have an explicit %start% arg
--https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#pcall
function pcalledLoadItem(name)
return (mw.loadJsonData(DATA_BASE .. name))
end
-- send help the code keeps duplicating
function mwnumberformatter(k, v)
local prefix = ""
local suffix = ""
local singleton = is_singleton_enchantment(k)
local value = (is_singleton_enchantment(k) and v > 0 and "✓") or (v ~= 0 and tostring(v)) or "✗"
if k == "armor" or k == "agility" or string.find(k, "_flat") or string.find(k, "_percent") then
if v > 0 then prefix = "+"
else prefix = "-" end
end
if k == "spell_power_base" or string.find(k, "_percent") then
suffix = "%"
end
return prefix .. value .. suffix
end
function p.MWTable(frame)
maybeLoadMasterworking()
local frameParent = frame:getParent()
loadSourceByFrameContent(frame)
local source = frame.args.source or frameParent.args.source or frameParent:getTitle()
local name = data.name
local disambig = frame.args.mwdisambig or frameParent.args.mwdisambig or nil
if disambig == nil and source ~= name .. "-" .. data.masterwork then
disambig = string.sub(source, string.len(name .. "-" .. data.masterwork) + 1)
end
if disambig and string.sub(disambig, 1, 1) ~= " " then disambig = " " .. disambig end
--tfw mandatory overrides
--this set should only be needed for items with nonstandard cost progressions
--like truest north or the miniquest things
local costs = {
frame.args.mwc0 or frameParent.args.mwc0 or nil,
frame.args.mwc1 or frameParent.args.mwc1 or nil,
frame.args.mwc2 or frameParent.args.mwc2 or nil,
frame.args.mwc3 or frameParent.args.mwc3 or nil,
frame.args.mwc4 or frameParent.args.mwc4 or nil,
frame.args.mwc5 or frameParent.args.mwc5 or nil,
frame.args.mwc6 or frameParent.args.mwc6 or nil,
frame.args.mwc7 or frameParent.args.mwc7 or nil,
}
--ideally this set never gets used
--but it does because redirects cant spot fix for multitools being wack
local names = {
frame.args.mwn0 or frameParent.args.mwn0 or nil,
frame.args.mwn1 or frameParent.args.mwn1 or nil,
frame.args.mwn2 or frameParent.args.mwn2 or nil,
frame.args.mwn3 or frameParent.args.mwn3 or nil,
frame.args.mwn4 or frameParent.args.mwn4 or nil,
frame.args.mwn5 or frameParent.args.mwn5 or nil,
frame.args.mwn6 or frameParent.args.mwn6 or nil,
frame.args.mwn7 or frameParent.args.mwn7 or nil,
}
local result = {}
-- mw level / .. stats .. / cost
local table_width = 2
local stat_cols = {}
local dd = {}
local base_mw = nil
local location = ""
if frame.args.test3 then
local t = {}
for i=0,MAX_MASTERWORK do t[i] = names[i+1] or (name .. "-" .. tostring(i) .. (disambig or "")) end
return mw.text.jsonEncode(t, mw.text.JSON_PRETTY)
end
--awkward that lua array functions assume base index 1
--because masterworks, like sane arrays, are base index 0
for i=0,MAX_MASTERWORK do
local success, d = pcall(pcalledLoadItem, names[i+1] or (name .. "-" .. tostring(i) .. (disambig or "")))
dd[i] = success and d and d.stats or false
if base_mw == nil and success then
base_mw = i
location = d.location or ""
end
end
-- the line of confused debugging
if frame.args.test4 then return mw.text.jsonEncode(dd, mw.text.JSON_PRETTY) end
table.insert(result, "{| class=\"wikitable\"\n!Masterwork Level")
--something to guarantee we're outputting each row's stats in the same order
--originally was just the order of stats in the highest mw version's api entry
--greenfrog asked for enchants before attributes
--split bins to clump columns with
local bin_ench = {}
local bin_attr = {}
if dd[MAX_MASTERWORK] then
for k,v in pairs(dd[MAX_MASTERWORK]) do
if not mwdata.hidden[k] then
if k == "armor" or k == "agility" or string.find(k, "_flat") or string.find(k, "_percent") or string.find(k, "_base") then
bin_attr[#bin_attr + 1] = k
else
bin_ench[#bin_ench + 1] = k
end
end
end
--awkward reversed pair naming and duplicate loops
for v,k in pairs(bin_ench) do
stat_cols[table_width] = k
table_width = table_width + 1
table.insert(result, "!"..(mwdata.headings[k] or statToNiceName(k)))
end
for v,k in pairs(bin_attr) do
stat_cols[table_width] = k
table_width = table_width + 1
table.insert(result, "!"..(mwdata.headings[k] or statToNiceName(k)))
end
table.insert(result, "!Cost")
end
for i=0,MAX_MASTERWORK do
table.insert(result, "|-\n|"..mwstars(i))
if dd[i] then
for k=2,table_width-1 do
local v = dd[i][stat_cols[k]] or 0
local dv = nil
local dvp = ""
if i ~= base_mw then
dv = v - (dd[i - 1][stat_cols[k]] or 0)
dv = dv > 0 and mwnumberformatter(stat_cols[k], dv) or nil
if dv and string.sub(dv, 1, 1) ~= "+" and string.sub(dv, 1, 1) ~= "-" then dvp = "+" end
end
v = mwnumberformatter(stat_cols[k], v)
if dv then
table.insert(result, "| " .. v .. " <span class=\"mwup\" style=\"color:#e6c100;\">(" .. dvp .. dv .. ")</span>")
else
table.insert(result, "| " .. v)
end
end
if i == base_mw then table.insert(result, "|Base Masterwork Level") else
table.insert(result, "|" .. (frame.args.test2 and (tostring(i) .. location) or "") .. (costs[i+1] or mwcost(frame, location, i) or "Unspecified Cost"))
end
end
end
table.insert(result, "|}")
return table.concat(result, "\n")
end
-- hopefully this is an improvement from invoking per infobox input
function p.InfoBox(frame)
loadSourceByFrameContent(frame)
local enchantments, attributes = InfoBoxStats(frame)
return frame:expandTemplate{ title = 'Item/InfoBox', args = {
name = getName(),
image = frame:getParent().args.image or "ItemTexture" .. getName() .. ".png",
type = getBaseItem(),
region = InfoBoxRegion(),
effects = InfoBoxEffects(frame),
enchantments = enchantments,
attributes = attributes
} }
end
function p.ItemPage(frame)
loadSourceByFrameContent(frame)
local frameParent = frame:getParent()
local result = {}
local skip_lore = frame.args.skip_lore or frameParent.args.skip_lore or nil
local skip_desc = frame.args.skip_desc or frameParent.args.skip_desc or nil
local manual_lore = frame.args.manual_lore or frameParent.args.manual_lore or nil
local manual_desc = frame.args.manual_desc or frameParent.args.manual_desc or nil
local manual_navbox = frame.args.manual_navbox or frameParent.args.manual_navbox or nil
local obtaining = frame.args.obtaining or frameParent.args.obtaining or nil
local usage = frame.args.usage or frameParent.args.usage or nil
local skins = frame.args.skins or frameParent.args.skins or nil
local trivia = frame.args.trivia or frameParent.args.trivia or nil
local see_also = frame.args.see_also or frameParent.args.see_also or nil
local exalted = (string.find(frameParent:getTitle(), "EX ", 1, true) and data.region == "Ring" and true) or false
table.insert(result, p.ItemPageCategories(frame))
table.insert(result, p.InfoBox(frame))
if not (skip_lore or skip_desc or manual_lore or manual_desc) then
table.insert(result, p.ItemPageIntro(frame))
else
if manual_lore then table.insert(result, "<p>"..manual_lore.."</p>")
elseif not skip_lore then table.insert(result, p.getLoreStyled(frame)) end
if manual_desc then table.insert(result, "<p>"..manual_desc.."</p>")
elseif not skip_desc then table.insert(result, p.getItemDesc(frame)) end
end
table.insert(result, "== Obtainment Methods ==")
if obtaining then table.insert(result, obtaining)
else
table.insert(result, "* Might drop in the related content.")
table.insert(result, "* Can probably be purchased from an associated [[Rare Trader - "..locationNameFromShort(getLocation()).."|Rare Trader]] after first clear of the related content.")
end
if usage then
table.insert(result, "== Usage == ")
table.insert(result, usage)
end
if data.masterwork and tonumber(data.masterwork) <= MAX_MASTERWORK then
table.insert(result, "== Masterworking Details ==")
table.insert(result, "Like many other items in the Architect's Ring, this item can be [[Masterwork|masterworked]] to increase its power level further. The below table shows its stats at each Masterwork level, and what is needed to reach that level. Levels with no statistics shown are levels which cannot be obtained on the given item.")
table.insert(result, p.MWTable(frame))
end
if trivia then
table.insert(result, "== Tips and Trivia ==")
table.insert(result, trivia)
end
if skins then
table.insert(result, "== Skins ==")
table.insert(result, skins)
end
if see_also or exalted then
table.insert(result, "== See Also ==")
table.insert(result, see_also)
if exalted then
table.insert(result, "* The [["..getName().."|base version]] of this item, sourced from the [[King's Valley]]")
end
end
if manual_navbox then
table.insert(result, manual_navbox)
elseif getLocation() then
pcall(function () table.insert(result, frame:expandTemplate{title = (exalted and "ItemNavboxDngnExalted") or ("ItemNavbox" .. getLocation()), args = {}}) end )
end
return table.concat(result, "\n")
end
return p