Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:CosmeticInfo: Difference between revisions

From MCC Island Wiki
getAllData function
Tag: Reverted
m return 0 in getDonationLimit and getReputationLimit if not in data
 
(21 intermediate revisions by 2 users not shown)
Line 5: Line 5:
return "Error: Unable to load data"
return "Error: Unable to load data"
end
end
local obtainabilityData = mw.loadData("Module:CosmeticInfo/Obtainability/Data")


local p = {}
local p = {}


function p.getDescription(frame)
local function getCosmetic(args)
return cosmeticData["cosmetics"][args.name]
end
 
local function isAnimated(frame, filename)
if not frame.preprocess then
return true
end
local content = frame:preprocess('{{:File:' .. filename .. '}}')
return content:find('Category:Animated images') ~= nil
end
 
local function getSimpleField(field)
return function(frame)
local args = getArgs(frame)
local cosmetic = getCosmetic(args)
return cosmetic and cosmetic[field]
end
end
 
local function isInCollection(collections)
return function(frame)
local args = getArgs(frame)
local cosmetic = getCosmetic(args)
return (cosmetic and collections[cosmetic.collection]) or false
end
end
 
local collectionSets = {
isInCrateCollection = {
"Mechanical","Natural","Oceanic","Magical","Mythic","Slimy","Cuckoo",
"Arena","Cloudy","Ninja","Explosive","Mystical Aquatic",
"Neon Galaxy","Candy Factory","Ancient Jungle","Seasonal Variety"
},
isFishingCosmetic = { "Fishing" },
isArcaneGateCosmetic = { "Arcane Gate" }
}
 
for key, list in pairs(collectionSets) do
local set = {}
for _, name in ipairs(list) do
set[name] = true
end
p[key] = isInCollection(set)
end
 
local function formatGlyphs(description)
local glyphs = {
local glyphs = {
["<glyph:\"mcc:icon.tooltips.veteran\"> "] = "<br />[[File:Icon-Veteran.png|16px]] <span style=\"color: #52C8FF; font-weight: bold\">",
["<glyph:\"mcc:icon.tooltips.veteran\"> "] = "<br />[[File:Icon-Veteran.png|16px]] <span style=\"color: #52C8FF; font-weight: bold\">",
Line 14: Line 62:
["<glyph:\"mcc:icon.info_blue\"> "] = "<br />[[File:Icon-Info-Blue.png|16px]] <span style=\"color: #55FF55; font-weight: bold\">",
["<glyph:\"mcc:icon.info_blue\"> "] = "<br />[[File:Icon-Info-Blue.png|16px]] <span style=\"color: #55FF55; font-weight: bold\">",
}
}
local args = getArgs(frame)
local description = cosmeticData["cosmetics"][args.name]["description"]
local openSpan = false
local openSpan = false
for key, val in pairs(glyphs) do
for key, val in pairs(glyphs) do
if string.find(description, key) then
if description:find(key) then
if openSpan == false then
description = description:gsub(key, (openSpan and val or "</span>" .. val))
description = description:gsub(key, "</span>" .. val)
else
description = description:gsub(key, val)
end
openSpan = true
openSpan = true
end
end
end
end
return openSpan and (description .. "</span>") or nil
if openSpan then
end
description = description .. "</span>"
 
local function formatArcaneBonus(description)
if description:find("Arcane Bonus") then
description = description:gsub("Arcane Bonus", "<br /><span style=\"color: #64FCFC\"><span class=\"white-text\">Arcane Bonus</span>")
description = description:gsub("(Grants you)(.-)( while)", function(startText, middle, endText)
return startText .. "<span class=\"white-text\">" .. middle .. "</span>" .. endText
end)
return description .. "</span>"
end
end
return description
return description
end
end


function p.getType(frame)
local function stripDescription(description)
local args = getArgs(frame)
description = description:gsub("<glyph:\".-\"> ?", "")
return cosmeticData["cosmetics"][args.name]["type"]
description = description:gsub("Arcane Bonus.*", "")
return mw.text.trim(description)
end
end


function p.getCollection(frame)
function p.getDescription(frame)
local args = getArgs(frame)
local args = getArgs(frame)
return cosmeticData["cosmetics"][args.name]["collection"]
local cosmetic = getCosmetic(args)
if not cosmetic then return "No data found" end
local plain = args.plain == "true"
if plain then
return stripDescription(cosmetic.description)
end
return formatGlyphs(cosmetic.description) or formatArcaneBonus(cosmetic.description)
end
end


function p.getRarity(frame)
p.getCategory = getSimpleField("category")
p.getCollection = getSimpleField("collection")
p.getRarity = getSimpleField("rarity")
p.isColorable = getSimpleField("colorable")
p.getTrophiesAwarded = getSimpleField("trophies")
p.isBonusTrophies = getSimpleField("isBonusTrophies")
p.canBeDonated = getSimpleField("canBeDonated")
 
function p.getDonationLimit(frame)
local args = getArgs(frame)
local args = getArgs(frame)
return cosmeticData["cosmetics"][args.name]["rarity"]
local cosmetic = getCosmetic(args)
return (cosmetic and cosmetic.royalReputation and cosmetic.royalReputation.donationLimit) or 0
end
end


function p.isColorable(frame)
function p.getReputationAmount(frame)
local args = getArgs(frame)
local args = getArgs(frame)
return cosmeticData["cosmetics"][args.name]["colorable"]
local cosmetic = getCosmetic(args)
return (cosmetic and cosmetic.royalReputation and cosmetic.royalReputation.reputationAmount) or 0
end
end


function p.getTrophiesAwarded(frame)
p.getGlobalNumberOwned = getSimpleField("globalNumberOwned")
local args = getArgs(frame)
p.getObtainmentHint = getSimpleField("obtainmentHint")
return cosmeticData["cosmetics"][args.name]["trophies"]
 
function firstToUpper(str)
return (str:gsub("^%l", string.upper))
end
end


function p.isBonusTrophies(frame)
function p.getType(frame)
local args = getArgs(frame)
local args = getArgs(frame)
return cosmeticData["cosmetics"][args.name]["isBonusTrophies"]
local cosmetic = getCosmetic(args)
return firstToUpper(cosmetic["type"]:lower())
end
end


function p.canBeDonated(frame)
function p.getFishingClimate(frame)
local args = getArgs(frame)
local args = getArgs(frame)
return cosmeticData["cosmetics"][args.name]["canBeDonated"]
local cosmetic = getCosmetic(args)
end
if not cosmetic or not p.isFishingCosmetic({name = args.name}) then
return nil
end


function p.getGlobalNumberOwned(frame)
local hint = cosmetic.obtainmentHint or ""
local args = getArgs(frame)
local climate = hint:match("while fishing in the (.-) Climate")
return cosmeticData["cosmetics"][args.name]["globalNumberOwned"]
if climate then
end
return firstToUpper(climate)
end


function p.getAllData(frame)
return nil
    local args = getArgs(frame)
    local name = args.name
    local cosmetic = cosmeticData["cosmetics"][name]
   
    if not cosmetic then
        return nil
    end
   
    return {
        description = p.getDescription(frame),
        type = p.getType(frame),
        collection = p.getCollection(frame),
        rarity = p.getRarity(frame),
        colorable = p.isColorable(frame),
        trophies = p.getTrophiesAwarded(frame),
        isBonusTrophies = p.isBonusTrophies(frame),
        canBeDonated = p.canBeDonated(frame),
        globalNumberOwned = p.getGlobalNumberOwned(frame),
        lastUpdated = p.getLastUpdatedDate(),
        lastUpdatedIcon = p.lastUpdatedIcon()
    }
end
end


Line 106: Line 158:


function p.lastUpdatedIcon()
function p.lastUpdatedIcon()
    return string.format('<sup><abbr title="Data updated every 12 hours from MCC Island\'s API. Last updated on: %s" tabindex="0">ⓘ</abbr></sup>', p.getLastUpdatedDate())
return string.format(
'<sup><abbr title="Last updated: %s" tabindex="0">ⓘ</abbr></sup>',
p.getLastUpdatedDate()
)
end
 
local function getOwnedNumber(raw)
raw = tostring(raw or "0"):gsub(",", ""):gsub("%+", "")
return tonumber(raw) or 0
end
 
local function sortCosmetics(list, order)
table.sort(list, function(a, b)
return order == "desc" and a.owned > b.owned or a.owned < b.owned
end)
end
 
local function formatCosmeticList(cosmetics)
local result = {}
for _, c in ipairs(cosmetics) do
table.insert(result, string.format("* %s (%s)", c.name, c.display or c.owned))
end
return table.concat(result, "\n")
end
 
function p.sortListByNumberOwned(frame)
local args = getArgs(frame)
local names = mw.text.split(args.names or "", ",%s*")
local order = args.order or "asc"
local unformatted = args.unformatted or ""
 
local cosmetics = {}
for _, name in ipairs(names) do
local data = cosmeticData["cosmetics"][name]
if data and data.globalNumberOwned then
table.insert(cosmetics, {
name = name,
owned = getOwnedNumber(data.globalNumberOwned),
display = data.globalNumberOwned
})
end
end
 
sortCosmetics(cosmetics, order)
if unformatted ~= "" then
return cosmetics
else
return formatCosmeticList(cosmetics)
end
end
 
function p.getNumberOwnedListByFieldValue(frame)
local args = getArgs(frame)
local field = args.field
local target = args.value
local order = args.order or "asc"
 
local filterValue = ({
["true"] = true,
["false"] = false
})[target] or target
 
local filtered = {}
for name, data in pairs(cosmeticData["cosmetics"]) do
if data[field] == filterValue and data.globalNumberOwned then
table.insert(filtered, {
name = name,
owned = getOwnedNumber(data.globalNumberOwned),
display = data.globalNumberOwned
})
end
end
 
sortCosmetics(filtered, order)
return formatCosmeticList(filtered)
end
 
function p.tradeablesPage(frame)
local function getGroup(cosmetic)
local obtainability = obtainabilityData[cosmetic.name]
local cType = p.getType({name = cosmetic.name})
if obtainability == "Grand Auction" then
return obtainability
elseif obtainability == "Returning" then
return "Returning in a future event"
elseif obtainability == "Unobtainable" then
return "Unobtainable other than trading"
elseif cType == "Collector" then
return cType
else
return "Unobtainable once this season ends"
end
end
 
local function getOwnershipBand(owned)
if owned == "10000+" or owned == "1000+" then
return owned .. " owned"
else
return "Less than 1000 owned"
end
end
local function groupCosmetics(cosmeticList)
local grouped = {}
for _, cosmetic in ipairs(cosmeticList) do
local category = getGroup(cosmetic)
local band = getOwnershipBand(cosmetic.display)
grouped[category] = grouped[category] or {}
grouped[category][band] = grouped[category][band] or {}
table.insert(grouped[category][band], cosmetic)
end
return grouped
end
local function renderTableForGroup(group, title)
local out = {'<h2>' .. title .. '</h2>'}
local bandOrder = { "Less than 1000 owned", "1000+ owned", "10000+ owned"  }
 
for _, band in ipairs(bandOrder) do
local list = group[band]
if list then
sortCosmetics(list)
if title ~= "Collector" and title ~= "Grand Auction" then
table.insert(out, '<h3>' .. band .. '</h3>')
end
table.insert(out, '<div class="tradeable-display">')
local count = 0
for _, item in ipairs(list) do
if count > 0 and count % 4 == 0 then
--table.insert(out, '<div>')
end
 
local name, owned = item.name, item.display
local filename = name .. '.png'
local cell
 
if band == "Less than 1000 owned" then
cell = string.format('<div><center><div class="afix" style="width: 100px">[[File:%s|link=%s]]</div></center><div style="word-wrap:break-word; text-align:center"><small>[[%s]]</small><br />Owned: <b>%s</b></div></div>', filename, name, name, owned)
else
cell = string.format('<div><center><div class="afix" style="width: 100px">[[File:%s|link=%s]]</div></center><div style="word-wrap:break-word; text-align:center"><small>[[%s]]</small></div></div>', filename, name, name)
end
 
table.insert(out, cell)
count = count + 1
end
table.insert(out, '</div>')
end
end
 
return table.concat(out, '\n')
end
local tradeables = {}
for name, _ in pairs(cosmeticData["cosmetics"]) do
local cType = p.getType({ name = name })
if cType == "Limited" or cType == "Collector" then
local data = cosmeticData["cosmetics"][name]
if data and data.globalNumberOwned then
table.insert(tradeables, {
name = name,
display = data.globalNumberOwned,
owned = getOwnedNumber(data.globalNumberOwned)
})
end
end
end
local grouped = groupCosmetics(tradeables)
local output = {}
local categoryOrder = {
"Returning in a future event", "Unobtainable other than trading", "Unobtainable once this season ends",
"Collector", "Grand Auction"
}
 
for _, category in ipairs(categoryOrder) do
if grouped[category] then
table.insert(output, renderTableForGroup(grouped[category], category))
end
end
return table.concat(output, '\n\n')
end
end


return p
return p

Latest revision as of 13:22, 30 August 2025

This module uses info gathered from the API and stored in the data page to:

It is also invoked by other modules, such as Module:CosmeticMachine and Module:CosmeticCrates.


local getArgs = require('Module:Arguments').getArgs

local cosmeticData = mw.loadData('Module:CosmeticInfo/Data')
if not cosmeticData then
	return "Error: Unable to load data"
end

local obtainabilityData = mw.loadData("Module:CosmeticInfo/Obtainability/Data")

local p = {}

local function getCosmetic(args)
	return cosmeticData["cosmetics"][args.name]
end

local function isAnimated(frame, filename)
	if not frame.preprocess then
		return true
	end
	local content = frame:preprocess('{{:File:' .. filename .. '}}')
	return content:find('Category:Animated images') ~= nil
end

local function getSimpleField(field)
	return function(frame)
		local args = getArgs(frame)
		local cosmetic = getCosmetic(args)
		return cosmetic and cosmetic[field]
	end
end

local function isInCollection(collections)
	return function(frame)
		local args = getArgs(frame)
		local cosmetic = getCosmetic(args)
		return (cosmetic and collections[cosmetic.collection]) or false
	end
end

local collectionSets = {
	isInCrateCollection = {
		"Mechanical","Natural","Oceanic","Magical","Mythic","Slimy","Cuckoo",
		"Arena","Cloudy","Ninja","Explosive","Mystical Aquatic",
		"Neon Galaxy","Candy Factory","Ancient Jungle","Seasonal Variety"
	},
	isFishingCosmetic = { "Fishing" },
	isArcaneGateCosmetic = { "Arcane Gate" }
}

for key, list in pairs(collectionSets) do
	local set = {}
	for _, name in ipairs(list) do
		set[name] = true
	end
	p[key] = isInCollection(set)
end

local function formatGlyphs(description)
	local glyphs = {
		["<glyph:\"mcc:icon.tooltips.veteran\"> "] = "<br />[[File:Icon-Veteran.png|16px]] <span style=\"color: #52C8FF; font-weight: bold\">",
		["<glyph:\"mcc:icon.tooltips.squidtek\"> "] = "<br />[[File:Icon-Squidtek.png|16px]] <span style=\"color: #52C8FF; font-weight: bold\">",
		["<glyph:\"mcc:icon.info_blue\"> "] = "<br />[[File:Icon-Info-Blue.png|16px]] <span style=\"color: #55FF55; font-weight: bold\">",
	}
	
	local openSpan = false
	for key, val in pairs(glyphs) do
		if description:find(key) then
			description = description:gsub(key, (openSpan and val or "</span>" .. val))
			openSpan = true
		end
	end
	return openSpan and (description .. "</span>") or nil
end

local function formatArcaneBonus(description)
	if description:find("Arcane Bonus") then
		description = description:gsub("Arcane Bonus", "<br /><span style=\"color: #64FCFC\"><span class=\"white-text\">Arcane Bonus</span>")
		description = description:gsub("(Grants you)(.-)( while)", function(startText, middle, endText)
			return startText .. "<span class=\"white-text\">" .. middle .. "</span>" .. endText
		end)
		return description .. "</span>"
	end
	return description
end

local function stripDescription(description)
	description = description:gsub("<glyph:\".-\"> ?", "")
	description = description:gsub("Arcane Bonus.*", "")
	return mw.text.trim(description)
end

function p.getDescription(frame)
	local args = getArgs(frame)
	local cosmetic = getCosmetic(args)
	if not cosmetic then return "No data found" end
	
	local plain = args.plain == "true"
	if plain then
		return stripDescription(cosmetic.description)
	end
	
	return formatGlyphs(cosmetic.description) or formatArcaneBonus(cosmetic.description)
end

p.getCategory = getSimpleField("category")
p.getCollection = getSimpleField("collection")
p.getRarity = getSimpleField("rarity")
p.isColorable = getSimpleField("colorable")
p.getTrophiesAwarded = getSimpleField("trophies")
p.isBonusTrophies = getSimpleField("isBonusTrophies")
p.canBeDonated = getSimpleField("canBeDonated")

function p.getDonationLimit(frame)
	local args = getArgs(frame)
	local cosmetic = getCosmetic(args)
	return (cosmetic and cosmetic.royalReputation and cosmetic.royalReputation.donationLimit) or 0
end

function p.getReputationAmount(frame)
	local args = getArgs(frame)
	local cosmetic = getCosmetic(args)
	return (cosmetic and cosmetic.royalReputation and cosmetic.royalReputation.reputationAmount) or 0
end

p.getGlobalNumberOwned = getSimpleField("globalNumberOwned")
p.getObtainmentHint = getSimpleField("obtainmentHint")

function firstToUpper(str)
	return (str:gsub("^%l", string.upper))
end

function p.getType(frame)
	local args = getArgs(frame)
	local cosmetic = getCosmetic(args)
	return firstToUpper(cosmetic["type"]:lower())
end

function p.getFishingClimate(frame)
	local args = getArgs(frame)
	local cosmetic = getCosmetic(args)
	if not cosmetic or not p.isFishingCosmetic({name = args.name}) then
		return nil
	end

	local hint = cosmetic.obtainmentHint or ""
	local climate = hint:match("while fishing in the (.-) Climate")
	if climate then
		return firstToUpper(climate)
	end

	return nil
end

function p.getLastUpdatedDate()
	local lang = mw.language.getContentLanguage()
	return lang:formatDate( 'd F Y, h:i a', '@' .. cosmeticData['last_updated'], false ) .. ' UTC'
end

function p.lastUpdatedIcon()
	return string.format(
		'<sup><abbr title="Last updated: %s" tabindex="0">ⓘ</abbr></sup>',
		p.getLastUpdatedDate()
	)
end

local function getOwnedNumber(raw)
	raw = tostring(raw or "0"):gsub(",", ""):gsub("%+", "")
	return tonumber(raw) or 0
end

local function sortCosmetics(list, order)
	table.sort(list, function(a, b)
		return order == "desc" and a.owned > b.owned or a.owned < b.owned
	end)
end

local function formatCosmeticList(cosmetics)
	local result = {}
	for _, c in ipairs(cosmetics) do
		table.insert(result, string.format("* %s (%s)", c.name, c.display or c.owned))
	end
	return table.concat(result, "\n")
end

function p.sortListByNumberOwned(frame)
	local args = getArgs(frame)
	local names = mw.text.split(args.names or "", ",%s*")
	local order = args.order or "asc"
	local unformatted = args.unformatted or ""

	local cosmetics = {}
	for _, name in ipairs(names) do
		local data = cosmeticData["cosmetics"][name]
		if data and data.globalNumberOwned then
			table.insert(cosmetics, {
				name = name,
				owned = getOwnedNumber(data.globalNumberOwned),
				display = data.globalNumberOwned
			})
		end
	end

	sortCosmetics(cosmetics, order)
	if unformatted ~= "" then
		return cosmetics
	else
		return formatCosmeticList(cosmetics)
	end
end

function p.getNumberOwnedListByFieldValue(frame)
	local args = getArgs(frame)
	local field = args.field
	local target = args.value
	local order = args.order or "asc"

	local filterValue = ({
		["true"] = true,
		["false"] = false
	})[target] or target

	local filtered = {}
	for name, data in pairs(cosmeticData["cosmetics"]) do
		if data[field] == filterValue and data.globalNumberOwned then
			table.insert(filtered, {
				name = name,
				owned = getOwnedNumber(data.globalNumberOwned),
				display = data.globalNumberOwned
			})
		end
	end

	sortCosmetics(filtered, order)
	return formatCosmeticList(filtered)
end

function p.tradeablesPage(frame)
	local function getGroup(cosmetic)
		local obtainability = obtainabilityData[cosmetic.name]
		local cType = p.getType({name = cosmetic.name})
		
		if obtainability == "Grand Auction" then
			return obtainability
		elseif obtainability == "Returning" then
			return "Returning in a future event"
		elseif obtainability == "Unobtainable" then
			return "Unobtainable other than trading"
		elseif cType == "Collector" then
			return cType
		else
			return "Unobtainable once this season ends"
		end
	end

	local function getOwnershipBand(owned)
		if owned == "10000+" or owned == "1000+" then
			return owned .. " owned"
		else
			return "Less than 1000 owned"
		end
	end
	
	local function groupCosmetics(cosmeticList)
		local grouped = {}
		for _, cosmetic in ipairs(cosmeticList) do
			local category = getGroup(cosmetic)
			local band = getOwnershipBand(cosmetic.display)
			grouped[category] = grouped[category] or {}
			grouped[category][band] = grouped[category][band] or {}
			table.insert(grouped[category][band], cosmetic)
		end
		return grouped
	end
	
	local function renderTableForGroup(group, title)
		local out = {'<h2>' .. title .. '</h2>'}
		local bandOrder = { "Less than 1000 owned", "1000+ owned", "10000+ owned"  }

		for _, band in ipairs(bandOrder) do
			local list = group[band]
			if list then
				sortCosmetics(list)
				if title ~= "Collector" and title ~= "Grand Auction" then
					table.insert(out, '<h3>' .. band .. '</h3>')
				end
				table.insert(out, '<div class="tradeable-display">')
				local count = 0
				for _, item in ipairs(list) do
					if count > 0 and count % 4 == 0 then
						--table.insert(out, '<div>')
					end

					local name, owned = item.name, item.display
					local filename = name .. '.png'
					local cell

					if band == "Less than 1000 owned" then
						cell = string.format('<div><center><div class="afix" style="width: 100px">[[File:%s|link=%s]]</div></center><div style="word-wrap:break-word; text-align:center"><small>[[%s]]</small><br />Owned: <b>%s</b></div></div>', filename, name, name, owned)
					else
						cell = string.format('<div><center><div class="afix" style="width: 100px">[[File:%s|link=%s]]</div></center><div style="word-wrap:break-word; text-align:center"><small>[[%s]]</small></div></div>', filename, name, name)
					end

					table.insert(out, cell)
					count = count + 1
				end
				table.insert(out, '</div>')
			end
		end

		return table.concat(out, '\n')
	end
	
	local tradeables = {}
	for name, _ in pairs(cosmeticData["cosmetics"]) do
		local cType = p.getType({ name = name })
		if cType == "Limited" or cType == "Collector" then
			local data = cosmeticData["cosmetics"][name]
			if data and data.globalNumberOwned then
				table.insert(tradeables, {
					name = name,
					display = data.globalNumberOwned,
					owned = getOwnedNumber(data.globalNumberOwned)
				})
			end
		end
	end
	
	local grouped = groupCosmetics(tradeables)
	
	local output = {}
	local categoryOrder = {
		"Returning in a future event", "Unobtainable other than trading", "Unobtainable once this season ends",
		"Collector", "Grand Auction"
	}

	for _, category in ipairs(categoryOrder) do
		if grouped[category] then
			table.insert(output, renderTableForGroup(grouped[category], category))
		end
	end
	
	return table.concat(output, '\n\n')
end

return p