Skip to content

site_report

Generate a scored hab-site Excel workbook from a save file.

tiargus.commands.site_report

Excel site-report generator.

Reads a Terra Invicta save file and writes a scored hab-site workbook with two sheets:

  • Sites — one row per prospected hab site (or all sites with --all-sites), with columns for name, body, max hab tier, location, daily resource income (Water, Vols, Metal, Nobles, Fissiles), a weighted score, the dominant resource, and faction. The Score and Most columns are live Excel formulas that update when the Weights sheet is edited.

  • Weights — a single editable row of multipliers (one per resource) that drive the score formula. Changing a weight instantly re-ranks all sites without re-running the tool.

The main entry point is generate_site_report, which can be called programmatically, or via the tiargus site-report CLI subcommand.

Resource income figures are monthly by default (daily figures × _DAYS_PER_MONTH); pass monthly=False to generate_site_report or --daily on the CLI for per-day values.

add_parser(subparsers)

Register the site-report subcommand on subparsers.

Source code in src/tiargus/commands/site_report.py
262
263
264
265
266
267
268
269
270
271
@register
def add_parser(subparsers) -> None:
    """Register the ``site-report`` subcommand on *subparsers*."""
    p = subparsers.add_parser(
        "site-report",
        help="Generate a scored hab-site Excel workbook.",
        description="Generate a Terra Invicta site report from a save file.",
    )
    _add_arguments(p)
    p.set_defaults(func=_run)

generate_site_report(save, output_path, default_weights=None, monthly=True, all_sites=False, reset_weights=False, config=None)

Write a scored hab-site Excel workbook from a parsed save file.

Creates a two-sheet workbook:

  • Sites — one row per hab site with name, body, max hab tier, location, resource income, a SUMPRODUCT score formula, the dominant resource, and owning faction.
  • Weights — editable multipliers (one per resource) referenced by the Score and Most formulas. Editing a weight cell instantly re-ranks all sites without re-running this function.

Parameters:

Name Type Description Default
save TerraInvictaSave

A TerraInvictaSave constructed with at least HabSiteModule.

required
output_path str | Path

Destination path for the .xlsx file.

required
default_weights Optional[dict[str, float]]

Resource weight overrides. Any key absent from this dict falls back to the config weights (DEFAULT_WEIGHTS by default). Pass None to use the config weights unchanged.

None
monthly bool

When True (default), resource values are multiplied by 30.44 to show monthly income. Pass False for daily values.

True
all_sites bool

When False (default), only sites on bodies the player has fully prospected are included. Pass True to include every site in the save regardless of prospecting status.

False
reset_weights bool

When False (default), any weights the player edited directly in an existing report's Weights sheet are read back and take priority over default_weights/config, so edits round-trip across regenerations. Pass True to discard those edited values and rebuild the Weights sheet from default_weights/config.

False
config Optional[Config]

App-wide Config supplying the base resource weights. Defaults to the cached get_config when None.

None
Source code in src/tiargus/commands/site_report.py
 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
122
123
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
def generate_site_report(
    save: TerraInvictaSave,
    output_path: str | Path,
    default_weights: Optional[dict[str, float]] = None,
    monthly: bool = True,
    all_sites: bool = False,
    reset_weights: bool = False,
    config: Optional[Config] = None,
) -> None:
    """Write a scored hab-site Excel workbook from a parsed save file.

    Creates a two-sheet workbook:

    - **Sites** — one row per hab site with name, body, max hab tier, location,
      resource income, a ``SUMPRODUCT`` score formula, the dominant resource,
      and owning faction.
    - **Weights** — editable multipliers (one per resource) referenced by the
      Score and Most formulas.  Editing a weight cell instantly re-ranks all
      sites without re-running this function.

    Args:
        save: A [TerraInvictaSave][tiargus.savegame.TerraInvictaSave] constructed
            with at least [HabSiteModule][tiargus.habs.HabSiteModule].
        output_path: Destination path for the `.xlsx` file.
        default_weights: Resource weight overrides.  Any key absent from this
            dict falls back to the config weights
            ([DEFAULT_WEIGHTS][tiargus.config.DEFAULT_WEIGHTS] by default).
            Pass `None` to use the config weights unchanged.
        monthly: When ``True`` (default), resource values are multiplied by
            ``30.44`` to show monthly income.  Pass ``False`` for daily values.
        all_sites: When ``False`` (default), only sites on bodies the player
            has fully prospected are included.  Pass ``True`` to include every
            site in the save regardless of prospecting status.
        reset_weights: When ``False`` (default), any weights the player edited
            directly in an existing report's Weights sheet are read back and
            take priority over ``default_weights``/config, so edits round-trip
            across regenerations.  Pass ``True`` to discard those edited values
            and rebuild the Weights sheet from ``default_weights``/config.
        config: App-wide [Config][tiargus.config.Config] supplying the base
            resource weights.  Defaults to the cached
            [get_config][tiargus.config.get_config] when ``None``.
    """
    base_weights = (config or get_config()).site_report.weights
    weights = {**base_weights, **(default_weights or {})}
    if not reset_weights:
        weights = {**weights, **_load_weights_from_workbook(Path(output_path))}

    faction_names = {
        f.id: f.display_name for f in save.get_module(FactionModule).factions.values()
    }
    faction_names_display = {k: v[:1].upper() + v[1:] for k, v in faction_names.items()}

    # --- Build Sites DataFrame (Score/Most filled in post-write as formulas) ---
    sites_df = sites_dataframe(save, monthly=monthly, all_sites=all_sites)
    fissiles_idx = list(sites_df.columns).index("Fissiles")
    sites_df.insert(fissiles_idx + 1, "Score", None)
    sites_df.insert(fissiles_idx + 2, "Most", None)

    computed_score = sum(
        sites_df[res].fillna(0) * weights[res] for res in _RESOURCE_NAMES
    )
    sites_df = (
        sites_df.assign(_score_key=computed_score)
        .sort_values("_score_key", ascending=False)
        .drop(columns="_score_key")
        .reset_index(drop=True)
    )

    headers = list(sites_df.columns)

    weights_df = pd.DataFrame(
        [[""] + [weights[name] for name in _RESOURCE_NAMES]],
        columns=["Weights"] + list(_RESOURCE_NAMES),
    )

    with pd.ExcelWriter(output_path, engine="openpyxl") as writer:
        sites_ws = write_sheet(writer, sites_df, "Sites")
        weights_ws = write_sheet(
            writer, weights_df, "Weights", freeze_header=False, auto_filter=False
        )

        last_data_row = len(sites_df) + 1

        faction_formula = '"' + ",".join(sorted(faction_names_display.values())) + '"'
        if len(faction_formula) <= 255 and last_data_row >= 2:
            dv_faction = DataValidation(
                type="list", formula1=faction_formula, allow_blank=True
            )
            faction_col = get_column_letter(headers.index("Faction") + 1)
            dv_faction.add(f"{faction_col}2:{faction_col}{last_data_row}")
            sites_ws.add_data_validation(dv_faction)

        for row_idx in range(2, last_data_row + 1):
            res = f"E{row_idx}:I{row_idx}"
            sites_ws.cell(row=row_idx, column=10).value = (
                f"=SUMPRODUCT({res},Weights!$B$2:$F$2)"
            )
            sites_ws.cell(row=row_idx, column=11).value = _most_formula(row_idx)
            for col in range(5, 11):  # E through J (resources + score)
                sites_ws.cell(row=row_idx, column=col).number_format = "0.0"

        for col_cells in weights_ws.columns:
            weights_ws.column_dimensions[
                get_column_letter(col_cells[0].column)
            ].width = 10

    qualifier = "all" if all_sites else "prospected"
    print(f"Wrote {len(sites_df)} {qualifier} hab sites to {output_path}")

main()

Standalone entry point for python -m tiargus.commands.site_report.

Source code in src/tiargus/commands/site_report.py
274
275
276
277
278
279
280
281
def main() -> None:
    """Standalone entry point for ``python -m tiargus.commands.site_report``."""
    parser = argparse.ArgumentParser(
        description="Generate a Terra Invicta site report from a save file."
    )
    _add_arguments(parser)
    args = parser.parse_args()
    _run(args)