b2 static findings: tech effects corrections, full g_TechIdNames dump; contract 176->211
This commit is contained in:
parent
ead46e2608
commit
db9b561964
3 changed files with 439 additions and 6 deletions
|
|
@ -190,3 +190,86 @@ an inferred field meaning; LOW = consumer identified but purpose inferred from c
|
|||
Not done: values of the 6-entry AI tech table (0x00a17888), the `+0x224/+0x228/+0x22c` player multipliers' producer
|
||||
(0x0077b620 copies them from a 0x50-byte per-player options record `+0x48/+0x4c/+0x50` — likely the game-setup
|
||||
difficulty/handicap block, MEDIUM), and the design-side consumers of the §3 masks.
|
||||
|
||||
---
|
||||
|
||||
## 9. B2 corrections (2026-09-08) — read from the instruction stream, ReVa + `objdump -b binary -m i386`
|
||||
|
||||
Nine things this note had wrong, missing, or at lower confidence than the binary supports.
|
||||
Where the two disagree, the binary wins.
|
||||
|
||||
1. **Every modifier is a float32 and every constant is a widened float literal.** The shape is
|
||||
`fld dword [field]; fadd/fmul qword [k]; fstp dword [field]`. The doubles at the `.rdata`
|
||||
addresses listed in §1 are *float32 values widened to double*, not the decimals: 0x009e5060 =
|
||||
0x3FA99999A0000000 = `(double)0.05f`, 0x009e2318 = `(double)0.1f`, 0x009ed188 = `(double)0.15f`,
|
||||
0x009e20d8 = `(double)0.2f`, 0x009e5df0 = `(double)0.3f`, 0x009f15b0 = `(double)0.35f`,
|
||||
0x00a33358 = `(double)0.45f`, 0x009e5068 = `(double)0.6f`, 0x00a33360 = `(double)0.06f`,
|
||||
0x009e23a0 = `(double)0.9f`. Exact: 0x009e5d70 = 0.25, 0x009e20a0 = 0.5, 0x009e8d28 = 0.75,
|
||||
0x009e90b8 = 1.5, 0x009e1ef0 = 1.0. `MaxOH`'s 0x009e22f0 is a **float32** 0.1f loaded with
|
||||
`fld dword` and passed to `std::max<float>`. `DRV_FarCast` writes float32 10.0 (0x00a2bed0),
|
||||
2.0 (0x009e5840) and `FLD1`. A reimplementation must round through float32 at *every* step.
|
||||
2. **`g_AITechValueTable` (0x00a17888) is dumped.** Six 12-byte rows `{int techId, float odds,
|
||||
float value}`, count at 0x00aea2ec = 6:
|
||||
`{10021,0.1,0.5} {10022,0.1,0.5} {10023,0.1,0.5} {10083,0.2,0.0} {10024,0,0} {10025,0,0}`.
|
||||
So the CCC_AI / AIAdmin / AIFac bonus is **0.5** into ResMod / IncMod(+0x30c) / OutMod, and the
|
||||
AI-rebellion odds column is 0.1 for those three and 0.2 for **CCC_AIFRCON (10083)** — which is
|
||||
in the table for its odds only; `ApplyAITechBonus` has no branch for it. `ApplyAITechBonus`
|
||||
multiplies the value by `AIBn ? 1.0f : (float)[0x009e1fac] = -1.0f` and narrows the product to
|
||||
float32 before adding.
|
||||
3. **`PrGtTrf` (+0x148) is an int.** `mov ecx,[PTR]; mov edx,[esi+0x148]; cmp edx,[ecx]; jl` — a
|
||||
signed integer max against an integer config word, not a float compare. §1's "PrGtTrf =
|
||||
max(...)" is right, the type was not stated.
|
||||
4. **`ServerPlayer+0x308` is a pointer, not three inline words.** `ServerPlayer::
|
||||
UpdateNodeBoreParams` (0x008182c0, called unconditionally in the tail) builds a local 3-word
|
||||
struct via `SelectNodeBoreParams` (0x006e18e0); on success it `operator new(0xc)`s the block if
|
||||
+0x308 is null and copies the three words in; on failure it `operator delete`s the block and
|
||||
nulls +0x308. `SelectNodeBoreParams(out, player)` tests **RAD (0x2752) first, then REND
|
||||
(0x2751), then RIP (0x2750)**, first hit wins — "highest wins" confirmed, HIGH not MEDIUM —
|
||||
returning {95,60,5} / {65,35,4} / {45,15,3}, and false with out = {INT_MAX, INT_MAX, 0} when
|
||||
none. **There is no species check**: these are not Zuul-gated in code.
|
||||
5. **`RebuildSpeciesTechFlags` (0x0082bf10) has an undocumented second pass.** After filling
|
||||
`flags[7]` at +0x348 (and writing the count word 7 at +0x364 — the 0x20 bytes are assigned as a
|
||||
unit), it loops species 0..6 and, for each `sp != 4` (_NPC) whose `flags[sp] & 1` (translation
|
||||
level 1) is set, ORs `1 << sp` into **`ServerPlayer+0x1a4`**. Sticky: only ever ORed, never
|
||||
cleared, so it survives the first pass clearing a flag. Not previously recorded.
|
||||
6. **Three tail steps are not effects of their tech.** `cdp` is a tail check —
|
||||
`if (!cdp) { if HasResearched(10034) && HasResearched(10035) then cdp = 1 }` — evaluated on
|
||||
every completion, not only on those two techs'. So are the +0x190/+0x194 masks and the
|
||||
node-bore selection. §1's table reads as if they belong to the completing tech.
|
||||
7. **The callback has no already-researched guard**, because `SetResearched` sets node state 4
|
||||
before invoking it.
|
||||
8. **`*(int*)TechDef` is NOT the TechId.** `MasterTechTree::IsTech(def, id)` (0x0057d5d0) does
|
||||
`if (id == 0xc5) fail; idx = id - 10000; if ((unsigned)idx > 0xc3) fail; return def &&
|
||||
master[0][idx] && def == master[0][idx]`. `TechTree::HasResearched(id)` (0x0057d810) does the
|
||||
same map through `this+4` (the MasterTechTree) to reach a `TechDef`, and *then* uses that def's
|
||||
first word as the index into `this+0x10` (the node vector), testing `node->state == 4`. So the
|
||||
def's first word is a node index in a larger key space, the TechId key space is exactly
|
||||
10000..10195, and 197 is the "none" sentinel special-cased before the subtraction. `TechTree+4`
|
||||
= `MasterTechTree*` is worth adding to the object map.
|
||||
9. **`g_TechIdNames` (0x009ff9e4) is dumped in full.** 196 × `{const char* name, int}`; the
|
||||
second word is `10001 + index` and is not the id (the id is `10000 + index`, per `IsTech`).
|
||||
The names, in position order, are now in `sots-engine`'s `src/game/effects/tech_id.h`. Anchors
|
||||
all agree: 0 CCC_AdvSens (0x2710), 30 IND_HrdStrct (0x272e), 38..43 the six vaccines
|
||||
(0x2736..0x273b), 64..66 DRV_RIP/REND/RAD (0x2750..0x2752). Consequences for §4's filler-order
|
||||
note: the block species order is **Human, Hiver, Tarkas, Liir, [Zuul,] Morrigi**; the families
|
||||
that omit the Zuul are Incorporate (132-136), Addict (137-141), Temperance (142-146),
|
||||
Accommodate (153-157) **and Proliferate (158-162)** — proliferate is five entries, not six.
|
||||
Index 130, the Zuul slot of the level-3 translation block, is `XNC_DOMZUUL`. **Ids 163 and 164
|
||||
are `CCC_NDTRKHUM` and `CCC_NDTRKZUL`**, the node-track techs of §1 — previously unlocated.
|
||||
§5's "no code reads them" list can now be stated by name rather than by index.
|
||||
10. **`g_TechBitmaskTableA/B` are `{int techId, uint bit}`.** Joined with §3's bit-ordered name
|
||||
lists every id matches the name table above, so §3's two lists are confirmed and are keyed by
|
||||
id, not by name: A = 10092, 10170, 10091, 10090, 10171, 10169, 10084, 10111, 10172,
|
||||
10173-10176, 10088, 10073, 10071, 10106, 10166, 10167, 10099, 10168, 10177, 10110, 10109,
|
||||
10178, 10085, 10086, 10179, 10000, 10180, 10181, 10182; B = 10056, 10057, 10058, 10061,
|
||||
10062, 10063, 10059, 10183, 10060, 10184, 10185, 10083, 10064, 10065, 10066, 10042, 10186,
|
||||
10187, 10188, 10189, 10190, 10094, 10067, 10068, 10069, 10191, 10192, 10036, 10037.
|
||||
|
||||
|
||||
Also confirmed unchanged: the chain is a strict if/else-if over `push 0x2710`..`push 0x272f`
|
||||
(10000..10031) with no gaps and at most one branch taken; the tail then tests 0x2730/0x2731
|
||||
(CruisCon → GetTechDef(BrdPod) → SetResearched(def,1,1,0), gated on `Species == 5`) and
|
||||
0x2732/0x2733 via HasResearched. `TechDef::GetPlagueCureMask` loops i = 0..5 over ids
|
||||
10038..10042 with a NULL at i == 5, returning `1 << i` on the first hit, then falls through to
|
||||
10043 returning 0x0f — and the per-id test is `0x0057d220(def, target)`, i.e. **def is the target
|
||||
or a descendant of it**, not an exact match. Every magnitude in §1 is confirmed.
|
||||
|
|
|
|||
|
|
@ -1214,9 +1214,9 @@
|
|||
"name": "g_AITechValueTable",
|
||||
"addr": "0x00a17888",
|
||||
"convention": "data",
|
||||
"prototype": "struct { int techId; int a; float value; }[6] /* values not dumped */",
|
||||
"status": "unverified",
|
||||
"source": "handoff/tech-effects.md#1"
|
||||
"prototype": "struct { int techId; float rebellionOdds; float bonus; }[6] /* rows: CCC_AI/CCC_AIAdmin/CCC_AIFac odds 0.1f bonus 0.5f, CCC_AIFRCON odds 0.2f bonus 0, CCC_AIVrus/CCC_AISlv odds 0 bonus 0 */",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "g_PERGATETRAFFIC_DRV_TpGate",
|
||||
|
|
@ -1409,6 +1409,286 @@
|
|||
"prototype": "std::vector<PlayerAid> (3 words; entry 0x18 B, {+0x8 int researchPercent, +0xc int researchActive, +0x10 int savings, +0x14 int savingsActive})",
|
||||
"status": "verified",
|
||||
"source": "findings/objects/struct-recovery.md#2 (Read/Write serializers) + findings/subsystems/strategic-turn-internals.md#1.3"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_SuitTol",
|
||||
"offset": "0xb4",
|
||||
"convention": "offset",
|
||||
"prototype": "float SuitTol -- raised by the two adaptation techs; also caps the hazard money cost",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_MaxOH",
|
||||
"offset": "0xb8",
|
||||
"convention": "offset",
|
||||
"prototype": "float MaxOH -- max over-harvest slider, raised by a float32 max() against 0.1f",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_TechTree",
|
||||
"offset": "0xf4",
|
||||
"convention": "offset",
|
||||
"prototype": "TechTree* the player's own tech tree; its +4 is the MasterTechTree the IsTech chain uses",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_AIBn",
|
||||
"offset": "0xfe",
|
||||
"convention": "offset",
|
||||
"prototype": "bool AIBn -- AI benefit active; gates ApplyAITechBonus and flips the bonus sign",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_CnTrd",
|
||||
"offset": "0xff",
|
||||
"convention": "offset",
|
||||
"prototype": "bool CnTrd -- trade routes allowed (set by CCC_FtlEcon unless RebAI)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_CnRad",
|
||||
"offset": "0x100",
|
||||
"convention": "offset",
|
||||
"prototype": "bool CnRad -- commerce raiding allowed (CCC_ComRaid)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_CnVItl",
|
||||
"offset": "0x101",
|
||||
"convention": "offset",
|
||||
"prototype": "bool CnVItl -- may view other empires' intel (CCC_DatCor)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_hgs",
|
||||
"offset": "0x102",
|
||||
"convention": "offset",
|
||||
"prototype": "bool hgs -- gravitic-syncing drive researched (DRV_GrvSyn); client-synced only",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_hadvs",
|
||||
"offset": "0x103",
|
||||
"convention": "offset",
|
||||
"prototype": "bool hadvs -- advanced sensors (CCC_AdvSens)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_harcc",
|
||||
"offset": "0x104",
|
||||
"convention": "offset",
|
||||
"prototype": "bool harcc -- arcologies (IND_ArcCon)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_pddm",
|
||||
"offset": "0x108",
|
||||
"convention": "offset",
|
||||
"prototype": "float pddm -- multiplied by 0.25 by IND_HrdStrct",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_ConMod",
|
||||
"offset": "0x10c",
|
||||
"convention": "offset",
|
||||
"prototype": "float ConMod[3] -- construction cost per hull class; techs subtract from all three, IND_OrbDry only from [1] and [2]",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_SavMod",
|
||||
"offset": "0x118",
|
||||
"convention": "offset",
|
||||
"prototype": "float SavMod[3] -- IND_OrbFound subtracts 0.05f from all three",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_OutMod",
|
||||
"offset": "0x124",
|
||||
"convention": "offset",
|
||||
"prototype": "float OutMod -- industrial output multiplier; several techs add, IND_HrdStrct multiplies by 0.9f",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_PopMod",
|
||||
"offset": "0x130",
|
||||
"convention": "offset",
|
||||
"prototype": "float PopMod",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_TerraMod",
|
||||
"offset": "0x134",
|
||||
"convention": "offset",
|
||||
"prototype": "float TerraMod",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_AMine",
|
||||
"offset": "0x138",
|
||||
"convention": "offset",
|
||||
"prototype": "bool AMine -- asteroid mining (IND_AstMine)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_MinRate",
|
||||
"offset": "0x140",
|
||||
"convention": "offset",
|
||||
"prototype": "float MinRate -- mining rate; IND_MsMine adds 1.0",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_PrGtTrf",
|
||||
"offset": "0x148",
|
||||
"convention": "offset",
|
||||
"prototype": "int PrGtTrf -- per-gate traffic capacity; the two gate techs raise it with a SIGNED INTEGER max against a config int, not a float compare",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_CstR",
|
||||
"offset": "0x150",
|
||||
"convention": "offset",
|
||||
"prototype": "float CstR, CstE, CstT at +0x150/+0x154/+0x158 -- set to 10.0f / 2.0f / 1.0f (FLD1) by DRV_FarCast",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_TechMaskA",
|
||||
"offset": "0x190",
|
||||
"convention": "offset",
|
||||
"prototype": "uint32 design-option mask A; +0x194 is mask B. Rewritten wholesale by ComputeTechBitmasks on every completion; not serialised",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_TranslationKnown",
|
||||
"offset": "0x1a4",
|
||||
"convention": "offset",
|
||||
"prototype": "uint32 sticky 'level-1 translation researched for species sp' bit mask, one bit per species, NPC (4) excluded. Second pass of RebuildSpeciesTechFlags; only ever ORed",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_HasVac",
|
||||
"offset": "0x288",
|
||||
"convention": "offset",
|
||||
"prototype": "uint32 HasVac; +0x28c HasImm. Both get |= the plague-cure mask of the completing tech",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_NPTrk",
|
||||
"offset": "0x290",
|
||||
"convention": "offset",
|
||||
"prototype": "uint32 NPTrk -- bit per species whose node-space traffic is visible; set by that species' node-track tech",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_NodeBore",
|
||||
"offset": "0x308",
|
||||
"convention": "offset",
|
||||
"prototype": "int (*)[3] -- pointer to a separately allocated 3-word node-bore parameter block, NULL while no bore drive is researched (the updater allocates and frees it)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_CaptureDesigns",
|
||||
"offset": "0x330",
|
||||
"convention": "offset",
|
||||
"prototype": "bool cdp -- set once CCC_SpyBm and IND_SlvgTech are both researched; the test is in the completion tail, not in either tech's branch",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_SpeciesTechFlags",
|
||||
"offset": "0x348",
|
||||
"convention": "offset",
|
||||
"prototype": "uint32 flags[7] xenotech bits per target species, followed by a count word 7 at +0x364 (0x20 bytes assigned as a unit)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_ResearchRollPending",
|
||||
"offset": "0x3b4",
|
||||
"convention": "offset",
|
||||
"prototype": "bool -- a pending plague-cure roll; run and cleared when the completing tech is the current research target",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_off_AIRebellion",
|
||||
"offset": "0x3b8",
|
||||
"convention": "offset",
|
||||
"prototype": "AIRebellion* -- non-null while an AI rebellion object exists; the two AI techs notify it",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "TechTree_off_Master",
|
||||
"offset": "0x4",
|
||||
"convention": "offset",
|
||||
"prototype": "MasterTechTree* -- the `this` MasterTechTree::IsTech / GetTechDef are called on",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_UpdateNodeBoreParams",
|
||||
"addr": "0x008182c0",
|
||||
"convention": "fastcall",
|
||||
"prototype": "void (ServerPlayer* this) -- re-selects the node-bore parameters from the researched set and stores them in the +0x308 block, allocating it on first use and freeing it when no bore drive is researched",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "SelectNodeBoreParams",
|
||||
"addr": "0x006e18e0",
|
||||
"convention": "cdecl",
|
||||
"prototype": "bool (int out[3], ServerPlayer* p) -- highest researched bore drive wins: DRV_RAD {95,60,5}, else DRV_REND {65,35,4}, else DRV_RIP {45,15,3}; false (and out left at {INT_MAX,INT_MAX,0}) when none. No species gate",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "ServerPlayer_SpeciesOfTranslationTech",
|
||||
"addr": "0x0080e410",
|
||||
"convention": "custom",
|
||||
"prototype": "int (TechDef* def in EBX) -- index of the species whose SpeciesDef+0x74 node-track tech this def is, or -1",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "AITechRow",
|
||||
"addr": "0x00690f70",
|
||||
"convention": "cdecl",
|
||||
"prototype": "struct {int techId; float rebellionOdds; float bonus;}* (TechDef* def) -- linear search of g_AITechValueTable, NULL when the def is none of them",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
},
|
||||
{
|
||||
"name": "g_AITechValueCount",
|
||||
"addr": "0x00aea2ec",
|
||||
"convention": "data",
|
||||
"prototype": "int -- number of rows in g_AITechValueTable (6)",
|
||||
"status": "verified",
|
||||
"source": "B2 own disassembly pass 2026-09-08 (ReVa read-memory + objdump -b binary -m i386): ServerPlayer::OnTechResearched 0x00891790, RebuildSpeciesTechFlags 0x0082bf10, ApplyAITechBonus 0x0080e330, SetAIBenefit 0x008186b0, UpdateNodeBoreParams 0x008182c0, SelectNodeBoreParams 0x006e18e0, GetPlagueCureMask 0x00537240"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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 @ 1e7428d, generated 2026-09-07 by tools/gen_addresses.py
|
||||
// Source: sots-re ghidra/addresses.json @ ead46e2, generated 2026-09-08 by tools/gen_addresses.py
|
||||
// Runtime address = (uintptr_t)GetModuleHandle(NULL) + RVA (the exe is ASLR-relocated).
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
|
@ -309,7 +309,7 @@ constexpr uint32_t g_SpeciesDefTable = 0x00710a00;
|
|||
constexpr uint32_t g_TechBitmaskTableA = 0x006df378;
|
||||
// data struct { int techId; uint bit; }[29] [verified]
|
||||
constexpr uint32_t g_TechBitmaskTableB = 0x006df478;
|
||||
// data struct { int techId; int a; float value; }[6] /* values not dumped */ [unverified]
|
||||
// data struct { int techId; float rebellionOdds; float bonus; }[6] /* rows: CCC_AI/CCC_AIAdmin/CCC_AIFac odds 0.1f bonus 0.5f, CCC_AIFRCON odds 0.2f bonus 0, CCC_AIVrus/CCC_AISlv odds 0 bonus 0 */ [verified]
|
||||
constexpr uint32_t g_AITechValueTable = 0x00617888;
|
||||
// data int (config storage; PTR slot 0x00aedfe0) [verified]
|
||||
constexpr uint32_t g_PERGATETRAFFIC_DRV_TpGate = 0x00723e2c;
|
||||
|
|
@ -359,5 +359,75 @@ constexpr uint32_t ServerPlayer_off_ResearchTarget = 0x00000294;
|
|||
constexpr uint32_t ServerPlayer_off_IncMod = 0x0000030c;
|
||||
// offset std::vector<PlayerAid> (3 words; entry 0x18 B, {+0x8 int researchPercent, +0xc int researchActive, +0x10 int savings, +0x14 int savingsActive}) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_Aid = 0x00000310;
|
||||
// offset float SuitTol -- raised by the two adaptation techs; also caps the hazard money cost [verified]
|
||||
constexpr uint32_t ServerPlayer_off_SuitTol = 0x000000b4;
|
||||
// offset float MaxOH -- max over-harvest slider, raised by a float32 max() against 0.1f [verified]
|
||||
constexpr uint32_t ServerPlayer_off_MaxOH = 0x000000b8;
|
||||
// offset TechTree* the player's own tech tree; its +4 is the MasterTechTree the IsTech chain uses [verified]
|
||||
constexpr uint32_t ServerPlayer_off_TechTree = 0x000000f4;
|
||||
// offset bool AIBn -- AI benefit active; gates ApplyAITechBonus and flips the bonus sign [verified]
|
||||
constexpr uint32_t ServerPlayer_off_AIBn = 0x000000fe;
|
||||
// offset bool CnTrd -- trade routes allowed (set by CCC_FtlEcon unless RebAI) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_CnTrd = 0x000000ff;
|
||||
// offset bool CnRad -- commerce raiding allowed (CCC_ComRaid) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_CnRad = 0x00000100;
|
||||
// offset bool CnVItl -- may view other empires' intel (CCC_DatCor) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_CnVItl = 0x00000101;
|
||||
// offset bool hgs -- gravitic-syncing drive researched (DRV_GrvSyn); client-synced only [verified]
|
||||
constexpr uint32_t ServerPlayer_off_hgs = 0x00000102;
|
||||
// offset bool hadvs -- advanced sensors (CCC_AdvSens) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_hadvs = 0x00000103;
|
||||
// offset bool harcc -- arcologies (IND_ArcCon) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_harcc = 0x00000104;
|
||||
// offset float pddm -- multiplied by 0.25 by IND_HrdStrct [verified]
|
||||
constexpr uint32_t ServerPlayer_off_pddm = 0x00000108;
|
||||
// offset float ConMod[3] -- construction cost per hull class; techs subtract from all three, IND_OrbDry only from [1] and [2] [verified]
|
||||
constexpr uint32_t ServerPlayer_off_ConMod = 0x0000010c;
|
||||
// offset float SavMod[3] -- IND_OrbFound subtracts 0.05f from all three [verified]
|
||||
constexpr uint32_t ServerPlayer_off_SavMod = 0x00000118;
|
||||
// offset float OutMod -- industrial output multiplier; several techs add, IND_HrdStrct multiplies by 0.9f [verified]
|
||||
constexpr uint32_t ServerPlayer_off_OutMod = 0x00000124;
|
||||
// offset float PopMod [verified]
|
||||
constexpr uint32_t ServerPlayer_off_PopMod = 0x00000130;
|
||||
// offset float TerraMod [verified]
|
||||
constexpr uint32_t ServerPlayer_off_TerraMod = 0x00000134;
|
||||
// offset bool AMine -- asteroid mining (IND_AstMine) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_AMine = 0x00000138;
|
||||
// offset float MinRate -- mining rate; IND_MsMine adds 1.0 [verified]
|
||||
constexpr uint32_t ServerPlayer_off_MinRate = 0x00000140;
|
||||
// offset int PrGtTrf -- per-gate traffic capacity; the two gate techs raise it with a SIGNED INTEGER max against a config int, not a float compare [verified]
|
||||
constexpr uint32_t ServerPlayer_off_PrGtTrf = 0x00000148;
|
||||
// offset float CstR, CstE, CstT at +0x150/+0x154/+0x158 -- set to 10.0f / 2.0f / 1.0f (FLD1) by DRV_FarCast [verified]
|
||||
constexpr uint32_t ServerPlayer_off_CstR = 0x00000150;
|
||||
// offset uint32 design-option mask A; +0x194 is mask B. Rewritten wholesale by ComputeTechBitmasks on every completion; not serialised [verified]
|
||||
constexpr uint32_t ServerPlayer_off_TechMaskA = 0x00000190;
|
||||
// offset uint32 sticky 'level-1 translation researched for species sp' bit mask, one bit per species, NPC (4) excluded. Second pass of RebuildSpeciesTechFlags; only ever ORed [verified]
|
||||
constexpr uint32_t ServerPlayer_off_TranslationKnown = 0x000001a4;
|
||||
// offset uint32 HasVac; +0x28c HasImm. Both get |= the plague-cure mask of the completing tech [verified]
|
||||
constexpr uint32_t ServerPlayer_off_HasVac = 0x00000288;
|
||||
// offset uint32 NPTrk -- bit per species whose node-space traffic is visible; set by that species' node-track tech [verified]
|
||||
constexpr uint32_t ServerPlayer_off_NPTrk = 0x00000290;
|
||||
// offset int (*)[3] -- pointer to a separately allocated 3-word node-bore parameter block, NULL while no bore drive is researched (the updater allocates and frees it) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_NodeBore = 0x00000308;
|
||||
// offset bool cdp -- set once CCC_SpyBm and IND_SlvgTech are both researched; the test is in the completion tail, not in either tech's branch [verified]
|
||||
constexpr uint32_t ServerPlayer_off_CaptureDesigns = 0x00000330;
|
||||
// offset uint32 flags[7] xenotech bits per target species, followed by a count word 7 at +0x364 (0x20 bytes assigned as a unit) [verified]
|
||||
constexpr uint32_t ServerPlayer_off_SpeciesTechFlags = 0x00000348;
|
||||
// offset bool -- a pending plague-cure roll; run and cleared when the completing tech is the current research target [verified]
|
||||
constexpr uint32_t ServerPlayer_off_ResearchRollPending = 0x000003b4;
|
||||
// offset AIRebellion* -- non-null while an AI rebellion object exists; the two AI techs notify it [verified]
|
||||
constexpr uint32_t ServerPlayer_off_AIRebellion = 0x000003b8;
|
||||
// offset MasterTechTree* -- the `this` MasterTechTree::IsTech / GetTechDef are called on [verified]
|
||||
constexpr uint32_t TechTree_off_Master = 0x00000004;
|
||||
// fastcall void (ServerPlayer* this) -- re-selects the node-bore parameters from the researched set and stores them in the +0x308 block, allocating it on first use and freeing it when no bore drive is researched [verified]
|
||||
constexpr uint32_t ServerPlayer_UpdateNodeBoreParams = 0x004182c0;
|
||||
// cdecl bool (int out[3], ServerPlayer* p) -- highest researched bore drive wins: DRV_RAD {95,60,5}, else DRV_REND {65,35,4}, else DRV_RIP {45,15,3}; false (and out left at {INT_MAX,INT_MAX,0}) when none. No species gate [verified]
|
||||
constexpr uint32_t SelectNodeBoreParams = 0x002e18e0;
|
||||
// custom int (TechDef* def in EBX) -- index of the species whose SpeciesDef+0x74 node-track tech this def is, or -1 [verified]
|
||||
constexpr uint32_t ServerPlayer_SpeciesOfTranslationTech = 0x0040e410;
|
||||
// cdecl struct {int techId; float rebellionOdds; float bonus;}* (TechDef* def) -- linear search of g_AITechValueTable, NULL when the def is none of them [verified]
|
||||
constexpr uint32_t AITechRow = 0x00290f70;
|
||||
// data int -- number of rows in g_AITechValueTable (6) [verified]
|
||||
constexpr uint32_t g_AITechValueCount = 0x006ea2ec;
|
||||
|
||||
} // namespace sots::addr
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue