Module:Pet

-- local p = {} -- Basics local loader = require('Module:Loader') local getArgs = require('Module:Arguments').getArgs local data, aliases = loader.loadData('Module:Pet/Data', 'Module:Pet/Aliases') local string, table = loader.require('String', 'Table') -- Modules local rarityTier = require('Module:RarityTier') local statModule = require('Module:Statname') local uitext = require('Module:UIText') -- Aliases local colorAliases = require('Module:Color/Aliases') local rarityAliases = require('Module:RarityTier/Aliases') local statAliases = require('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.getSkinsTemplate local petSkinsTable = {} for _, petName in ipairs(table.keys(data)) do		local skins = data[petName].skins; if skins then 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 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) local data = mw.loadData('Module:Pet/Data') local aliases = mw.loadData('Module:Pet/Aliases') 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 ab = { amounts = data.abilities.amounts and data.abilities.amounts:gsub('[^%d]', '') or '112234', names = data.abilities.name, descs = data.abilities.desc, bonus_descs = data.abilities.bonus_desc, variables = data.abilities.variables, }   local heldItem = data.heldItem if not stats then return error(string.format('Missing pet stats (Pet: %s)', pet), 2) end local tabs = {} for i = 1, #rarities, 1 do       --================================ -- construct the table --================================       -- headers -       local ved_buttons = ' v • e • d' local wikitable = mw.html.create('table'):addClass('wikitable'):css({['width']='100%'}) wikitable:tag('tr') :tag('th'):wikitext('Base Stats ⓘ '):css({['width']='50%'}):done :tag('th'):wikitext('Level 100 '..ved_buttons):css({['width']='50%'}):done :done local rarity = { letter = rarities:sub(i,i) }       rarity.name = rarityTier._getTier(rarity.letter).name rarity.full = rarityAliases[rarity.letter:lower] rarity.num = rarityOrder(rarity.full) wikitable:tag('tr') -	       -- base stats -           :tag('td'):wikitext(table.concat{                p.constructStats(stats, 'base', rarity.full), --(stats, _type)                p.processAbilities(ab, 'base', rarity.full, ab.amounts:sub(rarity.num, rarity.num)), --(ab, type, rarity, amount)                p.processHeldItems(heldItem, 'base', rarity.full), -- (heldItem, type, rarity)            }):done -           -- level 100 stats -           :tag('td'):wikitext(table.concat{                p.constructStats(stats, '100', rarity.full), --(stats, _type)                p.processAbilities(ab, '100', rarity.full, ab.amounts:sub(rarity.num, rarity.num)), --(ab, type, rarity, amount)                p.processHeldItems(heldItem, '100', rarity.full), -- (heldItem, type, rarity)            }):done :done -       -- bonus headers -       wikitable:tag('tr') :tag('th'):attr({ colspan=2 }):wikitext('Leveling Bonuses '):done :done wikitable:tag('tr') -	       -- bonus stats -           :tag('td'):attr({ colspan=2 }):wikitext(table.concat{                p.constructStats(stats, 'bonus', rarity.full), --(stats, _type)                p.processAbilities(ab, 'bonus', rarity.full, ab.amounts:sub(rarity.num, rarity.num)) --(ab, type, rarity, amount)            }):done tabs[#tabs+1] = table.concat{ '|-|', rarity.name, '=', tostring(rarityTier._link(rarity.full)), ' stats:', tostring(wikitable) } end return table.concat{' ', table.concat(tabs), ' '} end

function p.constructStats(stats, _type, rarity) checkType('constructStats', 1, stats, 'table') checkType('constructStats', 2, _type, {'string', 'nil'}) rarity = rarityAliases[rarity] or rarity local list = {} for key, value in pairs(stats) do   	local base = value.base or value[2] or 0 local lvl = value.level or value.lvl or value.bonus or value[1] reqRarity = value.req and rarityAliases[value.req:lower] or nil if not value.req or rarityOrder(rarity) >= rarityOrder(reqRarity) then local num if _type == '100' then num = base + 100 * lvl elseif _type == 'bonus' then num = lvl else num = base 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 == '100' and 'Stats:' or (           _type == 'bonus'             and 'Bonus stats:'            or 'Base stats:'        ), string.wrapHtml(list, 'ul') } end

function p.processVariables(variable, type, pet) -- check for errors 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 type and type == '100' or type == 100 then num = (variable.base or 0) + 100 * variable.per_lvl elseif type and type == 'bonus' then num = variable.per_lvl else num = (variable.base or 0) 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)	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            mw.log(tag)            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            mw.log(tag)            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) 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 = 10 -- process double digits first for j = 10, MAX, 1 do			if desc:find('VAR'..tostring(j)) then desc = desc:gsub('VAR'..tostring(j), p.processVariables(vars[j], _type, pet)) end end -- process single digit for j = 1, 9, 1 do			if desc:find('VAR'..tostring(j)) then desc = desc:gsub('VAR'..tostring(j), p.processVariables(vars[j], _type, pet)) 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, amount) checkType('processAbilities', 1, ab, 'table') checkType('processAbilities', 2, type, 'string') checkType('processAbilities', 3, rarity, 'string') --if not ab.names[amount] then error(string.format('Missing ability name #%s', amount), 2) end --if not ab.descs[amount] then error(string.format('Missing ability description #%s', amount), 2) end local list = {} for i=1, amount, 1 do       if type == '100' then desc = processVars(ab.descs[i], type, ab.variables[rarity][i]) table.push(list,                    string.wrapHtml({ makeAbility(ab.names[i]), ' - ', desc }, 'li')           ) elseif type == 'base' then desc = processVars(ab.descs[i], type, ab.variables[rarity][i]) table.push(list,                string.wrapHtml({ makeAbility(ab.names[i]), ' - ', desc }, 'li')           ) elseif type == 'bonus' then desc = processVars(ab.bonus_descs[i] or 'no leveling bonus', type, ab.variables[rarity][i]) table.push(list,               string.wrapHtml({ makeAbility(ab.names[i]), ': ', 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') checkType('processHeldItems', 3, rarity, 'string') --if not ab.names[amount] then error(string.format('Missing ability name #%s', amount), 2) end --if not ab.descs[amount] then error(string.format('Missing ability description #%s', amount), 2) end local list, desc if heldItem and (type == '100' or type == 'base') and rarity == heldItem.req then desc = processVars(heldItem.desc, type) list = string.wrapHtml(desc, 'li') else return end return table.concat{ makeAbility('Held Item: '..heldItem.name), 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 error("Unrecognized Pet: "..pet) end local rarities = (data.rarities):upper:gsub('[^%a]', '') i = #rarities -- highest rarity local rarity = rarityTier._getTier(rarities:sub(i,i)).name local stats = data.stats if not stats then return error(string.format('Missing pet stats (Pet: %s)', pet), 2) end 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_descs = data.abilities.desc.tooltip or data.abilities.desc.tooltips local abilityStr = ab_descs and (table.concat(table.map(ab_names, function(name, i)		   	return ('&6%s/&r%s'):format( name, ab_descs[i] )	    	end),'//')..'//') or '' local hi = data.heldItem local hiTooltip = hi and hi.tooltip local helditemStr = (hi and hiTooltip and rarity == heldItem.req) and ('&6Held Item: %s/&r%s'):format( hi, hiTooltip ) or '' return { pet, data.petType, rarity:upper, statStr, abilityStr, helditemStr } end), { id = '$o Pet' }) end

function p._petTooltip(pet) pet = pet:lower:gsub(' pet', '') pet = aliases[mw.text.trim(pet)] or string.ucfirst(pet) local 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 ab = { amounts = data.abilities.amounts and data.abilities.amounts:gsub('[^%d]', '') or '112234', names = data.abilities.name, descs = data.abilities.desc, bonus_descs = data.abilities.bonus_desc, variables = data.abilities.variables, }   local heldItem = data.heldItem if not stats then return error(string.format('Missing pet stats (Pet: %s)', pet), 2) end i = #rarities -- highest rarity local rarity = { letter = rarities:sub(i,i) } rarity.name = rarityTier._getTier(rarity.letter).name rarity.full = rarityAliases[rarity.letter:lower] rarity.num = rarityOrder(rarity.full) local id = string.ucfirst(pet.." pet") local name = id   local title = "&7[Lvl 100] "..getFormatting(rarity.full, string.ucfirst(pet)).."&r" local text = {} text = table.merge(text,		"&8"..(data.petType or "").." Pet",       p.constructTooltipStats(stats, rarity.full), --(stats, rarity)        p.processTooltipAbilities(ab, rarity.full, ab.amounts:sub(rarity.num, rarity.num)), --(ab, rarity, amount)        p.processTooltipHeldItems(heldItem, rarity.full), -- (heldItem, rarity)		"&eRight-click to add this pet to/your pet menu!",		"&l"..getFormatting(rarity.full, rarity.name:upper)	) text = data.tooltipText or data.tooltip or table.concat(text, "//") return {name = name, title = title, text = text} end

function p.constructTooltipStats(stats, rarity) checkType('constructStats', 1, stats, 'table') rarity = rarityAliases[rarity] or rarity local list = {} 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(list, ("&7%s: &a%s%s"):format( statModule._getstatdata(key).name, (num < 0 and '' or '+'), num ))	   end end return table.concat(list,'/') end

function p.processTooltipAbilities(ab, rarity, amount, pet) checkType('processTooltipAbilities', 1, ab, 'table') checkType('processTooltipAbilities', 2, rarity, 'string') --if not ab.names[amount] then error(string.format('Missing ability name #%s', amount), 2) end --if not ab.descs[amount] then error(string.format('Missing ability description #%s', amount), 2) end local list = {} for i=1, amount, 1 do       -- if type == '100' then desc = processVars(ab.descs[i], "tooltip", ab.variables[rarity][i]) table.push(list, '&6'..ab.names[i]..'/&7'..desc) end return list end

function p.processTooltipHeldItems(heldItem, rarity) checkType('processTooltipHeldItems', 1, heldItem, 'table', true) checkType('processTooltipHeldItems', 2, rarity, 'string') --if not ab.names[amount] then error(string.format('Missing ability name #%s', amount), 2) end --if not ab.descs[amount] then error(string.format('Missing ability description #%s', amount), 2) end local desc if heldItem and rarity == heldItem.req then desc = processVars(heldItem.desc, "tooltip") else return '' end return '&6Held Item: '..heldItem.name.."&r"..'/'..desc end

return p