Module:ShipArmorLister

From Terra Invicta Official Wiki

Documentation for this module may be created at Module:ShipArmorLister/doc

---
---Reads the Armor data files and presents them in readable formats, with additional calculated statistics.
---
---@module ArmorLister
local ArmorLister = {}

--region Dependencies
local IconModule = require('Module:Icon')
local ArmorData = mw.loadData('Module:CSVReader/ShipArmor')
local ArmorNames = mw.loadData('Module:ENReader/ShipArmor')
local ProjectNameBuilder = require('Module:ProjectLister/NameBuilder')
local HabModuleData = mw.loadData('Module:CSVReader/HabModule') 
--endregion

--region Private constants
local floor = math.floor
local round = function(num, decimals)
    local mult = 10^(decimals or 0)
    return floor(num * mult + 0.5) / mult
end
local PI = 3.1415927
-- Predefined hab module masses (fallback values if not in CSV)
local HAB_MODULE_MASSES = {
    PointDefenseArray = 50,
    LayeredDefenseArray = 100,
    Battlestations = 150,
    AlienPointDefenseArray = 60,
    AlienLayeredDefenseArray = 120,
    AlienBattlestations = 180
}
--endregion

--region Private methods
-- Safe value access with fallback
local function getValue(row, key, default)
    local value = row[key]
    if value == nil or value == '' then
        return default or 'None'
    end
    return value
end

local function calculateMassForGunshipArmor(vapor)
    return round(4 / tonumber(vapor) * 5 * 5 * PI, 3)
end

local function calculateThicknessPerPoint(density, vapor)
    return round(400000 / tonumber(vapor) / tonumber(density), 3)
end

local function calculateResourceCost(vapor, resourceWeight)
    local mass = calculateMassForGunshipArmor(vapor)
    return round(tonumber(resourceWeight) * mass / 10, 4)
end

local function calculateArmorForRadiation(halfValue, thicknessPerPoint)
    return round(tonumber(halfValue) / thicknessPerPoint, 3)
end

local function getSpecialtyDisplay(specialty, specialtyVal)
    if not specialty or specialty == 'None' then
        return ''
    end
    
    local specialtyNames = {
        ChippingResistance = specialtyVal .. "× Chip Damage Taken",
        KineticsResistance = specialtyVal .. "× Kinetic Damage Taken", 
        LaserResistance = specialtyVal .. "× Laser Damage Taken"
    }
    
    return specialtyNames[specialty] or specialty
end

-- Get hab module mass by name
local function getHabModuleMass(moduleName)
    -- First try to get from CSV data
    for rowID, row in pairs(HabModuleData) do
        if rowID == moduleName then
            return tonumber(row['baseMass_tons']) or HAB_MODULE_MASSES[moduleName] or 0
        end
    end
    -- Fallback to predefined values
    return HAB_MODULE_MASSES[moduleName] or 0
end

-- Calculate ground hab armor values
local function calculateGroundHabArmor(vapor, multiplier)
    return round(tonumber(vapor) / multiplier, 2) .. " × Module Tier"
end

-- Calculate space hab HP values
local function calculateSpaceHabHP(moduleMass, moduleTier, vapor)
    return round(0.3 * moduleMass / moduleTier / 20 * tonumber(vapor), 2)
end

-- Check if armor should be included in hab effects (non-exotic, non-alien)
local function shouldIncludeInHabEffects(row)
    local exotics = tonumber(getValue(row, 'weightedBuildMaterials/exotics', 0))
    local project = getValue(row, 'requiredProjectName')
    return exotics == 0 and project ~= 'Project_AlienMasterProject'
end
--endregion

--region Public methods
function ArmorLister.ListBasicArmor()
    local returnString = '{| class="wikitable sortable mw-collapsible mw-collapsed" style="text-align: center;"'
    returnString = returnString .. '\n! rowspan=2|Armor'
    returnString = returnString .. '\n! rowspan=2|Mass (tons)<br>for 0/0/1 Armor on a Gunship'
    returnString = returnString .. '\n! rowspan=2|Bonus Resistance'
    returnString = returnString .. '\n! colspan=4| Resource Cost for 0/0/1 Armor on a Gunship'
    returnString = returnString .. '\n! colspan=2|Armor Needed to Halve Radiation Damage'
    returnString = returnString .. '\n|-'
    returnString = returnString .. '\n!' .. IconModule.Icon({args={'volatiles'}}) .. ' Volatiles'
    returnString = returnString .. '\n!' .. IconModule.Icon({args={'metals'}}) .. ' Base Metals'
    returnString = returnString .. '\n!' .. IconModule.Icon({args={'nobles'}}) .. ' Noble Metals'
    returnString = returnString .. '\n!' .. IconModule.Icon({args={'exotics'}}) .. ' Exotics'
    returnString = returnString .. '\n! X-Ray'
    returnString = returnString .. '\n! Baryonic'
    returnString = returnString .. '\n|-'
    
    for rowID, row in pairs(ArmorData) do
        returnString = returnString .. '\n| ' .. (ArmorNames['TIShipArmorTemplate.displayName.' .. rowID] or rowID)
        
        local vapor = getValue(row, 'heatofVaporization_MJkg', 1)
        local mass = calculateMassForGunshipArmor(vapor)
        returnString = returnString .. '\n| ' .. mass
        
        local specialty = getValue(row, 'specialties/2/armorSpecialty')
        local specialtyVal = getValue(row, 'specialties/2/value')
        local specialtyDisplay = getSpecialtyDisplay(specialty, specialtyVal)
        returnString = returnString .. '\n| ' .. specialtyDisplay
        
        -- Resource costs
        local volatilesCost = calculateResourceCost(vapor, getValue(row, 'weightedBuildMaterials/volatiles'))
        local metalsCost = calculateResourceCost(vapor, getValue(row, 'weightedBuildMaterials/metals'))
        local noblesCost = calculateResourceCost(vapor, getValue(row, 'weightedBuildMaterials/nobleMetals'))
        local exoticsCost = calculateResourceCost(vapor, getValue(row, 'weightedBuildMaterials/exotics'))
        
        returnString = returnString .. '\n| ' .. volatilesCost
        returnString = returnString .. '\n| ' .. metalsCost
        returnString = returnString .. '\n| ' .. noblesCost
        returnString = returnString .. '\n| ' .. exoticsCost
        
        -- Radiation calculations
        local density = getValue(row, 'density_kgm3', 1)
        local thicknessPerPoint = calculateThicknessPerPoint(density, vapor)
        local xrayArmor = calculateArmorForRadiation(getValue(row, 'xRayHalfValue_cm'), thicknessPerPoint)
        local baryonArmor = calculateArmorForRadiation(getValue(row, 'baryonicHalfValue_cm'), thicknessPerPoint)
        
        returnString = returnString .. '\n| ' .. xrayArmor
        returnString = returnString .. '\n| ' .. baryonArmor
        returnString = returnString .. '\n|-'
    end
    
    returnString = returnString .. '\n|}'
    return returnString
end

function ArmorLister.ListDetailedArmor()
    local returnString = '{| class="wikitable sortable mw-collapsible mw-collapsed" style="text-align: center;"'
    returnString = returnString .. '\n! rowspan=2|Armor'
    returnString = returnString .. '\n! rowspan=2|Required Project'
    returnString = returnString .. '\n! rowspan=2|Density<br>(kg/m³)'
    returnString = returnString .. '\n! rowspan=2|Heat of Vaporization<br>(MJ/kg)'
    returnString = returnString .. '\n! rowspan=2|Thickness per point<br>(cm)'
    returnString = returnString .. '\n! rowspan=2|Mass (tons)<br>for 0/0/1 Armor on a Gunship'
    returnString = returnString .. '\n! rowspan=2|Bonus Resistance'
    returnString = returnString .. '\n! colspan=4| Resource Cost for 0/0/1 Armor on a Gunship'
    returnString = returnString .. '\n! colspan=2|Half Value (cm)'
    returnString = returnString .. '\n! colspan=2|Armor Needed to Halve Radiation Damage'
    returnString = returnString .. '\n|-'
    returnString = returnString .. '\n!' .. IconModule.Icon({args={'volatiles'}}) .. ' Volatiles'
    returnString = returnString .. '\n!' .. IconModule.Icon({args={'metals'}}) .. ' Base Metals'
    returnString = returnString .. '\n!' .. IconModule.Icon({args={'nobles'}}) .. ' Noble Metals'
    returnString = returnString .. '\n!' .. IconModule.Icon({args={'exotics'}}) .. ' Exotics'
    returnString = returnString .. '\n! X-Ray'
    returnString = returnString .. '\n! Baryonic'
    returnString = returnString .. '\n! X-Ray'
    returnString = returnString .. '\n! Baryonic'
    returnString = returnString .. '\n|-'
    
    for rowID, row in pairs(ArmorData) do
        returnString = returnString .. '\n| ' .. (ArmorNames['TIShipArmorTemplate.displayName.' .. rowID] or rowID)
        
		returnString = returnString .. '\n| ' .. ProjectNameBuilder.buildName({args={row['requiredProjectName']}})
        
        local density = getValue(row, 'density_kgm3', 1)
        local vapor = getValue(row, 'heatofVaporization_MJkg', 1)
        local thicknessPerPoint = calculateThicknessPerPoint(density, vapor)
        local mass = calculateMassForGunshipArmor(vapor)
        
        returnString = returnString .. '\n| ' .. density
        returnString = returnString .. '\n| ' .. vapor
        returnString = returnString .. '\n| ' .. thicknessPerPoint
        returnString = returnString .. '\n| ' .. mass
        
        local specialty = getValue(row, 'specialties/2/armorSpecialty')
        local specialtyVal = getValue(row, 'specialties/2/value')
        local specialtyDisplay = getSpecialtyDisplay(specialty, specialtyVal)
        returnString = returnString .. '\n| ' .. specialtyDisplay
        
        -- Resource costs
        local volatilesCost = calculateResourceCost(vapor, getValue(row, 'weightedBuildMaterials/volatiles'))
        local metalsCost = calculateResourceCost(vapor, getValue(row, 'weightedBuildMaterials/metals'))
        local noblesCost = calculateResourceCost(vapor, getValue(row, 'weightedBuildMaterials/nobleMetals'))
        local exoticsCost = calculateResourceCost(vapor, getValue(row, 'weightedBuildMaterials/exotics'))
        
        returnString = returnString .. '\n| ' .. volatilesCost
        returnString = returnString .. '\n| ' .. metalsCost
        returnString = returnString .. '\n| ' .. noblesCost
        returnString = returnString .. '\n| ' .. exoticsCost
        
        -- Half values
        local xrayHV = getValue(row, 'xRayHalfValue_cm', 0)
        local baryonHV = getValue(row, 'baryonicHalfValue_cm', 0)
        returnString = returnString .. '\n| ' .. xrayHV
        returnString = returnString .. '\n| ' .. baryonHV
        
        -- Radiation armor calculations
        local xrayArmor = calculateArmorForRadiation(xrayHV, thicknessPerPoint)
        local baryonArmor = calculateArmorForRadiation(baryonHV, thicknessPerPoint)
        returnString = returnString .. '\n| ' .. xrayArmor
        returnString = returnString .. '\n| ' .. baryonArmor
        
        returnString = returnString .. '\n|-'
    end
    
    returnString = returnString .. '\n|}'
    return returnString
end

function ArmorLister.ListHabEffects()
    local returnString returnString = '{| class="wikitable sortable mw-collapsible mw-collapsed" style="text-align: center;"'
    returnString = returnString .. '\n! rowspan=2|Armor'
    returnString = returnString .. '\n! colspan=3| Armor Value for Ground Hab Modules'
    returnString = returnString .. '\n! colspan=3|HP Value for Space Hab Modules'
    returnString = returnString .. '\n|-'
    returnString = returnString .. '\n! Combat Modules'
    returnString = returnString .. '\n! Critical Modules'
    returnString = returnString .. '\n! Other Modules'
    returnString = returnString .. '\n! Point Defense Array'
    returnString = returnString .. '\n! Layered Defense Array'
    returnString = returnString .. '\n! Battlestation'
    returnString = returnString .. '\n|-'
    
    -- Human armors (non-exotic, non-alien)
    for rowID, row in pairs(ArmorData) do
        if shouldIncludeInHabEffects(row) then
            local vapor = getValue(row, 'heatofVaporization_MJkg', 1)
            local armorName = ArmorNames['TIShipArmorTemplate.displayName.' .. rowID] or rowID
            
            returnString = returnString .. '\n| ' .. armorName
            returnString = returnString .. '\n| ' .. calculateGroundHabArmor(vapor, 2.5)
            returnString = returnString .. '\n| ' .. calculateGroundHabArmor(vapor, 5)
            returnString = returnString .. '\n| ' .. calculateGroundHabArmor(vapor, 10)
            
            -- Space hab HP values
            local pdMass = getHabModuleMass('PointDefenseArray')
            local ldMass = getHabModuleMass('LayeredDefenseArray')
            local bsMass = getHabModuleMass('Battlestations')
            
            returnString = returnString .. '\n| ' .. calculateSpaceHabHP(pdMass, 1, vapor)
            returnString = returnString .. '\n| ' .. calculateSpaceHabHP(ldMass, 2, vapor)
            returnString = returnString .. '\n| ' .. calculateSpaceHabHP(bsMass, 3, vapor)
            returnString = returnString .. '\n|-'
        end
    end
    
    -- Alien Adamantane Armor
    local alienAdamantane = ArmorData['AlienAdamantaneArmor']
    if alienAdamantane then
        local aVapor = getValue(alienAdamantane, 'heatofVaporization_MJkg', 1)
        local armorName = ArmorNames['TIShipArmorTemplate.displayName.AlienAdamantaneArmor'] or 'AlienAdamantaneArmor'
        
        returnString = returnString .. '\n| ' .. armorName 
        returnString = returnString .. '\n| ' .. calculateGroundHabArmor(aVapor, 2.5)
        returnString = returnString .. '\n| ' .. calculateGroundHabArmor(aVapor, 5)
        returnString = returnString .. '\n| ' .. calculateGroundHabArmor(aVapor, 10)
        
        -- Alien space hab HP values
        local aPdMass = getHabModuleMass('AlienPointDefenseArray')
        local aLdMass = getHabModuleMass('AlienLayeredDefenseArray')
        local aBsMass = getHabModuleMass('AlienBattlestations')
        
        returnString = returnString .. '\n| ' .. calculateSpaceHabHP(aPdMass, 1, aVapor)
        returnString = returnString .. '\n| ' .. calculateSpaceHabHP(aLdMass, 2, aVapor)
        returnString = returnString .. '\n| ' .. calculateSpaceHabHP(aBsMass, 3, aVapor)
        returnString = returnString .. '\n|-'
    end
    
    -- Alien Exotic Armor
    local alienExotic = ArmorData['AlienExoticArmor']
    if alienExotic then
        local eVapor = getValue(alienExotic, 'heatofVaporization_MJkg', 1)
        local armorName = ArmorNames['TIShipArmorTemplate.displayName.AlienExoticArmor'] or 'AlienExoticArmor'
        
        returnString = returnString .. '\n| ' .. armorName
        returnString = returnString .. '\n| ' .. calculateGroundHabArmor(eVapor, 2.5)
        returnString = returnString .. '\n| ' .. calculateGroundHabArmor(eVapor, 5)
        returnString = returnString .. '\n| ' .. calculateGroundHabArmor(eVapor, 10)
        
        -- Alien space hab HP values (using same modules as Adamantane)
        local aPdMass = getHabModuleMass('AlienPointDefenseArray')
        local aLdMass = getHabModuleMass('AlienLayeredDefenseArray')
        local aBsMass = getHabModuleMass('AlienBattlestations')
        
        returnString = returnString .. '\n| ' .. calculateSpaceHabHP(aPdMass, 1, eVapor)
        returnString = returnString .. '\n| ' .. calculateSpaceHabHP(aLdMass, 2, eVapor)
        returnString = returnString .. '\n| ' .. calculateSpaceHabHP(aBsMass, 3, eVapor)
        returnString = returnString .. '\n|-'
    end
    
    returnString = returnString .. '\n|}'
    
    return returnString
end

--endregion

return ArmorLister