Difference between revisions of "Module:UnitData"
(Refactor; weapon infobox printing attempt) |
(Attempt to inline heatup function...) |
||
| (23 intermediate revisions by 2 users not shown) | |||
| Line 2: | Line 2: | ||
local unit = {} | local unit = {} | ||
local unitData = mw.loadData('Module:UnitData/data') | local unitData = mw.loadData('Module:UnitData/data') | ||
| + | |||
| + | local function toPercent(amount) | ||
| + | -- amount is a string when ToSI is used before calling this function | ||
| + | if type(amount) == "string" then | ||
| + | amount = tonumber(amount) | ||
| + | end | ||
| + | |||
| + | return string.format("%.0f", amount * 100) .. "%" | ||
| + | end | ||
function unit.getData(frame) | function unit.getData(frame) | ||
if not frame then return '' end | if not frame then return '' end | ||
| − | + | local unitDefName = frame.args.defname or frame.args[1] or "<no name specified>" | |
local ud = unitData[unitDefName] | local ud = unitData[unitDefName] | ||
| − | + | if not (ud) then return 'unitdef ' .. unitDefName .. ' not found' end | |
| − | + | local property = (frame.args.defname == nil) and frame.args[2] or frame.args[1] | |
| − | + | local result = ud[property] | |
| − | + | return result or '' | |
| − | + | end | |
| + | |||
| + | function unit.getAbilityInfoboxTemplate(abType, args) | ||
| + | local tbl = {title = "Infobox zkability " .. abType, args = args} | ||
| + | return tbl | ||
| + | end | ||
| + | |||
| + | function unit.getInfoboxTemplate(frame) | ||
| + | local args = frame.args | ||
| + | local tbl = {title = "Infobox zkunit", args = {}} | ||
| + | local u = tbl.args | ||
| + | local defName = args.defname or args[1] or "<no name specified>" | ||
| + | local ud = unitData[defName] | ||
| + | if not (ud) then return 'unitdef ' .. defName .. ' not found' end | ||
| + | |||
| + | for key, value in pairs(ud) do | ||
| + | u[key] = args[key] or value | ||
| + | end | ||
| + | u.abilities = unit.printAbilityInfoboxes(frame) | ||
| + | u.weapons = unit.printWeaponInfoboxes(frame) | ||
| + | u.weaponIDs = nil | ||
| + | u.shieldIDs = nil | ||
| + | u.drones = nil | ||
| + | |||
| + | return tbl | ||
| + | end | ||
| + | |||
| + | function unit.printAbilityInfoboxes(frame) | ||
| + | if not frame then return '' end | ||
| + | local unitDefName = frame.args.defname or frame.args[1] or "<no name specified>" | ||
| + | local ud = unitData[unitDefName] | ||
| + | if not (ud) then return 'unitdef ' .. unitDefName .. ' not found' end | ||
| + | |||
| + | local result = '' | ||
| + | if ud.drones then | ||
| + | for index, entry in ipairs(ud.drones) do | ||
| + | local args = { | ||
| + | drone = "[[" .. entry.drone .. "]]", | ||
| + | maxdrones = entry.maxDrones, | ||
| + | range = entry.range, | ||
| + | interval = entry.interval, | ||
| + | spawnsize = entry.spawnSize, | ||
| + | buildtime = entry.buildTime, | ||
| + | maxbuilding = entry.maxBuilding | ||
| + | } | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("drone", args)) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | if ud.buildSpeed then | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("construction", {buildpower = ud.buildSpeed})) | ||
| + | end | ||
| + | if ud.transportLightSpeed or ud.transportMediumSpeed or ud.transportHeavySpeed then | ||
| + | local light = ud.transportLightSpeed | ||
| + | local medium = ud.transportMediumSpeed | ||
| + | local heavy = ud.transportHeavySpeed | ||
| + | local args = {} | ||
| + | if light then args.light = light .. "%" end | ||
| + | if medium then args.medium = medium .. "%" end | ||
| + | if heavy then args.heavy = heavy .. "%" end | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("transport", args)) | ||
| + | end | ||
| + | if ud.canCloak or ud.idleCloak then | ||
| + | local args = {} | ||
| + | if (ud.cloakCost or 0) > 0 then | ||
| + | args.upkeepidle = ud.cloakCost | ||
| + | args.upkeepmobile = (ud.cloakCostMoving ~= ud.cloakCost) and ud.cloakCostMoving or nil | ||
| + | elseif ud.idleCloak then | ||
| + | args.customdata1 = "Only when idle" | ||
| + | args.customdata2 = "Free and automated" | ||
| + | end | ||
| + | args.decloakradius = ud.decloakDistance | ||
| + | if ud.decloakOnFire == false then | ||
| + | args.customdata3 = "No decloak while shooting" | ||
| + | end | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("cloak", args)) | ||
| + | end | ||
| + | if ud.areaCloakUpkeep then | ||
| + | local args = {name = "Area Cloak", radius = ud.areaCloakRadius, upkeep = ud.areaCloakUpkeep} | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("cloak", args)) | ||
| + | end | ||
| + | if ud.shieldIDs then | ||
| + | local weaponData = mw.loadData('Module:WeaponData/data') | ||
| + | for index, shieldID in pairs(ud.shieldIDs or {}) do | ||
| + | local args = {} | ||
| + | local shieldDef = weaponData[shieldID] | ||
| + | args.name = shieldDef.name | ||
| + | args.strength = shieldDef.strength | ||
| + | args.regen = shieldDef.regen | ||
| + | args.regencost = shieldDef.regencost | ||
| + | args.radius = shieldDef.radius | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("shield", args)) | ||
| + | end | ||
| + | end | ||
| + | if ud.radarDistance or ud.jammerDistance then | ||
| + | local args = {} | ||
| + | if ud.jammerDistance then | ||
| + | if not ud.radarDistance then | ||
| + | args.name = "Radar Jammer" | ||
| + | end | ||
| + | args.jam = ud.jammerDistance | ||
| + | end | ||
| + | if ud.radarDistance then | ||
| + | args.radar = ud.radarDistance | ||
| + | end | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("intel", args)) | ||
| + | end | ||
| + | if ud.jumpRange then | ||
| + | local args = {range = ud.jumpRange, reload = ud.jumpReload, speed = ud.jumpSpeed, midairjump = ud.midairJump and "Yes" or "No"} | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("jump", args)) | ||
| + | end | ||
| + | if ud.idleRegen or ud.combatRegen or ud.waterRegen or ud.armoredRegen then | ||
| + | local args = {} | ||
| + | if ud.idleRegenTime then | ||
| + | args.idleregen = ud.idleRegen | ||
| + | args.timetoenable = ud.idleRegenTime | ||
| + | elseif ud.combatRegen then | ||
| + | args.combatregen = ud.combatRegen | ||
| + | end | ||
| + | if ud.waterRegen then | ||
| + | args.waterregen = ud.waterRegen | ||
| + | args.atdepth = ud.waterRegenDepth | ||
| + | end | ||
| + | if ud.armoredRegen then | ||
| + | args.customlabel1 = "Closed regen (HP/s)" | ||
| + | args.customdata1 = ud.armoredRegen | ||
| + | end | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("regen", args)) | ||
| + | end | ||
| + | if ud.morphTo then | ||
| + | local args = {to = "[[" .. ud.morphTo .. "]]", cost = ud.morphCost, time = ud.morphTime, disabled = ud.combatMorph and "No" or "Yes"} | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("morph", args)) | ||
| + | end | ||
| + | if ud.armorDamageReduction then | ||
| + | local args = {reduction = ud.armorDamageReduction .. '%'} | ||
| + | if ud.armorForceClose then | ||
| + | args.special1 = "Forced for " .. ud.armorForceClose .. "s on damage" | ||
| + | end | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("armored", args)) | ||
| + | end | ||
| + | |||
| + | local args = {} | ||
| + | local num = 1 | ||
| + | do | ||
| + | if ud.isMex then | ||
| + | args["customdata".. num] = "Extracts metal" | ||
| + | num = num + 1 | ||
| + | end | ||
| + | if ud.stealth then | ||
| + | args["customdata".. num] = "Invisible to radar" | ||
| + | num = num + 1 | ||
| + | end | ||
| + | if ud.fireproof then | ||
| + | args["customdata".. num] = "Immunity to afterburn" | ||
| + | num = num + 1 | ||
| + | end | ||
| + | if ud.dontFireAtRadar then | ||
| + | args["customdata".. num] = "Can ignore unidentified targets" | ||
| + | num = num + 1 | ||
| + | end | ||
| + | if ud.instaSelfDestruct then | ||
| + | args["customdata".. num] = "Instant self-destruction" | ||
| + | num = num + 1 | ||
| + | end | ||
| + | end | ||
| + | if num > 1 then | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("line", args)) | ||
| + | end | ||
| + | |||
| + | return result | ||
end | end | ||
function unit.printWeaponInfoboxes(frame) | function unit.printWeaponInfoboxes(frame) | ||
if not frame then return '' end | if not frame then return '' end | ||
| − | + | local unitDefName = frame.args.defname or frame.args[1] or "<no name specified>" | |
local ud = unitData[unitDefName] | local ud = unitData[unitDefName] | ||
| − | + | if not (ud) then return 'unitdef ' .. unitDefName .. ' not found' end | |
| − | + | ||
| − | + | local result = '' | |
local weaponModule = require('Module:WeaponData') | local weaponModule = require('Module:WeaponData') | ||
for index,weaponID in ipairs(ud.weaponIDs or {}) do | for index,weaponID in ipairs(ud.weaponIDs or {}) do | ||
| − | local | + | local tempFrame = mw.getCurrentFrame():newChild{title="Module:WeaponData",args={defname=weaponID}} |
| − | result = result .. weaponModule.printInfobox( | + | result = result .. weaponModule.printInfobox(tempFrame) |
end | end | ||
| − | + | ||
| − | + | if ud.heatPerShot then | |
| − | + | local args = {} | |
| + | args.heatpershot = ud.heatPerShot | ||
| + | args.heatdecay = ud.heatDecay | ||
| + | args.heatmaxslow = ud.heatMaxSlow | ||
| + | result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("heatup", args)) | ||
| + | end | ||
| + | |||
| + | if result == '' then result = "None" end | ||
| + | return result | ||
| + | end | ||
| + | |||
| + | function unit.printInfobox(frame) | ||
| + | return frame:expandTemplate(unit.getInfoboxTemplate(frame)) | ||
end | end | ||
return unit | return unit | ||
Latest revision as of 20:20, 1 September 2024
This module is used to autogenerate unit infoboxes by drawing data from Module:UnitData/data. The intent is to ease updating of unit infoboxes on the wiki; ideally, only the one data page needing to be changed every release. The concept is taken from e.g. the Combat Card Data module on the Library of Ruina Wiki.
This module is currently used with Template:Autoinfobox zkunit as follows:
{{Autoinfobox zkunit
|defname=striderdetriment
|name=Name override
}}
The module can also be invoked directly to generate an infobox (note that output may not be identical in some cases; observed with automatic detection of buildpic on Reef):
{{#invoke:UnitData|printInfobox|defname=striderdetriment|name=Name override}}
When invoking from module, defname may be passed as an anonymous parameter instead.
See also Module:WeaponData, which is used to generate the weapon infoboxes within the unit infoboxes.
Data page[edit]
Module:UnitData/data is a central store of data used by Module:UnitData to automatically populate unit infoboxes.
The page is a Lua table written to the local file temp/unitStats.lua by the Wiki Data Export (dbg_wiki_export.lua) widget in Zero-K. This widget should be run once each update and the data page on the wiki replaced accordingly. It should not be necessary to edit the data manually.
local getArgs = require('Module:Arguments').getArgs
local unit = {}
local unitData = mw.loadData('Module:UnitData/data')
local function toPercent(amount)
-- amount is a string when ToSI is used before calling this function
if type(amount) == "string" then
amount = tonumber(amount)
end
return string.format("%.0f", amount * 100) .. "%"
end
function unit.getData(frame)
if not frame then return '' end
local unitDefName = frame.args.defname or frame.args[1] or "<no name specified>"
local ud = unitData[unitDefName]
if not (ud) then return 'unitdef ' .. unitDefName .. ' not found' end
local property = (frame.args.defname == nil) and frame.args[2] or frame.args[1]
local result = ud[property]
return result or ''
end
function unit.getAbilityInfoboxTemplate(abType, args)
local tbl = {title = "Infobox zkability " .. abType, args = args}
return tbl
end
function unit.getInfoboxTemplate(frame)
local args = frame.args
local tbl = {title = "Infobox zkunit", args = {}}
local u = tbl.args
local defName = args.defname or args[1] or "<no name specified>"
local ud = unitData[defName]
if not (ud) then return 'unitdef ' .. defName .. ' not found' end
for key, value in pairs(ud) do
u[key] = args[key] or value
end
u.abilities = unit.printAbilityInfoboxes(frame)
u.weapons = unit.printWeaponInfoboxes(frame)
u.weaponIDs = nil
u.shieldIDs = nil
u.drones = nil
return tbl
end
function unit.printAbilityInfoboxes(frame)
if not frame then return '' end
local unitDefName = frame.args.defname or frame.args[1] or "<no name specified>"
local ud = unitData[unitDefName]
if not (ud) then return 'unitdef ' .. unitDefName .. ' not found' end
local result = ''
if ud.drones then
for index, entry in ipairs(ud.drones) do
local args = {
drone = "[[" .. entry.drone .. "]]",
maxdrones = entry.maxDrones,
range = entry.range,
interval = entry.interval,
spawnsize = entry.spawnSize,
buildtime = entry.buildTime,
maxbuilding = entry.maxBuilding
}
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("drone", args))
end
end
if ud.buildSpeed then
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("construction", {buildpower = ud.buildSpeed}))
end
if ud.transportLightSpeed or ud.transportMediumSpeed or ud.transportHeavySpeed then
local light = ud.transportLightSpeed
local medium = ud.transportMediumSpeed
local heavy = ud.transportHeavySpeed
local args = {}
if light then args.light = light .. "%" end
if medium then args.medium = medium .. "%" end
if heavy then args.heavy = heavy .. "%" end
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("transport", args))
end
if ud.canCloak or ud.idleCloak then
local args = {}
if (ud.cloakCost or 0) > 0 then
args.upkeepidle = ud.cloakCost
args.upkeepmobile = (ud.cloakCostMoving ~= ud.cloakCost) and ud.cloakCostMoving or nil
elseif ud.idleCloak then
args.customdata1 = "Only when idle"
args.customdata2 = "Free and automated"
end
args.decloakradius = ud.decloakDistance
if ud.decloakOnFire == false then
args.customdata3 = "No decloak while shooting"
end
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("cloak", args))
end
if ud.areaCloakUpkeep then
local args = {name = "Area Cloak", radius = ud.areaCloakRadius, upkeep = ud.areaCloakUpkeep}
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("cloak", args))
end
if ud.shieldIDs then
local weaponData = mw.loadData('Module:WeaponData/data')
for index, shieldID in pairs(ud.shieldIDs or {}) do
local args = {}
local shieldDef = weaponData[shieldID]
args.name = shieldDef.name
args.strength = shieldDef.strength
args.regen = shieldDef.regen
args.regencost = shieldDef.regencost
args.radius = shieldDef.radius
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("shield", args))
end
end
if ud.radarDistance or ud.jammerDistance then
local args = {}
if ud.jammerDistance then
if not ud.radarDistance then
args.name = "Radar Jammer"
end
args.jam = ud.jammerDistance
end
if ud.radarDistance then
args.radar = ud.radarDistance
end
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("intel", args))
end
if ud.jumpRange then
local args = {range = ud.jumpRange, reload = ud.jumpReload, speed = ud.jumpSpeed, midairjump = ud.midairJump and "Yes" or "No"}
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("jump", args))
end
if ud.idleRegen or ud.combatRegen or ud.waterRegen or ud.armoredRegen then
local args = {}
if ud.idleRegenTime then
args.idleregen = ud.idleRegen
args.timetoenable = ud.idleRegenTime
elseif ud.combatRegen then
args.combatregen = ud.combatRegen
end
if ud.waterRegen then
args.waterregen = ud.waterRegen
args.atdepth = ud.waterRegenDepth
end
if ud.armoredRegen then
args.customlabel1 = "Closed regen (HP/s)"
args.customdata1 = ud.armoredRegen
end
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("regen", args))
end
if ud.morphTo then
local args = {to = "[[" .. ud.morphTo .. "]]", cost = ud.morphCost, time = ud.morphTime, disabled = ud.combatMorph and "No" or "Yes"}
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("morph", args))
end
if ud.armorDamageReduction then
local args = {reduction = ud.armorDamageReduction .. '%'}
if ud.armorForceClose then
args.special1 = "Forced for " .. ud.armorForceClose .. "s on damage"
end
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("armored", args))
end
local args = {}
local num = 1
do
if ud.isMex then
args["customdata".. num] = "Extracts metal"
num = num + 1
end
if ud.stealth then
args["customdata".. num] = "Invisible to radar"
num = num + 1
end
if ud.fireproof then
args["customdata".. num] = "Immunity to afterburn"
num = num + 1
end
if ud.dontFireAtRadar then
args["customdata".. num] = "Can ignore unidentified targets"
num = num + 1
end
if ud.instaSelfDestruct then
args["customdata".. num] = "Instant self-destruction"
num = num + 1
end
end
if num > 1 then
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("line", args))
end
return result
end
function unit.printWeaponInfoboxes(frame)
if not frame then return '' end
local unitDefName = frame.args.defname or frame.args[1] or "<no name specified>"
local ud = unitData[unitDefName]
if not (ud) then return 'unitdef ' .. unitDefName .. ' not found' end
local result = ''
local weaponModule = require('Module:WeaponData')
for index,weaponID in ipairs(ud.weaponIDs or {}) do
local tempFrame = mw.getCurrentFrame():newChild{title="Module:WeaponData",args={defname=weaponID}}
result = result .. weaponModule.printInfobox(tempFrame)
end
if ud.heatPerShot then
local args = {}
args.heatpershot = ud.heatPerShot
args.heatdecay = ud.heatDecay
args.heatmaxslow = ud.heatMaxSlow
result = result .. frame:expandTemplate(unit.getAbilityInfoboxTemplate("heatup", args))
end
if result == '' then result = "None" end
return result
end
function unit.printInfobox(frame)
return frame:expandTemplate(unit.getInfoboxTemplate(frame))
end
return unit