Module:Dungeon

--Get Required Modules local loader = require('Module:Loader') local getArgs = require('Module:Arguments').getArgs

local string, table, yesno, lu, color, item, mctxt = loader.require('String', 'Table', 'Yesno', 'LibraryUtil', 'Color', 'Item', 'Mctxt')

local addColor = color._color local checkType = lu.checkType

local p = {} local MAXSTARS = 5 --local MAXITEMSTARS = 15

local prefixes = { ['Helmet'] = 'h', ['Chestplate'] = 'c', ['Leggings'] = 'l', ['Boots'] = 'b', } local pieces = { 'Helmet', 'Chestplate', 'Leggings', 'Boots', } local starColors = { [2] = "d", [3] = "b", }

local function needRow(tb, data) return table.some(tb, function(k, v)		return not not v[data]	end) end

local function getCumSum(tb, index, key) local sum = {} sum.essence = 0 if tb.conversion then for k, v in pairs(tb.conversion) do			if k ~= 'essence' then sum[k] = sum[k] and (sum[k] + (v or 0)) or v			else sum.essence = sum.essence + (v or 0) end end end if key and tb[key] then for k, v in pairs(tb[key]) do			if k ~= 'essence' then sum[k] = sum[k] and (sum[k] + (v or 0)) or v			else sum.essence = sum.essence + (v or 0) end end end for i = index, 1, -1 do		for k, v in pairs(tb[i]) do			if k ~= 'essence' then sum[k] = sum[k] and (sum[k] + (v or 0)) or v			else sum.essence = sum.essence + (v or 0) end end end return sum end

local function getHoriSum(tb, row, allPiecesSameStats) local sum = {} sum.essence = 0 if allPiecesSameStats then if tb[1] and tb[1][row] then for k, v in pairs(tb[1][row]) do				if k ~= 'essence' then sum[k] = sum[k] and (sum[k] + (v or 0)) or (v or 0) else sum.essence = sum.essence + (v or 0) end end end else for i = 1, #pieces, 1 do			if tb[i] and tb[i][row] then for k, v in pairs(tb[i][row]) do					if k ~= 'essence' then sum[k] = sum[k] and (sum[k] + (v or 0)) or (v or 0) else sum.essence = sum.essence + (v or 0) end end end end end

return sum end local function makeList(items, multipleItems) local list = {}

for k, v in pairs(items) do		if k ~= 'essence' then list[#list + 1] = tostring(v) .. ' ' .. k		end end

if table.length(list) > 1 then table.sort(list, function(a, b)			return a:match('[%d,%.]+%s+([%w%s%d]+)$') < b:match('[%d,%.]+%s+([%w%s%d]+)$')		end) end

for k, v in ipairs(list) do		list[k] = item._resourceDisplay(v) end

if items.essence and items.essence ~= 0 then table.unshift(list, addColor('#f5f', (string._formatNum(tostring(items.essence)) or '0') .. (multipleItems and ' Essence' or ''))) end

if table.length(list) == 0 then list = { multipleItems and addColor('#aaa', 'Free Upgrade') or addColor('#f5f', '0') } end

return table.concat(list, " ") end

local function convertUpgradeData(source) if not source then return nil end

local tb = {} tb.essence = source:match("([%d,%.]+);") or source:match("([%d,%.]+)$") or source:match("([%d,%.]+)%s+[Ee][Ss][Ss][Ee]?[Nn]?[Cc]?[Ee]?;") or source:match("([%d,%.]+)%s*[Ee][Ss][Ss][Ee]?[Nn]?[Cc]?[Ee]?$") source = source:gsub("([%d,%.]+)%s*[Ee][Ss][Ss][Ee]?[Nn]?[Cc]?[Ee]?;?", "") tb.essence = tonumber(tb.essence)

for number, item in source:gmatch("([%d,%.]+)%s+([%w%d%s]+);") do		tb[item] = tb[item] and (tb[item] + tonumber(number)) or tonumber(number) end

local number, item = source:match("([%d,%.]+)%s+([%w%d%s]+)$") if item then tb[item] = tb[item] and (tb[item] + tonumber(number)) or tonumber(number) end return tb end

local function starsCell(num) local color = starColors[math.ceil(num / 5)] if num == 0 then return p._stars(0), p._unfilledstars(5) end

return p._stars(num - ((math.ceil(num / 5) - 1) * 5), color), color and p._stars(math.abs(num - math.ceil(num / 5) * 5), starColors[math.ceil(num / 5) - 1]) or p._unfilledstars(5 - num) end

--- -- Template:Star -- -- Produces the star icon --- function p.stars(frame) local args = getArgs(frame) local amount = tonumber(args[1]) or 1 local starcolor = args.starcolor or args[2] local unfilled = yesno(args.unfilled, false) return string.pcall(unfilled and p._unfilledstars or p._stars, amount, starcolor) end

function p._stars(amount, starcolor) return string._repeat(mctxt._raw('&' .. (starcolor or '6') .. '✪', 18), amount, ' ') end

function p._unfilledstars(amount) return p._stars(amount, '7') end

--- -- Template:Dungeon Ranking -- -- Produces colored dungeon score with link to the Dungeons Score page and a hover info with the dungeon score needed to get that ranking. --- function p.dungeonRanking(frame) local args = getArgs(frame) local val = args[1] local nolink = yesno(args['nolink'] or args['no_link'] or args['nl'], false) return string.pcall(p._dungeonRanking, val, nolink) end

--Module Access Point function p._dungeonRanking(val, nolink) checkType('dungeonsRanking', 1, val, 'string') checkType('dungeonsRanking', 2, nolink, 'boolean', true) local data = { ['D'] = { class = 'color-dungeon_d', score = 'between 0 and 99' },		['C'] = { class = 'color-dungeon_c', score = 'between 100 and 159' },		['B'] = { class = 'color-dungeon_b', score = 'between 160 and 229' },		['A'] = { class = 'color-dungeon_a', score = 'between 230 and 269' },		['S'] = { class = 'color-dungeon_s', score = 'between 270 and 299' },		['S+'] = { class = 'color-dungeon_splus', score = 'above 300' }	}	local col = data[val:upper].class or error('Invalid value "' .. val .. '"', 2) local score = data[val:upper].score val = val:upper val = string.wrapHtml(val, 'span', { class = 'bold ' .. col }) val = string.wrapHtml(val, 'abbr', {title = 'Score ' .. score .. ' points. Click to go to Dungeon Score page.'}) val = nolink and val or string.wrapLink('Dungeon Score', val) return val end

--- --Template:Essence Crafting -- --Produces a table with all tiers of essence crafting (star upgrading) --- function p.essenceCrafting(frame) local args = getArgs(frame) local type = args['type'] or args['t'] local essence = args['essence'] or args['e'] local allPiecesSameStats = yesno(args['all_pieces_same_stats'], false) -- phased out, consider removing return p._essenceCrafting(type, essence, args) end

function p._essenceCrafting(type, essence, args) checkType('essenceCrafting', 1, type, 'string') checkType('essenceCrafting', 2, essence, 'string') checkType('essenceCrafting', 3, args, 'table') allPiecesSameStats = not (args['h1'] or args['c1'] or args['l1'] or args['b1'] or nil)

local USESITEMS = false for _, v in pairs(args) do		if v:find(';') then USESITEMS = true break end end

local MAXITEMSTARS = args.maxstars if not MAXITEMSTARS then MAXITEMSTARS = 5 if args[15] then MAXITEMSTARS = 15 elseif args[10] then MAXITEMSTARS = 10 elseif args[5] then MAXITEMSTARS = 5 end for _, v in pairs(prefixes) do			if args[v..'15'] then MAXITEMSTARS = 15 elseif args[v..'10'] then MAXITEMSTARS = 10 elseif args[v..'5'] then MAXITEMSTARS = 5 end end end essence = mw.text.trim(essence:gsub('[Ee][Ss][Ss][Ee]?[Nn]?[Cc]?[Ee]?', '')) type = type:lower local g_convert = args['convert'] or args['c'] or nil local prestige = args['prestige'] or args['p'] or nil local function forWeapon local costs = { conversion = convertUpgradeData(g_convert), prestige = convertUpgradeData(prestige), }		for i = 1, MAXITEMSTARS do			costs[i] = convertUpgradeData(args[i]) end return { costs } end local function forArmor local ret = {} if allPiecesSameStats then local costs = { conversion = convertUpgradeData(g_convert), prestige = convertUpgradeData(prestige), }			for i = 1, MAXITEMSTARS do				costs[i] = convertUpgradeData(args[i]) end costs.label = 'Any Armor Piece' return { costs } else for i, piece in ipairs(pieces) do				local costs = { conversion = convertUpgradeData(args[prefixes[piece] .. '_convert']) or convertUpgradeData(args[prefixes[piece] .. '_c']) or convertUpgradeData(g_convert), prestige = convertUpgradeData(args[prefixes[piece] .. '_prestige']) or convertUpgradeData(args[prefixes[piece] .. '_p']) or convertUpgradeData(prestige), }				for i = 1, MAXITEMSTARS do costs[i] = convertUpgradeData(args[prefixes[piece] .. i]) or convertUpgradeData(args[i]) end if table.length(costs) > 0 then costs.label = piece table.push(ret, costs) end end end return ret end -- Make Data local tabledata, horizontalSum if type == 'weapon' or type == 'w' then tabledata, horizontalSum = forWeapon, false elseif type == 'armor' or type == 'a' then tabledata, horizontalSum = forArmor, true else error(string.format('Invalid item type "%s"', type), 2) end -- Add 'Combined' Column if needed if horizontalSum then local tb = { label = 'Combined', conversion = needRow(tabledata, 'conversion') and getHoriSum(tabledata, 'conversion', allPiecesSameStats) or nil, prestige = needRow(tabledata, 'prestige') and getHoriSum(tabledata, 'prestige', allPiecesSameStats) or nil } if allPiecesSameStats then if g_convert then for k,v in pairs(tb['conversion']) do					tb['conversion'][k] = v*4 end end if prestige then for k,v in pairs(tb['prestige']) do					tb['prestige'][k] = v*4 end end end for i = 1, MAXITEMSTARS, 1 do			tb[i] = getHoriSum(tabledata, i, allPiecesSameStats) if allPiecesSameStats then for k,v in pairs(tb[i]) do					tb[i][k] = v*4 end end end tabledata[#tabledata + 1] = tb	end -- Construct Table local wikitable = mw.html.create('table'):addClass('wikitable article-essence-table centertxt') if essence == 'None' or essence == 'none' then wikitable:tag('tr') :tag('th'):addClass('article-essence-table-header'):attr('colspan', 1 + 2 * #tabledata):wikitext(				'Essence Required None'			):done :done else wikitable:tag('tr') :tag('th'):addClass('article-essence-table-header'):attr('colspan', 1 + 2 * #tabledata):wikitext(				('Essence Required %s Essence'):format(essence, essence, essence)			):done :done end local row = wikitable:tag('tr'):addClass('table-section-separator-top') if needRow(tabledata, 'label') then -- Label row exists row:tag('th'):attr('rowspan', 2):wikitext('Action'):done for n = 1, #tabledata, 1 do			row:tag('th'):addClass('table-section-separator-left'):attr('colspan', 2):wikitext(tabledata[n].label or ''):done end row = wikitable:tag('tr') else row:tag('th'):wikitext('Action'):done end for n = 1, #tabledata, 1 do		row:tag('th'):addClass('article-essence-table-legend table-section-separator-left'):wikitext('Cost'):done row:tag('th'):addClass('article-essence-table-legend'):wikitext(string.makeTitle('Cumul.', 'Cumulative')):done end if needRow(tabledata, 'conversion') then -- Conversion row exists row = wikitable:tag('tr') row:tag('td'):addClass('table-section-separator-top') :wikitext(string.makeTitle('Conversion', 'The cost of the conversion to a dungeon item.')):done for n = 1, #tabledata, 1 do			row:tag('td'):addClass('table-section-separator-top table-section-separator-left'):attr('colspan', 2) :wikitext(makeList(tabledata[n].conversion or {essence = 0}, USESITEMS)):done end end for i = 1, MAXITEMSTARS, 1 do		row = wikitable:tag('tr') row:tag('td'):addClass('txt-nowrap'):wikitext(('%s %s'):format(starsCell(i))):done for n = 1, #tabledata, 1 do			if tabledata[n][i] then local value, cumulativeSum = tabledata[n][i] or { essence = 0 }, getCumSum(tabledata[n] or { essence = 0 }, i)				--mw.log(value) mw.log(cumulativeSum) mw.log(value == cumulativeSum) if value == cumulativeSum then row:tag('td'):addClass('table-section-separator-left'):attr('colspan', 2):wikitext(makeList(value, USESITEMS)):done else row:tag('td'):addClass('table-section-separator-left'):wikitext(makeList(value or { essence = 0 }, USESITEMS)):done row:tag('td'):wikitext(makeList(cumulativeSum or { essence = 0 }, USESITEMS)):done end end end end if needRow(tabledata, 'prestige') then row = wikitable:tag('tr') row:tag('td'):wikitext('Prestige'):done for n = 1, #tabledata, 1 do			if tabledata[n]['prestige'] then local value, cumulativeSum = tabledata[n]['prestige'] or { essence = 0 }, getCumSum(tabledata[n] or { essence = 0 }, MAXITEMSTARS, 'prestige') if value == cumulativeSum then row:tag('td'):addClass('table-section-separator-left'):attr('colspan', 2):wikitext(makeList(value, USESITEMS)):done else row:tag('td'):addClass('table-section-separator-left'):wikitext(makeList(value or { essence = 0 }, USESITEMS)):done row:tag('td'):wikitext(makeList(cumulativeSum or { essence = 0 }, USESITEMS)):done end end end end return string.wrapHtml(tostring(wikitable), 'div', { class = 'article-scrollable' }) end

return p