Module:ShipHullLister
From Terra Invicta Official Wiki
Documentation for this module may be created at Module:ShipHullLister/doc
---
---Reads the Laser Weapon data files and presents them in readable formats, with additional calculated statistics.
---
---@module ShipHullLister
local ShipHullLister = {}
--region Dependencies
local IconModule = require('Module:Icon')
local ShipHullData = mw.loadData('Module:CSVReader/ShipHull')
local HabModuleData = mw.loadData('Module:CSVReader/HabModule')
local ShipHullNames = mw.loadData('Module:ENReader/ShipHull')
local ProjectNameBuilder = require('Module:ProjectLister/NameBuilder')
--endregion
--region Private constants
local floor = math.floor
local ssub = string.sub
local round = function(num, decimals)
local mult = 10^(decimals or 0)
return floor(num * mult + 0.5) / mult
end
local dockDataNames = {"SpaceDock", "Shipyard", "Spaceworks", "AlienSpacedock", "AlienShipyard", "AlienSpaceworks"}
local maxArmorMultipliers = {3.6, 12, 3.6, 1.8, 6, 0}
--endregion
--region Private methods
local function calculateResourceCost(mass, resourceWeight, crew, crewResource)
local baseCost = tonumber(mass) * (tonumber(resourceWeight) or 0) / 10
local crewCost = tonumber(crew) * (tonumber(crewResource) or 0)
return baseCost + crewCost
end
local function calculateBuildTime(baseDays, consTier, alien, dockTier)
if consTier < dockTier then
local constructionTimeModifier = 0
if alien then
constructionTimeModifier = HabModuleData[dockDataNames[dockTier + 3]]['constructionTimeModifier']
else
constructionTimeModifier = HabModuleData[dockDataNames[dockTier]]['constructionTimeModifier']
end
return baseDays * constructionTimeModifier ^ (dockTier - consTier)
elseif consTier > dockTier then
return baseDays * 1.5 ^ (consTier - dockTier)
else
return baseDays
end
end
-- param @facing 1 = Nose, 2 = Side, 3 = Tail
local function calculateMaxArmorThickness(length, width, simple, facing)
if facing == 2 then
if simple then
return floor(width * maxArmorMultipliers[facing + 3])
else
return floor(width * maxArmorMultipliers[facing])
end
else
if simple then
return floor(length * maxArmorMultipliers[facing + 3])
else
return floor(length * maxArmorMultipliers[facing])
end
end
end
-- param @facing 1 = Nose/Tail, 2 = Side
local function calculateRoughArmorMultiplier(length, width, facing, cinematic)
if facing == 2 then
if cinematic then
return 3.1415927 * length * width * 0.75
else
return 3.1415927 * length * width * 0.5
end
else
if cinematic then
return 3.1415927 * width ^ 2 / 4
else
return 3.1415927 * width ^ 2 / 4 * 3
end
end
end
-- Safe value access with fallback
local function getValue(row, key, default)
local value = row[key]
if value == nil or value == '' then
return default or 0
end
return value
end
--endregion
--region Public methods
--- Example Usage: {{#invoke:ShipHullLister|ListSpecific|detailed=true|alien=true}}
function ShipHullLister.ListSpecific(frame)
local detailed = frame.args['detailed'] == 'true'
local alien = frame.args['alien'] == 'true'
return ShipHullLister.ListShipHulls(detailed, alien)
end
---@param detailed boolean whether to show the detailed or basic version.
---@param alien boolean whether to show alien or human version.
---@return wiki table of batteries
function ShipHullLister.ListShipHulls(detailed, alien)
local returnString = '{| class="wikitable sortable mw-collapsible" style="text-align: center;"'
returnString = returnString .. '\n! rowspan=3| Ship<br>Hull'
if detailed and not alien then
returnString = returnString .. '\n! rowspan=3| Required<br>Project'
end
returnString = returnString .. '\n! colspan=3| Hard Points'
returnString = returnString .. '\n! rowspan=3| Structural<br>Integrity'
returnString = returnString .. '\n! rowspan=3| Max<br>Officers'
if detailed then
returnString = returnString .. '\n! colspan=5| Construction'
returnString = returnString .. '\n! colspan=2| Dimensions (m)'
returnString = returnString .. '\n! colspan=3| Maximum Armor Thickness (cm)'
else
returnString = returnString .. '\n! colspan=3| Construction Time (days)'
end
returnString = returnString .. '\n! colspan=4| Rough Armor Cost Multiplier'
if detailed then
returnString = returnString .. '\n! rowspan=3| Crew'
returnString = returnString .. '\n! rowspan=3| Mass<br>(tons)'
returnString = returnString .. '\n! colspan=5| Build Cost'
returnString = returnString .. '\n! colspan=2| Upkeep Cost'
end
returnString = returnString .. '\n|-'
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'nose slot'}}) .. '<br>Nose'
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'hull slot'}}) .. '<br>Hull'
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'utility slot'}}) .. '<br>Utility'
if detailed then
returnString = returnString .. '\n! rowspan=2| Base<br>Days'
returnString = returnString .. '\n! rowspan=2| Ship<br>Tier'
end
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'spacedock'}}) .. '<br>T1'
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'shipyard'}}) .. '<br>T2'
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'spaceworks'}}) .. '<br>T3'
if detailed then
returnString = returnString .. '\n! rowspan=2| Length'
returnString = returnString .. '\n! rowspan=2| Width'
returnString = returnString .. '\n! rowspan=2| Nose'
returnString = returnString .. '\n! rowspan=2| Side'
returnString = returnString .. '\n! rowspan=2| Tail'
end
returnString = returnString .. '\n! colspan=2| Cinematic'
returnString = returnString .. '\n! colspan=2| Realistic'
if detailed then
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'water'}})
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'volatiles'}})
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'metals'}})
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'nobles'}})
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'exotics'}})
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'mc'}})
returnString = returnString .. '\n! rowspan=2| ' .. IconModule.Icon({args={'money'}})
end
returnString = returnString .. '\n|-'
returnString = returnString .. '\n! Nose/Tail'
returnString = returnString .. '\n! Side'
returnString = returnString .. '\n! Nose/Tail'
returnString = returnString .. '\n! Side'
returnString = returnString .. '\n|-'
for rowID, row in pairs(ShipHullData) do
local projectID = getValue(row, 'requiredProjectName', '')
if (alien and (projectID == 'Project_AlienMasterProject' or projectID == 'Project_AlienAdvancedMasterProject')) or ((not alien) and projectID ~= 'Project_AlienMasterProject' and projectID ~= 'Project_AlienAdvancedMasterProject') then
returnString = returnString .. '\n| ' .. (ShipHullNames['TIShipHullTemplate.displayName.' .. rowID] or rowID)
if detailed and not alien then
returnString = returnString .. '\n| ' .. ProjectNameBuilder.buildName({args={row['requiredProjectName']}})
end
returnString = returnString .. '\n| ' .. getValue(row, 'noseHardpoints', 0)
returnString = returnString .. '\n| ' .. getValue(row, 'hullHardpoints', 0)
returnString = returnString .. '\n| ' .. getValue(row, 'internalModules', 0)
returnString = returnString .. '\n| ' .. getValue(row, 'structuralIntegrity', 0)
returnString = returnString .. '\n| ' .. getValue(row, 'maxOfficers', 0)
local baseDays = tonumber(getValue(row, 'baseConstructionTime_days', 0)) or 0
local consTier = tonumber(getValue(row, 'consTier', 0)) or 0
if detailed then
returnString = returnString .. '\n| ' .. baseDays
returnString = returnString .. '\n| ' .. consTier
end
local simple = (row['simpleHull'] == 'true')
if simple then
returnString = returnString .. '\n| '
returnString = returnString .. '\n| '
returnString = returnString .. '\n| '
else
returnString = returnString .. '\n| ' .. round(calculateBuildTime(baseDays, consTier, alien, 1),1)
returnString = returnString .. '\n| ' .. round(calculateBuildTime(baseDays, consTier, alien, 2),1)
returnString = returnString .. '\n| ' .. round(calculateBuildTime(baseDays, consTier, alien, 3),1)
end
local length = tonumber(getValue(row, 'length_m', 0)) or 0
local width = tonumber(getValue(row, 'width_m', 0)) or 0
if detailed then
returnString = returnString .. '\n| ' .. length
returnString = returnString .. '\n| ' .. width
returnString = returnString .. '\n| ' .. calculateMaxArmorThickness(length, width, simple, 1)
returnString = returnString .. '\n| ' .. calculateMaxArmorThickness(length, width, simple, 2)
returnString = returnString .. '\n| ' .. calculateMaxArmorThickness(length, width, simple, 3)
end
returnString = returnString .. '\n| ' .. round(calculateRoughArmorMultiplier(length, width, 1, true))
returnString = returnString .. '\n| ' .. round(calculateRoughArmorMultiplier(length, width, 2, true))
returnString = returnString .. '\n| ' .. round(calculateRoughArmorMultiplier(length, width, 1, false))
returnString = returnString .. '\n| ' .. round(calculateRoughArmorMultiplier(length, width, 2, false))
if detailed then
local crewCount = tonumber(getValue(row, 'crew', 0)) or 0
local baseMass = tonumber(getValue(row, 'mass_tons', 0)) or 0
local massWithCrew = baseMass + crewCount * 4
returnString = returnString .. '\n| ' .. crewCount
returnString = returnString .. '\n| ' .. massWithCrew
local waterCost = calculateResourceCost(baseMass, 0, crewCount, 0.2)
local volatilesCost = calculateResourceCost(baseMass, getValue(row, 'weightedBuildMaterials/volatiles'), crewCount, 0.2)
local metalsCost = calculateResourceCost(baseMass, getValue(row, 'weightedBuildMaterials/metals'), crewCount, 0)
local noblesCost = calculateResourceCost(baseMass, getValue(row, 'weightedBuildMaterials/nobleMetals'), crewCount, 0)
local exoticsCost = calculateResourceCost(baseMass, getValue(row, 'weightedBuildMaterials/exotics'), crewCount, 0)
returnString = returnString .. '\n| ' .. round(waterCost, 3)
returnString = returnString .. '\n| ' .. round(volatilesCost, 3)
returnString = returnString .. '\n| ' .. round(metalsCost, 3)
returnString = returnString .. '\n| ' .. round(noblesCost, 3)
returnString = returnString .. '\n| ' .. round(exoticsCost, 3)
returnString = returnString .. '\n| ' .. getValue(row, 'missionControl', 0)
local moneyUpkeep = ((tonumber(getValue(row, 'monthlyIncome_Money', 0)) or 0) * -1)
if moneyUpkeep > 0 then
returnString = returnString .. '\n| ' .. moneyUpkeep
else
returnString = returnString .. '\n| 0' -- If ships ever GIVE money, then this needs changing.
end
end
returnString = returnString .. '\n|-'
end
end
returnString = returnString .. '\n|}'
return returnString
end
function ShipHullLister.CompareShipHulls()
local returnString = '{| class="wikitable sortable mw-collapsible" style="text-align: center;"'
returnString = returnString .. '\n! rowspan=3| Ship<br>Hull'
returnString = returnString .. '\n! colspan=6| Hard Points'
returnString = returnString .. '\n! rowspan=2 colspan=2| Structural<br>Integrity'
returnString = returnString .. '\n! colspan=6| Construction Time (days)'
returnString = returnString .. '\n|-'
returnString = returnString .. '\n! colspan=2| ' .. IconModule.Icon({args={'nose slot'}}) .. '<br>Nose'
returnString = returnString .. '\n! colspan=2| ' .. IconModule.Icon({args={'hull slot'}}) .. '<br>Hull'
returnString = returnString .. '\n! colspan=2| ' .. IconModule.Icon({args={'utility slot'}}) .. '<br>Utility'
returnString = returnString .. '\n! colspan=2| ' .. IconModule.Icon({args={'spacedock'}}) .. '<br>T1'
returnString = returnString .. '\n! colspan=2| ' .. IconModule.Icon({args={'shipyard'}}) .. '<br>T2'
returnString = returnString .. '\n! colspan=2| ' .. IconModule.Icon({args={'spaceworks'}}) .. '<br>T3'
returnString = returnString .. '\n|-'
returnString = returnString .. '\n! Human'
returnString = returnString .. '\n! Alien'
returnString = returnString .. '\n! Human'
returnString = returnString .. '\n! Alien'
returnString = returnString .. '\n! Human'
returnString = returnString .. '\n! Alien'
returnString = returnString .. '\n! Human'
returnString = returnString .. '\n! Alien'
returnString = returnString .. '\n! Human'
returnString = returnString .. '\n! Alien'
returnString = returnString .. '\n! Human'
returnString = returnString .. '\n! Alien'
returnString = returnString .. '\n! Human'
returnString = returnString .. '\n! Alien'
returnString = returnString .. '\n|-'
for rowID, row in pairs(ShipHullData) do
if (getValue(row, 'alien') == 'true') then
returnString = returnString .. '\n| ' .. (ShipHullNames['TIShipHullTemplate.displayName.' .. rowID] or rowID)
local humanID = ssub(rowID,6)
if not ShipHullData[humanID] then
if rowID == 'SalamanderGunship' then
humanID = 'STOFighter'
else
humanID = nil
end
end
local alienHardpoints = {
tonumber(getValue(row, 'noseHardpoints', 0)) or 0,
tonumber(getValue(row, 'hullHardpoints', 0)) or 0,
tonumber(getValue(row, 'internalModules', 0)) or 0
}
if not ShipHullData[humanID] then
returnString = returnString .. '\n| \n| ' .. alienHardpoints[1]
returnString = returnString .. '\n| \n| ' .. alienHardpoints[2]
returnString = returnString .. '\n| \n| ' .. alienHardpoints[3]
else
local humanHardpoints = {
tonumber(getValue(ShipHullData[humanID], 'noseHardpoints', 0)) or 0,
tonumber(getValue(ShipHullData[humanID], 'hullHardpoints', 0)) or 0,
tonumber(getValue(ShipHullData[humanID], 'internalModules', 0)) or 0
}
for i = 1, 3 do
returnString = returnString .. '\n|' .. humanHardpoints[i] .. '\n| ' .. alienHardpoints[i]
if humanHardpoints[i] > alienHardpoints[i] then
returnString = returnString .. IconModule.Icon({args={'greenarrowdown'}})
elseif humanHardpoints[i] < alienHardpoints[i] then
returnString = returnString .. IconModule.Icon({args={'redarrowup'}})
end
end
end
local alienStructuralIntegrity = tonumber(getValue(row, 'structuralIntegrity', 0)) or 0
if not ShipHullData[humanID] then
returnString = returnString .. '\n| \n| ' .. alienStructuralIntegrity
else
local humanStructuralIntegrity = tonumber(getValue(ShipHullData[humanID], 'structuralIntegrity', 0)) or 0
returnString = returnString .. '\n|' .. humanStructuralIntegrity .. '\n| ' .. alienStructuralIntegrity
if humanStructuralIntegrity > alienStructuralIntegrity then
returnString = returnString .. IconModule.Icon({args={'greenarrowdown'}})
elseif humanStructuralIntegrity < alienStructuralIntegrity then
returnString = returnString .. IconModule.Icon({args={'redarrowup'}})
end
end
local simple = (row['simpleHull'] == 'true')
if simple then
returnString = returnString .. '\n| \n| '
returnString = returnString .. '\n| \n| '
returnString = returnString .. '\n| \n| '
else
local alienBaseDays = tonumber(getValue(row, 'baseConstructionTime_days', 0)) or 0
local alienConsTier = tonumber(getValue(row, 'consTier', 0)) or 0
local alienBuildTime = {
round(calculateBuildTime(alienBaseDays, alienConsTier, true, 1),1),
round(calculateBuildTime(alienBaseDays, alienConsTier, true, 2),1),
round(calculateBuildTime(alienBaseDays, alienConsTier, true, 3),1)
}
if not ShipHullData[humanID] then
returnString = returnString .. '\n| \n| ' .. alienBuildTime[1]
returnString = returnString .. '\n| \n| ' .. alienBuildTime[2]
returnString = returnString .. '\n| \n| ' .. alienBuildTime[3]
else
local humanBaseDays = tonumber(getValue(ShipHullData[humanID], 'baseConstructionTime_days', 0)) or 0
local humanConsTier = tonumber(getValue(ShipHullData[humanID], 'consTier', 0)) or 0
local humanBuildTime = {
round(calculateBuildTime(humanBaseDays, humanConsTier, false, 1),1),
round(calculateBuildTime(humanBaseDays, humanConsTier, false, 2),1),
round(calculateBuildTime(humanBaseDays, humanConsTier, false, 3),1)
}
for i = 1, 3 do
returnString = returnString .. '\n|' .. humanBuildTime[i] .. '\n| ' .. alienBuildTime[i]
if humanBuildTime[i] > alienBuildTime[i] then
returnString = returnString .. IconModule.Icon({args={'redarrowdown'}})
elseif humanBuildTime[i] < alienBuildTime[i] then
returnString = returnString .. IconModule.Icon({args={'greenarrowup'}})
end
end
end
end
returnString = returnString .. '\n|-'
end
end
returnString = returnString .. '\n|}'
return returnString
end
--endregion
return ShipHullLister


