REBEXE.EXE—Entity System Reference¶
Generated from Ghidra decompilation of REBEXE.EXE (Star Wars Rebellion 1998, LucasArts). Cross-referenced with: cpp-class-hierarchy.md, annotated-functions.md, modders-taxonomy.md, combat-formulas.md.
The entity system is built on a single Notification/Observer pattern used uniformly across every
mutable field of every game object. Every setter in the codebase follows an identical chain:
validate → range-check → write → bilateral observer notify → vtable change-event. No setter bypasses
this chain. The same design holds for pure notification dispatchers (no write step): they guard with
FUN_0053a010 instead of FUN_0053a000 and skip the range-check.
1. Character System¶
All character state setters and notification dispatchers in the 0x4ee030–0x4f2300 range.
1.1 Setter Chain (write-path functions)¶
These functions validate, write the field, dispatch bilateral observer notifications, and fire a
vtable change-event. They use FUN_0053a000 (strict validity guard) followed by FUN_0053fc90
(range check) before touching any field.
EnhancedLoyalty—FUN_004ee030¶
| Property | Value |
|---|---|
| Address | 0x004ee030 |
| Size | 87 bytes |
| Notif string | CharacterEnhancedLoyaltyNotif / EnhancedLoyalty |
| Field | +0x8a (short, 0–100, also clamped to 0x7fff) |
| Vtable event | +0x318 NotifyEnhancedLoyaltyChanged(old, new, ctx) |
| Observer dispatch | FUN_004f0190 (bilateral, sides 1 and 2) |
| Validity guard | FUN_0053a000 |
| Range check | FUN_0053fc90(value, 0, 100) then FUN_0053e0f0(value, 0, 0x7fff) |
This is the mission-bonus loyalty field, distinct from the base loyalty at +0x66. The
secondary 0x7fff clamp guards against short overflow. Vtable slot +0x318 differs from base
loyalty's +0x238—they are separate event channels.
int set_enhanced_loyalty(void* character, int new_loyalty, void* context) {
if (!FUN_0053a000(character)) return 0;
int valid = FUN_0053fc90(new_loyalty, 0, 100);
FUN_0053e0f0(new_loyalty, 0, 0x7fff);
if (valid && *(short*)(character+0x8a) != new_loyalty) {
short old = *(short*)(character+0x8a);
*(short*)(character+0x8a) = (short)new_loyalty;
FUN_004f0190(FUN_00539fd0(character, 1), context);
FUN_004f0190(FUN_00539fd0(character, 2), context);
(**(code**)(*(int*)character + 0x318))(old, *(short*)(character+0x8a), context);
}
return valid;
}
RegimentStrength—FUN_004ee350¶
| Property | Value |
|---|---|
| Address | 0x004ee350 |
| Size | ~150 bytes |
| Notif string | (type-dispatched via vtable) |
| Field | +0x96 (short, non-negative) |
| Vtable event | +0x330 NotifyCombatStrengthChanged(old, new, ctx) |
| Observer dispatch | FUN_004f04f0 (bilateral) |
| Validity guard | FUN_0053a000 |
| Range check | FUN_0053fc90(value, 0, value)—non-negative only, no upper bound |
Ground combat damage primitive. Every troop hit passes through here. Setting strength to 0
destroys the unit. The range check FUN_0053fc90(param_1, 0, param_1) is a non-negative gate
only—the upper bound is the caller's responsibility.
HyperdriveModifier—FUN_004ee470¶
| Property | Value |
|---|---|
| Address | 0x004ee470 |
| Size | 129 bytes |
| Notif string | MissionHyperdriveModifierNotif / MissionHyperdriveModifier |
| Field | +0x9a (short, non-negative, no upper bound) |
| Vtable event | +0x338 NotifyHyperdriveChanged(old, new, ctx) |
| Observer dispatch | FUN_004f0610 (bilateral) |
| Validity guard | FUN_0053a000 |
| Range check | FUN_0053fc90(value, 0, value)—non-negative only |
The Han Solo speed bonus. Applied when calculating ticks_per_hop in the movement system. Short
storage at +0x9a gives a max of 32767—effectively unbounded for gameplay purposes. The
MissionHyperdriveModifierNotif notification string is the game's canonical name for this effect.
Cross-reference (rebellion-core/src/movement.rs): When building ticks_per_hop, check
character.hyperdrive_modifier (field +0x9a) for any character assigned as admiral. Subtract
from the base hop duration.
BaseLoyalty—FUN_005341a0¶
| Property | Value |
|---|---|
| Address | 0x005341a0 |
| Notif string | SystemLoyaltyNotif / Loyalty |
| Field | +0x66 (short, 0–100) |
| Vtable event | +0x238 NotifyLoyaltyChanged(old, new, ctx) |
| Observer dispatch | FUN_00535380 (bilateral) |
| Validity guard | FUN_0053a000 |
| Range check | FUN_0053fc90(value, 0, 100) then FUN_0053e0f0(value, 0, 0x7fff) |
Base loyalty drives diplomacy missions, betrayal mechanics, and system control shifts. Two distinct loyalty fields exist:
Betrayal mechanic: The not betray string at 0x006ab3dc confirms a betrayal check function.
The is_unable_to_betray flag in MJCHARSD.DAT / MNCHARSD.DAT is the DAT-layer gate for major
characters (Luke, Vader cannot switch sides). FUN_005341a0 is the code-layer entry point for
loyalty changes that could trigger betrayal—any loyalty drop below a threshold (presumably
from the UPRIS1TB.DAT / UPRIS2TB.DAT tables) invokes the betrayal check path.
1.2 Enhanced Skill Notification Dispatchers (notification-only, no write step)¶
These functions use FUN_0053a010 (notification-path validity guard) and dispatch via
FUN_004f8980 without writing a field directly. They are called by the mission outcome system
after the outcome has already been committed. Each fires a named notification so observers can
react to the skill boost.
All of these follow the identical pattern:
int skill_notif(void* character, undefined4 new_val, undefined4 old_val, int ctx) {
if (!FUN_0053a010(character)) return 0;
FUN_004f8980(character, "Character*Notif", "SkillName", old_val, new_val, null, ctx);
return valid;
}
| Address | Notif String | Event Name | Data Address |
|---|---|---|---|
FUN_004f1c00 |
CharacterEnhancedDiplomacyNotif |
EnhancedDiplomacy |
0x006a88e0 |
FUN_004f1c40 |
CharacterEnhancedEspionageNotif |
EnhancedEspionage |
0x006a8918 |
FUN_004f1d40 |
CharacterEnhancedCombatNotif |
EnhancedCombat |
0x006a8a10 |
FUN_004ee030 |
CharacterEnhancedLoyaltyNotif |
EnhancedLoyalty |
(field writer—§1.1) |
FUN_004f2000 |
MissionHyperdriveModifierNotif |
MissionHyperdriveModifier |
0x006a8ba8 |
Note: EnhancedShipDesign, EnhancedTroopTraining, EnhancedFacilityDesign, and
EnhancedLeadership notif dispatchers exist in the binary (confirmed by the BaseShipyardRD,
BaseTrainingFacilRD, BaseConstructionYardRD, BaseLeadership notif strings in the 0x00536xxx
range) but have not been individually decompiled. They follow the same FUN_004f8980 pattern.
1.3 Force / Jedi System¶
All Force-related dispatchers use FUN_0053a010 (notification path). None of them write fields
directly—the actual Force value modification happens upstream (in the Jedi training mission
manager). The dispatchers are the observer-broadcast step.
| Address | Size | Notif String | Event Name | Event ID |
|---|---|---|---|---|
FUN_004f1e00 |
73 | CharacterForceNotif |
Force |
0x1e1 (481) |
FUN_004f1e50 |
73 | CharacterForceExperienceNotif |
ForceExperience |
— |
FUN_004f1ea0 |
73 | CharacterForceTrainingNotif |
ForceTraining |
0x1e5 (485) |
FUN_004f20e0 |
73 | CharacterForceUserDiscoveredKeyNotif |
ForceUserDiscovered |
0x362 (866) |
FUN_004f2240 |
51 | CharacterForceAwareNotif |
ForceAware |
— |
FUN_004f2280 |
51 | CharacterForcePotentialNotif |
ForcePotential |
— |
FUN_004f2300 |
51 | CharacterDiscoveringForceUserNotif |
(see binary) | — |
ForceUserDiscovered (FUN_004f20e0) is special: it dispatches via FUN_004f8aa0 (two
entity-ref params) and registers event 0x362. This is the entry point for the "Jedi discovered
by the other side" story moment.
Force object layout (CCharacter fields):
| Expression | Type | Field | Notes |
|---|---|---|---|
entity[9] >> 6 & 3 |
2-bit | force_potential_tier |
0=Low, 1=Med, 2=High, 3=Very High |
entity[0x23] as short |
short |
force_experience |
Accumulates through training/use |
entity+0x8c as short |
short |
force_potential_raw |
Detector's own Force potential |
entity[0x1e] & 1 |
bit | is_undiscovered_jedi |
Clear = undiscovered Jedi |
context+0x4c |
uint |
detection_pending |
Set to 1 when undiscovered Jedi found |
Force detection formula (FUN_0058a3f0, 306 bytes):
potential_tier = target[9] >> 6 & 3 // 2-bit, four levels
force_xp = (short)target[0x23] // experience accumulator
target_pot = *(short*)(detector+0x8c) // detector's potential
detected = FUN_0055e4d0(potential_tier, force_xp, target_pot, &out1, &out2)
if detected AND !(target[0x1e] & 1): // unknown Jedi
context->detection_pending = 1
FUN_0055e4d0 (stat check), FUN_0055ff60 (secondary),
FUN_0058a530 (finalize). All three must pass.
1.4 Mission Role Assignment¶
These dispatchers manage whether a character is currently on a mission and what their mission
status is. All use FUN_0053a010 and FUN_004f8880 (single entity-param pattern).
| Address | Notif String | Event Name | Notes |
|---|---|---|---|
FUN_00536b00 |
RoleOnMissionNotif |
OnMission |
Character has been assigned to a mission |
FUN_00536b40 |
OnHiddenMissionNotif |
OnHiddenMission |
Mission is concealed from opponent |
FUN_00536b80 |
RoleOnMandatoryMissionNotif |
OnMandatoryMission |
Story-driven forced assignment |
FUN_00536a40 |
RoleCanResignFromMissionNotif |
CanResignFromMission |
Character resignation eligibility |
FUN_00536a00 |
RoleMissionResignRequestNotif |
MissionResignRequest |
Player requested resignation |
FUN_00536880 |
RoleMissionSeedKeyNotif |
MissionSeed |
Starting mission (game initialization) |
OnHiddenMission marks missions invisible to the opposing side's intelligence. The OnMandatory
flag is set by story events and prevents player reassignment—Luke's training on Dagobah is
the canonical example.
Base skill role notifications (from the 0x005366xx range—confirmed in binary):
| Address | Notif String | Event Name |
|---|---|---|
FUN_00536600 |
RoleBaseDiplomacyNotif |
BaseDiplomacy |
FUN_00536640 |
RoleBaseEspionageNotif |
BaseEspionage |
FUN_00536680 |
RoleBaseShipyardRDNotif |
BaseShipyardRD |
FUN_005366c0 |
RoleBaseTrainingFacilRDNotif |
BaseTrainingFacilRD |
FUN_00536700 |
RoleBaseConstructionYardRDNotif |
BaseConstructionYardRD |
FUN_00536740 |
RoleBaseCombatNotif |
BaseCombat |
FUN_00536780 |
RoleBaseLeadershipNotif |
BaseLeadership |
FUN_005367c0 |
RoleBaseLoyaltyNotif |
BaseLoyalty |
These broadcast the character's base skill assignment when a character accepts a role (admiral, commander, general). The base skill values are read from MJCHARSD.DAT / MNCHARSD.DAT at load time.
2. Game Object Base¶
2.1 CRebObject → CNotifyObject Inheritance¶
All game entities inherit from this two-level base. CRebObject provides the vtable root and
entity identity. CNotifyObject adds observer plumbing and all mutable field infrastructure.
CRebObject (base)
+0x00 void* vtable
Virtual: GetFamilyId(), GetSideKey(), IsActive(), CanBombard()
└── CNotifyObject
+0x2c void* combat_data_ptr —associated combat data block
+0x24 uint difficulty_packed —bits 4-5 = difficulty level 0-3
+0x4c uint detection_pending —Jedi detection flag
+0x50 uint status_flags —bit0=active, bit3=fighter_eligible, bit12=special_disabled
+0x58 uint combat_phase_flags—space combat phase state machine
+0x60 int hull_current / squad_size_current (polymorphic by type)
+0x64 uint shield_weapon_packed
+0x66 short loyalty_base (CCharacter only)
+0x78 byte capability_flags —bit4=special_victory, bit6=disabled_a, bit7=alt_shield
+0x8a short enhanced_loyalty (CCharacter only)
+0x8c short force_potential_raw (CCharacter only)
+0x96 short regiment_strength (CTroopRegiment / CCombatUnit)
+0x9a short hyperdrive_mod (CCharacter only)
+0xac byte alive_flag —bit0=alive/combat-eligible
+0xb0 byte combat_ready_flags —bit1=combat_ready_for_fleet_eval
2.2 Common Notification Pattern¶
Every field mutation follows this exact chain. The pattern is consistent across all 4,900 decompiled functions with no documented exceptions.
Step 1: FUN_0053a000(this)—strict entity validity check. Returns 0 if dead/invalid.
Used by setter functions that write fields.
Step 2: FUN_0053fc90(value, min, max)—range validate. Returns 0 if out of [min, max].
Step 3: FUN_0053e0f0(value, min, 0x7fff)—secondary short-storage clamp (loyalty fields
only). Belt-and-suspenders guard against short overflow.
Step 4: Read old value, write new value to field. Early-exit if old == new.
Step 5: FUN_00539fd0(this, 1) → observer dispatch → side 1 (attacker).
Step 6: FUN_00539fd0(this, 2) → observer dispatch → side 2 (defender).
Step 7: (**(code**)(*this + vtable_slot))(old, new, context)—fire vtable change-event.
Notification-path variant (FUN_0053a010 instead of FUN_0053a000): Used by pure dispatchers
(no write step). Checks a different validity condition—likely a less strict live-check that
allows notifications on objects in transition states.
2.3 Object Lifecycle¶
Creation: Objects are heap-allocated via FUN_00618b70 (wrapper over new). Constructors
set the vtable pointer and initialize all fields. The tactical battle manager (FUN_005a7500)
is the largest constructor observed—4,856 bytes, allocates 0x3a8 words.
Destruction variants (from FUN_004fc080):
| Mission Type Code | Constant | Notif String | Event ID |
|---|---|---|---|
| 0x15 (21) | Autoscrap |
GameObjDestroyedAutoscrapNotif / DestroyedAutoscrap |
0x304 (772) |
| 6 | Sabotage |
GameObjDestroyedSabotageNotif / DestroyedSabotage |
0x305 (773) |
| 7 | Assassination |
GameObjDestroyedAssassinationNotif / DestroyedAssassination |
0x306 (774) |
| — | OnArrival |
GameObjDestroyedOnArrivalNotif / DestroyedOnArrival |
0x303 (771) |
| — | (generic) |
GameObjDestroyedNotif / Destroyed |
0x302 (770) |
The OnArrival variant is triggered when the object's status_flags bit5 is set and
+0x40 & 0xff0000 != 0—confirming the object was destroyed en route to a destination.
The mission type code is read from +0x40 & 0xff of the entity. The destroy function
(FUN_004fc080) fires the generic Destroyed event first, then conditionally fires the
specialized variant based on that byte. All destruction events use FUN_0053fe40 to register
the event ID.
Reference counting: FUN_004ece30 is the reference-counting helper called in destruction
paths—it manages object lifetime for objects referenced by multiple mission contexts.
2.4 Key Field Offsets (consolidated)¶
| Offset | Type | Field | Entity Type |
|---|---|---|---|
+0x00 |
void* |
vtable | all |
+0x24 |
uint |
difficulty_packed (bits 4-5 = difficulty 0-3) | all |
+0x2c |
void* |
combat_data_ptr | combat entities |
+0x40 |
uint |
mission_type_byte (bits 0-7), arrival_flags (bits 16-23) | CMission |
+0x4c |
uint |
detection_pending | detection context |
+0x50 |
uint |
status_flags | all |
+0x58 |
uint |
combat_phase_flags | CCombatUnit |
+0x60 |
int |
hull_current / squad_size_current | CCapitalShip / CFighterSquadron |
+0x64 |
uint |
shield_weapon_packed | CCapitalShip |
+0x66 |
short |
loyalty_base | CCharacter |
+0x78 |
byte |
capability_flags | all combat |
+0x80 |
uint |
entity_type_id | set during init (0x51–0x6a range) |
+0x8a |
short |
enhanced_loyalty | CCharacter |
+0x8c |
short |
force_potential_raw | CCharacter |
+0x94 |
short |
gnprtb_char_field (GNPRTB character stat) | CCharacter |
+0x96 |
short |
regiment_strength | CTroopRegiment, CCombatUnit |
+0x9a |
short |
hyperdrive_mod | CCharacter |
+0xac |
byte |
alive_flag | all combat |
+0xb0 |
byte |
combat_ready_flags | all combat |
3. Fleet System¶
3.1 Fleet Notification Dispatchers¶
All four fleet event dispatchers follow the same pattern: FUN_0053a010 validity, then
FUN_004f8880 (single entity-param), then FUN_0053fdd0 to register the event.
| Address | Size | Notif String | Event Name | Event ID |
|---|---|---|---|---|
FUN_004ff7a0 |
65 | FleetBattleNotif |
Battle |
0x180 (384) |
FUN_004ff7f0 |
65 | FleetBlockadeNotif |
Blockade |
0x181 (385) |
FUN_004ff840 |
65 | FleetBombardNotif |
Bombard |
0x182 (386) |
FUN_004ff890 |
65 | FleetAssaultNotif |
Assault |
0x183 (387) |
These four events are the core fleet-state transition broadcast points. Each fires from the
fleet object (this) with two integer parameters (param_1 = target system or battle context,
param_2 = secondary context). The event IDs form a contiguous block 0x180–0x183.
Troop destruction during blockade (FUN_00504a00, 231 bytes):
- Notif string: TroopRegDestroyedRunningBlockade
- Event ID: 0x340 (832)
- Uses FUN_004f8aa0 (two entity-ref params: troop + transport)
- Triggered when troops are caught in a hostile blockade during transit
Troop withdrawal (FUN_00504af0, 56 bytes):
- Notif string: TroopRegWithdrawPercentNotif
- Related: FUN_00511e70—SystemTroopRegWithdrawPercentNotif
3.2 Fleet Composition¶
| Address | Size | Purpose |
|---|---|---|
FUN_00502020 |
897 | Garrison/fleet strength aggregator—iterates entities by DatId family byte. Family ranges: 0x10–0x14 = troops, 0x1c–0x20 = facilities, 0x30–0x40 = ships. |
FUN_00555540 |
— | Fleet strength getter for bombardment side |
FUN_004f2640 |
— | Fleet unit iterator (used in FUN_004ff7a0 callers)—params: side=1, type=2 |
CFleet contains:
- Capital ship list (families 0x30–0x3b)
- Fighter squadron list (families 0x71–0x72)
- Character list (families 0x08–0x0f)
- Entry point: FUN_004ff7a0 (FleetBattleNotif) is the canonical start of the battle trigger chain
3.3 Fleet–Battle Integration¶
The fleet battle notification chain leads into the space combat pipeline documented in
space-combat.md. The key link: FUN_004ff7a0 fires event 0x180 which is handled by the
strategy-layer battle manager, which then instantiates the combat context and invokes the
7-phase combat pipeline.
FUN_004ff8e0 (84 bytes) is a fleet system initialization function—it registers 10 message
handlers (event IDs 0x200–0x223 range + 0x234) via FUN_00520690. This is the fleet
manager setup, run once at game load. All return 0 on failure.
4. Faction System¶
4.1 Side Resolution—FUN_004f8c60¶
Address: 0x004f8c60
Size: 208 bytes
Purpose: Faction notification handler—resolves faction name, sets difficulty, builds
notification payload, fires via the notification log system.
The faction bits live at *(uint*)(this + 0x24):
Bits 6-7 (>> 6 & 3): own_faction_id —1=Alliance, 2=Empire, 3=Neutral, else UNKNOWN
Bits 4-5 (>> 4 & 3): display_faction —1=Alliance, 2=Empire, else UNKNOWN
Faction string selection:
uint faction_bits = *(uint*)(this + 0x24) >> 6 & 3;
switch (faction_bits) {
case 1: local_1c = "Alliance"; break;
case 2: local_1c = "Empire"; break;
case 3: local_1c = "Neutral"; break;
default: local_1c = "UNKNOWN!"; break;
}
String data addresses:
| String | Address |
|--------|---------|
| "Alliance" | 0x006a8f04 |
| "Empire" | 0x006a8f10 |
| "Neutral" | 0x006a8f1c |
| "UNKNOWN!" | 0x006a8f28 |
The function also reads param_6 + 0x14 as an integer for difficulty-related secondary
processing, and calls FUN_004f62d0(this) → FUN_00583c40 to resolve the faction's display
name string. The notification payload is assembled via FUN_00616110 (string append) and
FUN_00617480 (integer insert) into a log buffer at DAT_006b2a70.
Cross-reference: The 0x24 packed field also carries difficulty at bits 4-5. FUN_004fd600
(difficulty modifier extractor) reads this field when applying difficulty bonuses in combat.
4.2 Victory Conditions¶
| Address | Purpose | Notif String | Event ID |
|---|---|---|---|
FUN_00532f40 |
Recruitment done | SideRecruitmentDoneNotif / RecruitmentDone |
0x12c (300) |
FUN_0054ba00 |
Final battle trigger | MissionMgrFinalBattleNotif / FinalBattle |
— |
FUN_0054b9c0 |
Final battle ready | FinalBattleReadyNotif |
— |
(string at 0x006aa764) |
Victory condition check | SideVictoryConditionsNotif / VictoryConditions |
— |
RecruitmentDone fires when a side has completed all available character recruitment. It uses
FUN_0053fdd0(300, this, param_2, param_3)—this is event 0x12c, the canonical
"recruitment phase complete" trigger.
The SideVictoryConditionsNotif string confirms a dedicated victory-check function exists.
Its exact address has not been isolated in the annotated corpus—it is called from the turn
end cycle and evaluates: HQ capture, Death Star status, and Rebel base detection.
Victory audio: VICTORY at 0x006ab5f8, VICTORY_II at 0x006ab5b0—two fanfares,
likely Alliance vs Empire.
4.3 System Control and Uprising¶
| Address | Notif String | Event ID |
|---|---|---|
FUN_00511ec0 |
ControlKindBattleWonNotif |
— |
FUN_00511f40 |
SystemControlKindUprisingNotif / ControlKindUprising |
— |
FUN_005121e0 |
SystemUprisingNotif / Uprising |
— |
FUN_005122d0 |
SystemBlockadeNotif / Blockade |
0x14e (334) |
FUN_00512280 |
SystemBattleNotif / Battle |
0x14d (333) |
FUN_00512580 |
SystemUprisingIncidentNotif / UprisingIncident |
0x152 (338) |
LoyaltyCausedCurrentControlKind notif string confirms loyalty thresholds directly trigger
faction control changes. Thresholds are stored in UPRIS1TB.DAT (3 entries) and UPRIS2TB.DAT
(4 entries).
5. Notification Dispatcher Reference¶
Three distinct notification dispatch helper functions serve different entity parameter counts:
FUN_004f8880—Single Entity Parameter¶
// Signature (approximate):
void notify_1(void* this,
char* notif_type_str, char* event_name_str,
int param1, char* null_arg, int context);
FUN_004f8980—Two Entity Parameters (reversed order)¶
// Signature (approximate):
void notify_2(void* this,
char* notif_type_str, char* event_name_str,
int param2, int param1, char* null_arg, int context);
Used by: Force notifs, enhanced skill notifs, BaseDiplomacy/Espionage/Combat notifs.
FUN_004f8aa0—Two Entity Reference Parameters¶
// Signature (approximate):
void notify_2ref(void* this,
char* notif_type_str, char* event_name_str,
uint** param2_ref, uint** param1_ref, char* null_arg, int context);
FUN_004f8b80—Mission Seed Key Variant¶
Used exclusively by FUN_00536880 (RoleMissionSeedKeyNotif). Likely a specialized variant for
the initial mission seeding path.
6. Event ID Registry (Entity Range)¶
All confirmed event IDs from FUN_0053fcf0 / FUN_0053fe40 / FUN_0053fdd0 call sites.
| Event ID | Hex | Notification / Event String | Class / Source |
|---|---|---|---|
| 300 | 0x12c | RecruitmentDone | FUN_00532f40 |
| 333 | 0x14d | SystemBattle | FUN_00512280 |
| 334 | 0x14e | SystemBlockade | FUN_005122d0 |
| 338 | 0x152 | UprisingIncident | FUN_00512580 |
| 384 | 0x180 | FleetBattle | FUN_004ff7a0 |
| 385 | 0x181 | FleetBlockade | FUN_004ff7f0 |
| 386 | 0x182 | FleetBombard | FUN_004ff840 |
| 387 | 0x183 | FleetAssault | FUN_004ff890 |
| 416 | 0x1a0 | FightSquadSquadSizeDamage | CFighterSquadron |
| 448 | 0x1c0 | CapShipHullValueDamage | CCapitalShip |
| 449 | 0x1c1 | ShieldRechargeRateCHAllocated | CCapitalShip |
| 450 | 0x1c2 | WeaponRechargeRateCHAllocated | CCapitalShip |
| 481 | 0x1e1 | CharacterForce | FUN_004f1e00 |
| 485 | 0x1e5 | CharacterForceTraining | FUN_004f1ea0 |
| 770 | 0x302 | GameObjDestroyed (generic) | FUN_004fc080 |
| 771 | 0x303 | GameObjDestroyedOnArrival | FUN_004fc080 |
| 772 | 0x304 | GameObjDestroyedAutoscrap | FUN_004fc080 |
| 773 | 0x305 | GameObjDestroyedSabotage | FUN_004fc080 |
| 774 | 0x306 | GameObjDestroyedAssassination | FUN_004fc080 |
| 832 | 0x340 | TroopRegDestroyedRunningBlockade | FUN_00504a00 |
| 866 | 0x362 | CharacterForceUserDiscovered | FUN_004f20e0 |
7. Cross-Reference: Vtable Slots¶
Character and troop vtable slots for all confirmed setters in the entity range.
| Vtable Offset | Decimal | Event | Source Function |
|---|---|---|---|
+0x238 |
568 | NotifyLoyaltyChanged(old, new, ctx) | FUN_005341a0 |
+0x318 |
792 | NotifyEnhancedLoyaltyChanged(old, new, ctx) | FUN_004ee030 |
+0x330 |
816 | NotifyCombatStrengthChanged(old, new, ctx) | FUN_004ee350 |
+0x338 |
824 | NotifyHyperdriveChanged(old, new, ctx) | FUN_004ee470 |
Ship vtable slots (for completeness—defined in CCombatUnit / CCapitalShip):
| Vtable Offset | Decimal | Event | Source Function |
|---|---|---|---|
+0x260 |
608 | NotifySquadChanged(old, new, ctx) | FUN_005032c0 |
+0x29c |
668 | NotifyHullChanged(old, new, ctx) | FUN_00501490 |
+0x2a0 |
672 | NotifyShieldChanged(old, new, ctx) | FUN_00501510 |
+0x2a4 |
676 | NotifyWeaponChanged(old, new, ctx) | FUN_005015a0 |
8. Utility Functions¶
| Address | Signature | Purpose |
|---|---|---|
FUN_0053a000 |
bool(int this) |
Strict entity validity guard—write-path setters |
FUN_0053a010 |
bool(int this) |
Notification-path validity guard—dispatchers |
FUN_0053fc90 |
int(value, min, max) |
Range validator: 0 if outside [min, max] |
FUN_0053e0f0 |
int(value, min, 0x7fff) |
Secondary clamp for short storage |
FUN_00539fd0 |
void*(this, side) |
Side observer getter: side=1 (attacker), 2 (defender) |
FUN_0053fcf0 |
void(type, this, p1, p2, ctx) |
Register event (notification path A) |
FUN_0053fe40 |
int(type, this, p1, p2, ctx) |
Register event (notification path B—returns result) |
FUN_0053fdd0 |
void(type, this, p1, p2) |
Register event (fleet notification path) |
FUN_004fd340 |
int() |
Get bombardment base value (GNPRTB 0x1400) |
FUN_004fd600 |
int(ctx, bits) |
Apply difficulty modifier (extracts bits 4-5 of +0x24) |
FUN_004f62d0 |
undefined*(int this) |
Get faction object from entity |
FUN_00583c40 |
char*(int faction) |
Get faction display name string |
FUN_00618b70 |
void*(size) |
Heap allocator (new) |
FUN_004ece30 |
void*(void**) |
Reference counting / object lifetime helper |
9. Implementation Notes for rebellion-core¶
Character world struct (crates/rebellion-core/src/world/mod.rs)¶
The following fields are confirmed by RE and must be present in the Character struct for
full game simulation parity:
pub struct Character {
// Already present in current world model:
pub dat_id: DatId,
pub name: String,
pub skills: [SkillPair; 8],
pub jedi_probability: u8,
pub jedi_level: SkillPair,
pub is_known_jedi: bool,
pub is_jedi_trainer: bool,
pub is_unable_to_betray: bool,
pub can_be_admiral: bool,
pub can_be_commander: bool,
pub can_be_general: bool,
pub loyalty: SkillPair,
// Required for entity system parity—not yet in world model:
pub enhanced_loyalty: i16, // +0x8a, mission bonus, 0-100 clamped
pub hyperdrive_modifier: i16, // +0x9a, Han Solo bonus, non-negative
pub force_potential_tier: u8, // entity[9] >> 6 & 3, 2-bit 0-3
pub force_experience: i16, // entity[0x23] as short
pub force_potential_raw: i16, // +0x8c, detector's Force potential
pub is_undiscovered_jedi: bool, // !(entity[0x1e] & 1)
pub on_mission: bool, // OnMission flag
pub on_hidden_mission: bool, // OnHiddenMission flag
pub on_mandatory_mission: bool, // OnMandatoryMission flag
pub can_resign: bool, // CanResignFromMission flag
}
Movement system (crates/rebellion-core/src/movement.rs)¶
The hyperdrive_modifier field (+0x9a) must be consulted when computing ticks_per_hop.
Subtract from BASE_TICKS_PER_HOP for fleets containing a character (admiral) with a non-zero
modifier:
let han_bonus = fleet.admiral()
.and_then(|c| world.characters.get(c))
.map(|c| c.hyperdrive_modifier as u32)
.unwrap_or(0);
let ticks = (BASE_TICKS_PER_HOP.saturating_sub(han_bonus))
.max(MIN_TICKS_PER_HOP);
Event IDs for rebellion-core/src/events.rs¶
The following event IDs should be added to the EventCondition::EventFired variant's known
set for scripted event chaining:
pub const EVT_RECRUITMENT_DONE: u32 = 0x12c; // 300
pub const EVT_SYSTEM_BATTLE: u32 = 0x14d; // 333
pub const EVT_SYSTEM_BLOCKADE: u32 = 0x14e; // 334
pub const EVT_UPRISING_INCIDENT: u32 = 0x152; // 338
pub const EVT_FLEET_BATTLE: u32 = 0x180; // 384
pub const EVT_FLEET_BLOCKADE: u32 = 0x181; // 385
pub const EVT_FLEET_BOMBARD: u32 = 0x182; // 386
pub const EVT_FLEET_ASSAULT: u32 = 0x183; // 387
pub const EVT_CHARACTER_FORCE: u32 = 0x1e1; // 481
pub const EVT_CHARACTER_FORCE_TRAIN: u32 = 0x1e5; // 485
pub const EVT_GAME_OBJ_DESTROYED: u32 = 0x302; // 770
pub const EVT_DESTROYED_ON_ARRIVAL: u32 = 0x303; // 771
pub const EVT_DESTROYED_AUTOSCRAP: u32 = 0x304; // 772
pub const EVT_DESTROYED_SABOTAGE: u32 = 0x305; // 773
pub const EVT_DESTROYED_ASSASSINATION: u32 = 0x306; // 774
pub const EVT_TROOP_BLOCKADE_KILL: u32 = 0x340; // 832
pub const EVT_FORCE_USER_DISCOVERED: u32 = 0x362; // 866