b1 corrections: budget out-param is int[22], researchMoneyKept gated on a research target

This commit is contained in:
alex 2026-09-07 23:24:58 -04:00
parent 1e7428d5aa
commit 3a3e167242
2 changed files with 19 additions and 1 deletions

View file

@ -117,6 +117,24 @@ if (ResT) researchAlloc.push_back({ResT, [21]}); [9] = researchMoney - [13]
[14] savingsGiven = min(max(remaining,0), savAid)
net = [1]+[2]+[3]+[4]+[5]+[6] - [7]-[8]-[9]-[10]-[11]-[12]-[13]-[14]
```
**Corrections from the B1 live trace (2026-09-08, sots-engine `docs/B1.md`, 4,623 traced +
4,437 compared calls on `ref-turn2.sav`):**
- The out parameter is **`int[22]`, not `int[25]`**. It is a `Budget` object:
`{ int slot[22]; std::vector<{Tech* node, int points}> researchAlloc @+0x58; int overBudget @+0x64 }`.
The three words after slot 21 are the vector's `{first, last, end}`; they grow by exactly one
8-byte element for a player with `ResT` and stay `{0,0,0}` otherwise. (What was read as
"[22]..[24]" is that header.)
- **`[9] researchMoneyKept` is written inside the `if (ResT)` branch**, together with the
`researchAlloc.push_back`. A player with no research target still gets `[16] researchMoney`
and `[17]/[21]` research points, but `[9]` stays 0 and the money is never subtracted from the
net. Independent evidence: player 0 of the reference save has no `ResT`, and its End Turn
moves `Sav` 289,688 -> 532,369, i.e. `+[1] 239,785 +[5] 2,896` with nothing deducted.
- `GetDifficultyMods` rows, measured: **AI (`isAI && !NPC`) = {maintenance divisor 3, research
multiplier 1.5}; human/NPC = {1, 1}** for this game (AI Normal, econ/research 100 %).
`[8] = Maint / ftol(divisor)` confirmed at 500->166, 1000->333 (AI) and 1000->1000 (human row).
- `p+0xf9` is the AI gate as described: player 7 is `isAI && NPC` and takes the human row.
So the "budget sliders" are `ResRate` (research share of net) and the `Nexp` entries; construction is not a slider —
it is whatever the build queues demand up to `avail`. The UI pie chart (`PIECHARTCOLOR_INCOME/COST_FLEETS/COST_RESEARCH/
COST_RESEARCH_AID/COST_FLEETS_QUEUED/COST_FLEETS_TOTAL`) is drawn from this same array.

View file

@ -1,5 +1,5 @@
// GENERATED — do not edit. Facts about Sword of the Stars.exe (GOG 1.8.1).
// Source: sots-re ghidra/addresses.json @ 73f5f1e, generated 2026-09-07 by tools/gen_addresses.py
// Source: sots-re ghidra/addresses.json @ 1e7428d, generated 2026-09-07 by tools/gen_addresses.py
// Runtime address = (uintptr_t)GetModuleHandle(NULL) + RVA (the exe is ASLR-relocated).
#pragma once
#include <cstdint>