Module:Item/Variants

local table = require("Module:Table") local string = require("Module:String") local MCColors = require("Module:Color/Data").MCColors local pet = require('Module:Pet')

local minionData = mw.loadData('Module:Minion/Data')

require('Module:LibraryUtil')

-- -- TABLE OF CONTENTS -- 01: More aliases support: Conversion tables -- 02: Main function for the aliases processing -- 03: Main table for lists of item variants -- 04: Individual procedures to generate lists of item variants -- -- Notes: -- 1. More aliases -- Add the *singular forms* of additional aliases to the singularFormConversions table -- 2. Plurals -- Use $s to set plural positions, for example: 'Crab Hat$s of Celebration' (default: the end of string) -- Add $u *at the end of the string* to disable plural, for example: 'Clay$u', 'Stairs$u' -- Add irregular plurals to the pluralOverrides table --

-- 01: More aliases support: Conversion tables -- --	Other names to copy from the original name must be declared here	On the left side, $? formatting doesn't matter (e.g. Entry 'Crab$0 Hat$s of Cel$1$2' is the same as 'Crab Hat of Cel')	On the right side, $? formatting should be used to set plurals if needed. -- local singularFormConversions = { -- [' '] = ' '	-- [' '] = {' ', ...}	['Crab Hat of Celebration'] = 'Crab Hat', } --	Irregular plurals (i.e. not 's', 'es', 'ies', 'ves') must be substituted here,	including new aliases from singularFormConversions (if their plurals are irregular) 	Only the single word on plural positions (default is the end of string) needs to be added,	unless you want to be specific so as to not affect other items -- local pluralOverrides = { -- irregular: [' '] = ' ' }

local variants = {}

local function gsubFn(...) -- Function for one or more gsub + trim -- function: gsubFn(<...>) | parameters must be in pairs of, , and in order local args = { ... }	assertFalse(#args % 2 == 1, "gsubFn: Patterns and replacements not in pairs") return function(n) for i = 1, #args, 2 do			n = n:gsub(args[i], args[i+1]) end return string.trim(n) end end

-- 02: Main function for the aliases processing -- --	function: createMultiAliases(name: str, items: table, customPrefixSingular: str/table, customPrefixPlural?: str/table)	Additional prefixes for singular form (other than 'Any'/'Match') (if any) can be passed into 3rd param or items.CPS	Additional prefixes for plural form (other than 'All') (if any) can be passed into 4th param or items.CPP -- local function createMultiAliases(name, items, customPrefixSingular, customPrefixPlural) local normalize = gsubFn('%$.', '') customPrefixSingular, customPrefixPlural = customPrefixSingular or items.customPrefixSingular or items.CPS, customPrefixPlural or items.customPrefixPlural or items.CPP local function search(name) for k, v in pairs(singularFormConversions) do			if normalize(k) == normalize(name) then return v			end end return {} end local allSingularAliases = table.map(table.merge({}, name, search(name)), function(sing)		return gsubFn('[]', '')(sing)	end) local allPluralAliases = table.map(allSingularAliases, function(sing)		-- get plural		if sing:match('%$u$') then return gsubFn('%$u$', '')(sing) end		local a, b = sing:find('%$s')		for k, v in pairs(pluralOverrides) do			if (a and sing:match(k..'%$s') or sing:match(k..'$')) then				return (a and gsubFn(k..'%$s', v)(sing) or gsubFn(k..'$', v)(sing))			end		end		if a then			assertFalse(a < 2, 'Wrong plural placement of item %s', 2, sing)			return gsubFn( '(sh?)%$s', '%1es', '(x)%$s', '%1es', '(ch)%$s', '%1es', 'y%$s', 'ies', 'fe?%$s', 'ves', '%$s', 's'			)(sing)		else			return gsubFn( '(sh?)$', '%1es', '(x)$', '%1es', '(ch)$', '%1es', 'y$', 'ies', '([^s])$', '%1s' )(sing)		end	end) items, allSingularAliases, allPluralAliases = table.map(items, normalize), table.map(allSingularAliases, normalize), table.map(allPluralAliases, normalize) table.each(allSingularAliases, function(n) -- Don't use .eachNamed: we don't want named indexes		table.each(table.merge({'Any', 'Matching'}, customPrefixSingular or {}), function(p) variants[p .. ' ' .. n] = items end)		table.each({'*', '?'}, function(p) variants[p .. n] = items end)	end) table.each(allPluralAliases, function(n) -- Don't use .eachNamed: we don't want named indexes		table.each(table.merge({'All'}, customPrefixPlural or {}), function(p) variants[p .. ' ' .. n] = items end)	end) end

-- 03: Main table for lists of item variants -- --	Mainly for adding items with lesser iteration	Use keys CPS (for singular) and CPP (for plural) to add additional custom prefixes -- local itemVariants = { -- ['Item group'] = { 'Item1', <'Item2'>, <...>, ,  } -- MISC -- ['Biome Stick'] = table.map({ 		'Birch Forest', 'Deep Ocean', 'Desert', 'End', 'Forest', 'Jungle', 'Nether', 'Roofed Forest', 'Savanna', 'Taiga',	}, function(v) return v .. " Biome Stick" end), ['Music Disc'] = { 'Music Disc Cat', 'Music Disc Blocks', 'Music Disc Far', 'Music Disc Strad', 'Music Disc Mellohi', 'Music Disc Ward', 'Music Disc Chirp', 'Music Disc 11', 'Music Disc 13', 'Music Disc Stal', 'Music Disc Mall', 'Music Disc Wait', 'Spooky Disc', 'Battle Disc', 'Winter Disc' }, ['Flower'] = { 'Dandelion', 'Poppy', 'Blue Orchid', 'Azure Bluet', 'Oxeye Daisy', 'Allium', 'Lilac', 'Rose Bush', 'White Tulip', 'Pink Tulip', 'Red Tulip', 'Orange Tulip', 'Sunflower', }, ['Mixin'] = { 'Zombie Brain Mixin', 'Spider Egg Mixin', 'Wolf Fur Mixin', 'End Portal Fumes', }, ['Lucky Block'] = { 'Green Lucky Block', 'Red Lucky Block', 'Yellow Lucky Block', }, ['Null Head'] = { 'Steve Head', 'Alex Head' }, ['Coin'] = { 'Iron Coin', 'Gold Coin', 'Diamond Coin', 'Emerald Coin', 'Redstone Coin', 'Lapis Coin' }, ['Travel Scroll'] = table.map({		'Blazing Fortress','Deep Caverns','Dwarven Mines','the Gold Mine',		'Mushroom Island','Spider\'s Den','the Barn','the End', 'the Void Sepulture',		'The Park','Hub Castle','Dark Auction','Hub Crypts',		'Spider\'s Den Top of Nest','Magma Fields','Dragon\'s Nest',		'Jungle Island','Howling Cave',	}, function(v) return "Travel Scroll to " .. v end), ['Fishing Bait$u'] = { 'Minnow Bait', 'Fish Bait', 'Light Bait', 'Dark Bait', 'Spiked Bait', 'Spooky Bait', 'Carrot Bait', 'Blessed Bait', 'Whale Bait', 'Ice Bait', 'Shark Bait' }, ['Brew'] = { 'Cheap Coffee', 'Tepid Green Tea', 'Pulpous Orange Juice', 'Bitter Ice Tea', 'KnockOff Cola', 'Decent Coffee', 'Viking\'s Tear', 'Tutti-Frutti Flavored Poison', 'Dctr. Paper', 'Slayer Energy Drink' }, ['Power Orb'] = { 'Radiant Power Orb', 'Mana Flux Power Orb', 'Overflux Power Orb', 'Plasmaflux Power Orb' }, ['Gift'] = { 'White Gift', 'Green Gift', 'Red Gift', }, ['Candy$u'] = { 'Green Candy', 'Purple Candy' }, ['2020 Crab Hat$s of Celebration'] = table.map({		'Red','Orange','Yellow','Lime','Green','Aqua','Purple','Pink','Black',	}, function(v) return v .. " Crab Hat of Celebration" end), ['2022 Crab Hat$s of Celebration'] = table.map({		'Red','Orange','Yellow','Lime','Green','Aqua','Purple','Pink','Black',	}, function(v) return v .. " Crab Hat of Celebration - 2022 Edition" end), ['Century Cake'] = { 'Crab-Colored Century Cake', 'Pet Rock Century Cake', 'aPunch Century Cake', 'Potato-Style Century Cake', 'Barry Century Cake', 'Sea Emperor Century Cake', 'Century Cake of the Next Dungeon Floor', 'Latest Update Century Cake', 'Streamer\'s Century Cake', 'Chocolate Century Cake', 'Cloudy Century Cake', 'Century Cake of Hype' }, ['Repelling Candle'] = table.map({		'Red','Orange','Yellow','Green','Blue','Purple','Black','Pink','Lilac','Aqua','Cyan','Brown','Gray','White',	}, function(v) return v .. " Repelling Candle" end), ['Gemstone Crystal'] = { 'Ruby Crystal', 'Amber Crystal', 'Sapphire Crystal', 'Jade Crystal', 'Amethyst Crystal', 'Topaz Crystal', 'Jasper Crystal', }, ['Horse Armor$u'] = { 'Iron Horse Armor', 'Gold Horse Armor', 'Diamond Horse Armor' }, ['Mushroom'] = { 'Red Mushroom', 'Brown Mushroom' }, ['Enchanted Mushroom'] = { 'Enchanted Red Mushroom', 'Enchanted Brown Mushroom' }, ['Quartz Block'] = { 'Block of Quartz', 'Chiseled Quartz Block', 'Quartz Pillar' }, ['Red Sandstone'] = { 'Red Sandstone', 'Chiseled Red Sandstone', 'Smooth Red Sandstone' }, ['Sandstone'] = { 'Sandstone', 'Chiseled Sandstone', 'Smooth Sandstone' }, ['Stone Bricks$u'] = { 'Stone Bricks', 'Mossy Stone Bricks', 'Cracked Stone Bricks', 'Chiseled Stone Bricks' }, ['Stone Slab'] = { 'Sandstone Slab', 'Cobblestone Slab', 'Brick Slab', 'Stone Brick Slab', 'Nether Brick Slab', 'Quartz Slab' }, ['Stone'] = { 'Stone', 'Andesite', 'Granite', 'Diorite', 'Polished Andesite', 'Polished Granite', 'Polished Diorite' }, ['Tulip'] = { 'Red Tulip', 'Orange Tulip', 'White Tulip', 'Pink Tulip' }, ['Custom Dye'] = { 'Iceberg Dye', 'Aquamarine Dye', 'Bone Dye', 'Brick Red Dye', 'Byzantium Dye', 'Carmine Dye', 'Celadon Dye', 'Celeste Dye', 'Cyclamen Dye', 'Dark Purple Dye', 'Emerald Dye', 'Flame Dye', 'Livid Dye', 'Mango Dye', 'Midnight Dye', 'Nadeshiko Dye', 'Necron Dye', 'Nyanza Dye', 'Pure Black Dye', 'Pure Blue Dye', 'Pure White Dye', 'Pure Yellow Dye', 'Wild Strawberry Dye' }, -- put iceberg first for infobox to work ['Abiphone'] = {'Abiphone X Plus', 'Abiphone X Plus Special Edition', 'Abiphone XI Ultra', 'Abiphone XI Ultra Style', 'Abiphone XII Mega', 'Abiphone XII Mega Color', 'Abiphone XIII Pro Giga'}, ['Trophy Fish$u'] = {'Blobfish', 'Flyfish', 'Golden Fish', 'Gusher', 'Karate Fish', 'Lava Horse', 'Mana Ray', 'Moldfin', 'Skeleton Fish', 'Slugfish', 'Soul Fish', 'Steaming-Hot Flounder', 'Sulphur Skitter', 'Vanille', 'Volcanic Stonefish', 'Obfuscated 1', 'Obfuscated 2', 'Obfuscated 3'}, } itemVariants['Crab Hat$s of Celebration'] = table.merge(itemVariants['2020 Crab Hat$s of Celebration'], itemVariants['2022 Crab Hat$s of Celebration'])

for n, v in pairs(itemVariants) do	createMultiAliases(n, v) end

-- Below this line: 04: Individual procedures to generate lists of item variants -- -- Pets -- createMultiAliases('Pet', pet.getPetList(nil, ' Pet')) createMultiAliases('Mystery Pet', pet.getPetList('Mystery ', ' Pet')) createMultiAliases('Pet Skin', pet.getSkinsList)

-- Colored dye (in Minecraft Namespace ID Order) -- coloredDyes = { --'Bone Meal', 'Orange Dye', 'Magenta Dye', 'Light Blue Dye', 'Dandelion Yellow', 'Lime Dye', 'Pink Dye', 'Gray Dye', 'Light Gray Dye', 'Cyan Dye', 'Purple Dye', 'Lapis Lazuli', 'Cocoa Beans', 'Cactus Green', 'Rose Red', 'Ink Sack', };

createMultiAliases('Colored Dye', coloredDyes) table.insert(coloredDyes, 1, 'Bone Meal') createMultiAliases('Dye', coloredDyes)

-- Colored items: General items that use the sixteen colors -- local zapkeep = gsubFn('%$k.-%s+', , '%$k', , '%$r', '') local zapremove = gsubFn('%$r.-%s+', , '%$k', , '%$r', '') -- ColorItmes Array -- --	Parameters	   first param: General name for ALL (colored & non-colored) items	    [second param]: General name for ALL COLORED items	    ['nocolor']: Alternative name for no-color item, otherwise assume no-color item as the White Item	    ['CPS'], ['CPP']	Irregular Insersions		For irregular color-indicating words (e.g. Dyed/Stained), insert symbol in front of a word. Symbols available:	    $k for color indicating term to be *KEPT in the actual item names* BUT to be removed for the general name	    $r for color indicating term to be *REMOVED in the actual item names* BUT to be kept for the general name -- local coloredItems = { {'Carpet', '$rDyed Carpet'}, {'Wool', '$rDyed Wool'}, {'Jumbo Backpack$s ($1)', '$rDyed Jumbo Backpack$s ($1)', nocolor='Jumbo Backpack$s'}, {'Greater Backpack$s ($1)', '$rDyed Greater Backpack$s ($1)', nocolor='Greater Backpack$s'}, {'Large Backpack$s ($1)', '$rDyed Large Backpack$s ($1)', nocolor='Large Backpack$s'}, {'Medium Backpack$s ($1)', '$rDyed Medium Backpack$s ($1)', nocolor='Medium Backpack$s'}, {'Small Backpack$s ($1)', '$rDyed Small Backpack$s ($1)', nocolor='Small Backpack$s'}, {'$kStained Glass$u', 'Stained Glass$u', nocolor='Glass'}, {'$kStained Glass Pane$u', 'Stained Glass Pane$u', nocolor='Glass'}, {'Hardened Clay$u', '$rStained Hardened Clay$u', nocolor='Hardened Clay'}, }

for _, item in ipairs(coloredItems) do	local itemAny, listAny, itemColored, listColored, nocolor local cps, cpp = item.CPS, item.CPP itemAny, listAny = item[1], {} itemColored, listColored = item[2], {} noColorItem = item['nocolor'] table.push(listAny, noColorItem) table.eachNamed(MCColors, function(color)		table.push(listAny, itemAny:match('%$1') and gsubFn('%$1', color)(zapremove(itemAny)) or color..' '..zapremove(itemAny) )		if (not not noColorItem or color:lower ~= "white") and not not itemColored then			table.push(listColored, itemColored:match('%$1') and gsubFn('%$1', color)(zapremove(itemColored)) or color..' '..zapremove(itemColored) )		end	end) createMultiAliases(gsubFn('%$1%s*', '')(zapkeep(itemAny)), listAny, cps, cpp) if itemColored then createMultiAliases(gsubFn('%$1%s*', '')(zapkeep(itemColored)), listColored, cps, cpp) end end

-- Item groups -- -- Dragon armors -- local dragonArmors = { 'Protector', 'Old', 'Unstable', 'Holy', 'Wise', 'Young', 'Strong', 'Superior' } for _, piece in ipairs{ 'Helmet', 'Chestplate', 'Leggings$u', 'Boots$u', 'Fragment' } do	local dragonRelatedAliases = table.map(table.deepCopy(dragonArmors), function(v) 		return v .. ' Dragon ' .. piece	end) createMultiAliases('Dragon ' .. piece, dragonRelatedAliases) end

-- Dungeon Boss Heads -- local dungeonBosses = { 'Bonzo', 'Scarf', 'Professor', 'Thorn', 'Livid', 'Sadan', 'Necron' } for _, tier in ipairs{ 'Golden', 'Diamond' } do	local dungBossHeads = table.map(table.deepCopy(dungeonBosses), function(v) 		return ('%s %s Head'):format(tier, v)	end) createMultiAliases(tier .. ' Dungeon Boss Head', dungBossHeads) end

-- Wood -- local woods = { 'Oak', 'Spruce', 'Birch', 'Dark Oak', 'Acacia', 'Jungle' } local woodItems = { 'Wood', 'Wood Plank', -- Skyblock specific 'Wood Slab', 'Wood Stairs$u', 'Fence', 'Fence Gate', 'Sapling', 'Leaves$u', } for _, item in ipairs(woodItems) do	local itemName; local woodAliases = {} for _, wood in ipairs(woods) do		if item:find('wood') then itemName = item:gsub('wood', wood) elseif item:find('%$1') then itemName = item:gsub('%$1', wood) else itemName = wood .. ' ' .. item end table.insert(woodAliases, itemName) end item = item:gsub('%$1 ', '') createMultiAliases(item, woodAliases) end

-- Minions local minions, perTier = table.keys(minionData), {}

local function eachMinion(name) local stats = minionData[name].stats local description = minionData[name].description or 'No Description' for i = 1,table.length(stats),1 do perTier[i] = table.merge(perTier[i] or {}, name.." Minion "..string._toRoman(i)) end return table.map(stats, function(v,i)   	return name.." Minion "..string._toRoman(i)	end) end

table.each(minions, function(name)	createMultiAliases(name.." Minion", eachMinion(name)) end)

table.each(perTier, function(vals, i)	createMultiAliases('Tier '..string._toRoman(i)..' Minion', vals) end) createMultiAliases('Minion', table.flat(perTier[1]))

-- Gemstones local gemstoneTiers = { 'Rough', 'Flawed', 'Fine', 'Flawless', 'Perfect', }

local gemstoneTypes = { 'Ruby', 'Amber', 'Sapphire', 'Jade', 'Amethyst', 'Topaz', 'Jasper', 'Opal', }

for _, a in ipairs(gemstoneTiers) do	createMultiAliases(('%s Gemstone'):format(a), table.map(gemstoneTypes, function(b) return ('%s %s Gemstone'):format(a, b)	end)) end

for _, b in ipairs(gemstoneTypes) do	createMultiAliases(('%s Gemstone'):format(b), table.map(gemstoneTiers, function(a) return ('%s %s Gemstone'):format(a, b)	end)) end

-- Power Scrolls createMultiAliases('Power Scroll', table.map(gemstoneTypes, function(b) return ('%s Power Scroll'):format(b) end))

-- Sacks local sackTypes = { 'Agronomy', 'Combat', 'Husbandry', 'Foraging', 'Fishing', 'Mining', 'Slayer', 'Gemstone', 'Nether', 'Lava Fishing', }

for _, b in ipairs(sackTypes) do	createMultiAliases(('%s Sack'):format(b), table.map( {'Small', 'Medium', 'Large'}, function(a) return ('%s %s Sack'):format(a, b)	end)) end

return variants