Module:TraitLister
From Terra Invicta Official Wiki
Documentation for this module may be created at Module:TraitLister/doc
---
---Reads the Trait data files and presents them in readable formats, with additional calculated statistics.
---
---@module TraitLister
local TraitLister = {}
--region Dependencies
local RestrictionChecker = require('Module:RestrictionChecker')
local StringReplace = require('Module:StringReplace')
local IconModule = require('Module:Icon')
local TVModule = require('Module:TV')
local TraitData = mw.loadData('Module:CSVReader/Trait')
local TraitNames = mw.loadData('Module:ENReader/Trait')
local CouncilorTypeData = mw.loadData('Module:CSVReader/CouncilorType')
local CouncilorTypeTraits = mw.loadData('Module:TraitLister/Chances')
local CouncilorTypeNames = mw.loadData('Module:ENReader/CouncilorType')
local ProjectNameBuilder = require('Module:ProjectLister/NameBuilder')
--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 sfind = string.find
local ssub = string.sub
local sreplace = StringReplace.replace
local priorityNamesToIcons = {
Economy = 'economy',
Welfare = 'welfare',
Knowledge = 'knowledge',
Environment = 'environment',
Government = 'government priority',
Unity = 'unity',
Oppression = 'oppression',
Funding = 'funding',
Spoils = 'spoils',
Civilian_InitiateSpaceflightProgram = 'found space program',
LaunchFacilities = 'boost priority',
MissionControl = 'mission control priority',
Military_FoundMilitary = 'found military',
Military = 'military priority',
Military_BuildArmy = 'build army',
Military_BuildNavy = 'build navy',
Military_BuildNuclearWeapons = 'nuclear weapons',
Military_InitiateNuclearProgram = 'develop atomic bomb',
}
local restrictedLocationsString = {
HomeNation = 'Banned from Home [[Nation]]',
HomeNationRivals = 'Banned from [[Rival]]s of Home [[Nation]]',
HighUnrestNations = 'Banned from [[Nations]] with >6 ' .. IconModule.Icon({args={'unrest', bgcolor='DarkSlateGray'}}) .. '[[Unrest]]',
Space = 'Banned from Space',
}
local conditionStringTable = {
TICouncilorCondition_bInHomeNation = ' When in Home [[Nation]]',
TIGlobalCondition_bNuclearWeaponsUsed = ' When ' .. IconModule.Icon({args={'nuke'}}) .. '[[Nuclear Weapons|Nukes]] have been used',
TIFactionCondition_efResourceValue = ' When {TV}',
TINationCondition_fInequality = ' When in [[Nation]] with ' .. TVModule.TV({args={'inequality', '{sign}{value}'}}),
TINationCondition_fEducation = ' When in [[Nation]] with ' .. TVModule.TV({args={'education', '{sign}{value}'}}) ,
TINationCondition_fUnrest = ' When in [[Nation]] with ' .. TVModule.TV({args={'unrest', '{sign}{value}'}}),
TINationCondition_fCohesion = ' When in [[Nation]] with ' .. TVModule.TV({args={'cohesion', '{sign}{value}'}}),
TINationCondition_fDemocracy = ' When in [[Nation]] with ' .. TVModule.TV({args={'democracy', '{sign}{value}'}}),
}
local conditionSignTable = {
LessThanOrEqualTo = '≤',
GreaterThanOrEqualTo = '≥',
LessThan = '<',
GreaterThan = '>',
EqualTo = '=',
}
local specialTraitRulesTable = {
Undercover = 'Can board enemy tier 1 [[Habs]] and [[Spaceships]].',
LoyaltyLossOnFactionAtrocity = TVModule.TV({args={'loyalty', '{value}'}}) .. " When [[Councilors|Councilor's]] [[Factions|Faction]] commits an [[Atrocity]].",
LoyaltyLossOnPersonalCritFailure = TVModule.TV({args={'loyalty', '{value}'}}) .. " When [[Councilors|Councilor]] critically fails a [[Missions|Mission]].",
LoyaltyLossOnFactionCriticalFailure = TVModule.TV({args={'loyalty', '{value}'}}) .. " When any [[Councilors|Councilor]] of the same [[Factions|Faction]] critically fails a [[Missions|Mission]].",
LoyaltyLossOnFactionHabDestroyedPerTier= TVModule.TV({args={'loyalty', '{value}'}}) .. " When a (non-automated) [[Habs|hab]] of [[Councilors|Councilor's]] [[Factions|Faction]] is destroyed. Larger [[Habs]] will cause a greater loss.",
LoyaltyLossOnHomeRegionNuked = TVModule.TV({args={'loyalty', '{value}'}}) .. " When home [[Regions|region]] is " .. IconModule.Icon({args={'nuke'}}) .. "[[Nuclear Weapons|Nuked]]. Double when [[Councilors|Councilor's]] [[Factions|Faction]] is responsible",
LoyaltyLossOnFactionCouncilorKilled = TVModule.TV({args={'loyalty', '{value}'}}) .. " When any [[Councilors|Councilor]] of the same [[Factions|Faction]] is " .. IconModule.MissionIcon({args={'assassinate'}}) .. "[[Assassinate]]d.",
AtrocityIfAssassinationAttemptUpon = "Any attempt to " .. IconModule.MissionIcon({args={'assassinate'}}) .. "[[Assassinate]] this [[Councilors|Councilor]] that does not critically succeed will count as an [[Atrocity]] for the assassin's [[Factions|Faction]].",
MarkedToAssassin = "Any attempt to " .. IconModule.MissionIcon({args={'assassinate'}}) .. '[[Assassinate]] this [[Councilors|Councilor]] that does not critically succeed will give the assassin the "Marked" trait.',
GlobalPropagandaIfKilled = "If this councilor dies violently, every [[Nation]] on [[Earth]] will receive [[propaganda]] of strength {value} for the [[Councilors|Councilor's]] [[Factions|Faction]].",
ProjectUnlockChance = 'Increases every [[Technology#Unlocking_Projects|Project Unlock Chance]] by {value}%.'
}
--endregion
--region Private member variables
--none
--endregion
--region Private methods
--endregion
--region Public methods
function TraitLister.ListRestrictedTraits(frame)
local focus = frame.args['Focus']
if focus and focus ~= '' then
focus = mw.text.trim(slower(focus))
frame.args['Focus'] = nil
end
return TraitLister.ListTraits(frame.args, focus)
end
---@param restrictionsTable table of restrictions
---@return wiki table of traits
function TraitLister.ListTraits(restrictionsTable, focus)
-- TODO add focus handling, maybe.
local returnString = '{| class="wikitable sortable mw-collapsible" '
returnString = returnString .. '\n|-'
returnString = returnString .. '\n! Trait'
returnString = returnString .. '\n! Group'
returnString = returnString .. '\n! Description'
returnString = returnString .. '\n! Initial Chances'
returnString = returnString .. '\n! Effects'
returnString = returnString .. '\n! Requirements'
returnString = returnString .. '\n|-'
for rowID, row in pairs(TraitData) do
if rowID ~= 'dummy' and RestrictionChecker.AllPass(restrictionsTable, row) then
returnString = returnString .. '\n| ' .. (TraitNames['TITraitTemplate.displayName.' .. rowID] or rowID)
returnString = returnString .. '\n| ' .. (row['grouping'] or '')
returnString = returnString .. '\n| ' .. (TraitNames['TITraitTemplate.description.' .. rowID] or '')
-- Chances
returnString = returnString .. '\n| '
local chanceRows = ''
for profession, _ in pairs(CouncilorTypeData) do
if CouncilorTypeTraits[profession][rowID] > 0 then
chanceRows = chanceRows .. '\n| ' .. (CouncilorTypeNames['TICouncilorTypeTemplate.displayName.' .. profession] or profession)
chanceRows = chanceRows .. '\n| ' .. round(CouncilorTypeTraits[profession][rowID],2) .. '%'
chanceRows = chanceRows .. '\n|-'
end
end
if chanceRows ~= '' then
returnString = returnString .. '\n{| class="wikitable sortable mw-collapsible" style="text-align: center;"'
returnString = returnString .. '\n|-'
returnString = returnString .. '\n! Profession'
returnString = returnString .. '\n! Chance'
returnString = returnString .. '\n|-'
returnString = returnString .. chanceRows
returnString = returnString .. '\n|}'
else
returnString = returnString .. '0%'
end
-- Effects
returnString = returnString .. '\n| '
local incomesString = ''
local incomeValue = tonumber(row['incomeMoney'] or 0) or 0
if incomeValue ~= 0 then
incomesString = incomesString .. TVModule.TV({args={'money', incomeValue}})
end
incomeValue = tonumber(row['incomeInfluence'] or 0) or 0
if incomeValue ~= 0 then
incomesString = incomesString .. TVModule.TV({args={'influence', incomeValue}})
end
incomeValue = tonumber(row['incomeOps'] or 0) or 0
if incomeValue ~= 0 then
incomesString = incomesString .. TVModule.TV({args={'ops', incomeValue}})
end
incomeValue = tonumber(row['incomeBoost'] or 0) or 0
if incomeValue ~= 0 then
incomesString = incomesString .. TVModule.TV({args={'boost', incomeValue}})
end
incomeValue = tonumber(row['incomeResearch'] or 0) or 0
if incomeValue ~= 0 then
incomesString = incomesString .. TVModule.TV({args={'research', incomeValue}})
end
incomeValue = tonumber(row['incomeProjects'] or 0) or 0
if incomeValue ~= 0 then
incomesString = incomesString .. TVModule.TV({args={'projects', incomeValue}})
end
if incomesString ~= '' then
returnString = returnString .. '\n* Income: ' .. incomesString
end
local missionGrantString = ''
for i = 0, 2 do
if row['missionsGrantedNames/' .. i] and row['missionsGrantedNames/' .. i] ~= '' then
missionGrantString = missionGrantString .. IconModule.MissionIcon({args={row['missionsGrantedNames/' .. i]}})
end
end
if missionGrantString ~= '' then
returnString = returnString .. '\n* Grants ' .. missionGrantString
end
local missionBlockString = ''
for i = 0, 4 do
if row['restrictedMissionNames/' .. i] and row['restrictedMissionNames/' .. i] ~= '' then
missionBlockString = missionBlockString .. IconModule.MissionIcon({args={row['restrictedMissionNames/' .. i]}})
end
end
if missionBlockString ~= '' then
returnString = returnString .. '\n* Blocks ' .. missionBlockString
end
if row['restrictedLocations'] and restrictedLocationsString[row['restrictedLocations']] then
returnString = returnString .. '\n* ' .. restrictedLocationsString[row['restrictedLocations']]
end
local XPModifier = tonumber(row['XPModifier'] or 0) or 0
XPModifier = XPModifier * 100 -- Convert to %
if XPModifier > 0 then
returnString = returnString .. '\n* ' .. TVModule.TV({args={'xp', '+' .. XPModifier .. '%'}}) .. ' Costs'
elseif XPModifier < 0 then
returnString = returnString .. '\n* ' .. TVModule.TV({args={'xp', XPModifier .. '%'}}) .. ' Costs'
end
local priorityString = ''
for i = 0, 2 do
if row['priorityBonuses/' .. i .. '/priority'] and row['priorityBonuses/' .. i .. '/priority'] ~= '' then
local priorityBonus = tonumber(row['priorityBonuses/' .. i .. '/bonus'] or 0) or 0
priorityBonus = priorityBonus * 100 -- Convert to %
if priorityBonus ~= 0 then
priorityString = priorityString .. TVModule.TV({args={priorityNamesToIcons[row['priorityBonuses/' .. i .. '/priority']], priorityBonus .. '%', 'true'}})
end
end
end
if priorityString ~= '' then
returnString = returnString .. '\n* ' .. priorityString
end
local detectionInvBonus = tonumber(row['detectionInvBonus'] or 0) or 0
local detectionEspBonus = tonumber(row['detectionEspBonus'] or 0) or 0
if detectionInvBonus ~= 0 then
returnString = returnString .. '\n* ' .. TVModule.TV({args={'investigation', detectionInvBonus}}) .. ' for [[Detection]]'
end
if detectionEspBonus ~= 0 then
returnString = returnString .. '\n* ' .. TVModule.TV({args={'espionage', detectionEspBonus}}) .. ' for [[Detection]]'
end
for i = 0, 4 do
local statValue = row['statMods/' .. i .. '/strValue']
local statString = row['statMods/' .. i .. '/stat']
if statValue and statValue ~= '' and statString then
if statValue == 'Loyalty' then
statValue = IconModule.Icon({args={'Loyalty'}})
end
if row['statMods/' .. i .. '/operation'] == 'Additive' then
returnString = returnString .. '\n* ' .. TVModule.TV({args={statString, statValue}})
elseif row['statMods/' .. i .. '/operation'] == 'SetToFixedValue' then
returnString = returnString .. '\n* Set ' .. TVModule.TV({args={statString}}) .. ' to ' .. statValue
elseif row['statMods/' .. i .. '/operation'] == 'SetToAnotherAttribute' then
returnString = returnString .. '\n* Set ' .. TVModule.TV({args={statString}}) .. ' to ' .. statValue
end
local conditionType = row['statMods/' .. i .. '/condition/$type']
if conditionType and conditionType ~= '' and conditionStringTable[conditionType] then
local conditionString = conditionStringTable[conditionType]
conditionString = sreplace(conditionString, '{TV}', TVModule.TV({args={row['statMods/' .. i .. '/condition/strIdx'], '{sign}{value}'}}))
conditionString = sreplace(conditionString, '{sign}', conditionSignTable[row['statMods/' .. i .. '/condition/sign']])
conditionString = sreplace(conditionString, '{value}', row['statMods/' .. i .. '/condition/strValue'])
returnString = returnString .. conditionString
end
end
end
if row['specialTraitRule'] and specialTraitRulesTable[row['specialTraitRule']] then
returnString = returnString .. '\n* ' .. sreplace(specialTraitRulesTable[row['specialTraitRule']], '{value}', row['specialTraitRuleValue'])
end
if row['techBonuses/0/category'] and row['techBonuses/0/category'] ~= '' then
local techBonusValue = tonumber(row['techBonuses/0/bonus'] or 0) or 9
techBonusValue = techBonusValue * 100 -- Convert to %
returnString = returnString .. '\n* ' .. TVModule.TV({args={row['techBonuses/0/category'], techBonusValue .. '%', 'true'}})
end
-- Requirements
returnString = returnString .. '\n| '
local costsString = ''
local costValue = tonumber(row['XPCost'] or 0) or 0
if costValue ~= 0 then
costsString = costsString .. TVModule.TV({args={'xp', costValue}})
end
costValue = tonumber(row['moneyCost'] or 0) or 0
if costValue ~= 0 then
costsString = costsString .. TVModule.TV({args={'money', costValue}})
end
costValue = tonumber(row['influenceCost'] or 0) or 0
if costValue ~= 0 then
costsString = costsString .. TVModule.TV({args={'influence', costValue}})
end
costValue = tonumber(row['opsCost'] or 0) or 0
if costValue ~= 0 then
costsString = costsString .. TVModule.TV({args={'ops', costValue}})
end
costValue = tonumber(row['boostCost'] or 0) or 0
if costValue ~= 0 then
costsString = costsString .. TVModule.TV({args={'boost', costValue}})
end
if costsString ~= '' then
returnString = returnString .. '\n* ' .. costsString
end
if row['projectDataName'] and row['projectDataName'] ~= '' then
returnString = returnString .. '\n* ' .. ProjectNameBuilder.buildName({args={row['projectDataName']}})
end
if row['upgradesFrom'] and row['upgradesFrom'] ~= '' then
returnString = returnString .. '\n* Upgrades from ' .. (TraitNames['TITraitTemplate.displayName.' .. row['upgradesFrom']] or row['upgradesFrom'])
end
returnString = returnString .. '\n|-'
end
end
returnString = returnString .. '\n|}'
return returnString
end
--endregion
return TraitLister


