Skip to content

orgs

Data model and query module for organisations, their bonuses, and market availability.

tiargus.orgs

Data model and SavegameModule for organisations (orgs).

Provides:

  • Org — an individual org, including its tier, its non-zero stat bonuses, and which faction's market it is currently available in (if any).
  • OrgModule (key: "orgs") — parses every org from the save and resolves each org's market availability.
Example
from tiargus import TerraInvictaSave, OrgModule

save = TerraInvictaSave("Autosave.gz", OrgModule)
for org in save.get_module(OrgModule).orgs.values():
    if org.available_to_faction_id is not None:
        print(org.display_name, org.tier, org.bonuses)

BonusField

Bases: AliasedStrEnum

A stat or economy bonus an Org can confer.

Each member's value is the raw save-file key for that bonus. Members subclass str, so a member compares and hashes equal to its raw key (e.g. BonusField.ESPIONAGE == "espionage"), keeping it interchangeable with the raw-string keys used in Org.bonuses.

Each member also carries a curated tuple of synonyms — short, friendly names intended for interactive (REPL) use. The seven councilor-stat fields use the in-game three-letter abbreviations:

Member Raw key Synonyms
PERSUASION persuasion PER
COMMAND command CMD
INVESTIGATION investigation INV
ESPIONAGE espionage ESP
ADMINISTRATION administration ADM
SCIENCE science SCI
SECURITY security SEC
MISSION_CONTROL MCBonus MC, mission control

Use from_alias to resolve any raw key, member name, or synonym (case- and separator-insensitively) to a member, and the aliases property to list every accepted spelling for a member.

Members are declared as NAME = (raw_key, *synonyms).

Source code in src/tiargus/orgs.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class BonusField(AliasedStrEnum):
    """A stat or economy bonus an [Org][tiargus.orgs.Org] can confer.

    Each member's value is the raw save-file key for that bonus.  Members
    subclass ``str``, so a member compares and hashes equal to its raw key
    (e.g. ``BonusField.ESPIONAGE == "espionage"``), keeping it interchangeable
    with the raw-string keys used in [Org.bonuses][tiargus.orgs.Org].

    Each member also carries a curated tuple of **synonyms** — short, friendly
    names intended for interactive (REPL) use.  The seven councilor-stat fields
    use the in-game three-letter abbreviations:

    | Member | Raw key | Synonyms |
    | ------ | ------- | -------- |
    | ``PERSUASION`` | ``persuasion`` | ``PER`` |
    | ``COMMAND`` | ``command`` | ``CMD`` |
    | ``INVESTIGATION`` | ``investigation`` | ``INV`` |
    | ``ESPIONAGE`` | ``espionage`` | ``ESP`` |
    | ``ADMINISTRATION`` | ``administration`` | ``ADM`` |
    | ``SCIENCE`` | ``science`` | ``SCI`` |
    | ``SECURITY`` | ``security`` | ``SEC`` |
    | ``MISSION_CONTROL`` | ``MCBonus`` | ``MC``, ``mission control`` |

    Use [from_alias][tiargus.orgs.BonusField.from_alias] to resolve any
    raw key, member name, or synonym (case- and separator-insensitively) to a
    member, and the [aliases][tiargus.orgs.BonusField.aliases] property to
    list every accepted spelling for a member.

    Members are declared as ``NAME = (raw_key, *synonyms)``.
    """

    PERSUASION = ("persuasion", "PER")
    COMMAND = ("command", "CMD")
    INVESTIGATION = ("investigation", "INV")
    ESPIONAGE = ("espionage", "ESP")
    ADMINISTRATION = ("administration", "ADM")
    SCIENCE = ("science", "SCI")
    SECURITY = ("security", "SEC")
    ECONOMY = ("economyBonus",)
    WELFARE = ("welfareBonus",)
    ENVIRONMENT = ("environmentBonus",)
    GOVERNMENT = ("governmentBonus",)
    UNITY = ("unityBonus",)
    MILITARY = ("militaryBonus",)
    OPPRESSION = ("oppressionBonus",)
    SPOILS = ("spoilsBonus",)
    KNOWLEDGE = ("knowledgeBonus",)
    MINING = ("miningBonus",)
    SPACEFLIGHT = ("spaceflightBonus",)
    SPACE_DEV = ("spaceDevBonus",)
    MISSION_CONTROL = ("MCBonus", "MC", "mission control")

aliases property

Every spelling that resolves to this member, in declaration order.

Comprises the raw value, the member name, and the curated synonyms, de-duplicated. Handy for listing accepted inputs in a REPL.

synonyms property

The curated friendly aliases for this member (excludes value & name).

from_alias(name) classmethod

Resolve a flexible alias to its canonical member.

Lookup is case- and separator-insensitive (spaces, underscores, and hyphens are ignored) and a trailing "bonus" is optional. A member's raw value, its name, and its curated synonyms are all valid aliases.

Parameters:

Name Type Description Default
name str

The alias to resolve.

required

Returns:

Type Description
_AS

The matching member.

Raises:

Type Description
ValueError

If no member matches the normalized alias.

Source code in src/tiargus/_aliased_enum.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
@classmethod
def from_alias(cls: type[_AS], name: str) -> _AS:
    """Resolve a flexible alias to its canonical member.

    Lookup is case- and separator-insensitive (spaces, underscores, and
    hyphens are ignored) and a trailing ``"bonus"`` is optional.  A
    member's raw value, its name, and its curated ``synonyms`` are all valid
    aliases.

    Args:
        name: The alias to resolve.

    Returns:
        The matching member.

    Raises:
        ValueError: If no member matches the normalized alias.
    """
    try:
        return cls._alias_index()[_normalize_alias(name)]
    except KeyError:
        raise ValueError(f"Unknown {cls.__name__} alias: {name!r}") from None

Org dataclass

An organisation as recorded in the save file.

Attributes:

Name Type Description
id int

Numeric game-state ID.

display_name str

Org name as shown in-game.

tier int

Org tier (1–3).

available_to_faction_id Optional[int]

ID of the faction in whose market this org is currently available, or None if it is not in any faction's market. If an org appears in more than one market, the last one scanned wins.

bonuses dict[str, float]

Mapping of bonus-field name to value, including only fields with a non-zero value. Keys are the raw save-file strings, each of which is the value of a BonusField member.

missions_granted frozenset[str]

Internal identifiers of the missions this org grants to a councilor it is assigned to (from the org template's missionsGrantedNames).

research_bonuses dict[ResearchCategory, float]

Mapping of research category to its bonus multiplier (from the org template's techBonuses). Keys are ResearchCategory members, each of which (being a str subclass) stays interchangeable with its raw category string. Empty when the org confers no research bonuses.

Source code in src/tiargus/orgs.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
@dataclass
class Org:
    """An organisation as recorded in the save file.

    Attributes:
        id: Numeric game-state ID.
        display_name: Org name as shown in-game.
        tier: Org tier (1–3).
        available_to_faction_id: ID of the faction in whose market this org is
            currently available, or ``None`` if it is not in any faction's
            market.  If an org appears in more than one market, the last one
            scanned wins.
        bonuses: Mapping of bonus-field name to value, including only fields
            with a non-zero value.  Keys are the raw save-file strings, each of
            which is the value of a [BonusField][tiargus.orgs.BonusField]
            member.
        missions_granted: Internal identifiers of the missions this org grants to
            a councilor it is assigned to (from the org template's
            ``missionsGrantedNames``).
        research_bonuses: Mapping of research category to its bonus multiplier
            (from the org template's ``techBonuses``).  Keys are
            [ResearchCategory][tiargus.technology.ResearchCategory] members,
            each of which (being a ``str`` subclass) stays interchangeable with
            its raw category string.  Empty when the org confers no research
            bonuses.
    """

    id: int
    display_name: str
    tier: int
    available_to_faction_id: Optional[int]
    bonuses: dict[str, float]
    missions_granted: frozenset[str]
    research_bonuses: dict[ResearchCategory, float]

OrgModule

Bases: SavegameModule

Parses all orgs and resolves each org's market availability.

Depends on FactionModule; an org is "in the market" when its ID appears in some faction's availableOrgs list.

Source code in src/tiargus/orgs.py
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
class OrgModule(SavegameModule):
    """Parses all orgs and resolves each org's market availability.

    Depends on [FactionModule][tiargus.factions.FactionModule]; an org is
    "in the market" when its ID appears in some faction's ``availableOrgs`` list.
    """

    KEY = "orgs"

    def __init__(self) -> None:
        self._orgs: dict[int, Org] = {}

    @property
    def orgs(self) -> dict[int, Org]:
        """All orgs keyed by their numeric game-state ID."""
        return self._orgs

    @classmethod
    def requires(cls) -> list[str]:
        return [FactionModule.KEY]

    def parse(self, gs: dict, modules: dict[str, SavegameModule]) -> None:
        market = self._org_markets(gs)
        org_missions = load_game_data("org_missions.yaml")
        org_research = load_game_data("org_research_bonuses.yaml")
        for item in gs[GS_ORG]:
            oid = item["Key"]["value"]
            value = item["Value"]
            template_name = value.get("templateName", "")
            bonuses = {
                f.value: float(value[f.value])
                for f in BonusField
                if value.get(f.value, 0.0)
            }
            research_bonuses = {
                ResearchCategory(cat): float(bonus)
                for cat, bonus in org_research.get(template_name, {}).items()
            }
            self._orgs[oid] = Org(
                id=oid,
                display_name=value["displayName"],
                tier=int(value.get("tier", 1)),
                available_to_faction_id=market.get(oid),
                bonuses=bonuses,
                missions_granted=frozenset(org_missions.get(template_name, [])),
                research_bonuses=research_bonuses,
            )

    @staticmethod
    def _org_markets(gs: dict) -> dict[int, int]:
        """Map each org ID to a faction whose market currently offers it."""
        market: dict[int, int] = {}
        for item in gs[GS_FACTION]:
            fid = item["Key"]["value"]
            for ref in item["Value"].get("availableOrgs", []):
                market[ref["value"]] = fid
        return market

orgs property

All orgs keyed by their numeric game-state ID.

__init_subclass__(**kwargs)

Register subclasses in _REGISTRY at definition time.

Raises:

Type Description
TypeError

If a subclass does not define KEY.

Source code in src/tiargus/savegame.py
141
142
143
144
145
146
147
148
149
150
def __init_subclass__(cls, **kwargs: object) -> None:
    """Register subclasses in ``_REGISTRY`` at definition time.

    Raises:
        TypeError: If a subclass does not define ``KEY``.
    """
    super().__init_subclass__(**kwargs)
    if not hasattr(cls, "KEY"):
        raise TypeError(f"{cls.__name__} must define KEY as a class variable")
    SavegameModule._REGISTRY[cls.KEY] = cls