Module:Pet

-- local p = {} -- Basics local loader = require('Module:Loader') local getArgs = require('Module:Arguments').getArgs local data, aliases, skindata = loader.loadData('Module:Pet/Data', 'Module:Pet/Aliases', 'Module:Pet/Skins') local string, table = loader.require('String', 'Table') -- Modules local rarityTier, statModule, uitext = loader.require('Module:RarityTier', 'Module:Statname', 'Module:UIText') -- Aliases local colorAliases, rarityAliases, statAliases = loader.loadData('Module:Color/Aliases', 'Module:RarityTier/Aliases', 'Module:Statname/Aliases') -- Functions local makeColor = require('Module:Color')._colorTemplates local makeCoins = require('Module:Currency')._coins local makeAbility = require('Module:Ability')._ability local checkType = require('Module:LibraryUtil').checkType local uitextData = require('Module:UIText/Data').conversions local getFormatting = require('Module:UIText').getFormatting

local curtitle = mw.title.getCurrentTitle local pagename = curtitle.prefixedText local fullpagename = curtitle.fullText local reverseConv = table.invert(uitextData)

local function rarityOrder(rarity) return rarityTier._getTier(rarity).order end

function p.inquirerarities(pet) local pet_ = pet:gsub(' Pet$','') if not data[pet_] then return end local dt = data[pet_] local rarities = dt.rarities if not rarities then return end rarities = rarities:upper:gsub('[^%a]', '') local ret = {} for i = 1,#rarities,1 do		local r = rarities:sub(i,i) local p = pet_:gsub(' ','_') table.push(ret, ('%s;%d'):format(string.upper(p), rarityOrder(r))) end return table.concat(ret, ' ') end

function p.getSkinsTemplate local petSkinsTable = {} for petName, skins in pairs(skindata) do		for _,v in ipairs(skins) do			local attrs = string.split(v[2], '%s+') local r = rarityTier._getTier(attrs[1]).name table.remove(attrs,1) local animated, daynight = false, false for _,attr in ipairs(attrs) do				if attr:lower == 'animated' then animated = true elseif attr:lower == 'daynight' then daynight = true end end local suppStr = string.format('%s%s',				animated and getFormatting(r,'This skin is animated!//') or ,				daynight and getFormatting(r,'This skin adapts to the day-night cycle!//') or ) table.push(petSkinsTable, { v[1], petName, r:upper, getFormatting(r), suppStr }) end end return petSkinsTable end

function p.getSkinsList local petSkinsTable = {} for _, petName in ipairs(table.keys(data)) do		local skins = data[petName].skins; if skins then for _,v in ipairs(skins) do table.push(petSkinsTable, v[1]) end end end return petSkinsTable end

function p.getPetList(prepend, append) return table.map(table.keys(data), function(petName)		return (prepend or )..petName..(append or )	end) end

function p.getMysteryTemplate local ls = table.map(table.keys(data), function(petName)		local petData = data[petName]		local stats = {}		for stat, value in pairs(petData.stats) do			if not value.req then				value = tonumber(value[1])				table.push(stats, ('&r%s: &a%s'):format(string.ucfirst(statAliases[stat]), value < 0 and value or '+'..value))			end		end		return { petName, petData.petType, table.concat(stats, '/') }	end) return table.merge(ls, { id = 'Mystery $o Pet' }) end

function p.petStatsTable(frame) local args = getArgs(frame) local pet = args[1] or args["p"] or args["pet"] or (curtitle.namespace == 0 and (fullpagename:find("Pet") and fullpagename or 'ERROR') or 'ERROR') if pet == 'ERROR' then return string.error('Pet name expected, got none') end return frame:preprocess(string.pcall(p._petStatsTable, pet)) end

function p._petStatsTable(pet) pet = pet:lower:gsub(' pet', '') pet = aliases[mw.text.trim(pet)] or string.ucfirst(pet) data = data[pet] if not data then error("Unrecognized Pet: "..pet) end --create various variables local rarities = (data.rarities):upper:gsub('[^%a]', '') local stats = data.stats local heldItem = data.heldItem local baselv, maxlv = 0, 100 if data.levels then baselv, maxlv = data.levels:match('(%d+)[^%d](%d+)') end if not stats then return error(string.format('Missing pet stats (Pet: %s)', pet), 2) end local tabs = {} local infosymbol = 'ⓘ' for i = 1, #rarities, 1 do		--================================ -- construct the table --================================		-		-- headers -		local ved_buttons = string.wrapHtml(			'v • e • d', 'span',			{ style = 'float: right; font-size: 11px;' }		) local wikitable = mw.html.create('table'):addClass('wikitable'):css({['width']='100%'}) wikitable:tag('tr') :tag('th'):wikitext(('Base Stats (Level %d) %s '):format(baselv, infosymbol)):css({['width']='50%'}):done :tag('th'):wikitext(('Max Stats (Level %d) %s %s'):format(maxlv, infosymbol, ved_buttons)):css({['width']='50%'}):done :done local rarityletter = rarities:sub(i,i) local raritykey = rarityAliases[rarityletter:lower] wikitable:tag('tr') -			-- Base stats -			:tag('td'):wikitext(table.concat{				p.constructStats(stats, baselv, raritykey, baselv), --(stats, type)				p.processAbilities(data.abilities, baselv, raritykey, baselv), --(ab, type, rarity, amount)				p.processHeldItems(heldItem, baselv, raritykey), -- (heldItem, type, rarity)			}):done -			-- Max level stats -			:tag('td'):wikitext(table.concat{				p.constructStats(stats, maxlv, raritykey, baselv), --(stats, type)				p.processAbilities(data.abilities, maxlv, raritykey, baselv), --(ab, type, rarity, amount)				p.processHeldItems(heldItem, maxlv, raritykey), -- (heldItem, type, rarity)			}):done :done -		-- bonus headers -		wikitable:tag('tr') :tag('th'):attr({ colspan=2 }):wikitext(('Leveling Bonuses%s '):format(infosymbol)):done :done wikitable:tag('tr') -			-- bonus stats -			:tag('td'):attr({ colspan=2 }):wikitext(table.concat{				p.constructStats(stats, 'bonus', raritykey, baselv), --(stats, type)				p.processAbilities(data.abilities, 'bonus', raritykey) --(ab, type, rarity, amount)			}):done tabs[#tabs+1] = table.concat{ '|-|', rarityTier._getTier(rarityletter).name, '=', tostring(rarityTier._link(raritykey)), ' stats:', tostring(wikitable) } end return table.concat{' ', table.concat(tabs), ' '} end

function p.constructStats(stats, type, rarity, baselv) checkType('constructStats', 1, stats, 'table') checkType('constructStats', 2, type, {'string', 'number'}) rarity = rarityAliases[rarity] or rarity local list = {} for key, value in pairs(stats) do		local lvl = value.level or value.lvl or value.bonus or value[1] local base = value.base or value[2] or 0 reqRarity = value.req and rarityAliases[value.req:lower] or nil if not value.req or rarityOrder(rarity) >= rarityOrder(reqRarity) then local num if tonumber(type) then num = base + (tonumber(type) - baselv) * lvl elseif type == 'bonus' then num = lvl end table.push(list, string.wrapHtml({ tostring(statModule._getStatName(key)), (num < 0 and ': ' or ': +'), num, (type == 'bonus' and ' per level' or '') }, 'li')) end end return table.concat{ type == 'bonus' and 'Bonus stats:' or 'Stats:', string.wrapHtml(list, 'ul') } end

function p.processVariables(variable, type, baselv) -- check for errors if not variable then return end if not variable.color then error(string.format('Variable argument missing (color) (Pet: %s)', pet), 2) end if variable.is_roman then if variable.per_lvl then return type == "tooltip" and getFormatting(variable.color, variable.per_lvl).."&r" or makeColor(variable.color, variable.per_lvl) else return type == "tooltip" and getFormatting(variable.color, variable.base).."&r" or makeColor(variable.color, variable.base) end end -- check for errors again if not variable.per_lvl and variable.per_lvl ~= 0 then return error(string.format('Variable argument missing (per_lvl) (Pet: %s)', pet), 2) end --perform calculations local num if tonumber(type) then num = (variable.base or 0) + (tonumber(type) - baselv) * variable.per_lvl elseif type == 'bonus' then num = variable.per_lvl end if variable.round_to_full then num = math.floor(num) end --add suffix num = tostring(num)..(variable.suffix or '') --colorize return type == "tooltip" and getFormatting(variable.color, num).."&r" or makeColor(variable.color, num) end

function p.processSTAT(str, type) if str:find('STAT_[%u-]+') then str = str:gsub('STAT_([%u-]+)', function(s)			local dt = statModule._getstatdata(s)			return type == "tooltip" and getFormatting(dt.color, dt.character.." "..dt.name).."&r" or statModule._getStatName(s)		end) end if str:find('STATs_([%u-]+)') then str = str:gsub('STATs_([%u-]+)', function(s)			local dt = statModule._getstatdata(s)			return type == "tooltip" and getFormatting(dt.color, dt.character.." "..dt.nameShort).."&r" or statModule._getStatName(s, nil, true)		end) end return str end

function p.processRARITY(str, type) if str:find('RARITY_%u+') then str = str:gsub('RARITY_(%u+)', function(s)			local dt = rarityTier._getTier(s)			return type == "tooltip" and getFormatting(dt.color, dt.name).."&r" or rarityTier._link(s)		end) end return str end

function p.replaceCoins(str, type) return str:gsub('COINS', type == "tooltip" and "&6coins" or tostring(makeCoins)) end

-- function p.recursiveGsub(val, t) --	 for i = 1,#t,1 do --		 val = val:gsub(t[i][1], t[i][2]) --	 end --	 return val -- end

function p.formatFakeAbility(s, type) checkType('formatFakeAbility', 1, s, 'string') return s:gsub('{ABILITY}(.+){/ABILITY}', function(s)		return type == "tooltip" and "&6"..s or makeAbility(s, false, 'abilityName')	end) end

function p.xmlColorConvert(s, type) checkType('xmlColorConvert', 1, s, 'string') return s:gsub(		'(.-)',		function(tag, str, endTag) 			tag = string.trim(tag):lower			endTag = string.trim(endTag):lower			if tag and (not endTag or endTag == "")					then error(string.format('XML color tags syntax error: No closing tag found for tag ', tag), 4)				elseif tag:lower ~= endTag:lower					then error( string.format(							'XML color tags syntax error: Expected closing tag for \'\' is \'\', got ',							tag,							tag,							endTag						), 4)			end			local c = colorAliases[tag] or reverseConv[tag]			return c and (type == "tooltip" and getFormatting(c, str).."&r" or makeColor(c, str)) or '<'..tag..'>'..str..''		end	) end

local function processVars(desc, type, vars, baselv) desc = p.xmlColorConvert(desc, type) desc = p.processSTAT(desc, type) desc = p.processRARITY(desc, type) desc = p.replaceCoins(desc, type) desc = p.formatFakeAbility(desc, type) if vars then local MAX = 99 for j = 0, MAX, 1 do			if desc:find(('{%d}'):format(j)) then local subst = p.processVariables(vars[j+1], type, baselv) desc = subst and desc:gsub(('{%d}'):format(j), subst) or desc else break end end end -- fullstop handler if type ~= "tooltip" then if desc:match("%w$") then desc = desc..'.' end else if desc:match(".$") then desc = desc:sub(1,#desc-1) end -- linebreaks handler desc = desc:gsub("", "/") end return desc end

function p.processAbilities(ab, type, rarity, baselv) checkType('processAbilities', 1, ab, 'table') checkType('processAbilities', 2, type, {'string', 'number'}) checkType('processAbilities', 3, rarity, 'string') --if not ab.names[ab.amounts] then error(string.format('Missing ability name #%s', amount), 2) end --if not ab.descs[ab.amounts] then error(string.format('Missing ability description #%s', amount), 2) end local amounts = data.abilities.amounts and data.abilities.amounts:gsub('[^%d]', '') local raritynum = rarityOrder(rarity) local amount = amounts and amounts:sub(raritynum, raritynum) or table.length(ab.variables[rarity]) local list = {} for i=1, amount, 1 do		if tonumber(type) then desc = processVars(ab.desc[i], type, ab.variables[rarity][i], baselv) table.push(list,					string.wrapHtml({ makeAbility(ab.name[i], false, 'abilityName'), ' - ', desc }, 'li')			) elseif type == 'bonus' then desc = processVars(ab.bonus_desc[i] or 'No leveling bonus', type, ab.variables[rarity][i], baselv) table.push(list,				string.wrapHtml({ makeAbility(ab.name[i], false, 'abilityName'), ': ', desc }, 'li')			) end end return table.concat{ makeAbility('Abilities:'), string.wrapHtml{ list, '', { style = "list-style-type: circle; line-height: inherit;" } }	} end

function p.processHeldItems(heldItem, type, rarity) checkType('processHeldItems', 1, heldItem, 'table', true) checkType('processHeldItems', 2, type, { 'string', 'number' }) checkType('processHeldItems', 3, rarity, 'string') local list, desc if heldItem and (tonumber(type)) and rarity == heldItem.req then desc = processVars(heldItem.desc, type, nil, nil) list = string.wrapHtml(desc, 'li') else return end return table.concat{ makeAbility('Held Item: '..heldItem.name, false, 'abilityName'), string.wrapHtml{ list, '', { style = "list-style-type: none; line-height: inherit;" } }	} end

function p.getPetsTemplate return table.merge(table.map(table.keys(data), function(pet) local data = data[pet] if not data then return end if not data.rarities then return end local baselv, maxlv = 0, 100 if data.levels then baselv, maxlv = data.levels:match('(%d+)[^%d](%d+)') end local rarities = (data.rarities):upper:gsub('[^%a]', '') i = #rarities -- highest rarity local rarity = rarityTier._getTier(rarities:sub(i,i)).name if not data.stats then return end local stats = data.stats local statStr = {} for key, value in pairs(stats) do			reqRarity = value.req and rarityAliases[value.req:lower] or nil if not value.req or rarityOrder(rarity) >= rarityOrder(reqRarity) then local num = (value[2] or 0) + 100 * value[1] table.push(statStr,("&7%s: &a%s%s"):format( statModule._getstatdata(key).name, (num < 0 and '' or '+'), num ))			end end statStr = table.concat(statStr,'/')..'//' local ab_names = data.abilities.name local ab_tooltips = data.abilities.tooltip or data.abilities.tooltips local abilityStr = (ab_tooltips and (#ab_names == #ab_tooltips)) and (table.concat(table.map(ab_names, function(name, i)				if not ab_tooltips[i] then error(pet..' Pet: desc and tooltip length mismatch') end				return ('&6%s/&r%s'):format( name, ab_tooltips[i]:gsub('^/+(.*)','%1'):gsub('(.-)/+$','%1') )			end),'//')..'//') or '' local hi = data.heldItem local hiTooltip = hi and (hi.tooltip or hi.tooltips) local helditemStr = (hi and hiTooltip and (rarity == rarityTier._getTier(hi.req).name)) and ('&6Held Item: %s/&r%s//'):format( hi.name, hiTooltip:gsub('^/+(.*)','%1'):gsub('(.-)/+$','%1') ) or '' return { pet, data.petType, maxlv, statStr, abilityStr, helditemStr, r=rarity } end), { id = '$o Pet' }) end

return p