Module:C: Difference between revisions
From Teriock
More actions
// via Wikitext Extension for VSCode |
No edit summary |
||
| (48 intermediate revisions by the same user not shown) | |||
| Line 36: | Line 36: | ||
end | end | ||
-- === NEW: shared abilities parsing helpers === | |||
local function parseAbilitiesString(abilitiesString) | |||
local abilities = {} | local abilities = {} | ||
for ability in mw.text.gsplit(abilitiesString, ";;", true) do | for ability in mw.text.gsplit(abilitiesString or '', ";;", true) do | ||
ability = mw.text.trim(ability) | ability = mw.text.trim(ability) | ||
if ability ~= "" then | if ability ~= "" then | ||
| Line 99: | Line 63: | ||
end | end | ||
-- clean name (strip markers + | -- clean name (strip markers + payloads/flags) | ||
name = mw.ustring.gsub(name, "%-l%-.+", "") | name = mw.ustring.gsub(name, "%-l%-.+", "") | ||
name = mw.ustring.gsub(name, "%-i%-.+", "") | name = mw.ustring.gsub(name, "%-i%-.+", "") | ||
| Line 116: | Line 80: | ||
end | end | ||
table.sort(abilities, function(a, b) return a.name < b.name end) | table.sort(abilities, function(a, b) return a.name < b.name end) | ||
return abilities | |||
end | |||
local function buildAETransclusions(abilities) | |||
local transclusions = {} | local transclusions = {} | ||
for _, a in ipairs(abilities) do | for _, a in ipairs(abilities or {}) do | ||
local t = {"{{AE|", a.name} | local t = {"{{AE|", a.name} | ||
if a.limited ~= "" then table.insert(t, "|limited=" .. a.limited) end | if a.limited ~= "" then table.insert(t, "|limited=" .. a.limited) end | ||
| Line 132: | Line 97: | ||
table.insert(transclusions, table.concat(t)) | table.insert(transclusions, table.concat(t)) | ||
end | end | ||
-- no visible separators between AE templates | |||
return table.concat(transclusions, "") | |||
end | |||
-- === Body parts parsing helpers === | |||
local function parseBodyPartsString(bodyPartsString) | |||
local bodyParts = {} | |||
for part in mw.text.gsplit(bodyPartsString or '', ";;", true) do | |||
part = mw.text.trim(part) | |||
if part ~= "" then table.insert(bodyParts, part) end | |||
end | |||
table.sort(bodyParts) | |||
return bodyParts | |||
end | |||
local function buildBPTransclusions(bodyParts) | |||
local transclusions = {} | |||
for _, part in ipairs(bodyParts or {}) do | |||
table.insert(transclusions, "{{BP|" .. part .. "}}") | |||
end | |||
return table.concat(transclusions, "") | |||
end | |||
-- === Equipment parsing helpers === | |||
local function parseEquipmentString(equipmentString) | |||
local equipment = {} | |||
for part in mw.text.gsplit(equipmentString or '', ";;", true) do | |||
part = mw.text.trim(part) | |||
if part ~= "" then table.insert(equipment, part) end | |||
end | |||
table.sort(equipment) | |||
return equipment | |||
end | |||
local function buildEQTransclusions(equipment) | |||
local transclusions = {} | |||
for _, part in ipairs(equipment or {}) do | |||
table.insert(transclusions, "{{EQ|" .. part .. "}}") | |||
end | |||
return table.concat(transclusions, "") | |||
end | |||
-- === END helpers === | |||
function p.c(frame) | |||
local args = frame.args | |||
local rawAbilities = args['a'] or '' | |||
local rawBodyParts = args['b'] or '' | |||
local rawEquipment = args['e'] or '' | |||
-- === TAGS & CATEGORIES via TagBuilder === | |||
local TagBuilder = require('Module:TagBuilder') | |||
local DiceEval = require('Module:DiceEval') | |||
local typeRaw = args['c'] or '' | |||
local traitRaw = args['t'] or '' | |||
local looks = args['l'] or '' | |||
local description = args['d'] or '' | |||
local ranks = args['r'] or '' | |||
local instructions = args['i'] or '' | |||
local regionRaw = args['region'] or args['g'] or '' | |||
local name = args['name'] or '' | |||
local attributeSizeIncrease = args['as'] or '' | |||
local hpDice = args['hp'] or '1d10' | |||
local mpDice = args['mp'] or '1d10' | |||
local hpDiceNumberStep = args['hpn'] or '' | |||
local mpDiceNumberStep = args['mpn'] or '' | |||
local hpDiceNumberText = 'hit die' | |||
local mpDiceNumberText = 'mana die' | |||
if hpDiceNumberStep:len() > 0 then | |||
if hpDiceNumberStep == '1' then | |||
hpDiceNumberStep = '' | |||
else | |||
hpDiceNumberStep = hpDiceNumberStep .. ' ' | |||
end | |||
hpDiceNumberText = hpDiceNumberStep .. 'hit dice' | |||
end | |||
if mpDiceNumberStep:len() > 0 then | |||
if mpDiceNumberStep == '1' then | |||
mpDiceNumberStep = '' | |||
else | |||
mpDiceNumberStep = mpDiceNumberStep .. ' ' | |||
end | |||
mpDiceNumberText = mpDiceNumberStep .. 'mana dice' | |||
end | |||
local hpDiceSizeStep = args['hps'] or '' | |||
local mpDiceSizeStep = args['mps'] or '' | |||
local hpDiceMinSize = args['hpm'] or '' | |||
local mpDiceMinSize = args['mpm'] or '' | |||
if hpDiceMinSize:len() > 0 then | |||
hpDiceMinSize = " above " .. hpDiceMinSize | |||
end | |||
if mpDiceMinSize:len() > 0 then | |||
mpDiceMinSize = " above " .. mpDiceMinSize | |||
end | |||
if hpDiceSizeStep:len() > 0 then | |||
local hpPlural = 's' | |||
if hpDiceSizeStep == '1' then hpPlural = '' end | |||
hpDiceSizeStep = "Gain another " .. hpDiceNumberText .. " for every " .. | |||
hpDiceSizeStep .. " additional size" .. hpPlural .. | |||
hpDiceMinSize .. "." | |||
end | |||
if mpDiceSizeStep:len() > 0 then | |||
local mpPlural = 's' | |||
if mpDiceSizeStep == '1' then mpPlural = '' end | |||
mpDiceSizeStep = "Gain another " .. mpDiceNumberText .. " for every " .. | |||
mpDiceSizeStep .. " additional size" .. mpPlural .. | |||
mpDiceMinSize .. "." | |||
end | |||
local baseHp = '0' | |||
local baseMp = '0' | |||
local size = args['size'] or '3' | |||
local br = args['br'] or '0' | |||
local int = args['int'] or '0' | |||
local str = args['str'] or '0' | |||
local mov = args['mov'] or '0' | |||
local snk = args['snk'] or '0' | |||
local per = args['per'] or '0' | |||
local preAbilities = '' | |||
if (int == '0') then | |||
preAbilities = preAbilities .. "Normal Intelligence;; " | |||
end | |||
if (str == '0') then preAbilities = preAbilities .. "Normal Strength;; " end | |||
if (mov == '0') then preAbilities = preAbilities .. "Normal Movement;; " end | |||
if (snk == '0') then preAbilities = preAbilities .. "Normal Sneak;; " end | |||
if (per == '0') then | |||
preAbilities = preAbilities .. "Normal Perception;; " | |||
end | |||
local abilitiesString = preAbilities .. rawAbilities | |||
local opts = { | |||
name = name, | |||
ns = 'Creature', | |||
transparent = args.o or args.transparent | |||
} | |||
local traitOut, traitCatOut = TagBuilder.build(traitRaw, 'TagCreatures', | |||
'traits', opts) | |||
local typeOut, typeCatOut = TagBuilder.build(typeRaw, 'TagCreatures', | |||
'types', opts) | |||
local regionOut, regionCatOut = TagBuilder.build(regionRaw, 'TagCreatures', 'regions', opts) | |||
-- === Parse and render main abilities with shared helpers === | |||
local abilities = parseAbilitiesString(abilitiesString) | |||
local inner = buildAETransclusions(abilities) | |||
-- | -- === Parse body parts === | ||
local | local bodyParts = parseBodyPartsString(rawBodyParts) | ||
local bodyPartsInner = buildBPTransclusions(bodyParts) | |||
local | -- === Parse equipment === | ||
local equipment = parseEquipmentString(rawEquipment) | |||
local equipmentInner = buildEQTransclusions(equipment) | |||
local categoryString = '[[Category:Creatures]]' | |||
local statContent = '' | local statContent = '' | ||
statContent = | local inheritedStats = false | ||
statContent .. "{{Tag|" .. baseHp .. " HP|❤️|l=:Category:" .. baseHp .. | |||
if (hpDice == 'x') then | |||
statContent = statContent .. | |||
"{{Tag|Variable Hit Dice|❤️|l=:Category:Variable hit die creatures|c=#e01b24|class=hp-dice-tagged x}}" | |||
statContent = | categoryString = categoryString .. | ||
statContent .. "{{Tag|" .. baseMp .. " MP|🩵|l=:Category:" .. baseMp .. | "[[Category:Variable hit die creatures]]" | ||
inheritedStats = true | |||
else | |||
baseHp = tostring(DiceEval._eval(hpDice)) | |||
statContent = statContent .. "{{Tag|Size " .. size .. | statContent = statContent .. "{{Tag|" .. hpDice .. | ||
" Hit Dice|❤️|l=:Category:" .. hpDice .. | |||
" hit die creatures|c=#e01b24|class=hp-dice-tagged " .. | |||
hpDice .. "}}" .. "{{Tag|" .. baseHp .. | |||
" HP|❤️|l=:Category:" .. baseHp .. | |||
" HP creatures|c=#e01b24|class=cost-tagged hp" .. | |||
baseHp .. "}}" | |||
categoryString = categoryString .. "[[Category:" .. hpDice .. | |||
" hit die creatures" .. "]]" | |||
categoryString = categoryString .. "[[Category:" .. baseHp .. | |||
" HP creatures" .. "]]" | |||
end | |||
if (mpDice == 'x') then | |||
statContent = statContent .. | |||
"{{Tag|Variable Mana Dice|🩵|l=:Category:Variable mana die creatures|c=#3584e4|class=mp-dice-tagged x}}" | |||
categoryString = categoryString .. | |||
"[[Category:Variable mana die creatures]]" | |||
inheritedStats = true | |||
else | |||
baseMp = tostring(DiceEval._eval(mpDice)) | |||
statContent = statContent .. "{{Tag|" .. mpDice .. | |||
" Mana Dice|🩵|l=:Category:" .. mpDice .. | |||
" mana die creatures|c=#3584e4|class=mp-dice-tagged " .. | |||
mpDice .. "}}" .. "{{Tag|" .. baseMp .. | |||
" MP|🩵|l=:Category:" .. baseMp .. | |||
" MP creatures|c=#3584e4|class=cost-tagged hp" .. | |||
baseMp .. "}}" | |||
categoryString = categoryString .. "[[Category:" .. baseMp .. | |||
" MP creatures" .. "]]" | |||
categoryString = categoryString .. "[[Category:" .. mpDice .. | |||
" mana die creatures" .. "]]" | |||
end | |||
if (size == 'x') then | |||
statContent = statContent .. | |||
"{{Tag|Variable Size|⬆️|l=:Category:Variable size creatures|c=#e4a835|class=size-tagged x}}" | |||
categoryString = categoryString .. | |||
"[[Category:Variable size creatures]]" | |||
inheritedStats = true | |||
else | |||
statContent = statContent .. "{{Tag|Size " .. size .. | |||
"|⬆️|l=:Category:Size " .. size .. | |||
" creatures|c=#e4a835|class=size-tagged size" .. size .. | |||
"}}" | |||
categoryString = categoryString .. "[[Category:Size " .. size .. | |||
" creatures" .. "]]" | |||
end | |||
local attributeContent = '' | local attributeContent = '' | ||
attributeContent = "" | attributeContent = "" | ||
attributeContent = attributeContent .. "{{Tag|" .. int .. | if (int ~= 'x') then | ||
attributeContent = attributeContent .. "{{Tag|" .. int .. | |||
"|INT|l=:Category:INT value of " .. int .. | |||
" creatures}}" | |||
categoryString = categoryString .. "[[Category:INT value of " .. int .. | |||
attributeContent = attributeContent .. "{{Tag|" .. str .. | " creatures]]" | ||
end | |||
if (str ~= 'x') then | |||
attributeContent = attributeContent .. "{{Tag|" .. str .. | |||
"|STR|l=:Category:STR value of " .. str .. | |||
attributeContent = attributeContent .. "{{Tag|" .. mov .. | " creatures}}" | ||
categoryString = categoryString .. "[[Category:STR value of " .. str .. | |||
" creatures]]" | |||
end | |||
if (mov ~= 'x') then | |||
attributeContent = attributeContent .. "{{Tag|" .. snk .. | attributeContent = attributeContent .. "{{Tag|" .. mov .. | ||
"|MOV|l=:Category:MOV value of " .. mov .. | |||
" creatures}}" | |||
categoryString = categoryString .. "[[Category:MOV value of " .. mov .. | |||
" creatures]]" | |||
attributeContent = attributeContent .. "{{Tag|" .. per .. | end | ||
if (snk ~= 'x') then | |||
attributeContent = attributeContent .. "{{Tag|" .. snk .. | |||
"|SNK|l=:Category:SNK value of " .. snk .. | |||
" creatures}}" | |||
categoryString = categoryString .. "[[Category:SNK value of " .. snk .. | |||
" creatures]]" | |||
end | |||
if (per ~= 'x') then | |||
attributeContent = attributeContent .. "{{Tag|" .. per .. | |||
"|PER|l=:Category:PER value of " .. per .. | |||
" creatures}}" | |||
categoryString = categoryString .. "[[Category:PER value of " .. per .. | |||
" creatures]]" | |||
end | |||
traitContent = (traitOut or '') .. "{{Tag|BR " .. br .. | |||
"|⚠️|l=:Category:BR " .. br .. | |||
" creatures|class=br-tagged br" .. br .. "}}" | |||
typeContent = (typeOut or '') | |||
regionContent = (regionOut or '') | |||
categoryString = categoryString .. "[[Category:BR " .. br .. " creatures]]" | |||
local out = "" | local out = "" | ||
out = out .. makeBar(frame, "Stats", statContent, | out = out .. makeBar(frame, "Stats", statContent, nil, nil, false) | ||
out = out .. makeBar(frame, "Attributes", attributeContent, | out = out .. makeBar(frame, "Attributes", attributeContent, nil, nil, false) | ||
out = out .. makeBar(frame, "Traits", ( | out = out .. makeBar(frame, "Traits", traitContent, nil, nil, false) | ||
out = out .. makeBar(frame, "Looks", looks, | out = out .. makeBar(frame, "Creature types", typeContent, nil, nil, false) | ||
out = out .. makeBar(frame, "Regions", regionContent, nil, nil, false) | |||
out = out .. makeBar(frame, "Looks", looks, nil, nil, false) | |||
out = out .. makeBar(frame, "Innate ranks", ranks, nil, nil, false) | |||
out = out .. makeBar(frame, "HP increase", hpDiceSizeStep, nil, nil, false) | |||
out = out .. makeBar(frame, "MP increase", mpDiceSizeStep, nil, nil, false) | |||
out = out .. | |||
makeBar(frame, "Attribute increase", attributeSizeIncrease, nil, | |||
nil, false) | |||
if (inheritedStats) then | |||
out = out .. makeBar(frame, "Inherited stats", | |||
"Variable stats are inherited from the parent {{L|Category|Creatures|creature}}.", | |||
nil, nil, false) | |||
end | |||
if args['lifespan'] then | |||
local lifespanText = args['lifespan'] .. " years." | |||
categoryString = categoryString .. "[[Category:" .. args['lifespan'] .. | |||
" year lifespan creatures]]" | |||
if args['adult'] then | |||
lifespanText = lifespanText .. " Adult at age " .. args['adult'] .. | |||
"." | |||
end | |||
out = out .. makeBar(frame, "Lifespan", lifespanText, nil, nil, false) | |||
end | |||
out = out .. makeBar(frame, "Instructions", instructions, nil, nil, false) | |||
out = out .. '<hr>' | out = out .. '<hr>' | ||
if args['d'] then out = out .. | if description:len() > 0 then | ||
out = out .. '<div class="expandable-table"><div>' .. | out = out .. '<span class="creature-description>' .. args['d'] .. | ||
'</span><hr>' | |||
out = out .. ( | end | ||
-- main abilities block | |||
out = out .. makeBar(frame, "Abilities", | |||
'<div class="expandable-table"><div>' .. | |||
frame:preprocess(inner) .. '</div></div>', nil, | |||
nil, false) | |||
-- === body parts block (after abilities, before equipment) === | |||
if rawBodyParts ~= '' and #bodyParts > 0 then | |||
out = out .. '<hr>' .. makeBar(frame, "Body Parts", | |||
'<div class="expandable-table"><div>' .. | |||
frame:preprocess(bodyPartsInner) .. | |||
'</div></div>', nil, nil, false) | |||
end | |||
-- === equipment block (after body parts, before familiar abilities) === | |||
if rawEquipment ~= '' and #equipment > 0 then | |||
out = out .. '<hr>' .. makeBar(frame, "Equipment", | |||
'<div class="expandable-table"><div>' .. | |||
frame:preprocess(equipmentInner) .. | |||
'</div></div>', nil, nil, false) | |||
end | |||
-- === familiar abilities (args['f']) using the same parsing === | |||
if args['f'] and mw.text.trim(args['f']) ~= '' then | |||
local fAbilities = parseAbilitiesString(args['f']) | |||
local fInner = buildAETransclusions(fAbilities) | |||
-- You can wrap in a bar or just mirror the main output style; here we label it: | |||
out = out .. '<hr>' .. makeBar(frame, "Familiar Abilities", | |||
frame:preprocess( | |||
'<div class="expandable-table"><div>' .. | |||
fInner .. '</div></div>'), nil, | |||
nil, false) | |||
end | |||
out = out .. (traitCatOut or '') .. (typeCatOut or '') .. (regionCatOut or '') | |||
local page = mw.title.getCurrentTitle().text | local page = mw.title.getCurrentTitle().text | ||
local namespace = frame:preprocess('{{NAMESPACE}}') | local namespace = frame:preprocess('{{NAMESPACE}}') | ||
| Line 201: | Line 432: | ||
end | end | ||
return frame:preprocess(out) | return frame:preprocess(out) | ||
end | end | ||
return p | return p | ||
Latest revision as of 16:34, 17 July 2026
Documentation for this module may be created at Module:C/doc
local p = {}
local function makeBar(frame, title, content, link, flags, bottom)
if content == '' then return '' end
local barSpace = mw.html.create('span')
barSpace:wikitext(frame:preprocess(' ')):css('display', 'none')
local barTitle = mw.html.create('span')
local barTitleClass = "{{lc:" .. title .. "}}"
barTitleClass = barTitleClass:gsub(' ', '-')
barTitleClass = barTitleClass:gsub('\'', '')
barTitleClass = barTitleClass:gsub('\"', '')
local barText = "{{ucfirst:" .. title .. "}}"
if link then barText = "[[" .. link .. "|" .. barText .. "]]" end
barText = barText .. ":"
barTitle:addClass('ability-bar-title'):wikitext(frame:preprocess(barText))
:css('font-weight', 'bold'):css('margin-right', '0.5em')
local barContent = mw.html.create('span')
barContent:addClass('ability-bar-content'):wikitext(content)
local output = mw.html.create('div')
if bottom then output = mw.html.create('span') end
if not flags then flags = {} end
for k, v in pairs(flags) do
if type(v) == 'string' then
output:addClass('flag-' .. k .. '-' .. v)
end
end
output:addClass('ability-bar'):addClass('ability-bar-' .. barTitleClass)
:attr(flags):attr('test', 'out'):node(barSpace):node(barTitle):node(
barSpace):node(barContent):css('display', 'block')
-- if flags then
-- for k, v in ipairs(flags) do
-- output:attr(k, v)
-- end
-- end
return tostring(output)
end
-- === NEW: shared abilities parsing helpers ===
local function parseAbilitiesString(abilitiesString)
local abilities = {}
for ability in mw.text.gsplit(abilitiesString or '', ";;", true) do
ability = mw.text.trim(ability)
if ability ~= "" then
local name = ability
local limited, improved = "", ""
local gifted, adept = false, false
-- flags
if mw.ustring.find(ability, "%-g%-") then gifted = true end
if mw.ustring.find(ability, "%-a%-") then adept = true end
-- notes (order-insensitive, tolerate any following marker)
local limitedMatch = mw.ustring.match(ability,
"%-l%-(.-)(%-[liag]%-|$)") or
mw.ustring.match(ability, "%-l%-(.+)$")
if limitedMatch then limited = mw.text.trim(limitedMatch) end
local improvedMatch = mw.ustring.match(ability,
"%-i%-(.-)(%-[liag]%-|$)") or
mw.ustring.match(ability, "%-i%-(.+)$")
if improvedMatch then
improved = mw.text.trim(improvedMatch)
end
-- clean name (strip markers + payloads/flags)
name = mw.ustring.gsub(name, "%-l%-.+", "")
name = mw.ustring.gsub(name, "%-i%-.+", "")
name = mw.ustring.gsub(name, "%-g%-", "")
name = mw.ustring.gsub(name, "%-a%-", "")
name = mw.text.trim(name)
table.insert(abilities, {
name = name,
limited = limited,
improved = improved,
gifted = gifted,
adept = adept
})
end
end
table.sort(abilities, function(a, b) return a.name < b.name end)
return abilities
end
local function buildAETransclusions(abilities)
local transclusions = {}
for _, a in ipairs(abilities or {}) do
local t = {"{{AE|", a.name}
if a.limited ~= "" then table.insert(t, "|limited=" .. a.limited) end
if a.improved ~= "" then
table.insert(t, "|improved=" .. a.improved)
end
if a.gifted then table.insert(t, "|gifted=1") end
if a.adept then table.insert(t, "|adept=1") end
table.insert(t, "}}")
table.insert(transclusions, table.concat(t))
end
-- no visible separators between AE templates
return table.concat(transclusions, "")
end
-- === Body parts parsing helpers ===
local function parseBodyPartsString(bodyPartsString)
local bodyParts = {}
for part in mw.text.gsplit(bodyPartsString or '', ";;", true) do
part = mw.text.trim(part)
if part ~= "" then table.insert(bodyParts, part) end
end
table.sort(bodyParts)
return bodyParts
end
local function buildBPTransclusions(bodyParts)
local transclusions = {}
for _, part in ipairs(bodyParts or {}) do
table.insert(transclusions, "{{BP|" .. part .. "}}")
end
return table.concat(transclusions, "")
end
-- === Equipment parsing helpers ===
local function parseEquipmentString(equipmentString)
local equipment = {}
for part in mw.text.gsplit(equipmentString or '', ";;", true) do
part = mw.text.trim(part)
if part ~= "" then table.insert(equipment, part) end
end
table.sort(equipment)
return equipment
end
local function buildEQTransclusions(equipment)
local transclusions = {}
for _, part in ipairs(equipment or {}) do
table.insert(transclusions, "{{EQ|" .. part .. "}}")
end
return table.concat(transclusions, "")
end
-- === END helpers ===
function p.c(frame)
local args = frame.args
local rawAbilities = args['a'] or ''
local rawBodyParts = args['b'] or ''
local rawEquipment = args['e'] or ''
-- === TAGS & CATEGORIES via TagBuilder ===
local TagBuilder = require('Module:TagBuilder')
local DiceEval = require('Module:DiceEval')
local typeRaw = args['c'] or ''
local traitRaw = args['t'] or ''
local looks = args['l'] or ''
local description = args['d'] or ''
local ranks = args['r'] or ''
local instructions = args['i'] or ''
local regionRaw = args['region'] or args['g'] or ''
local name = args['name'] or ''
local attributeSizeIncrease = args['as'] or ''
local hpDice = args['hp'] or '1d10'
local mpDice = args['mp'] or '1d10'
local hpDiceNumberStep = args['hpn'] or ''
local mpDiceNumberStep = args['mpn'] or ''
local hpDiceNumberText = 'hit die'
local mpDiceNumberText = 'mana die'
if hpDiceNumberStep:len() > 0 then
if hpDiceNumberStep == '1' then
hpDiceNumberStep = ''
else
hpDiceNumberStep = hpDiceNumberStep .. ' '
end
hpDiceNumberText = hpDiceNumberStep .. 'hit dice'
end
if mpDiceNumberStep:len() > 0 then
if mpDiceNumberStep == '1' then
mpDiceNumberStep = ''
else
mpDiceNumberStep = mpDiceNumberStep .. ' '
end
mpDiceNumberText = mpDiceNumberStep .. 'mana dice'
end
local hpDiceSizeStep = args['hps'] or ''
local mpDiceSizeStep = args['mps'] or ''
local hpDiceMinSize = args['hpm'] or ''
local mpDiceMinSize = args['mpm'] or ''
if hpDiceMinSize:len() > 0 then
hpDiceMinSize = " above " .. hpDiceMinSize
end
if mpDiceMinSize:len() > 0 then
mpDiceMinSize = " above " .. mpDiceMinSize
end
if hpDiceSizeStep:len() > 0 then
local hpPlural = 's'
if hpDiceSizeStep == '1' then hpPlural = '' end
hpDiceSizeStep = "Gain another " .. hpDiceNumberText .. " for every " ..
hpDiceSizeStep .. " additional size" .. hpPlural ..
hpDiceMinSize .. "."
end
if mpDiceSizeStep:len() > 0 then
local mpPlural = 's'
if mpDiceSizeStep == '1' then mpPlural = '' end
mpDiceSizeStep = "Gain another " .. mpDiceNumberText .. " for every " ..
mpDiceSizeStep .. " additional size" .. mpPlural ..
mpDiceMinSize .. "."
end
local baseHp = '0'
local baseMp = '0'
local size = args['size'] or '3'
local br = args['br'] or '0'
local int = args['int'] or '0'
local str = args['str'] or '0'
local mov = args['mov'] or '0'
local snk = args['snk'] or '0'
local per = args['per'] or '0'
local preAbilities = ''
if (int == '0') then
preAbilities = preAbilities .. "Normal Intelligence;; "
end
if (str == '0') then preAbilities = preAbilities .. "Normal Strength;; " end
if (mov == '0') then preAbilities = preAbilities .. "Normal Movement;; " end
if (snk == '0') then preAbilities = preAbilities .. "Normal Sneak;; " end
if (per == '0') then
preAbilities = preAbilities .. "Normal Perception;; "
end
local abilitiesString = preAbilities .. rawAbilities
local opts = {
name = name,
ns = 'Creature',
transparent = args.o or args.transparent
}
local traitOut, traitCatOut = TagBuilder.build(traitRaw, 'TagCreatures',
'traits', opts)
local typeOut, typeCatOut = TagBuilder.build(typeRaw, 'TagCreatures',
'types', opts)
local regionOut, regionCatOut = TagBuilder.build(regionRaw, 'TagCreatures', 'regions', opts)
-- === Parse and render main abilities with shared helpers ===
local abilities = parseAbilitiesString(abilitiesString)
local inner = buildAETransclusions(abilities)
-- === Parse body parts ===
local bodyParts = parseBodyPartsString(rawBodyParts)
local bodyPartsInner = buildBPTransclusions(bodyParts)
-- === Parse equipment ===
local equipment = parseEquipmentString(rawEquipment)
local equipmentInner = buildEQTransclusions(equipment)
local categoryString = '[[Category:Creatures]]'
local statContent = ''
local inheritedStats = false
if (hpDice == 'x') then
statContent = statContent ..
"{{Tag|Variable Hit Dice|❤️|l=:Category:Variable hit die creatures|c=#e01b24|class=hp-dice-tagged x}}"
categoryString = categoryString ..
"[[Category:Variable hit die creatures]]"
inheritedStats = true
else
baseHp = tostring(DiceEval._eval(hpDice))
statContent = statContent .. "{{Tag|" .. hpDice ..
" Hit Dice|❤️|l=:Category:" .. hpDice ..
" hit die creatures|c=#e01b24|class=hp-dice-tagged " ..
hpDice .. "}}" .. "{{Tag|" .. baseHp ..
" HP|❤️|l=:Category:" .. baseHp ..
" HP creatures|c=#e01b24|class=cost-tagged hp" ..
baseHp .. "}}"
categoryString = categoryString .. "[[Category:" .. hpDice ..
" hit die creatures" .. "]]"
categoryString = categoryString .. "[[Category:" .. baseHp ..
" HP creatures" .. "]]"
end
if (mpDice == 'x') then
statContent = statContent ..
"{{Tag|Variable Mana Dice|🩵|l=:Category:Variable mana die creatures|c=#3584e4|class=mp-dice-tagged x}}"
categoryString = categoryString ..
"[[Category:Variable mana die creatures]]"
inheritedStats = true
else
baseMp = tostring(DiceEval._eval(mpDice))
statContent = statContent .. "{{Tag|" .. mpDice ..
" Mana Dice|🩵|l=:Category:" .. mpDice ..
" mana die creatures|c=#3584e4|class=mp-dice-tagged " ..
mpDice .. "}}" .. "{{Tag|" .. baseMp ..
" MP|🩵|l=:Category:" .. baseMp ..
" MP creatures|c=#3584e4|class=cost-tagged hp" ..
baseMp .. "}}"
categoryString = categoryString .. "[[Category:" .. baseMp ..
" MP creatures" .. "]]"
categoryString = categoryString .. "[[Category:" .. mpDice ..
" mana die creatures" .. "]]"
end
if (size == 'x') then
statContent = statContent ..
"{{Tag|Variable Size|⬆️|l=:Category:Variable size creatures|c=#e4a835|class=size-tagged x}}"
categoryString = categoryString ..
"[[Category:Variable size creatures]]"
inheritedStats = true
else
statContent = statContent .. "{{Tag|Size " .. size ..
"|⬆️|l=:Category:Size " .. size ..
" creatures|c=#e4a835|class=size-tagged size" .. size ..
"}}"
categoryString = categoryString .. "[[Category:Size " .. size ..
" creatures" .. "]]"
end
local attributeContent = ''
attributeContent = ""
if (int ~= 'x') then
attributeContent = attributeContent .. "{{Tag|" .. int ..
"|INT|l=:Category:INT value of " .. int ..
" creatures}}"
categoryString = categoryString .. "[[Category:INT value of " .. int ..
" creatures]]"
end
if (str ~= 'x') then
attributeContent = attributeContent .. "{{Tag|" .. str ..
"|STR|l=:Category:STR value of " .. str ..
" creatures}}"
categoryString = categoryString .. "[[Category:STR value of " .. str ..
" creatures]]"
end
if (mov ~= 'x') then
attributeContent = attributeContent .. "{{Tag|" .. mov ..
"|MOV|l=:Category:MOV value of " .. mov ..
" creatures}}"
categoryString = categoryString .. "[[Category:MOV value of " .. mov ..
" creatures]]"
end
if (snk ~= 'x') then
attributeContent = attributeContent .. "{{Tag|" .. snk ..
"|SNK|l=:Category:SNK value of " .. snk ..
" creatures}}"
categoryString = categoryString .. "[[Category:SNK value of " .. snk ..
" creatures]]"
end
if (per ~= 'x') then
attributeContent = attributeContent .. "{{Tag|" .. per ..
"|PER|l=:Category:PER value of " .. per ..
" creatures}}"
categoryString = categoryString .. "[[Category:PER value of " .. per ..
" creatures]]"
end
traitContent = (traitOut or '') .. "{{Tag|BR " .. br ..
"|⚠️|l=:Category:BR " .. br ..
" creatures|class=br-tagged br" .. br .. "}}"
typeContent = (typeOut or '')
regionContent = (regionOut or '')
categoryString = categoryString .. "[[Category:BR " .. br .. " creatures]]"
local out = ""
out = out .. makeBar(frame, "Stats", statContent, nil, nil, false)
out = out .. makeBar(frame, "Attributes", attributeContent, nil, nil, false)
out = out .. makeBar(frame, "Traits", traitContent, nil, nil, false)
out = out .. makeBar(frame, "Creature types", typeContent, nil, nil, false)
out = out .. makeBar(frame, "Regions", regionContent, nil, nil, false)
out = out .. makeBar(frame, "Looks", looks, nil, nil, false)
out = out .. makeBar(frame, "Innate ranks", ranks, nil, nil, false)
out = out .. makeBar(frame, "HP increase", hpDiceSizeStep, nil, nil, false)
out = out .. makeBar(frame, "MP increase", mpDiceSizeStep, nil, nil, false)
out = out ..
makeBar(frame, "Attribute increase", attributeSizeIncrease, nil,
nil, false)
if (inheritedStats) then
out = out .. makeBar(frame, "Inherited stats",
"Variable stats are inherited from the parent {{L|Category|Creatures|creature}}.",
nil, nil, false)
end
if args['lifespan'] then
local lifespanText = args['lifespan'] .. " years."
categoryString = categoryString .. "[[Category:" .. args['lifespan'] ..
" year lifespan creatures]]"
if args['adult'] then
lifespanText = lifespanText .. " Adult at age " .. args['adult'] ..
"."
end
out = out .. makeBar(frame, "Lifespan", lifespanText, nil, nil, false)
end
out = out .. makeBar(frame, "Instructions", instructions, nil, nil, false)
out = out .. '<hr>'
if description:len() > 0 then
out = out .. '<span class="creature-description>' .. args['d'] ..
'</span><hr>'
end
-- main abilities block
out = out .. makeBar(frame, "Abilities",
'<div class="expandable-table"><div>' ..
frame:preprocess(inner) .. '</div></div>', nil,
nil, false)
-- === body parts block (after abilities, before equipment) ===
if rawBodyParts ~= '' and #bodyParts > 0 then
out = out .. '<hr>' .. makeBar(frame, "Body Parts",
'<div class="expandable-table"><div>' ..
frame:preprocess(bodyPartsInner) ..
'</div></div>', nil, nil, false)
end
-- === equipment block (after body parts, before familiar abilities) ===
if rawEquipment ~= '' and #equipment > 0 then
out = out .. '<hr>' .. makeBar(frame, "Equipment",
'<div class="expandable-table"><div>' ..
frame:preprocess(equipmentInner) ..
'</div></div>', nil, nil, false)
end
-- === familiar abilities (args['f']) using the same parsing ===
if args['f'] and mw.text.trim(args['f']) ~= '' then
local fAbilities = parseAbilitiesString(args['f'])
local fInner = buildAETransclusions(fAbilities)
-- You can wrap in a bar or just mirror the main output style; here we label it:
out = out .. '<hr>' .. makeBar(frame, "Familiar Abilities",
frame:preprocess(
'<div class="expandable-table"><div>' ..
fInner .. '</div></div>'), nil,
nil, false)
end
out = out .. (traitCatOut or '') .. (typeCatOut or '') .. (regionCatOut or '')
local page = mw.title.getCurrentTitle().text
local namespace = frame:preprocess('{{NAMESPACE}}')
if ((namespace == "Creature") and (page == name)) then
out = out .. categoryString
end
return frame:preprocess(out)
end
return p