CSV and JSON Reference

From Imperium Sine Fine Wiki

CSV and JSON Reference is the complete technical schema for every data file Imperium Sine Fine reads — every column of every CSV, and every field of every JSON structure. See Desktop Modding Manual for the conceptual side of modding: folder structure, override rules, and how to actually get a mod running.

All CSV files use a semicolon (;) as the column separator. Lines beginning with // or ; are treated as comments and ignored. The row ID is always in column 0, and is always an integer.

CSV File Reference

data_troops.csv

Defines all troop types. Each row is one troop. Columns 0–20.

Col Name Type Description
0 Troop set int Faction troop group (0 = default, used when no faction-specific set exists).
1 Name string Display name.
2 Troop id int Row key — the troop's position (1–8) within its set.
3 Melee combat float Base Melee Value (MV).
4 Ranged combat float Base Ranged Value (RV).
5 Armour float Base Armour Value (AV).
6 Shock value float Base Shock Value (SV).
7 Resolve value float Base Resolve Value (RSV).
8 Hit points int Base hit points.
9 Training int Training value used in the Battle Honours XP formula, not recruitment cost.
10 Movement int Base movement points per cycle.
11 Sight int Vision radius in hexes.
12 Description string In-game flavour text.
13 Manpower float Manpower cost to recruit one troop.
14 Melee weapons float Melee weapon equipment cost.
15 Ranged weapons float Ranged weapon equipment cost.
16 Armour equipment float Armour equipment cost.
17 Horses float Horse resource cost.
18 Support equipment float Support equipment cost.
19 Grain consumption float Grain consumed per cycle.
20 Abilities string Comma-separated ability tags (e.g. Footmen, Cavalry, Aquaphobia).

See Troop Types for the generic (Troop Set 0) roster in full, and any individual faction page for its own troop set.

data_factions.csv

Defines the 14 major factions. Columns 0–23.

Col Name Type Description
0 Faction id int Row key.
1 Race id int The race this faction belongs to.
2 Colour id int Map colour.
3 Troop set int Which data_troops.csv troop set this faction uses.
4 Focus set string Focus tree filename (without .json), or GENERIC_FOCUS_TREE_ID.
5 Name string Display name.
6 Threat distance int AI: hex range for detecting enemy threats.
7 Exercise distance int AI: hex range for army training decisions.
8 Patrol distance int AI: hex range for patrol army response.
9 Main troop type int Preferred troop type id for Army Composition Bonus.
10 Main troop percentage float Target fraction (0.0–1.0) of that troop type for maximum ACB.
11 Favourite terrain type int AI: preferred terrain id for expansion.
12 Favourite tech 1 int AI: first technology priority id.
13 Research modifier float Not used (legacy column). Set to 0.
14 Manpower modifier float Modifier to manpower collection.
15 Horses modifier float Modifier to horse collection — see Resources.
16 Organisation modifier float Modifier to army organisation.
17 Exercise modifier float Modifier to exercise effectiveness.
18 New farm distance int AI: maximum hex distance for establishing new farms.
19–21 Personality 1–3 int Three personality ids defining AI behaviour.
22 Favourite strategy int AI: preferred combat strategy id.
23 Reinforce int AI: whether the faction actively reinforces armies (1 = yes, 0 = no).

data_terrain.csv

Defines every terrain type. Columns 0–14.

Col Name Type Description
0 id int Row key.
1 name string Display name.
2 popCap int Maximum population a single hex of this terrain can support.
3 horses int Horses produced per hex per cycle.
4 iron int Iron produced per hex per cycle.
5 leather int Leather produced per hex per cycle.
6 wood int Wood produced per hex per cycle.
7 stone int Stone produced per hex per cycle.
8 grain int Grain produced per hex per cycle.
9 moveTimeIn int Cycles for an army to enter this hex. −1 = impassable.
10 moveTimeOut int Cycles for an army to exit this hex. −1 = impassable.
11 defensive bonus float Combat defensive multiplier for a defending army (1.00 = no bonus).
12 terrainValue int Strategic value used in AI calculations.
13 supportWear float Equipment wear rate for an army stationary on this terrain.
14 Description string In-game flavour text.

See Terrain for the full player-facing reference table built from this file.

data_technologies.csv

Defines all researchable technologies. Columns 0–4.

Col Name Type Description
0 id int Row key.
1 race int Race that can research this technology (0 = all races).
2 name string Display name.
3 cost int Research cost in cycles.
4 description string In-game description shown in the Research panel.

data_equipment.csv

Defines the four manufactured equipment types. Columns 0–8.

Col Name Type Description
0 id int Row key.
1 name string Display name.
2 manpower int Manpower cost per unit produced.
3 horses int Horses cost.
4 iron int Iron cost.
5 leather int Leather cost.
6 wood int Wood cost.
7 workshopCapacity int Workshop slots consumed per unit produced.
8 description string In-game description.

data_projects.csv

Defines all army and settlement projects. Columns 0–8.

Col Name Type Description
0 id int Row key.
1 name string Display name.
2 type int Project category: 1 = settlement project, 2 = army project.
3 infantry demand int Manpower required to start the project.
4 project time int Base time in cycles to complete.
5 distance limit int Minimum hex distance from the nearest settlement or outpost (0 = no restriction).
6 tech modifier float Technology modifier applied to completion time.
7 equipment wear float Equipment wear rate during the project.
8 stone cost int Stone resource cost to initiate the project.

See Projects for the full player-facing reference built from this file.

data_skills.csv

Defines leader skills for Generals and Governors. Columns 0–7.

Col Name Type Description
0 id int Row key.
1 leaderType int Leader type this skill applies to: 2 = Governor, 3 = General.
2 name string Display name.
3–7 level1–level5 float Effect value at each of the five skill levels.

See Leader Skills for the full player-facing reference.

data_strategies.csv

Defines the combat strategies available to armies. Columns 0–23.

Col Name Type Description
0 Strategy id int Row key.
1 Name string Display name.
2–12 Combat modifiers float Multipliers against each opposing strategy, in fixed order: Garrison, Rush Enemy, Shield Wall, Phalanx, Archer Fire, Feigned Retreat, Flanking Manoeuvres, Cavalry Charge, Oblique Order, Siege Warfare, Skirmish.
13 xpLevel int Minimum General XP level required.
14 tech2 int Minimum level of Archery (technology 2) required.
15 tech5 int Minimum level of Field Manoeuvres (technology 5) required.
16 tech12 int Minimum level of Marching (technology 12) required.
17 tech13 int Minimum level of Military Academy (technology 13) required.
18 troop4Percentage float Minimum fraction of troop type 4 (Marksmen) required.
19 cavalryPercentage float Minimum fraction of cavalry required.

See Combat Strategies for the full player-facing reference.

data_province_development.csv

Defines the ten Province Development Levels. Columns 0–17.

Col Name Type Description
0 Development id int Row key.
1 Name string Display name.
2 development level int The PDL number (1–10) this row represents.
3 workshopMaximum int Maximum workshops a settlement at this level can build.
4 basePopulationCap int Base population cap contribution (flat).
5 baseCapitalCap int Base capital population cap contribution (flat).
6 capTerrainModifier float Terrain Modifier applied to a hex's population cap contribution — see Province Development.
7 upgradePopulation int Population required to upgrade to the next level. −1 = no further upgrade possible (Imperial Hub).
8 upgradeHexes int Controlled hexes required to unlock the next upgrade.
9 upgradeCycles int Time in cycles required to complete the upgrade.
10 upgradeStoneCost int Stone cost for the upgrade.
11 horsesModifier float Resource modifier for horse production.
12 resourcesModifier float General resource production modifier.
13 expansionProjectTime float Multiplier on expansion project time.
14 settlementProjectTime float Multiplier on settlement project time.
15 armyProjectTime float Multiplier on army project time.
16 movementCostModifier float Multiplier on army movement cost through this hex.
17 workshopCapacity float Workshop capacity modifier.

See Province Development for the full player-facing reference built from this file.

data_names.csv

Defines name pools for settlements, armies, and leaders, per faction. Columns 0–2.

Col Name Type Description
0 Faction id int Faction the name belongs to — matches data_factions.csv column 0.
1 Type int Name category: 1 = settlement, 2 = army, 3 = leader.
2 Name string The name string itself.

Mods load names additively on top of vanilla — there's no override mechanism here, new names are simply added to the pool.

data_personality.csv

Defines AI personality profiles, referenced by data_factions.csv columns 19–21. Columns 0–10.

Col Name Type Description
0 Personality id int Row key.
1 Name string Display name.
2 scoreWarLimit int AI decision threshold.
3 relationRaceModifier float Multiplier applied to the Race Modifier described on Relation Values.
4 relationNegativeModifier float Multiplier applied to negative relation modifiers.
5 relationNegativeNorm float Baseline adjustment for negative relations.
6 acceptNeutral int AI decision threshold for accepting Neutral-status requests.
7 acceptTreaty int AI decision threshold for accepting treaty upgrade requests.
8 relationCalmBorder int Modifier to the Calm Border mechanic described on Relation Values.
9 relationBorderTension int Modifier to the Border Tension mechanic described on Relation Values.
10 militaryStyle int AI decision category affecting army composition and strategy choices.

Event JSON Reference

Event files are JSON arrays — each element is one event object. Place files in the events\ folder.

Event Object Fields

Field Type Required Description
id int Yes Unique event ID. Vanilla uses 100001–199999 (general), 1001–1999 (army), 2001–2999 (settlement). Mods should use IDs above 300,000.
title string Yes Short title shown in the event popup.
description string Yes Narrative text of the event.
targetType string Yes Who the event targets: "EMPIRE", "ARMY", or "SETTLEMENT".
triggerConditions array No Conditions that must all be true for the event to fire. Empty = always eligible.
triggerChance float Yes Probability the event fires when all conditions are met.
triggerCooldownCycles int Yes Minimum cycles between firings of this event.
tags string array No Descriptive tags for filtering — common values include MINOR, MAJOR, GOOD_EVENT, BAD_EVENT, ECONOMY, LEADER, CRIME, IMPERIAL_COURT.
options array Yes The player choice(s) presented.

Condition Object

{ "type": "CONDITION_TYPE", "targetId": 0, "value": 0 }
Type targetId value Description
ARMY_HAS_GENERAL — — Army has an undamaged general assigned.
ARMY_IS_COMBAT — — Army is currently in combat.
EMPIRE_AT_WAR — — Empire is at war with at least one other major faction.
EMPIRE_HAS_ADVISOR — — Empire has at least one advisor in the Imperial Court.
EMPIRE_HAS_EMPEROR — — Empire has an emperor in the Imperial Court.
EMPIRE_HAS_HEIR — — Empire has an heir in the Imperial Court.
EMPIRE_HAS_REBELLION — — Empire is a major faction with at least one settlement controlled by its connected rebel faction.
EMPIRE_MAX_LOYALTY — loyalty Combined empire loyalty is at most this value.
EMPIRE_MIN_LOYALTY — loyalty Combined empire loyalty is at least this value.
EMPIRE_NO_HEIR — — Empire has no heir in the Imperial Court.
EMPIRE_NOT_AT_WAR — — Empire is at peace with every other major faction.
EVENT_HAS_FIRED — event id The specified event has already triggered.
EVENT_NOT_FIRED — event id The specified event has not yet triggered.
GENERAL_HAS_TRAIT trait id — Army's general has this trait.
GENERAL_WITHOUT_TRAIT trait id — Army's general does not have this trait.
GOVERNOR_HAS_TRAIT trait id — Settlement's governor has this trait.
GOVERNOR_WITHOUT_TRAIT trait id — Settlement's governor does not have this trait.
IS_EMPIRE_ID faction id — Fires only for this faction.
IS_NOT_EMPIRE_ID faction id — Does not fire for this faction.
IS_MIN_CYCLE — min cycle Total cycles played must exceed this value.
IS_MONTH — month (1–12) Only fires in this calendar month.
IS_NOT_MONTH — month (1–12) Does not fire in this month.
IS_PLAYER_EMPIRE — — Fires only for the human player's empire.
IS_SUMMER — — True for months 5–9.
IS_WINTER — — True for months 11, 12, 1, 2, 3.
SETTLEMENT_HAS_GOVERNOR — — Settlement has an undamaged governor assigned.
SETTLEMENT_IS_CAPITAL — — Settlement is the empire's capital.
SETTLEMENT_IS_COMBAT — — Settlement is currently under siege.
SETTLEMENT_LESS_WORKSHOPS — count Settlement has fewer than this many workshops.
SETTLEMENT_MAX_LOYALTY — loyalty Settlement loyalty is at most this value.
SETTLEMENT_MIN_LOYALTY — loyalty Settlement loyalty is at least this value.
SETTLEMENT_MORE_WORKSHOPS — count Settlement has more than this many workshops.
SETTLEMENT_NEED_GARRISON — — Settlement garrison is below its wanted amount.
SETTLEMENT_NOT_CAPITAL — — Settlement is not the empire's capital.
SETTLEMENT_WORKSHOP_POSSIBLE — count Settlement's current workshops plus this value must still be at or below the maximum allowed.

Option Object

{
  "text": "Description of what happens.",
  "optionConditions": [ ... ],
  "effects": [ ... ],
  "nextEventId": -1
}
Field Type Required Description
text string Yes Button text shown to the player.
optionConditions array No Conditions (same vocabulary as the Condition Object above) that must all pass for this option to be offered. Lets a single event present different choices to different empires — a poor empire might see an option a wealthy one never does.
effects array Yes Effects applied when this option is chosen.
nextEventId int No Event ID to fire immediately after this option resolves, chaining two events into one continuous story beat. Omit or use −1 for none.

Effect Object

{
  "type": "EFFECT_TYPE",
  "targetId": 0,
  "value": 0,
  "stringData": "",
  "excludeCapital": false,
  "filter": "",
  "fallback": "",
  "race": null,
  "raiseWanted": null,
  "strength": 0
}

Many effect names follow a consistent pattern worth knowing up front: SETTLEMENT_* effects act on a single settlement (either one chosen at random, or a specific one via the NAMED_* family), while EMPIRE_* effects act across every settlement the empire owns at once. Scope also determines how a value is read:

Prefix Scope Value Type
EMPIRE_* Every settlement the empire owns Percentages
CAPITAL_* The capital only Percentages
SETTLEMENT_* One randomly chosen settlement (respects filter/excludeCapital) Flat values only
NAMED_* One specific settlement by targetId (fallback required) Either, depending on the effect

Optional fields — apply to the scope families above, ignored by effects that don't use them:

Field Type Description
excludeCapital bool EMPIRE_* and SETTLEMENT_* scope: skip the capital. Default false.
filter string Restricts which settlements qualify: coastal, has-harbour, non-core, forest-adjacent, open-terrain, rough-terrain, borders-enemy, or race:{id}. Also doubles as the ALL/NAMED scope selector for ARMY_ADD_TRAINING and LEADER_GRANT_XP, and as the city selector for CREATE_DIPLOMATIC_REQUEST. An unrecognised filter matches everything rather than nothing.
fallback string Required on every NAMED_* effect. Uses the same filter vocabulary above, applied if the named settlement doesn't exist in the current world — e.g. a random map, or a scenario that omitted it. A NAMED_* effect must degrade gracefully rather than silently doing nothing.
race int Optional race filter for population and soul effects. Omit for all races.
raiseWanted bool *_CHANGE_GARRISON only. Also raises the wanted garrison by the same amount so new troops don't drain away again. Omit or true to raise; explicit false opts out.
strength int *_SPAWN_ARMY/*_SPAWN_FLEET only. Troop-count multiplier over the baseline raised unit. 0 or 1 = baseline, 3 = triple. The baseline raised army is deliberately weak, so a spawn intended as a genuine reward usually wants 2–3.

Empire — Leaders and Court

Type targetId value Description
EMPIRE_NEW_HEIR — — Generates a new heir. Requires the empire to currently have none.
EMPEROR_DAMAGE / EMPEROR_SICKNESS — cycles Emperor incapacitated / sick.
HEIR_DAMAGE / HEIR_SICKNESS — cycles Heir incapacitated / sick.
GENERAL_DAMAGE / GENERAL_SICKNESS — cycles General incapacitated / sick.
GENERAL_DEATH — — General dies; a replacement is appointed automatically.
GENERAL_CHANGE_XP — ±xp Changes the general's XP (never below 0).
GOVERNOR_DAMAGE / GOVERNOR_SICKNESS — cycles Governor incapacitated / sick.
GOVERNOR_DEATH — — Governor dies; a replacement is appointed automatically.
GOVERNOR_CHANGE_XP — ±xp Changes the governor's XP (never below 0).
LEADER_GRANT_XP army id when filter is NAMED xp Grants flat XP. StringData: ARMY, FLEET, or GOVERNOR. filter: ALL (default) or NAMED.

Empire — Stock, Research, and Loyalty

Type stringData value Description
EMPIRE_CHANGE_EQUIPMENT GES type ±amount Credits the Global Equipment Stock immediately. Despite the name, this covers everything the GES holds — SUPPORT_EQUIPMENT, ARMOUR, MELEE_WEAPONS, RANGED_WEAPONS, and MANPOWER. This is the right effect for most equipment grants — see Resource Grants below.
EMPIRE_CHANGE_EQUIPMENTS — ±amount Same as above, applied to every GES type at once.
EMPIRE_CHANGE_LOYALTY — ±loyalty Empire-wide loyalty.
GRANT_IMI — ±amount Imperial Influence, clamped to IMI_CAPACITY. Overflow is discarded.
ADVANCE_RESEARCH — percent or −cycles Positive value = percent of remaining research completed; negative value = that many cycles advanced. Floored at 1 cycle remaining — never completes research outright.

Empire / Capital / Settlement Scope

Type stringData value Description
EMPIRE_CHANGE_POPULATION — ±percent Population change in every settlement. race is optional.
EMPIRE_ADD_POPULATION — ±amount Flat population added to every settlement. race is optional.
EMPIRE_CHANGE_RESOURCE resource ±amount Stone, Horses, or Grain only — see Resource Grants below.
EMPIRE_CHANGE_GARRISON — ±amount Garrison change across every settlement. raiseWanted defaults to true.
EMPIRE_ADVANCE_PROJECT category cycles category: SETTLEMENT, EXPANSION, or ARMY. Floored at 1 cycle remaining.
CAPITAL_CHANGE_POPULATION — ±percent Capital population.
CAPITAL_CHANGE_RESOURCE resource ±amount Stone, Horses, or Grain only.
CAPITAL_CHANGE_GARRISON — ±amount Capital garrison.
CAPITAL_INCREASE_DEV — levels Raises capital development level.
CAPITAL_SPAWN_ARMY — training level Spawns an army at the capital. strength multiplies troop count.
SETTLEMENT_ADD_POPULATION — amount Flat population in one random settlement.
SETTLEMENT_CHANGE_POPULATION — ±percent One random settlement. (CHANGE_SETTLEMENT_POPULATION is kept as a deprecated loading alias.)
SETTLEMENT_SPAWN_ARMY — training level Army in one random settlement. strength multiplies troop count.
SETTLEMENT_SPAWN_FLEET — count Fleet in one random settlement. strength multiplies crews. Always raises a War Galley hull — hullType isn't honoured.
SETTLEMENT_ADVANCE_PROJECT category cycles One random settlement.
SETTLEMENT_ADD_WORKSHOP / SETTLEMENT_REMOVE_WORKSHOP — count Adjusts workshop count (settlement already in scope).
SETTLEMENT_CHANGE_GARRISON — ±troops Garrison (settlement already in scope). If the result exceeds the wanted garrison, that target increases in steps of 50, unless raiseWanted is set to false.
SETTLEMENT_CHANGE_LOYALTY — ±loyalty Loyalty (settlement already in scope).
SETTLEMENT_CHANGE_RESOURCE resource ±amount One resource in the settlement. StringData: MANPOWER, HORSES, IRON, LEATHER, or WOOD.
SETTLEMENT_CHANGE_RESOURCES — ±amount All resource types at once, in this one settlement — despite the similarly-named EMPIRE_CHANGE_RESOURCE, this does not apply empire-wide.
SETTLEMENT_REBELLION — minimum garrison See below for the full description of this effect.
SETTLEMENT_RESET_COOLDOWN — event id Resets every settlement in the empire's cooldown for the specified event.
SETTLEMENT_ADD_SOULS — amount Adds souls to an Ende settlement — see Population and Special Races. filter sets scope.

SETTLEMENT_REBELLION in full: the settlement leaves the empire and joins its corresponding rebel faction. A disloyal or corrupt governor stays in power; otherwise a new one is assigned. Garrison is topped up to the effect value if below it. Every remaining city in the empire loses 6 loyalty. If the rebel faction previously held no assets, it inherits the empire's technology, its diplomacy resets toward every major faction (and theirs toward it), and it receives starting resources: 250 Manpower, 100 Horses, 500 Support Equipment, 250 Armour, 250 Melee Weapons, 100 Ranged Weapons.

Named Settlement (targetId = settlement id, fallback required)

Type value Description
NAMED_SETTLEMENT_CHANGE_POPULATION ±percent Population.
NAMED_SETTLEMENT_CHANGE_RESOURCE ±amount stringData = resource.
NAMED_SETTLEMENT_CHANGE_GARRISON ±amount Garrison. raiseWanted defaults to true.
NAMED_SETTLEMENT_CHANGE_LOYALTY ±loyalty Loyalty.
NAMED_SETTLEMENT_CHANGE_DEVELOPMENT ±levels Development level.
NAMED_SETTLEMENT_ADVANCE_PROJECT cycles stringData = category.
NAMED_SPAWN_ARMY training level strength multiplies troop count.
NAMED_SPAWN_FLEET — strength multiplies crews.
NAMED_GRANT_OUTPOST outpost id Grants an outpost.

Army

Type targetId value Description
ARMY_CHANGE_TROOPS troop type id ±count Adds or removes troops (never below 0). StringData: INFANTRY, HEAVY_INFANTRY, MARKSMEN, CAVALRY, HEAVY_CAVALRY, or SIEGE_ENGINE.
ARMY_ADD_TRAINING army id when filter is NAMED levels Adds training toward the equivalent XP threshold for the named tier — see Leader Age and Experience. filter: ALL (default) or NAMED. Clamped to maximum training; overflow is discarded, not banked.

Diplomatic

Type targetId value Description
CHANGE_OPINION_EMPIRE target empire id ±opinion Changes diplomatic opinion toward another empire. Requires the two empires to have translated each other's language — see Languages and Translation. Omitting targetId applies to every empire the actor has met.
CHANGE_STANDING_RELATION other empire id ±steps Moves standing one or more rungs along the Hatred/Disliked/Trustworthy ladder — see Standing Relations below. StringData sets direction: TOWARD_TARGET (default) changes your own standing toward them; FROM_TARGET changes their standing toward you.
DECLARE_WAR target empire id — Declares war on the player's behalf. Allies of the target join automatically.
WARN_EMPIRE target empire id — Sends a warning report to the target. stringData is an i18n key resolved through the string table; when absent, falls back to the firing event's own title and description.
UNLOCK_DIPLOMATIC_ACTION — action id Permanently unlocks a diplomatic action for the empire. Currently meaningful for action 13 (Demand Return of Cities) and 14 (Demand Reparation) — both locked by default.
CREATE_DIPLOMATIC_REQUEST target empire id — Sends a demand directly — no diplomatic slot, no Imperial Influence cost, no research pause. stringData: demand-return-of-cities or demand-reparation. filter: optional city selector (most-isolated, highest-heritage-population, or lowest-loyalty — the default). See the Focus Tree JSON Reference section for how this is used from a focus.

Spirits and Misc

Type stringData Description
GRANT_SPIRIT spirit id Grants an empire spirit.
REMOVE_SPIRIT spirit id Removes an empire spirit.
DISABLE_TUTORIAL_EVENTS — Turns off remaining tutorial events.

RACE_SET_TERRAIN_LOYALTY (stringData "race:condition") is reserved but not implemented — it's blocked on a planned refactor of the racial terrain-loyalty table. Use the keyed spirit modifier RACE_TERRAIN_LOYALTY_ instead, covered further down this page.

Resource Grants and the Monthly Cycle

Settlements collect resources through the month up to the production phase, where Iron, Leather, and Wood are zeroed out, and Stone, Horses, and produced equipment ship to the Global Equipment Stock. This matters for how a grant effect actually pays out:

  • EMPIRE_CHANGE_EQUIPMENT credits the GES immediately — use it for anything the player should be able to spend right away, including Manpower, despite the effect's name.
  • *_CHANGE_RESOURCE effects are restricted to Stone, Horses, and Grain specifically, because these are the only three resources that survive the monthly sweep. A grant of Iron, Leather, or Wood is worth whatever gets consumed before month end and nothing after — the same effect would pay out very differently depending on which day of the month it happened to fire.
  • Settlement-level grants of Stone, Grain, and Horses are safe but delayed — they land locally right away, and reach the central stock at month end.

Standing Relations (the Hatred/Trustworthy Ladder)

Most diplomatic relation values, covered on Relation Values, are reactions to a specific event and decay back toward zero over time. Standing Relations work differently — Hatred, Disliked, and Trustworthy express a settled opinion rather than a recent grievance, and are mutually exclusive: an empire occupies exactly one rung of a four-step ladder toward any other empire.

Rung Relation Value Meaning
Hatred −225 Permanent enmity
Disliked −75 Standing distrust
(neutral) 0 No standing opinion — none of the three is set
Trustworthy +75 Proven reliable

CHANGE_STANDING_RELATION moves along this ladder rather than setting a value directly. A step past either end simply does nothing. Because the rungs are unevenly spaced, climbing out of a hole is worth considerably more than gilding an existing friendship: Hatred to Disliked is a +150 swing, Disliked to neutral +75, neutral to Trustworthy +75.

Direction matters. stringData selects which side of the relationship changes:

  • TOWARD_TARGET (the default) changes your own empire's standing toward the target — and the AI reads this directly for its own diplomatic vetoes. An AI empire will not offer peace, open borders, friendship, or an alliance to anyone it holds at Disliked or Hatred, regardless of what the overall relation total happens to say.
  • FROM_TARGET changes the target's standing toward you instead — reputation rather than policy. This is what the Return Cities diplomatic action uses.

Two vanilla diplomatic actions step this ladder up by one: Return Cities, and accepting a Demand Return of Cities or Demand Reparation request. Standing can also step down automatically, without any scripted effect at all — see Relation Values for how the base game's own conquest-reaction system does this.

Complete Event Examples

Simple Example

A minor event with a single condition and a single effect:

[
  {
    "id": 300001,
    "title": "A Legendary Sword",
    "description": "A blacksmith has forged a blade of extraordinary quality...",
    "targetType": "ARMY",
    "triggerConditions": [
      { "type": "ARMY_HAS_GENERAL" },
      { "type": "IS_SUMMER" },
      { "type": "EVENT_NOT_FIRED", "value": 300001 }
    ],
    "triggerChance": 1.0,
    "triggerCooldownCycles": 960,
    "tags": ["MINOR", "LEADER", "GOOD_EVENT"],
    "options": [
      {
        "text": "Present it to the general.",
        "effects": [
          { "type": "GENERAL_CHANGE_XP", "value": 50 }
        ]
      },
      {
        "text": "Sell it and equip the levies instead.",
        "optionConditions": [
          { "type": "EMPIRE_MAX_LOYALTY", "value": 50 }
        ],
        "effects": [
          { "type": "EMPIRE_CHANGE_EQUIPMENT", "stringData": "MELEE_WEAPONS", "value": 40 }
        ]
      }
    ]
  }
]

The second option only appears when empire loyalty is at or below 50 — a realm doing well never sees the choice to sell an heirloom. This demonstrates optionConditions: the same event can offer genuinely different choices depending on the empire's own circumstances.

Complex Example

A major empire-wide event demonstrating several fields together: filter restricting an effect to specific settlements, excludeCapital protecting the capital from a penalty, fallback covering a NAMED_* effect when the target doesn't exist in a given scenario, and strength scaling a spawned army beyond its baseline size:

[
  {
    "id": 300050,
    "title": "The Coastal Uprising",
    "description": "Discontent has been building in your coastal territories for months. A fleet of raiders has landed, and your harbour towns are in open revolt...",
    "targetType": "EMPIRE",
    "triggerConditions": [
      { "type": "EMPIRE_MAX_LOYALTY", "value": 30 },
      { "type": "IS_MIN_CYCLE", "value": 2000 },
      { "type": "EVENT_NOT_FIRED", "value": 300050 }
    ],
    "triggerChance": 0.15,
    "triggerCooldownCycles": 2000,
    "tags": ["MAJOR", "BAD_EVENT", "CRIME"],
    "options": [
      {
        "text": "Crack down hard. Reinforce every coastal settlement and make an example of the ringleaders at the capital.",
        "effects": [
          {
            "type": "EMPIRE_CHANGE_GARRISON",
            "value": 150,
            "filter": "coastal",
            "excludeCapital": true,
            "raiseWanted": true
          },
          {
            "type": "NAMED_SPAWN_ARMY",
            "targetId": 4001,
            "fallback": "coastal",
            "strength": 3
          },
          {
            "type": "SETTLEMENT_CHANGE_LOYALTY",
            "value": -10
          },
          {
            "type": "EMPIRE_CHANGE_LOYALTY",
            "value": 3,
            "excludeCapital": false
          }
        ]
      },
      {
        "text": "Negotiate. Grant concessions to the coastal towns and let the matter die down quietly.",
        "effects": [
          {
            "type": "EMPIRE_CHANGE_RESOURCE",
            "stringData": "GRAIN",
            "value": -500,
            "filter": "coastal"
          },
          {
            "type": "EMPIRE_CHANGE_LOYALTY",
            "value": 8,
            "filter": "coastal"
          }
        ]
      }
    ]
  }
]

A few things worth pointing out in the first option above:

  • filter: "coastal" on EMPIRE_CHANGE_GARRISON means only coastal settlements get reinforced — inland cities are untouched.
  • excludeCapital: true on that same effect protects the capital from the garrison change entirely, while the empire-wide loyalty boost right below it deliberately sets excludeCapital: false to make sure the capital does benefit from that one.
  • NAMED_SPAWN_ARMY targets a specific settlement ID (4001) — if that settlement doesn't exist in whatever scenario the mod is running in, fallback: "coastal" means the game picks any coastal settlement instead, so the effect never silently fails.
  • strength: 3 triples the size of that spawned army beyond its baseline.

Focus Tree JSON Reference

Focus trees are wired into the game already, sitting ahead of a future expansion that hasn't been announced yet — think of this section as a bit of a spoiler. Without that content, the focus panel never opens and the AI never selects a focus tree at all; a focus tree in a mod simply lies dormant for every player until it does. Build with this section in mind, but don't expect it to do anything visible yet.

Place focus files in the focus\ folder. A focus file is either a bare JSON array of focus nodes, or an object with optional AI disposition metadata:

{
  "aiAxes":  [ ... ],
  "focuses": [ ... ]
}

Both forms load correctly. Use the object form only if you want to declare AI disposition — see below.

Focus Node Fields

Only id is strictly required, but a node with no name and no effects does nothing.

Field Type Description
id int Required. Unique focus ID within the tree.
label string Design code such as "A.2a". Used in logs and as a display fallback; never shown as the primary name.
name string Display name.
description string Shown in the focus tooltip.
iconId int Image id from the game's icon table — not a file path.
branch string Grouping tag: "A"–"F", "R" (root), "RA" (racial), "DY", "W", "REP". Branches A–D are the ones affected by the FOCUS_TIME_BRANCH_* spirit modifiers.
timeRequired string Either a tier ("T3") or a literal cycle count ("840"). A string, not an int — see Focus Duration below.
requirements array Conditions that must all pass for the focus to be selectable. Prerequisites live here too — see Requirement Object below.
visibleWhen array Conditions that must all pass for the node to be drawn at all. Omit for always-visible.
mutuallyExclusiveWith int array Sibling focus ids. Completing any of them permanently locks this one out — an XOR choice.
effects array Effects applied on completion. Same vocabulary as events — see the Event JSON Reference above.
alternateEffects array Used instead of effects when alternateWhen passes.
alternateWhen object A single requirement object. When it passes, the alternate payload is used instead of the default one.
alternateSpirit string Spirit granted instead of grantSpirit when alternateWhen passes.
alternateDescription string Tooltip text for the alternate case, so the description never promises something the player won't actually get.
grantSpirit string Spirit id granted on completion.
replacesSpirit string Spirit id silently revoked first — the chain-upgrade mechanism for a focus that supersedes an earlier one.
spiritByHeld object Map of heldSpiritId → spiritIdToGrant. Checked in order; first match wins, no match grants nothing. Built for convergence nodes where two different paths meet at the same focus.
removeSpiritOnTier int If set, grantSpirit is auto-revoked the moment any focus of this tier or higher completes.
repeatable object See Repeatable Focuses below.
warnings array See Warnings below.
aiWeight, aiTags, aiRequirements, aiTrough — See AI Selection Fields below.
displayX, displayY int Grid column and row on the focus canvas. Layout hints only — no gameplay logic reads them.
redeclareCostImi int Marks this focus re-declarable: the cost in Imperial Influence to swap to it after an exclusive choice was already made.
redeclareLoyaltyPenalty int Empire loyalty lost when re-declaring.
redeclareFreezeCycles int Cycles during which no new focus can be started after re-declaring.

Focus Duration

timeRequired is a string — either a tier name or an explicit cycle count:

Tier Cycles
"T0" 120
"T1" 240
"T2" 300
"T3" 360
"T4" 420
"T5" 540
"T6" 660

A literal number as a string, such as "840", sets that many cycles directly. An unrecognised tier falls back to 360 cycles and logs a warning. The final duration is then scaled by the empire's FOCUS_TIME_ALL and FOCUS_TIME_BRANCH_A–_D spirit modifiers, floored at 0.50× of the base — no combination of modifiers can push a focus below half its authored length.

Requirement Object

{ "type": "REQUIREMENT_TYPE", "targetId": 0, "targetIds": [], "value": 0, "stringData": "" }

The same object is used by requirements, visibleWhen, aiRequirements, and alternateWhen.

Prerequisites are just requirements — there's no separate requiredFocusIds field. Use FOCUS_COMPLETED for a single prerequisite, or FOCUS_COMPLETED_COUNT_MIN for "any of these" or "any N of these."

Type targetId value Description
FOCUS_COMPLETED focus id — That focus has been completed.
FOCUS_COMPLETED_COUNT_MIN — how many targetIds lists the candidates. value: 1 means "any one of them."
OWNS_SETTLEMENT settlement id — Empire owns that settlement.
SETTLEMENT_DEVELOPMENT_MIN / _MAX settlement id dev level Settlement at least / at most this development level.
PLAYER_RESOURCE_MIN resource id min amount Empire holds at least this much of the resource.
HAS_GENERAL — — At least one army has a general.
HAS_GENERAL_WITH_SKILL skill id min level Any general has that skill at this level.
HAS_GOVERNOR — — At least one settlement has a governor.
NOT_AT_WAR / IS_AT_WAR — — War state.
TECHNOLOGY_RESEARCHED tech id min level Technology at this level (0 is treated as 1).
RACE_IS race id — Empire's race matches.
IS_COASTAL_EMPIRE — — At least one settlement borders water.
IS_LANDLOCKED_OR_ROUGH — — Not coastal, or at least 40% of controlled hexes are hills, mountains, broken ground, forest, or dark forest.
RACE_HAS_NO_CRIME — — The empire's race has a base crime rate of zero — see Crime and Provincial Order.
RACE_CANNOT_ASSIMILATE — — The empire's race cannot assimilate other populations — see Assimilation.
EMPIRE_HOLDS_SPIRIT — — stringData = spirit id the empire must currently hold.
EMPIRE_LOST_SETTLEMENT — min lost Empire has lost at least this many settlements to conquest. Counts real empire-vs-empire conquest only — enables failure-triggered focuses.
EMPIRE_WRONGED_BY other empire id — That empire has declared war on, or taken a settlement from, this empire within the last 20 years.
WORLD_STATE — threshold stringData holds the predicate — see below.

WORLD_STATE predicates. stringData is "PREDICATE:X" or "PREDICATE:X:Y", where X and Y are faction ids or the literal SELF (the empire being evaluated):

stringData value Meaning
"WAR_BETWEEN:X:Y" — X and Y are currently at war with each other.
"HOLDS_FOUNDED_BY:X:Y" count X holds at least value settlements originally founded by Y.
"HOLDS_SETTLEMENTS_MIN:X" count X holds at least value settlements in total.

Unknown predicates log a warning and evaluate as false.

Repeatable Focuses

"repeatable": {
  "cooldownCycles": 480,
  "costEscalation": 60,
  "maxRepeats": 5,
  "effectCap": 3
}
Field Meaning
cooldownCycles Cycles before the focus becomes selectable again. 0 = immediately.
costEscalation Cycles added to the duration per previous completion.
maxRepeats Hard cap on completions. 0 = unlimited.
effectCap Completions after which perCompletion spirit deltas (see the Spirit JSON Reference section) stop applying.

Effects cap while cost does not — deliberately. A long campaign has something to keep spending time on, without the reward inflating indefinitely.

Warnings

Fires a notification to another empire at a point in a focus's lifecycle — the mechanism behind something like "the Storm Palace has begun moving envoys among the harbours."

"warnings": [
  {
    "targetEmpireId": 4,
    "messageId":      "warn.mymod.fleet_gathering",
    "trigger":        "50"
  }
]
Field Meaning
targetEmpireId Faction id to warn. Takes precedence over targetGroup.
targetGroup Used when targetEmpireId is absent. Only "all-met" (every empire this one has established communications with) is implemented — other values log a warning and are skipped.
messageId i18n key for the warning text. Add the key in your mod's i18n/strings.properties file.
trigger "start", "50" (halfway), or "completion".

AI Selection Fields

Field Type Meaning
aiWeight int Selection weight. Default 50. Only set it on genuine decision points.
aiTags string array Tags compared against the empire's rolled disposition. A tag matching the empire's disposition multiplies weight by 2.0; a tag belonging to a declared axis but not matching multiplies by 0.4. Tags belonging to no declared axis are simply ignored — safe to use for readability.
aiRequirements array Hard gates for the AI only. Checked at selection and re-checked at completion — if a gate has since failed, DECLARE_WAR effects are skipped while every other effect still applies.
aiTrough bool Marks a focus whose own effects are net negative but which unlocks something better. Such a node is scored purely on what it leads to, so the AI doesn't avoid it forever.

One caveat worth knowing: the AI's pre-combat "should I attack" check doesn't read targeted combat bonuses such as ARMY_COMBAT_VS_EMPIRE_<id>. An AI holding a grudge bonus therefore fights better when it meets that empire, without being any more inclined to actually seek them out. If a tree depends on the AI going after a specific rival, that intent belongs in aiWeight on the war-declaring focus, gated with aiRequirements (e.g. EMPIRE_WRONGED_BY) — weight is the only lever the selector actually reads.

AI Axes (Disposition)

Declared once per tree, at the top level of the object form. Each axis is rolled once per empire at first evaluation and then fixed for the rest of the campaign — this is what makes two AI empires running the same tree play differently from each other.

"aiAxes": [
  {
    "id":     "course",
    "source": "faction",
    "options": [
      { "tag": "governance", "weight": 30, "matchPlayStyle": 1 },
      { "tag": "economy",    "weight": 35 },
      { "tag": "military",   "weight": 25, "matchPlayStyle": 3 }
    ]
  }
]
Field Meaning
id Axis name. Only used as a key.
source "literal" (plain weights), "faction" (weights plus a +50 bonus when matchPlayStyle matches the empire's AI play style), or "race" (per-race weights).
options[].tag The tag matched against aiTags on focus nodes.
options[].weight Roll weight. Defaults: 50 for literal/race, 25 for faction.
options[].matchPlayStyle source: "faction" only. Play-style id that grants the roll bonus.
options[].weightByRace source: "race" only. Map of race id to weight; unlisted races default to 50.

Diplomatic Demands from a Focus

CREATE_DIPLOMATIC_REQUEST (see the Event JSON Reference section above) lets a focus send an ultimatum without paying the usual diplomatic cost. It names one settlement, chosen by the filter selector:

Selector Picks
most-isolated The candidate furthest from the target's capital.
highest-heritage-population The candidate with the most population of the demanding empire's race.
lowest-loyalty The least loyal candidate. This is the default.

The target's capital is never a candidate. For demand-return-of-cities, candidates are further restricted to settlements the demanding empire originally founded — so in a scenario, set founderId on every settlement that lore says belonged to the demanding realm, regardless of who actually holds it at game start. Get this wrong and the request silently finds no candidate and never fires.

The target may accept (the settlement transfers), refuse, or ignore the demand. Refusing or ignoring grants the sender WAR_UNRESTRICTED against the refuser — free, penalty-free, truce-ignoring war — so refusal is never actually free either. Omitting targetId on a demand-reparation sends one request to every empire that currently qualifies under EMPIRE_WRONGED_BY.

Focus Tree Naming

The file generic_focus.json replaces the built-in generic focus tree, which every faction uses unless it names a different tree in data_factions.csv column 4. Its tree id is GENERIC_FOCUS_TREE.

Any other filename creates a new tree, whose id is simply the filename without .json. To assign it to a faction, put that same string in column 4 of data_factions.csv.

Focus Node Example

{
  "id":           5001,
  "label":        "M.2a",
  "name":         "The Long Watch",
  "description":  "Border forts are manned year-round, at a cost the treasury feels.",
  "branch":       "A",
  "timeRequired": "T3",
  "requirements": [
    { "type": "FOCUS_COMPLETED", "targetId": 5000 },
    { "type": "IS_LANDLOCKED_OR_ROUGH" }
  ],
  "mutuallyExclusiveWith": [5002],
  "effects": [
    {
      "type": "EMPIRE_CHANGE_GARRISON",
      "value": 50,
      "filter": "borders-enemy",
      "raiseWanted": true
    }
  ],
  "grantSpirit": "MYMOD_LONG_WATCH",
  "aiWeight": 60,
  "aiTags":   ["defensive"],
  "displayX": 2,
  "displayY": 4
}

Spirit JSON Reference

Spirit files are individual JSON objects — one file, one spirit. Place files in the spirits\ folder; the filename (without .json) becomes the spirit's ID. Every faction's empire spirit is defined this way — see any faction page for a worked example of a real spirit's effects.

Spirit Fields

Field Type Required Description
id string Yes Unique spirit ID. Must match the filename (without .json).
name string Yes Display name.
description string Yes Shown in the Imperial Court panel.
rawModifiers object No Map of modifier name to float value. Plain modifiers and keyed modifiers both go in this same object — see below.
perCompletion object No Incremental modifier deltas applied each time a repeatable focus granting this spirit completes. (Only relevant once focus trees exist — see the note below.)
onGainEffects array No Event effects applied when the empire gains this spirit.
onLossEffects array No Event effects applied when the empire loses this spirit.
isAdoptableManually boolean Yes Whether the player can adopt this spirit voluntarily. Faction and government spirits are usually false.

rawModifiers Keys — Plain Modifiers

All default to 0.0 unless noted. Sign convention: for anything named *_TIME, *_COST, *_WEAR, *_CONSUMPTION, or LOCAL_CRIME, negative is always better for the empire holding the modifier. For everything else, positive is better. There's exactly one deliberate exception to this rule, flagged in its own row below.

Empire, research, and diplomacy:

Key Description
IMI_GENERATION Imperial Influence generated per cycle (base 0.2).
IMI_CAPACITY Maximum stored Imperial Influence (base 100). The ceiling, not the rate.
DIPLOMATIC_RELATIONS Flat bonus/malus to relations with all empires.
DIPLOMATIC_SPEED Diplomacy completion speed.
DIPLOMATIC_COST Imperial Influence cost of diplomatic actions. Negative is cheaper.
RESEARCH_TIME Research duration. Negative is faster. (Renamed from RESEARCH_SPEED, which still loads as an alias so older spirit files keep working.)
RESEARCH_SETTLEMENT_PENALTY Reduces the per-settlement research penalty described on Technology Tree. That penalty compounds, so blunting it matters more than the base rate once an empire passes six or seven cities.
GES_MANPOWER_CAPACITY Global manpower stock capacity — see Global Equipment Stock.
GES_HORSES_CAPACITY Global horses stock capacity.
GES_EQUIPMENT_CAPACITY Global equipment stock capacity.
GES_GRAIN_CAPACITY Global grain stock capacity.
BUILD_CHURCHES Non-zero enables the Build Churches project — see Outposts.
GROW_FOREST Non-zero enables the Grow Forest project — see Projects.
SEA_FARING Non-zero lets armies enter open ocean hexes — see Movement.

Settlement (applies to every settlement in the empire):

Key Description
LOCAL_LOYALTY Flat loyalty per settlement — see Loyalty.
LOCAL_CRIME Multiplies the derived crime rate. Negative reduces crime — see Crime and Provincial Order.
LOCAL_CITY_DEFENCE Modifier to garrison combat values.
LOCAL_EXPANSION_TIME Modifier to hex expansion project time.
LOCAL_PROJECT_TIME Modifier to settlement project time.
LOCAL_WALL_TIME Modifier to the Build Walls project's duration.
LOCAL_MANPOWER_COLLECTION Modifier to recruits drawn from each population group.
LOCAL_RESOURCE_COLLECTION Modifier to Manpower, Horses, Iron, Leather, and Wood collection. Excludes Stone.
LOCAL_STONE_COLLECTION Modifier to Stone output specifically.
LOCAL_GRAIN_COLLECTION Modifier to daily grain collection.
LOCAL_RESOURCE_CHURCHES Non-zero grants bonus resources from Churches.
LOCAL_PRODUCTIVITY Modifier to workshop capacity.
LOCAL_WORKSHOP_SLOTS Flat addition to the workshop slot formula.
LOCAL_WORKSHOP_STAFFING Modifier to workers required per workshop. Negative means workshops need fewer people — see Production and Equipment.
LOCAL_POPULATION_GROWTH Modifier to birth rate. Does not affect resource income, which derives from hexes rather than population — see Population Growth.
LOCAL_ASSIMILATION Modifier to assimilation rate — see Assimilation.
LOCAL_MIGRATION_SPEED Modifier to the rate of gentle forced migration between settlements — see Migration.

Army:

Key Description
ARMY_MV / ARMY_AV / ARMY_RV / ARMY_SV / ARMY_RSV Melee, Armour, Ranged, Shock, and Resolve values.
ARMY_CR Combat Readiness. Also raises the minimum allowed Combat Readiness.
ARMY_CR_AT_WAR Additional Combat Readiness modifier applying only while the empire is at war.
ARMY_CAP Flat extra armies beyond the Military Academy limit — see Armies.
ARMY_PROJECT_TIME Modifier to army project duration.
ARMY_MOVEMENT_SPEED Modifier to army movement rate.
ARMY_EQUIPMENT_WEAR Modifier to equipment wear while marching.
ARMY_GRAIN_CONSUMPTION Modifier to army grain demand. Negative means an army that eats less.
ARMY_EMBARK_COST Modifier to embark/disembark cost — see Movement.
ARMY_EXERCISE Modifier to Exercise Army effectiveness.
ARMY_SIGHT Modifier to sight range, capped at 4. Only matters with Fog of War on.
ARMY_ORGANISATION_CHURCHES Non-zero means armies near Churches lose less organisation.
ENEMY_SUPPLY_IN_TERRITORY Equipment wear inflicted on enemy armies resting inside the holder's own territory. The one deliberate exception to the sign convention above — positive is better here, because the value describes damage done to somebody else, not a cost paid by the holder.

Naval: Fleets are Army objects internally, so the ARMY_* modifiers above already apply to them — this separate NAVAL_* set exists so a naval-flavoured spirit doesn't silently buff every land army too. These are wired into existing calculations ahead of a future expansion that hasn't been announced yet. Naval combat and fleets aren't part of the base game — don't build a mod expecting these to do anything meaningful until that content actually ships.

Key Description
NAVAL_MV / NAVAL_AV / NAVAL_RV / NAVAL_SV / NAVAL_RSV Combat values applied only to fleets.
NAVAL_MOVEMENT_SPEED Modifier to fleet movement rate.
FLEET_CAP Extra fleets beyond one per coastal settlement.
RAISE_FLEET_TIME Modifier to the Raise Fleet project's duration.
SIEGE_SUPPORT Modifier to a fleet's naval bombardment support to an ongoing land siege — see Sieges.

Leaders, heirs, and race:

Key Description
LEADER_XP_GAIN Modifier to XP gain for army, fleet, and governor leaders — see Leader Age and Experience.
HEIR_QUALITY Flat skill levels on generated heirs.
RACE_ENABLE_ASSIMILATION Grants assimilation to a race that cannot normally assimilate (such as the Ende), at this rate. Removed entirely rather than merely reduced when the spirit is lost — see Population and Special Races.
SOUL_CAPTURE Multiplies the Ende kill-to-troop conversion rate. Affects combat only — it does not affect population growth.

Conquest-conditional: applied realm-wide the instant a settlement is captured, depending on whether the empire it was taken from had wronged the conqueror within the last 20 years.

Key Description
LOYALTY_ON_UNJUSTIFIED_CONQUEST Loyalty change when taking a settlement from an empire that hasn't wronged the conqueror. Negative is a penalty.
LOYALTY_ON_JUSTIFIED_CONQUEST Loyalty change when taking a settlement from an empire that has. Positive is a reward.

Focus system: read only by the focus manager — see the Focus Tree JSON Reference section above for the same forward-looking caveat as naval content.

Key Description
FOCUS_TIME_ALL Modifier to all focus durations.
FOCUS_TIME_BRANCH_A … _D Per-branch focus duration, matching a node's own branch field.

rawModifiers Keys — Keyed Modifiers

Some modifiers need a key as well as a value — a specific terrain, project, or empire. These go in the same rawModifiers object as the plain modifiers above, with the key appended to the modifier name after an underscore. There's no separate schema for this, and unknown names are simply ignored rather than erroring — safe to author even if you're not entirely sure of an ID.

"rawModifiers": {
  "ARMY_TERRAIN_COMBAT_140": 0.15,
  "REDUCE_BUILDING_COST_115": -0.20
}
Prefix Key Is Description
ARMY_TERRAIN_COMBAT_ terrain id Combat modifier in that terrain only — see Terrain for terrain IDs.
ARMY_COMBAT_VS_EMPIRE_ faction id Combat modifier against that empire specifically. See the AI caveat under Focus Tree JSON Reference — the AI's own attack decision doesn't read this.
OUTPOST_BUILD_TIME_ project id Outpost project duration. Keyed by the project, not the outpost type — see Outposts.
REDUCE_BUILDING_COST_ project id Permanent Stone-cost reduction for that project.
RACE_TERRAIN_LOYALTY_ condition Adjusts a race's terrain loyalty reaction. Conditions: no-forest, forest-adjacent, open-terrain — see Loyalty.
RACE_BUILDING_LOYALTY_ condition Adjusts a race's per-building loyalty reaction. Conditions: marketplace, city-wall.
LOCAL_LOYALTY_AT_RECRUIT_LEVEL_ recruit level (0/1/2) Loyalty applied only at that recruitment setting — see Population Growth for recruit levels.
WAR_UNRESTRICTED_ faction id Non-zero: declaring war on that empire costs no Imperial Influence, incurs no reputation penalty, and ignores the usual post-war waiting period — see Diplomatic Actions.
DEFECTION_PRESSURE_ faction id Lowers the relation threshold at which that empire's AI yields to diplomatic demands. (Ties into the focus-driven demand system — see Diplomatic Demands from a Focus above.)

perCompletion — Repeatable Focus Scaling

Only relevant once focus trees exist — see the note at the top of that section above.

When a spirit is granted by a repeatable focus, perCompletion adds its deltas again on every completion, until the focus's own effectCap is reached.

{
  "id": "MYMOD_LEDGER_OF_DEBTS",
  "name": "The Ledger of Debts",
  "description": "Each account settled makes the next easier to open.",
  "rawModifiers": { "ARMY_CR": 0.01 },
  "perCompletion": { "ARMY_CR": 0.01 },
  "isAdoptableManually": false
}

Base modifiers apply once, when the spirit is first granted. perCompletion then stacks further deltas on top per completion. Keyed modifier names work here too.

Spirit Naming Conventions

  • Faction spirits: FACTION_<id>.json (e.g. FACTION_1.json for faction id 1)
  • Government spirits: GOVERNMENT_<TYPE>_<LEVEL>.json
  • Custom spirits: any ID — available as national spirits for events and focus effects

Spirit Example

{
  "id": "SPIRIT_IRON_DISCIPLINE",
  "name": "Iron Discipline",
  "description": "Your armies are drilled beyond endurance. They fight harder but resent it.",
  "rawModifiers": {
    "ARMY_MV": 1.5,
    "ARMY_RSV": 2.0,
    "LOCAL_LOYALTY": -1.0
  },
  "onGainEffects": [],
  "onLossEffects": [],
  "isAdoptableManually": true
}

See also