Faction
A Faction is an entity that owns objects in the universe, has bilateral relations with every other faction, accumulates money, and decides strategic actions. Every persistent thing in the universe (Station, Ship, Module, NPC) is owned by some faction.
Subtypes (by behavior): Player (faction.player) and NPC factions share the same datatype but differ in how engine-side AI drives them — NPC factions run factionlogic.xml heartbeat, the player does not. Some properties (willclaimspace, isaggressive, iseconomic) are tag-driven; see libraries/factions.xml for the definitive list.
Primary races: Argon, Paranid, Teladi, Split, Terran, Boron, Xenon, Khaak — see .primaryrace accessor. Note that “Riptide” is a scavenger sub-faction with primaryrace=argon, not Fallen Families — easy mistake.
Properties
Section titled “Properties”The most-used accessors for modders. The full list (~60 properties) is in vanilla libraries/scriptproperties.xml:1820.
Identity
Section titled “Identity”| Property | Type | Description |
|---|---|---|
.id | string | Internal id (e.g. argon, khaak) |
.name | string | Display name (respects unknown-status — may show ”???”) |
.knownname | string | Display name, ignoring unknown-status |
.shortname / .prefixname | string | Short / prefix forms |
.primaryrace | race | The race this faction is associated with |
.isactive | bool | Currently active (some factions deactivate mid-game) |
.knowntoplayer | bool | Player has met them |
Relations
Section titled “Relations”| Property | Type | Description |
|---|---|---|
.relationto.{faction} | float | Relation to another faction. Raw float -1.0 .. +1.0 |
.relationto.{object} | float | Relation to owner of an object |
.defaultrelationto.{faction} | float | What relation would be without runtime changes |
.relation.{rangename}.min / .mid / .max | float | Edges of a named relation range |
.relation.{numeric}.uivalue | int | UI form (-30 .. +30) of a float relation value |
.hasrelation.{rangename}.{X} | bool | Is relation to X in the given range |
.mayattack.{component or faction} | bool | Will this faction shoot at X |
.ishostileto.{component or faction} | bool | Either side may shoot |
.isrelationlocked | bool | Relation cannot be changed |
Relation ranges (named ranges in libraries/factions.xml):
| Range | Float | UI | Meaning |
|---|---|---|---|
| nemesis | −30 only | −30 | Maximally hostile, flavour |
| kill | −25 .. −30 | −25 .. −30 | All assets attacked on sight |
| killmilitary | −20 .. −30 | −20 .. −30 | Military assets attacked |
| enemy | −10 .. −30 | −10 .. −30 | No docking; stations don’t report player attacks |
| neutral | 0 (excl.) | 0 | Tolerated |
| friend / ally / dock | various positive | 10..30 | Docking and trading allowed |
| Property | Type | Description |
|---|---|---|
.money | money (Cr × 100 internally) | Current faction account balance |
.hasownaccount | bool | If false, uses dummy random-sum account |
Tags & roles
Section titled “Tags & roles”| Property | Type | Description |
|---|---|---|
.tags | list | All faction tags (tag.claimspace, tag.economic, tag.aggressive, …) |
.hastag.{tag} | bool | Has tag |
.isaggressive / .iseconomic / .ispolice / .isprotective | bool | Behavioural tags |
.willclaimspace | bool | Will claim sectors if it has a claim-granting station |
.policefaction | faction | Which faction is its police force |
Resources & licences
Section titled “Resources & licences”| Property | Type | Description |
|---|---|---|
.headquarters | station | This faction’s HQ station |
.representative | entity | Embassy representative NPC |
.diplomat | entity | Diplomat NPC |
.licences | list | All licences this faction grants |
.heldlicences | list | All licences this faction holds (from other factions) |
.haslicence.{type}.{faction} | bool | Has licence of <type> from {faction} |
.doesresupply | bool | Will resupply ships at owned docks |
Actions
Section titled “Actions”Change a faction’s relation to another faction (permanent)
Section titled “Change a faction’s relation to another faction (permanent)”<set_faction_relation faction="$Faction" otherfaction="faction.player" value="$Faction.relation.dock.min + 0.001" reason="relationchangereason.missioncompleted"/>reason= is the engine’s audit trail — pick a relationchangereason.X enum value. The comment in vanilla:
+ 0.001to move into the ‘docking’ UI value range — range edges are exclusive on one side.
Change a single object’s relation (temporary, with decay)
Section titled “Change a single object’s relation (temporary, with decay)”<set_relation_boost object="$AttackedShip" otherobject="$Attacker" value="$AttackedShip.owner.relation.kill.min" delay="10min" decay="1" reason="relationchangereason.attackedobject" silent="true"/>This affects only the object, decays over time. silent="true" suppresses the on-screen notification. Use this for “make this NPC hate the player for 10 min” rather than permanent shifts.
Engine-computed reputation changes
Section titled “Engine-computed reputation changes”For attacks, kills, and boarding the engine has dedicated actions that read damage / weapon / context and apply the right curve:
<change_relation_on_attack attacker="player.controlled" attacked="event.param" method="event.param2" weapon="event.param3.{2}" result="$relchange"/>
<change_relation_on_kill killer="player.controlled" killed="event.param" method="event.param2" result="$relchange"/>
<change_relation_on_boarding boarder="player.controlled" boarded="$object" attempt="true" result="$relchange"/>See vanilla notifications.xml:1515, 1737, 1796 for the canonical wiring.
Find all factions with a given relation
Section titled “Find all factions with a given relation”<get_factions_by_relation result="$EnemyFactions" faction="$Faction" relation="enemy" activeonly="true"/>relation= takes a named range; activeonly=true skips inactive factions.
Transfer money
Section titled “Transfer money”<transfer_money from="$Faction" to="faction.player" amount="($Reward)Cr"/>amount= must be a money type — wrap dynamic numbers as ($N)Cr, not bare integers.
Change asset ownership
Section titled “Change asset ownership”<set_owner object="$Station" faction="$NewOwner"/>For ships, prefer md.LIB_Generic.TransferShipOwnership — it severs the old commander’s fleet link, which bare set_owner does not. See Station → Actions.
Libraries
Section titled “Libraries”Vanilla helpers for working with factions. Source: md/lib_generic.xml.
| Library | Purpose | Source line |
|---|---|---|
md.LIB_Generic.DetermineEnemyFaction | Find a random enemy of $Faction (or return all) | 1482 |
md.LIB_Generic.CalculateReputation | Compute reputation gain from a contribution | 376 |
md.LIB_Generic.CalculateReputationDrop | Compute reputation drop from a hostile act | 411 |
md.LIB_Generic.FixFactionRepresentative | Restore missing representative NPC after save load | 1651 |
md.LIB_Generic.WaitForFactionsToHaveStations | Wait until ALL given factions have at least one station | 4254 |
md.LIB_Generic.FindNearestStationForFaction | Closest station of given faction to position | 1240 |
md.LIB_Generic.FindStationsForFactionByDistance | All stations sorted by distance | 1270 |
md.LIB_Generic.FindNearestEnemySectorForFaction | Nearest sector controlled by an enemy of $Faction | 1326 |
md.LIB_Generic.GetSectorSafety | Friend/enemy station ratio in a sector, evaluated for a faction | 4703 |
Events
Section titled “Events”| Event | When | Notes |
|---|---|---|
event_faction_relation_changed | Bilateral relation between two factions changed | event.param = [fA, fB]. Use faction= and optionally otherfaction= attributes to filter |
event_faction_activated | Faction transitioned to active | Vanilla uses for diplomacy intros |
event_faction_deactivated | Faction transitioned to inactive | Triggers cleanup of pending operations |
event_faction_police_changed | policefaction changed | Used by faction_relations.xml |
event_object_changed_owner | An object changed faction (boarding, transfer, capture) | Object-side; not faction-side |
Common gotchas
Section titled “Common gotchas”- ⚠
.relationtoreturns a raw float (-1.0..+1.0), not the UI value. Doing.relationto.{Y}.uivaluesilently returns null. To get UI:$F.relation.{$F.relationto.{Y}}.uivalue. For float thresholds (most common), compare floats directly (0.10, 0.20, 0.50). - ⚠
.moneyis stored as 1/100-credit integer. A reading of1000000means 10 000 Cr. The same scale applies tosellprice/buypricein logs. Divide by 100 only for display. - ⚠
transfer_money amount=needsmoneytype. A dynamic($val)Crworks; a bare integer logs “not of type money” and silently no-ops. See memory: transfer_money requires money type. - ⚠
set_faction_relationvsset_relation_boost.set_faction_relationis the permanent baseline between two factions.set_relation_boostis time-decaying per-object. For “this NPC ship is mad at the player for 10 min” use boost; for “Argon now likes the player +5 from a mission” useset_faction_relation(or let the engine do it viachange_relation_on_*). - ⚠ Relation range edges are exclusive on one side. Vanilla often adds
+0.001torelation.dock.minto actually land inside the docking range. Read the property description: “in ‘neutral’ and ‘dock’ the .min value is NOT included”. - ⚠
faction.Xlookups for missing factions return null silently. A DLC-gatedfaction.terranis null on a Base-only install. Wrap DLC-faction references with<do_if value="@faction.terran">.
Examples
Section titled “Examples”Example 1: Find a random enemy faction for AI raiders
Section titled “Example 1: Find a random enemy faction for AI raiders”<run_actions ref="md.LIB_Generic.DetermineEnemyFaction" result="$Enemy"> <param name="Faction" value="faction.argon"/> <param name="ClaimSpaceFactionsOnly" value="true"/></run_actions>
<do_if value="@$Enemy"> <write_to_logbook text="'Picked enemy: ' + $Enemy.knownname"/></do_if>Example 2: Reward the player when a side mission completes
Section titled “Example 2: Reward the player when a side mission completes”<set_value name="$RewardCr" exact="50000"/>
<transfer_money from="$QuestGiver" to="faction.player" amount="($RewardCr)Cr"/>
<set_faction_relation faction="$QuestGiver" otherfaction="faction.player" value="$QuestGiver.relationto.{faction.player} + 0.05" reason="relationchangereason.missioncompleted"/>Example 3: Listen for player relation reaching docking with Argon
Section titled “Example 3: Listen for player relation reaching docking with Argon”<cue name="WatchArgonRelation" instantiate="true"> <conditions> <event_faction_relation_changed faction="faction.player" otherfaction="faction.argon"/> <check_value value="faction.player.hasrelation.dock.{faction.argon}"/> </conditions> <actions> <write_to_logbook text="'Argon now allows player docking.'"/> </actions></cue>Architectural context
Section titled “Architectural context”- How factions decide what to produce, build, or buy: Architectural overview Faction economy — per-faction
Econ_Managerreads shortages, picks one of 7 corrective actions. - How factions pick strategic actions (invade, hold, plunder, patrol): Architectural overview Faction goals — Registry + two-tier evaluation (PriorityGoals must-run + EvaluatedGoals competition).
- How factions evaluate distress calls: Architectural overview Patrol coordination — galaxy combat bus + per-faction priority queue.
- Faction relations seeding:
libraries/factions.xmldeclares default relations; runtime changes go throughset_faction_relationwithrelationchangereason.Xaudit.