AI Behavior Analysis—Original REBEXE.EXE¶
Architecture: No Single AI Function¶
The original Rebellion AI is event-driven and distributed across a 6-function pipeline, not a monolithic decision function. It uses the CRebObject → CNotifyObject → CCombatUnit hierarchy with a setter-notify-event pattern. The AI never runs as a single top-level call—it's triggered through the notification/observer system and evaluated per-system.
The AI Pipeline (6 Functions)¶
1. Galaxy Evaluation (FUN_00519d00)
↓ categorizes all 200 systems into 7 faction-specific buckets
2. System Iteration (FUN_00537180 / FUN_005385f0)
↓ for each system: check faction, evaluate entities, trigger deployment
3. Strength Assessment (FUN_00502020)
↓ per-system: count ships (0x30-0x3f), troops (0x10-0x13), facilities (0x1c-0x1f)
4. System Validation (FUN_00508250)
↓ pre-check: can this operation proceed? (~18 validators)
5. Entity Dispatch (FUN_00508660)
↓ route entities to placement handlers by family type (10+ handlers)
6. Movement Orders (FUN_00520580)
↓ set fleet deployment/movement parameters
Function Details¶
1. Galaxy-Wide System Distribution—FUN_00519d00 (252 lines)¶
Address: 0x00519d00 | Purpose: Strategic evaluation of all 200 systems
- Iterates ALL systems via
FUN_0051cad0(0x90)(family byte 0x90 = explored systems) - Checks specific DatIds:
0x92000121(unexplored),0x90000109(Coruscant) - Calls
FUN_005597e0(faction, type)with 4 combinations: (1, 0)—Alliance systems, type 0(2, 0)—Empire systems, type 0(1, 1)—Alliance systems, type 1(2, 1)—Empire systems, type 1- Distributes systems into 7 strategic buckets at offsets:
+0x100,+0x110—primary faction buckets+0xe0,+0xf0—secondary buckets+0x120,+0x130,+0x140—tertiary buckets- Validates: total across all buckets == total system count
- Calls
FUN_0053e190—ratio/percentage scoring function
Implication: The original AI has a global strategic awareness layer that our Rust implementation lacks. It doesn't just evaluate systems one-at-a-time—it categorizes the entire galaxy first, then makes decisions based on the distribution.
2. System-Level Entity Deployment—FUN_00537180 (381 lines)¶
Address: 0x00537180 | Purpose: Per-system fleet movement decisions
- Iterates systems via linked list at
this+0x40usingFUN_0041c210 - Faction ownership check:
(*(uint*)(entity + 0x24) >> 6 & 3) != local_c8 - Offset +0x24 is the entity's ownership byte
- Bits 6-7 encode faction: 0=neutral, 1=Alliance, 2=Empire
- Validates troops at each system (family 0x14-0x1b)
- Calls
FUN_00553410for faction-specific system operations - Checks sectors (family 0xa0-0xa2)
- Triggers fleet movement via
FUN_00520580to set deployment parameters
This is the fleet movement decision point. When this function determines a system needs reinforcement or an enemy system is vulnerable, it calls FUN_00520580 to issue the movement order.
3. Garrison/Fleet Strength Aggregator—FUN_00502020 (897 lines)¶
Address: 0x00502020 | Purpose: Evaluate whether a system/fleet is strong enough
- Checks entity family ranges:
0x30-0x3f—capital ships0x1c-0x1f—facilities0x10-0x13—troops- Faction alignment:
((byte)*(uint*)(entity + 0x24) ^ (byte)param_1[9]) & 0xc0) == 0 - XOR of ownership bytes, masked to bits 6-7
- Returns true only if same faction
- Calls sub-functions:
FUN_005007a0—fleet unit counter (iterates type=3 entities)FUN_004f6b50—entity resolverFUN_005039d0—facility iterator (family 0x1c-0x20)FUN_00504c40—troop iterator (family 0x10-0x14)- Compares entity counts against capacity:
vtable+0x248—GetMaxHullValue()(ship capacity)vtable+0x26c/+0x270—additional capacity checks- Returns boolean: is this system/fleet adequate?
Implication: The original AI evaluates garrison strength by counting EVERY entity type at a system—ships, troops, and facilities. Our AI only checks fleet presence (is_empty/is_not_empty). The original is much more nuanced.
4. Entity Placement Dispatcher—FUN_00508660 (304 lines)¶
Address: 0x00508660 | Purpose: Route entities to type-specific placement handlers
Uses vtable+0x04 (GetFamilyId) to dispatch by entity family:
| Family Range | Handler | Entity Type |
|---|---|---|
| 0x08-0x0f | FUN_0050ac80 + FUN_0050bc60 + FUN_0050be00 + FUN_0050a1b0 | Characters |
| 0x10-0x13 | FUN_0050b610 + FUN_0050ba90 + FUN_0050b500 | Troops |
| 0x1c-0x1f | FUN_0050a1b0 + FUN_0050c6c0 | Facilities |
| 0x20-0x21 | FUN_0050c9f0 | Ships (type A) |
| 0x22 | FUN_0050b310 | Ships (type B) |
| 0x28 | FUN_0050bb70 + FUN_0050c180 | Ships (type C) |
| 0x29 | FUN_0050c1b0 | Ships (type D) |
| 0x2a | FUN_0050c1e0 | Ships (type E) |
| 0x2c-0x2f | FUN_0050c560 | Ships (type F) |
Character assignment happens through FUN_0050ac80 (character placement) + FUN_0050a1b0 (faction-conditioned placement). The faction check uses param_1[9] >> 6 & 3—the same ownership bit pattern.
5. System-Level Deployment Companion—FUN_005385f0 (252 lines)¶
Address: 0x005385f0 | Purpose: Second pass of system evaluation
- Same linked-list iteration as FUN_00537180
- Same faction check:
(*(uint*)(local_94 + 0x24) >> 6 & 3) != local_7c - Calls
FUN_00520580for deployment parameters - Calls
FUN_00551190—collection setup for deployment - Calls
FUN_00506ea0—faction-specific evaluator - Calls
FUN_0052e970—scoring/evaluation function
This appears to be a second evaluation pass that handles edge cases or secondary deployments after FUN_00537180's primary pass.
6. System Validation—FUN_00508250 (137 lines)¶
Address: 0x00508250 | Purpose: Pre-check for whether an operation is valid
Calls approximately 18 validator functions before allowing entity deployment. This is the gatekeeper that prevents invalid fleet movements or character assignments.
Helper Functions¶
| Address | Lines | Purpose |
|---|---|---|
| FUN_005039d0 | — | Facility iterator (family 0x1c-0x20) |
| FUN_00504c40 | — | Troop iterator (family 0x10-0x14) |
| FUN_005007a0 | — | Fleet unit counter |
| FUN_004f6b50 | — | Entity resolver by DatId |
| FUN_00520580 | — | Set movement/deployment orders |
| FUN_00553b80 | — | Faction resolver from system |
| FUN_005597e0 | — | Faction-specific system count getter |
| FUN_0053e190 | — | Math/scoring function (ratio or percentage) |
| FUN_005202d0 | — | System pre-validation |
| FUN_00551190 | — | Collection setup for deployment |
| FUN_00504e60 | — | Entity lookup with family filter |
| FUN_0050a1b0 | — | Faction-conditioned entity placement |
| FUN_0050ac80 | — | Character placement |
| FUN_00506ea0 | — | Faction-specific evaluator |
| FUN_0052e970 | — | Scoring/evaluation function |
Key Patterns¶
Faction Ownership Encoding¶
The original encodes faction as bits 6-7 of offset +0x24 on every entity:
Same-faction check via XOR:
Entity Family Byte Ranges¶
| Range | Entity Type |
|---|---|
| 0x08-0x0f | Characters (major + minor) |
| 0x10-0x13 | Troops |
| 0x14-0x1b | Troop classes |
| 0x1c-0x1f | Facilities |
| 0x20-0x2f | Ships (various sub-types) |
| 0x30-0x3f | Capital ships |
| 0x90 | Explored systems |
| 0x92 | Unexplored systems |
| 0xa0-0xa2 | Sectors |
What Our Rust AI Is Missing¶
| Feature | Original (REBEXE.EXE) | Current (ai.rs) |
|---|---|---|
| Galaxy-wide evaluation | FUN_00519d00: 7-bucket system categorization | None—evaluates systems individually |
| Strength assessment | FUN_00502020: counts ships + troops + facilities | Only checks s.fleets.is_empty() |
| Entity-type routing | FUN_00508660: 10+ family-specific handlers | Only places characters on missions |
| Two-pass evaluation | FUN_00537180 + FUN_005385f0 | Single pass |
| System validation | FUN_00508250: 18 pre-checks | No validation beyond on_mission check |
| Faction bit encoding | +0x24 >> 6 & 3 |
is_alliance: bool (simpler but equivalent) |
Recommendations for Open Rebellion¶
- Add galaxy evaluation phase: Before per-system decisions, categorize all systems into strategic buckets (our-controlled, enemy-controlled, contested, unoccupied, HQ, frontier)
- Implement garrison strength scoring: Count total ship hulls + troop strength + facility count at each system, not just fleet presence/absence
- Add two-pass evaluation: First pass identifies needs (defense, reinforcement, attack targets). Second pass matches available assets to needs.
- Use
controlling_faction+ asset counting: The original checks every entity's faction bits. Our simplifiedcontrolling_factionfield serves the same purpose when combined with fleet/facility counting.
Connection to AutoResearch¶
The original AI has ~20 tunable thresholds across these functions (strength adequacy, bucket boundaries, scoring ratios). These map directly to the AiConfig struct in our autoresearch plan. The Karpathy loop can discover optimal values for these thresholds without hand-tuning—something LucasArts spent months doing manually.