Module:Sandbox/C.Ezra.M/Pokémon
Documentation for this module may be created at Module:Sandbox/C.Ezra.M/Pokémon/doc
--- Individual modules of the Pokémon template.
--- Experimental template -- Work in progress!
--- Do not rely on this module in a production environment!
-- (c) 2024 C.Ezra.M <cezram AT proton DOT me>
-- This code is licensed under Creative Commons BY-NC-SA 2.5
local p = {}
-- library functions, will probably be moved somewhere else.
local function ifNilThen(x, y)
if x == nil then
return y
else
return x
end
end
--- returns true if x is false, nil, 0, an empty string, or an empty table
local function isEmpty(x)
if not x or x == "" or x == 0 then
return true
elseif type(x) == "table" and next(x) == nil then
return true
end
return false
end
local function colorTemplate(f, typ)
return f:expandTemplate { title = ifNilThen(typ, "") .. " color" }
end
local function colorLightTemplate(f, typ)
return f:expandTemplate { title = ifNilThen(typ, "") .. " color light" }
end
-- template proper -- some functions are local to prevent them from being exported
local function convertPokemonName(name)
local convert = {
["Nidoran♀️"] = "Nidoran",
["Nidoran♂️"] = "Nidoran",
["Mime Jr."] = "Mime Jr",
}
return ifNilThen(convert[name], name)
end
local function spriteGenderOrForm(name, form)
local convert = {
["male"] = "-Male",
["male shiny"] = "-Male",
["female"] = "-Female",
["female shiny"] = "-Female",
}
return ifNilThen(convert[name], form)
end
local function isShiny(spriteGender)
local convert = {
["male shiny"] = true,
["female shiny"] = true,
["shiny"] = true,
}
return ifNilThen(convert[spriteGender], false)
end
--- work in progress - currently only yields Sugimori artwork if the `img` argument is not supplied
local function getPokemonImage(f)
local image = f.args.img
if isEmpty(image) then
image = table.concat({
f.args.ndex,
convertPokemonName(f.args.pokemon),
ifNilThen(spriteGenderOrForm(f.args.spritegender, f.args.form), ""),
".png",
})
end
return mw.ustring.format('<div class="image">[[File:%s|100x100px|alt=]]</div>', image)
-- disable alt text, the sprite is pretty much used only for decoration,
-- whatever would be said by the screen reader wouldn't really make sense
-- (linking is still enabled)
end
--- work in progress
local function makeTag(f)
local pokeLink = f.args.character
local gender = ""
local shinyStar = ""
if isEmpty(pokeLink) then
local nickname = f.args.nickname
if isEmpty(nickname) then
nickname = f.args.pokemon
end
pokeLink = f:expandTemplate { title = "p", args = { f.args.pokemon, nickname } }
end
if f.args.gender == "male" or f.args.gender == "♂️" then
gender = f:expandTemplate { title = "male" }
elseif f.args.gender == "female" or f.args.gender == "♀️" then
gender = f:expandTemplate { title = "female" }
elseif f.args.gender == "both" then
gender = f:expandTemplate { title = "male" } .. "/" .. f:expandTemplate { title = "female" }
end
if isShiny(f.args.spritegender) then
shinyStar = "[[File:ShinyVIIIStar.png|20px|link=Shiny Pokémon]]"
end
return mw.ustring.format('<div class="tag">%s%s Lv.%s%s</div>', pokeLink, gender, f.args.level, shinyStar)
end
local function typeColumn(f)
local template = "[[File:%sIC SV.png|x20px|link=%s (type)|alt=%s]]"
local t1 = f.args.type1
local type1link = mw.ustring.format(template, t1, t1, t1)
local type2link = ""
if not isEmpty(f.args.type2) then
local t2 = f.args.type2
type2link = mw.ustring.format(template, t2, t2, t2)
end
return mw.ustring.format('<div class="type"><span class="field-name">Type:</span>%s%s</div>', type1link, type2link)
end
local function moveEntry(f, name, typ, cat)
-- if move not given, represent its slot as — (em dash)
if name == "" or name == nil then
return '* <span class="move-name">—</span>'
else
local moveLink = f:expandTemplate { title = "m", args = { name } }
-- mw.ustring.format is the same as string.format, but has Unicode support
local typeImg = mw.ustring.format(
'<span class="type-icon" style="background-color: #%s">[[File:%s icon.png|20px|link=%s (type)|alt=%s]]</span>',
colorTemplate(f, typ), typ, typ, typ)
if tonumber(f.args.gen) <= 3 then
-- in Gen 3 and below, a move's category is determined from its type, so we can ignore the category icon
return mw.ustring.format('* <span class="move-name">%s</span>%s', moveLink, typeImg)
else
-- using the same class for type and category icons
local catImg = mw.ustring.format(
'<span class="type-icon" style="background-color: #%s">[[File:%sIC SV.png|20px|link=%s move|alt=%s]]</span>',
colorTemplate(f, cat), cat, cat, cat)
return mw.ustring.format('* <span class="move-name">%s</span>%s%s', moveLink, typeImg, catImg)
end
end
end
local function secondaryInfoRow(name, data)
return mw.ustring.format('! class="field-name" | %s\n| %s\n', name, data)
end
--- Returns a table of mechanics that existed in the given generation.
--- Currently only recognizes numbers, LG (Let's Go), and LA (Legends: Arceus)
local function mechanicsInGen(gen)
gen = mw.ustring.lower(gen)
return {
-- ifNilThen is only used for comparisons, since Lua errors out when comparing any value with nil.
-- Lua can check equality of nil with any non-nil value, but always returns false if so.
gender = ifNilThen(tonumber(gen), 0) >= 2,
held = ifNilThen(tonumber(gen), 0) >= 2 and gen ~= "lg" and gen ~= "la",
ability = ifNilThen(tonumber(gen), 0) >= 3 and gen ~= "lg" and gen ~= "la",
category = ifNilThen(tonumber(gen), 0) >= 4,
spritegender = ifNilThen(tonumber(gen), 0) >= 4,
megastone = gen == "lg", -- this is only used for LGPE - for other games with Mega Evolution, use the held item field.
dynamax = tonumber(gen) == 8,
tera = tonumber(gen) == 9,
}
end
--- Checks if a mechanic exists in a given generation.
local function mechanicExistsInGen(gen, mechanic)
return ifNilThen(mechanicsInGen(gen)[mechanic], false)
end
-- exported functions
function p.primaryInfo(f)
return table.concat({ '<div class="primary">', getPokemonImage(f), makeTag(f), typeColumn(f), '</div>' })
end
--- work in progress - only the item, Ability, and Tera Type have been added
--- TODO: make a better generation checker (for game mechanics, sprites, etc.)
function p.secondaryInfo(f)
local info = {}
local gen = f.args.gen
if not isEmpty(f.args.held) and mechanicExistsInGen(gen, "held") then
info["held"] = f.args.held
end
if not isEmpty(f.args.ability) and mechanicExistsInGen(gen, "ability") then
info["ability"] = f.args.ability
end
if not isEmpty(f.args.tera) and mechanicExistsInGen(gen, "tera") then
info["tera"] = f.args.tera
end
local rows = {}
if info["held"] then
table.insert(
rows,
secondaryInfoRow(
"Held item:",
-- for now, it's safe to assume the image size is 24px, and no items need to link to a disambiguated page
-- (with exceptions like the Poké Ball or Pearl items, but those almost never happen)
mw.ustring.format("[[File:Bag %s Sprite.png|24px|alt=|link=%s]] [[%s]]", info["held"], info["held"], info["held"])
)
)
end
-- show if the held item mechanic exists but there is no held item
if info["held"] == nil and mechanicExistsInGen(gen, "held") then
table.insert(
rows,
secondaryInfoRow("Held item:", "None")
)
end
if info["ability"] then
table.insert(
rows,
secondaryInfoRow(
"Ability:",
f:expandTemplate { title = "a", args = { info["ability"] } }
)
)
end
if info["ability"] == nil and mechanicExistsInGen(gen, "ability") then
table.insert(
rows,
secondaryInfoRow("Ability:", "None")
)
end
if info["tera"] then
table.insert(
rows,
secondaryInfoRow(
"Tera Type:",
mw.ustring.format("[[File:%sIC Tera.png|x24px|link=%s (type)|alt=%s]]", info["tera"], info["tera"], info["tera"])
)
)
end
if not isEmpty(rows) then
return mw.ustring.format('<div class="secondary">\n{| class="data"\n%s|}</div>', table.concat(rows, "|-\n"))
end
return "" -- skip this div were the table empty
end
function p.moves(f)
local moveTable = {
{ f.args.move1, f.args.move1type, f.args.move1cat },
{ f.args.move2, f.args.move2type, f.args.move2cat },
{ f.args.move3, f.args.move3type, f.args.move3cat },
{ f.args.move4, f.args.move4type, f.args.move4cat },
}
local moveTags = {}
for k, mv in ipairs(moveTable) do
moveTags[k] = moveEntry(f, mv[1], mv[2], mv[3])
end
return '<div class="moves"><span class="field-name">Moves:</span>\n' .. table.concat(moveTags, "\n") .. '</div>'
end
return p
Categories
- No categories associated with this article