Skip to content

REBEXE.EXE—C++ Class Hierarchy (Reconstructed)

Generated from Ghidra decompilation of REBEXE.EXE (Star Wars Rebellion 1998, LucasArts). Cross-referenced with: annotated-functions.md, combat-formulas.md, space-combat.md.

The game uses the Notification/Observer pattern with pure C++ virtual dispatch throughout. Every mutable field on every game object is modified only through validated setters that check entity validity, range-validate the new value, write the field, broadcast to both side-observers, then fire a vtable change-event. No setter bypasses this chain.


1. Vtable Map

Vtable offsets are byte offsets from *(void**)this (i.e., *this dereferences to the vtable array; *this + N is the pointer at slot N). All are confirmed from direct (**(code **)(*this + N)) call sites in decompiled code.

GameObject Base Vtable Slots

These slots appear on all combat entity objects; they are the base interface.

+0x004  GetFamilyId()                  —entity class identifier byte (id >> 0x18)
+0x00c  GetSideKey()                   —which combat side (1=attacker, 2=defender)
+0x034  CanBombard()                   —boolean, whether unit can perform orbital bombardment
+0x038  IsActive()                     —reads status_flags bit0

CapitalShip / CombatEntity Vtable Slots

Hull, shield, and weapon change-event slots. Used by the validate-write-notify setter chain.

+0x1c4  ResolveWeaponFire(side, ctx)   —phase 3: per-side weapon fire resolver
                                           (FUN_00543b60 → inner gate mask 0x04/bit2; outer wrapper FUN_00544030 gates on bit0 & ~bit6)
+0x1c8  ResolveShieldAbsorb(side, ctx) —phase 4: per-side shield absorption resolver
                                           (FUN_00543bd0 → gate on combat_phase_flags bit5/0x20)
+0x1d0  ResolveHullDamage(side, ctx)   —phase 5: per-side hull damage resolver
                                           (FUN_00543cb0 → gate on combat_phase_flags bit7/0x80)
+0x1d4  ResolveFighterEngage(side, ctx)—phase 6: per-side fighter engagement resolver
                                           (FUN_00543d20 → gate on combat_phase_flags bit8/0x100)
+0x1d8  ResolveShieldAlt(side, ctx)    —alt shield path for special units (family 0x71-0x72,
                                           capability_flags bit7 set); called from FUN_00544130
+0x1f4  ApplyWeaponDamage(side, ctx)   —notification handler called by FUN_0054a1d0;
                                           also reached as vtable+500 decimal (0x1f4)
+0x244  GetMaxSquadSize()              —FighterSquadron only; returns max for range check;
                                           error string "Invalid_SquadSizeDamage_value_"
+0x248  GetMaxHullValue()              —CapitalShip/facility; returns max for range check;
                                           error string "Invalid_HullValueDamage_value_"
+0x260  NotifySquadChanged(old, new, ctx) —FighterSquadron change event (FUN_005032c0)
+0x29c  NotifyHullChanged(old, new, ctx)  —CapitalShip hull change event (FUN_00501490)
+0x2a0  NotifyShieldChanged(old, new, ctx)—shield recharge rate change (FUN_00501510)
+0x2a4  NotifyWeaponChanged(old, new, ctx)—weapon recharge rate change (FUN_005015a0)

Character / Unit Vtable Slots

Used by character stat setters; distinct from the ship combat slots above.

+0x238  NotifyLoyaltyChanged(old, new, ctx)        —base loyalty setter (FUN_005341a0)
+0x318  NotifyEnhancedLoyaltyChanged(old, new, ctx)—EnhancedLoyalty mission bonus (FUN_004ee030)
+0x330  NotifyCombatStrengthChanged(old, new, ctx) —regiment/troop strength change (FUN_004ee350)
+0x338  NotifyHyperdriveChanged(old, new, ctx)     —MissionHyperdriveModifier (FUN_004ee470)

2. Class Hierarchy (Reconstructed)

The hierarchy is inferred from: - Which vtable slots a given setter accesses (different slots → different leaf type) - Field offset overlap (hull_current and squad_size_current share +0x60 → polymorphic field) - Family byte ranges from entity ID high-byte (id >> 0x18) - Error strings (hull vs squad have distinct "Invalid_*value" literals at separate vtable slots) - Notification strings (CapShip vs FightSquad vs TroopReg vs Character prefixes)

CRebObject (base)
│  +0x00  void* vtable
│  Virtual:
│    GetFamilyId(), GetSideKey(), IsActive(), CanBombard()
│    (and many more base slots not yet traced)
├── CNotifyObject (adds observer plumbing)
│   │  +0x2c  void* combat_data_ptr    —ptr to associated combat data block
│   │  +0x50  uint  status_flags       —bit0=active, bit3=fighter_combat_eligible,
│   │                                     bit12=special_disabled
│   │  +0x58  uint  combat_phase_flags —space combat phase state machine bitfield
│   │  +0x78  byte  capability_flags   —bit4=special_victory_eligible,
│   │                                     bit6=disabled_a, bit7=alt_shield_path / disabled_b
│   │  +0xac  byte  alive_flag         —bit0=alive/combat-eligible
│   │  +0xb0  byte  combat_ready_flags —bit1=combat_ready_for_fleet_eval
│   │
│   ├── CCombatUnit (adds the combat phase vtable block)
│   │   │  Virtual (new in CCombatUnit):
│   │   │    +0x1c4 ResolveWeaponFire
│   │   │    +0x1c8 ResolveShieldAbsorb
│   │   │    +0x1d0 ResolveHullDamage
│   │   │    +0x1d4 ResolveFighterEngage
│   │   │    +0x1d8 ResolveShieldAlt
│   │   │    +0x1f4 ApplyWeaponDamage
│   │   │
│   │   ├── CCapitalShip
│   │   │      Family bytes: 0x30-0x33, 0x35-0x38, 0x3a-0x3b
│   │   │      +0x60  int   hull_current            —current hull damage value
│   │   │      +0x64  uint  shield_weapon_packed     —bits 0-3: shield_recharge_allocated
│   │   │                                               bits 4-7: weapon_recharge_allocated
│   │   │                                               bits 8-31: unknown (preserved)
│   │   │      +0x96  short regiment_strength        —(ships only: used for unit strength too)
│   │   │      Virtual (override from CCombatUnit):
│   │   │        +0x248 GetMaxHullValue()             → error "Invalid_HullValueDamage_value_"
│   │   │        +0x29c NotifyHullChanged(old,new,ctx)
│   │   │        +0x2a0 NotifyShieldChanged(old,new,ctx)
│   │   │        +0x2a4 NotifyWeaponChanged(old,new,ctx)
│   │   │      Vtable address: PTR_LAB_0066c2d0  (set in FUN_005a7500 constructor at *param_1)
│   │   │      Event IDs: 0x1c0 (hull damage), 0x1c1 (shield recharge), 0x1c2 (weapon recharge)
│   │   │
│   │   ├── CDeathStar
│   │   │      Family byte: 0x34
│   │   │      Inherits CCapitalShip layout; special-cased in combat result (FUN_005445d0)
│   │   │      Family 0x73-0x74: "special combat entity"—triggers FUN_00534640 victory path
│   │   │      Fire condition: !(alive_flag & 1) AND (status_flags & 1)
│   │   │      faction_control field: bits 6-7 at +0x24 of faction object (0x80 = Empire)
│   │   │      Tactical message: cmSHIP_POST_DS_STATUS, DEATHSTAR_UPDATE, DEATHSTAR_FIRE,
│   │   │                         DEATHSTAR_WITHDRAW
│   │   │
│   │   └── CFighterSquadron
│   │          Family bytes: 0x71-0x72 (shield absorb special path), 0x30-0x3b range
│   │          +0x60  int   squad_size_current       —shares offset with hull_current
│   │          Virtual (override):
│   │            +0x244 GetMaxSquadSize()             → error "Invalid_SquadSizeDamage_value_"
│   │            +0x260 NotifySquadChanged(old,new,ctx)
│   │            +0x1d8 ResolveShieldAlt (triggered by capability_flags bit7)
│   │          Event ID: 0x1a0 (squad size damage)
│   │          Combat eligible via dead state: status_flags bit3 overrides alive_flag==0
│   │
│   ├── CTroopRegiment
│   │      Family bytes: 0x14-0x1b
│   │      +0x96  short regiment_strength            —ground combat strength (16-bit)
│   │      Virtual:
│   │        +0x330 NotifyCombatStrengthChanged(old,new,ctx)
│   │      Ground combat primitive: FUN_004ee350 (set_regiment_strength)
│   │      Blockade event: 0x340 (TroopRegDestroyedRunningBlockade)
│   │
│   ├── CSpecialForces  (sub-type of troop family)
│   │      Family bytes: 0x14-0x1b (overlaps troops—distinguished by mission_id bitmask)
│   │      Layout: same as CTroopRegiment at combat layer
│   │
│   └── CFacility
│          Family bytes: 0x1c-0x1f (defense/manufacturing/production)
│          +0x60  int  hull_current                  —facility integrity
│          Virtual:
│            +0x248 GetMaxHullValue()  (same slot as CCapitalShip—shared base)
│            +0x29c NotifyHullChanged(old,new,ctx)
├── CCharacter (separate branch—no CCombatUnit)
│   │  +0x66  short loyalty_base             —base loyalty skill (0-100)
│   │  +0x8a  short enhanced_loyalty         —EnhancedLoyalty mission bonus (0-100, short-safe)
│   │  +0x9a  short hyperdrive_mod           —MissionHyperdriveModifier (Han Solo bonus)
│   │  Force fields (from FUN_0058a3f0):
│   │    entity[9] >> 6 & 3                  —force_potential_tier (2-bit, 0-3)
│   │    entity[0x23]  (short)               —force_experience
│   │    entity+0x8c   (short)               —force_potential_raw
│   │    entity[0x1e] & 1                    —is_unknown_jedi flag
│   │  Virtual:
│   │    +0x238 NotifyLoyaltyChanged(old,new,ctx)
│   │    +0x318 NotifyEnhancedLoyaltyChanged(old,new,ctx)
│   │    +0x330 NotifyCombatStrengthChanged(old,new,ctx)  (reused on Character for combat skill)
│   │    +0x338 NotifyHyperdriveChanged(old,new,ctx)
│   │  Event IDs: 0x1e1 (Force), 0x1e5 (ForceTraining)
│   │
│   ├── CMajorCharacter
│   │      Family bytes: 0x08-0x0b
│   │      is_unable_to_betray flag (Luke, Vader cannot switch sides)
│   │      Plot-gated: DarthToLukeFinalBattle, DarthToEmperorFinalBattle, LukeFinalBattleReady
│   │
│   └── CMinorCharacter
│          Family bytes: 0x0c-0x0f
│          Stats: base+variance at game-start
├── CStarSystem
│      Family bytes: 0x90 (explored), 0x92 (unexplored)
│      DatId target example: 0x90000109 (Alderaan or current Death Star target)
│      Fields from FUN_0049eea0:
│        +0x18  HWND   window_handle
│        +0x30  uint   display_id
│        +0x114 void*  battle_info_ptr
├── CFleet
│      Fleet battle entry: FUN_004ff7a0 (FleetBattleNotif)
│      Contains: CCapitalShip + CFighterSquadron list + CCharacter list
└── CMission
       Mission type codes (from FUN_004fc080 switch):
         6  = Sabotage
         7  = Assassination
         21 = Autoscrap (0x15)
       Base duration, max officers, target_flags at entity layer

3. Known Vtable Pointers

Vtable address constants observed in decompiled code, mapped to class types.

Vtable Address Class Source
PTR_LAB_0066c2d0 CTacticalBattleManager (or CShipGroup root) FUN_005a7500, line 108: *param_1 = &PTR_LAB_0066c2d0
PTR_FUN_0066bdd0 CShipGroupHandler (message router) FUN_005a7500, slots 0x262-0x274: 7× param_1[N] = &PTR_FUN_0066bdd0
PTR_FUN_0066bdb8 CNavPointHandler FUN_005a7500, slot 0x277: param_1[0x277] = &PTR_FUN_0066bdb8
PTR_LAB_0066c390 CShipEventHandler FUN_005a7500, slot 0x291: param_1[0x291] = &PTR_LAB_0066c390
PTR_FUN_0066c380 CShipEventHandler variant B FUN_005a7500, slot 0x394
PTR_FUN_0066c370 CShipEventHandler variant C FUN_005a7500, slot 0x397

Note: FUN_005a7500 is the tactical ship constructor—it allocates and initializes the object that handles the 2D tactical battle view. It installs all tactical-layer message handlers (SHIP_ADD, SHIP_REMOVE, SHIP_FIRELASERCANNON, SHIP_TAKE_LASER_HIT, DEATHSTAR_FIRE, etc.) and sets the root vtable pointer to PTR_LAB_0066c2d0. The FUN_00585640 constructor (GNPRTB parser) allocates 0x44 bytes and calls FUN_005855f0—this is the GNPRTB parameter table reader, not a game object.


4. Object Field Layout

Consolidated struct layout for the shared base. Fields confirmed across multiple decompiled functions.

CNotifyObject / CCombatUnit Base (all combat entities)

Offset Type Field Source Functions Notes
+0x00 void* vtable all setters C++ vtable pointer
+0x24 uint difficulty_packed FUN_0054a1d0 bits 4-5 = difficulty level 0-3 (space combat)
+0x2c void* combat_data_ptr FUN_00509620 → combat data block; +0x4c within = bombardment stat
+0x4c uint detection_pending FUN_0058a3f0 set to 1 when undiscovered Jedi detected (context obj)
+0x50 uint status_flags many bit0=active, bit3=fighter_combat_eligible, bit12=special_disabled
+0x58 uint combat_phase_flags FUN_00543b60-d20, space-combat.md Phase state machine—see bitfield table below
+0x60 int hull_current / squad_size_current FUN_00501490, FUN_005032c0 Polymorphic: hull for ships, size for squadrons
+0x64 uint shield_weapon_packed FUN_00501510, FUN_005015a0 bits 0-3: shield_recharge_alloc; bits 4-7: weapon_recharge_alloc
+0x66 short loyalty_base FUN_005341a0 Character only: base loyalty skill (0-100)
+0x78 byte capability_flags FUN_005442f0, FUN_00544130, FUN_005445d0 bit4=special_victory_eligible, bit6=disabled_a, bit7=alt_shield_path/disabled_b
+0x8a short enhanced_loyalty FUN_004ee030 Character only: EnhancedLoyalty mission bonus (0-100)
+0x96 short regiment_strength FUN_004ee350 Troop/ship regiment current strength
+0x9a short hyperdrive_mod FUN_004ee470 Character only: MissionHyperdriveModifier (Han Solo)
+0xac byte alive_flag FUN_005445d0, FUN_005617b0 bit0=alive/combat-eligible; 0=dead
+0xb0 byte combat_ready_flags annotated-functions.md bit1=combat_ready_for_fleet_eval

combat_phase_flags Bitfield (at +0x58)

Bit Mask Meaning Gate Phase
0 0x0001 Space combat active Phase 3 weapon fire entry
1 0x0002 Weapon fire (attacker side)
2 0x0004 Weapon fire type code Phase 3 type
5 0x0020 Shield absorb type code Phase 4 type
6 0x0040 Combat phases enabled (shields, hull, fighters) Phases 4-6 gate
7 0x0080 Hull damage type code Phase 5 type
8 0x0100 Fighter engagement type code Phase 6 type
12 0x1000 Post-combat flag Phase 8 gate

Character-Specific Fields (CCharacter branch)

Offset Type Field Notes
+0x66 short loyalty_base 0-100, validated + 0x7fff clamped
+0x8a short enhanced_loyalty EnhancedLoyalty mission bonus
+0x8c short force_potential_raw Detector's Force sensitivity (FUN_0058a3f0)
+0x9a short hyperdrive_mod MissionHyperdriveModifier
entity[9] >> 6 & 3 2 bits force_potential_tier 0-3 (None/Low/Medium/High/Very High)
entity[0x23] short force_experience Influences Jedi detectability
entity[0x1e] & 1 bit is_unknown_jedi 0 = undiscovered Jedi

Tactical Battle Object (FUN_005a7500—CTacticalBattleManager)

This 0x3a8-word object (initialized in FUN_005a7500) is the tactical view controller.

Offset (words) Field Notes
param_1[0] vtable set to &PTR_LAB_0066c2d0
param_1[4] message_router_a FUN_00618c80(param_1+4, 0xc, 0x80, ...)—0x80-slot message router
param_1[0x184] message_router_b FUN_00618c80(param_1+0x184, 0xc, 0x26, ...)—0x26-slot router
param_1[0x1f6]–[0x215] float4[4] ship position/state blocks (init to 0,0,0,-1.0f)
param_1[0x22b] = 3 init constant
param_1[0x22c] = 5 init constant
param_1[0x22d] = 1 init constant
param_1[0x230] = 1 active flag
param_1[0x231] = 0 phase/state
param_1[0x232] = 0 phase/state
param_1[0x236] = 0 cleanup state
param_1[0x21f] = 3 init constant
param_1[0x3a1] = 0x13d (317) timer or counter
param_1[0x3a5] = 0 state
param_1[0x3a6] = 0x13d (317) timer or counter
param_1[0x3a7] = 1 active flag
param_1[0x262]–[0x274] (7 slots) CShipGroupHandler vtables each set to &PTR_FUN_0066bdd0
param_1[0x277] CNavPointHandler vtable set to &PTR_FUN_0066bdb8

Message slots registered (in constructor order):

Message String Slot Index (words from base)
SHIP_ADD +0x4
SHIP_REMOVE +0x7
SHIP_ABSTRACT_DESTROY +0xa
SHIP_DESTROY +0xd
cmSHIP_POST_DS_STATUS +0x10
NAV_ADD +0x13
NAV_REMOVE +0x16
NAV_PURGE +0x19
NAV_DELETE +0x1c
SHIPGROUP_MOVE +0x1f
SHIPGROUP_NEWMISSION +0x22
SHIPGROUP_NEWFORMATION +0x25
SHIPGROUP_NEWTARGETLIST +0x28
SHIP_FIRELASERCANNON +0x2b
SHIP_FIRETURBOLASER +0x2e
SHIP_FIREIONCANNON +0x31
SHIP_FIRETORPEDO +0x34
SHIP_TAKE_LASER_HIT +0x37
SHIP_TAKE_ION_HIT +0x3a
SHIP_TAKE_TURBO_HIT +0x3d
SHIP_TAKE_TORPEDO_HIT +0x40
SHIP_ION_DAMAGE +0x46
SHIP_LAUNCH +0x4f
SHIP_RECOVER +0x52
SHIP_ENGINE_DOWN +0x55
SHIP_WEAPON_DOWN +0x58
SHIP_TRACTOR_DOWN +0x5b
SHIP_SHIELD_HIT +0x5e
SHIP_WEAPON_HIT +0x61
SHIP_TRACTOR_HIT +0x64
SHIP_ENGINE_HIT +0x67
SHIP_HYPERDRIVE_HIT +0x6a
SHIP_SHIELD_FIX +0x6d
SHIP_WEAPON_FIX +0x70
SHIP_TRACTOR_FIX +0x73
SHIP_ENGINE_FIX +0x76
SHIP_HYPERDRIVE_FIX +0x79
SHIP_TRACTOR_LOCK +0x7c
SHIP_TRACTOR_UNLOCK +0x7f
SHIP_GRAVITY_LOCK +0x82
SHIP_GRAVITY_UNLOCK +0x85
SHIP_SET_RECOVERY_SHIP +0x88
SHIP_HYPERSPACE +0x8b
SHIP_WITHDRAW +0x8e
SHIP_SCUTTLE +0x91
TASKFORCE_NEW +0x94
FIGHTERGROUP_NEW +0x97
SHIPGROUP_DELETE +0x9a
SHIPGROUP_ADDSHIP +0x9d
SHIPGROUP_ADDTARGET +0xa0
SHIPGROUP_REMOVETARGET +0xa3
SHIPGROUP_REPLACETARGETLIST +0xa6
SHIPGROUP_REMOVESHIP +0xa9
SHIPGROUP_ADDNAVPOINT +0xac
SHIPGROUP_REMOVENAVPOINT +0xaf
SHIPGROUP_REPLACENAVLIST +0xb2
SHIPGROUP_CHANGETARGET +0xb5
SHIPGROUP_TACTMISS_CHANGE_STATE +0xb8
FORMATION_ACCELERATE +0xbe
CAPITALSHIP_UPDATE +0xc1
FIGHTERSQUADRON_UPDATE +0xc4
TACTCHAR_UPDATE +0xc7 (199)
TACTICALRESULT_UPDATE +0xca
DEATHSTAR_UPDATE +0xcd
DEATHSTAR_FIRE +0xd0
DEATHSTAR_WITHDRAW +0xd3
ALLIANCE_START_TURN +0xd6
ALLIANCE_END_TURN +0xd9
EMPIRE_START_TURN +0xdc
EMPIRE_END_TURN +0xdf
GAME_OVER +0xe2
SYSTEM_TURN_COMPLETED +0xe5
SYSTEM_PAUSE +0xe8
SYSTEM_UNPAUSE +0xeb
SYSTEM_SAVE +0xee
SYSTEM_QUIT +0xf1
SYSTEM_WAIT_FOR_GAME_OVER +0xf4
SYSTEM_GAME_OVER +0xf7
SYSTEM_SYNCHRONIZE_BEGIN +0xfa
SYSTEM_SYNCHRONIZE_END +0xfd
SYSTEM_ABORT +0x100

5. Event ID Registry

All confirmed event IDs from FUN_0053fcf0 / FUN_0053fe40 call sites.

Event ID Hex Notification String Class / Context
416 0x1a0 FightSquadSquadSizeDamageNotif / SquadSizeDamage CFighterSquadron
448 0x1c0 CapShipHullValueDamageNotif / HullValueDamage CCapitalShip
449 0x1c1 ShieldRechargeRateCHAllocated CCapitalShip
450 0x1c2 WeaponRechargeRateCHAllocated CCapitalShip
481 0x1e1 CharacterForceNotif / Force CCharacter
485 0x1e5 CharacterForceTrainingNotif / ForceTraining CCharacter
832 0x340 TroopRegDestroyedRunningBlockade CTroopRegiment

6. Utility Functions

Key support functions used across all class setters.

Address Signature Purpose
FUN_0053a000 bool(int this) Entity validity guard—entry check in all setters
FUN_0053a010 bool(int this) Entity validity guard—notification path variant
FUN_0053fc90 int(value, min, max) Range validator: returns 0 if out of [min, max]
FUN_0053e0f0 int(value, min, max) Secondary clamp to [0, 0x7fff] for short storage
FUN_00539fd0 void*(this, side) Side observer getter: side=1 (attacker), side=2 (defender)
FUN_0053a640 int(type_mask, side, flags*) Phase gate evaluator—checks combat_phase_flags bitmask
FUN_0053a610 int(type_mask, flags, flags*) Alternate phase gate (notification side)
FUN_005404d0 int(this, entity_id_at+8) Entity ID lookup from param
FUN_004fd3d0 int() Difficulty check—returns non-zero if combat enabled
FUN_004fd600 int(ctx, difficulty_bits) Apply difficulty modifier (extracts bits 4-5 of +0x24)
FUN_00618b70 void*(size) Heap allocator (new)—called in GNPRTB parser constructor

7. Design Patterns Summary

Setter-Notify-Event chain (all field mutations): 1. FUN_0053a000—entity live check 2. vtable call to get max value (for hull, squad) or FUN_00500670 (for shield/weapon rate) 3. FUN_0053fc90—range validate 4. Write field only if new_value != current_value 5. FUN_00539fd0(this, 1) + notify dispatcher → side 1 observer 6. FUN_00539fd0(this, 2) + notify dispatcher → side 2 observer 7. vtable change-event slot → fires the registered listener chain

Phase Gate pattern (all 4 space combat phases): - FUN_0053a000 validity check - FUN_0053a640(phase_type_mask, side, &combat_phase_flags)—gate evaluator - If gate passes: call notify dispatcher for side 1 and side 2 - Then call vtable phase-handler slot

Bilateral observer dispatch: every state change notifies both side=1 (attacker) and side=2 (defender) through their respective observer chains. The observer is retrieved via FUN_00539fd0 and is itself a polymorphic object whose dispatch method is a separate call (e.g., FUN_005023b0 for hull notifications, FUN_00502430 for shield, FUN_005024c0 for weapon, FUN_005037f0 for squad, FUN_004f04f0 for regiment strength).