Module:Reskins holds the master list of cosmetic reskin items (Cherub, Halloween, Valentine's, Christmas, Custom) and renders them either as a gallery for a theme page or as an "Applicable Reskins" list inside an item's infobox.
Overview
A "reskin" is a cosmetic skin that can be applied to one or more item types (e.g. the Christmas "Sharpened Candy Cane" reskins any Sword). All of the reskins the wiki knows about are stored as a single Lua table inside this module — each entry records the skin's name, its theme, where it's obtained, a flavour desc, and the list of item types it applies to.
The module is used two ways:
- On theme pages (e.g. the Cherub reskins template) — it renders a full infobox gallery of every reskin in that theme.
- Inside
{{ItemInfobox}}— for a given item type it lists the named reskins that can be applied to that type, in the infobox's "Applicable Reskins" section.
Because the data lives in this module, adding or editing a reskin means editing the reskins table here — there is no separate per-reskin page to maintain.
Functions / entry points
| Function (#invoke) | What it does | Called by |
|---|---|---|
p.forType |
Given an item type name (e.g. Sword), returns a -separated list of clickable reskin entries (sprite icon + "<Name> Skin" linking to the Reskins page) for every reskin whose types include that type. Skips themes flagged NO_APPLY (currently Custom). Used to fill the Reskins section of an item infobox. |
{{ItemInfobox}} (via )
|
p.theme |
Given a theme key (e.g. Cherub), renders a full {{ItemInfobox}} for every reskin in that theme — using the skin's sprite, description, "Applies to:" type list, and "obtained" text. Returns No reskins in this category yet. if the theme has none. |
Theme listing templates, e.g. {{Cherub/Reskins}}, {{Christmas/Reskins}}, {{Custom/Reskins}}
|
How it's used
Inside the item infobox (already wired into {{ItemInfobox}} — editors don't add this themselves). The infobox only requests reskins for untiered items (when none of T1–T8 are set):
|ReskinList={{#if:{{{T1|}}}...{{{T8|}}}||{{#invoke:Reskins|forType|{{{type|{{#var:itemtype}}}}}}}}}
On a theme page (e.g. the Cherub reskins listing template):
<div class="display-items">
{{#invoke:Reskins|theme|Cherub}}
</div>
To add a new reskin, edit the reskins table in the module and give it a name, theme, obtained, desc and types. To list a new theme on its own page, create a template that calls No reskins in this category yet..
Notes
- Sprite file naming. Reskin sprite files are built automatically as
<ThemePrefix>Reskin-<NameWithoutSpaces>.png. The theme prefixes are: Cherub →CH, Halloween →H, Valentines →V, Christmas →C, Custom →Custom. Example: the Cherub "Blade of False Eden" expectsFile:CHReskin-BladeOfFalseEden.png. The name is title-cased and stripped of spaces before the prefix is added, so the uploaded file must match that exact form. - Type → sprite/link table. The module's
TYPEStable maps each item type to a T1 icon (e.g.T1Sword.png) and a section link (e.g.Weapons#Swords,Abilities#Bombs, or justArmours). This is used byp.themeto render the clickable "Applies to:" list. - Custom theme is excluded from item infoboxes.
NO_APPLY = { Custom = true }means custom/community reskins are shown only on their own theme page viap.theme, not in the per-item "Applicable Reskins" list. - The CLAUDE/project convention notes that reskins live on a separate page rather than on the base item's page; this module is the mechanism behind that separation.
- Related:
{{Infobox}}m(renders each infobox),{{Equipment}}mand{{Shinies}}m(sibling display modules),{{ItemInfobox}}.
local p = {}
local reskins = {
{ name = 'Bramble Bow', theme = 'Halloween', obtained = 'Halloween Event', desc = 'Woven from cursed brambles that thirst for wandering souls.', types = { 'Bow' } },
}
local THEME_PREFIX = { Cherub = 'CH', Halloween = 'H', Valentines = 'V', Christmas = 'C', Custom = 'Custom' }
local NO_APPLY = { Custom = true }
local TYPES = {
['Sword'] = { t1 = 'T1Sword.png', link = 'Weapons#Swords' },
['Katana'] = { t1 = 'T1Katana.png', link = 'Weapons#Katanas' },
['Bow'] = { t1 = 'T1Bow.png', link = 'Weapons#Bows' },
['Dagger'] = { t1 = 'T1Dagger.png', link = 'Weapons#Daggers' },
['Staff'] = { t1 = 'T1Staff.png', link = 'Weapons#Staves' },
['Sceptre'] = { t1 = 'T1Sceptre.png', link = 'Weapons#Sceptres' },
['Bomb'] = { t1 = 'T1Bomb.png', link = 'Abilities#Bombs' },
['Jewel'] = { t1 = 'T1Jewel.png', link = 'Abilities#Jewels' },
['Poison'] = { t1 = 'T1Poison.png', link = 'Abilities#Poisons' },
['Emblem'] = { t1 = 'T1Emblem.png', link = 'Abilities#Emblems' },
['Scripture'] = { t1 = 'T1Scripture.png', link = 'Abilities#Scriptures' },
['Orb'] = { t1 = 'T1Orb.png', link = 'Abilities#Orbs' },
['Star'] = { t1 = 'T1Star.png', link = 'Abilities#Stars' },
['Kunai'] = { t1 = 'T1Kunai.png', link = 'Abilities#Kunais' },
['Shield'] = { t1 = 'T1Shield.png', link = 'Abilities#Shields' },
['Cloak'] = { t1 = 'T1Cloak.png', link = 'Abilities#Cloaks' },
['Skull'] = { t1 = 'T1Skull.png', link = 'Abilities#Skulls' },
['Trap'] = { t1 = 'T1Trap.png', link = 'Abilities#Traps' },
['Heavy Helmet'] = { t1 = 'T1HeavyH.png', link = 'Armours' },
['Heavy Chestplate'] = { t1 = 'T1HeavyC.png', link = 'Armours' },
['Heavy Leggings'] = { t1 = 'T1HeavyL.png', link = 'Armours' },
['Heavy Boots'] = { t1 = 'T1HeavyB.png', link = 'Armours' },
['Light Helmet'] = { t1 = 'T1LightH.png', link = 'Armours' },
['Light Chestplate'] = { t1 = 'T1LightC.png', link = 'Armours' },
['Light Leggings'] = { t1 = 'T1LightL.png', link = 'Armours' },
['Light Boots'] = { t1 = 'T1LightB.png', link = 'Armours' },
['Magical Helmet'] = { t1 = 'T1MagicH.png', link = 'Armours' },
['Magical Chestplate'] = { t1 = 'T1MagicC.png', link = 'Armours' },
['Magical Leggings'] = { t1 = 'T1MagicL.png', link = 'Armours' },
['Magical Boots'] = { t1 = 'T1MagicB.png', link = 'Armours' },
}
local function spriteFile(r)
local s = r.name:gsub("(%a)([%w']*)", function(a, b) return a:upper() .. b end)
s = s:gsub("%s+", "")
return (THEME_PREFIX[r.theme] or '') .. 'Reskin-' .. s .. '.png'
end
local function typeLink(t)
local info = TYPES[t]
if not info then return t end
return string.format('[[File:%s|16x16px|link=%s]] [[%s|%s]]', info.t1, info.link, info.link, t)
end
function p.forType(frame)
local t = mw.text.trim(frame.args[1] or '')
if t == '' then return '' end
local out = {}
for _, r in ipairs(reskins) do
if not NO_APPLY[r.theme] then
for _, rt in ipairs(r.types) do
if rt == t then
out[#out + 1] = string.format(
'[[File:%s|16x16px|link=Reskins]] [[Reskins|%s]]', spriteFile(r), r.name .. ' Skin')
break
end
end
end
end
return table.concat(out, '<br>')
end
function p.theme(frame)
local key = mw.text.trim(frame.args[1] or '')
local out = {}
for _, r in ipairs(reskins) do
if r.theme == key then
local applies = {}
for _, t in ipairs(r.types) do
applies[#applies + 1] = typeLink(t)
end
out[#out + 1] = frame:expandTemplate{ title = 'ItemInfobox', args = {
title = r.name .. ' Skin',
images = spriteFile(r),
Desc = r.desc,
Ability = "'''Applies to:'''<br>" .. table.concat(applies, '<br>'),
Drop = r.obtained,
} }
end
end
if #out == 0 then return "''No reskins in this category yet.''" end
return table.concat(out, '\n')
end
return p