Experience levels WIRED: the egg field drives the simulation tier (Gitea #2)
BTPlayer's master ctor now seeds the flag block from btMission->ExperienceLevel() + AdvancedDamageOn() (accessors from the SURVIVED 1995 BTMSSN.HPP [T0]) instead of the NULL-stubbed scenario role -- the egg experience knob works for the first time. Both switch slot errors fixed vs the binary @4c0bc8; phantom btMission duplicate member removed (+0x1f8 IS Player::playerMission). SEVEN gate stubs unified onto the real flags (two found empirically): HeatModelActive, OwnerAdvancedDamage, LiveFireEnabled, ControlsAllowLights, powersub @4b0efc, emitter's file-local FUN_004ad7d4 + FUN_004ac9c8 stubs. FUN_004ac9c8 family swept (incl. a live raw-offset databinding trap in MechSubsystem::IsDamaged). Flag block renamed to its true semantics (simLive/heatModelOn/...), scoring-era names kept as comments. Includes the #5 [aud-tail] diag in emitter.cpp. ALL 19 shipped eggs say experience=expert -> default behavior UNCHANGED (per-tier verified: novice/standard = no heat/jams, authentic; veteran/ expert = today's exact behavior). Real delta: egg advancedDamage=1 now reaches player+0x264/0x268 (was hardwired 0). Follow-up flagged: the glass FE defaults empty experience to veteran (one tier below shipped). Awaiting human verification. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a0cec48e3f
commit
d7158f1f82
@@ -449,20 +449,22 @@ void
|
||||
// @004b0efc -- pass the message to the HeatSink base; if the part is alive,
|
||||
// the source short flag is set and message 4 arrives, force a short-recovery.
|
||||
//
|
||||
extern int BTPlayerExperienceSimLive(void *owner_mech); // btplayer.cpp (player+0x25c; issue #2)
|
||||
extern int BTPlayerRoleLocksAdvanced(void *owner_mech); // btplayer.cpp (FUN_004ac9c8: player+0x274 == 0)
|
||||
|
||||
Logical
|
||||
PoweredSubsystem::HandleMessage(int message)
|
||||
{
|
||||
HeatSink::HandleMessage(message); // FUN_004ad748
|
||||
|
||||
// Raw @004b0efc reads *(int*)(*(owner+0x190) + 0x25c) -- the message-manager's
|
||||
// short-event flag (NOT a Generator field). The manager is null in bring-up
|
||||
// (BT_GetMessageManager stub), so guard the deref; the real read resumes once
|
||||
// the SubsystemMessageManager (0xBD3) roster lookup is wired.
|
||||
SubsystemMessageManager *msgMgr = BT_GetMessageManager((Mech *)owner); // *(this[0x34]+0x190)
|
||||
|
||||
if (!IsDamaged() // FUN_004ac9c8 == 0
|
||||
&& msgMgr != 0
|
||||
&& *(LWord *)((char *)msgMgr + 0x25c) != 0 // message-manager short-event flag
|
||||
// CORRECTED (issue #2 [T1]): @004b0efc reads *(int*)(*(owner+0x190)+0x25c)
|
||||
// -- owner mech+0x190 is the PLAYER LINK, and +0x25c is the BTPlayer's
|
||||
// "sim live" EXPERIENCE flag (0 only for novice), NOT a message-manager
|
||||
// field (the old misattribution left this path dead behind the null
|
||||
// BT_GetMessageManager stub). The leading FUN_004ac9c8==0 term is the
|
||||
// not-novice predicate (BTPlayerRoleLocksAdvanced), not a damage query.
|
||||
if (!BTPlayerRoleLocksAdvanced(owner) // FUN_004ac9c8 == 0 (not novice)
|
||||
&& BTPlayerExperienceSimLive(owner) != 0 // *(player+0x25c) != 0
|
||||
&& message == 4)
|
||||
{
|
||||
ForceShortRecovery(); // FUN_004b11bc(this)
|
||||
@@ -477,10 +479,15 @@ Logical
|
||||
void
|
||||
PoweredSubsystem::ForceShortRecovery() // internal helper for @004b0efc
|
||||
{
|
||||
if (IsDamaged()) // FUN_004ac9c8
|
||||
// CORRECTED (issue #2 [T1]): both FUN_004ac9c8 calls here are the
|
||||
// not-novice EXPERIENCE predicate on the owning player (each subsystem
|
||||
// hops sub->owner mech->playerLink; this part and its source share the
|
||||
// same mech, hence the same player) -- NOT damage-state queries (the old
|
||||
// HeatSink::IsDamaged stand-in read simulationState).
|
||||
if (BTPlayerRoleLocksAdvanced(owner)) // FUN_004ac9c8(this)
|
||||
return;
|
||||
Generator *source = (Generator *)voltageSource.Resolve(); // FUN_00417ab4(this+0x1d0)
|
||||
if (source != 0 && !source->IsDamaged())
|
||||
if (source != 0 && !BTPlayerRoleLocksAdvanced(owner)) // FUN_004ac9c8(source): same mech -> same player
|
||||
{
|
||||
source->stateAlarm.SetLevel(Generator::GeneratorShorted); // source+0x1fc -> 3
|
||||
source->outputVoltage = 0.0f; // source+0x1f8 = 0
|
||||
@@ -1086,7 +1093,8 @@ Logical
|
||||
{
|
||||
if (message == 4)
|
||||
{
|
||||
if ((simulationState == 2 || simulationState == 0) && !IsDamaged()) // this[0x10]; FUN_004ac9c8
|
||||
if ((simulationState == 2 || simulationState == 0) // this[0x10]
|
||||
&& !BTPlayerRoleLocksAdvanced(owner)) // FUN_004ac9c8 == 0 (not novice; issue #2 -- was the state-based IsDamaged stand-in, which wrongly blocked state 2)
|
||||
{
|
||||
stateAlarm.SetLevel(GeneratorShorted); // 3
|
||||
shortTimer = 0.0f; // this[0x7e]
|
||||
@@ -1255,7 +1263,10 @@ Logical
|
||||
Generator *source = (watched != 0) // FUN_00417ab4(watched+0x1d0)
|
||||
? (Generator *)((PoweredSubsystem *)watched)->ResolveVoltageSource()
|
||||
: 0;
|
||||
if (source != 0 && !source->IsDamaged())
|
||||
// @004b179c's FUN_004ac9c8(source) [T1] = the not-novice EXPERIENCE
|
||||
// predicate on the source's owner (same mech as ours; issue #2 -- was
|
||||
// the state-based IsDamaged stand-in).
|
||||
if (source != 0 && !BTPlayerRoleLocksAdvanced(owner))
|
||||
{
|
||||
source->stateAlarm.SetLevel(Generator::GeneratorShorted); // source+0x1fc -> 3
|
||||
source->outputVoltage = 0.0f; // source+0x1f8 = 0
|
||||
|
||||
Reference in New Issue
Block a user