Audio Phase 4a (AUDIO_FIDELITY F6/F7): coolant-leak warning + missile alarm
F6 ReportLeak (the largest dead authored block -- 38 of 54 match watchers):
recovered the binary HeatSink attribute table (16-byte {id,name,off+1} rows
@0x50e438..0x50e4c8, ids 3..12) [T1] -- it confirms EVERY existing heat
binding (CurrentTemperature@0x114 .. CoolantMassLeakRate@0x130, HeatSink@
0x164) and adds the one row we never published: ReportLeak (id 12) ->
+0x138 = coolantActive, the INT leak hysteresis flag UpdateCoolant
(@004adbf8) drives 1/0 around draw 0.003/0.0025. PoweredSubsystem derives
from HeatSink, so the single row serves all 19 authored leak watchers
through the chained index, exactly like the binary. MechWeapon's pinned-id
pad absorbed the +1 chain shift (0x0E -> 0x0F, tripwire fired as designed).
F7 IncomingLock/DistanceToMissile (missile alarm): binary Mech table walked
in full (ids 21..56 [T1] -- also settles FootStep@0x394, CollisionSpeed@
0x4B4, UnstablePercentage@0x3F0, ReduceButton@0x340 for the next findings).
IncomingLock id 54 @0x3fc, DistanceToMissile id 56 @0x400; the old
"maxSpeed @0x400 = FLT_MAX" member was a MISREAD of the far default and is
retired (its 1000.0f "override" was RadarRange id 47 @0x404, already
published). Real members + accumulators: Missile::MoveAndCollide reports
target + range each tick (BTReportIncomingMissile bridge); PerformAndWatch
latches per frame. The authored beeper (match 1/0) + range->TEMPO scale
(100..800 -> 600..10, accelerating as the missile closes) read them
unchanged. Drive is intent-level [T3]; init 0/FLT_MAX matches the binary
reset (part_012.c:9446-9447).
Regression (30s): stable; ReportLeak binds real on every subsystem (0 pad
redirects); DistanceToMissile binds with FLT_MAX live; attrnull 41 -> 3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
0ca7d269d2
commit
cc2b109cc8
@@ -417,7 +417,13 @@ const HeatSink::IndexEntry
|
|||||||
ATTRIBUTE_ENTRY(HeatSink, DegradationPressure, coolantEfficiency), // @0x124
|
ATTRIBUTE_ENTRY(HeatSink, DegradationPressure, coolantEfficiency), // @0x124
|
||||||
ATTRIBUTE_ENTRY(HeatSink, CoolantMassLeakRate, coolantDraw), // @0x130 (LeakGauge; damage-driven)
|
ATTRIBUTE_ENTRY(HeatSink, CoolantMassLeakRate, coolantDraw), // @0x130 (LeakGauge; damage-driven)
|
||||||
ATTRIBUTE_ENTRY(HeatSink, HeatSink, linkedSinks), // @0x164 (Eng linked-sink temp readout)
|
ATTRIBUTE_ENTRY(HeatSink, HeatSink, linkedSinks), // @0x164 (Eng linked-sink temp readout)
|
||||||
ATTRIBUTE_ENTRY(HeatSink, ValveSetting, coolantFlowScale) // @0x15C (condenser valve slider @2; init 1.0f)
|
ATTRIBUTE_ENTRY(HeatSink, ValveSetting, coolantFlowScale), // @0x15C (condenser valve slider @2; init 1.0f)
|
||||||
|
// (AUDIO_FIDELITY F6) the coolant-leak warning: binary id 12 @0x138 = the
|
||||||
|
// coolantActive leak flag (binary table @0x50e4c8; watchers match ==1/==0).
|
||||||
|
// PoweredSubsystem (weapons/sensor/myomers) DERIVES from HeatSink, so this
|
||||||
|
// single row serves ALL 19 authored leak watchers through the chained
|
||||||
|
// index -- exactly like the binary (one ReportLeak row in the image).
|
||||||
|
ATTRIBUTE_ENTRY(HeatSink, ReportLeak, coolantActive) // @0x138 (leak-active hysteresis flag)
|
||||||
};
|
};
|
||||||
|
|
||||||
HeatSink::AttributeIndexSet&
|
HeatSink::AttributeIndexSet&
|
||||||
|
|||||||
@@ -369,6 +369,14 @@ inline int
|
|||||||
CoolantMassLeakRateAttributeID, // @0x130 coolantDraw (damage-driven leak)
|
CoolantMassLeakRateAttributeID, // @0x130 coolantDraw (damage-driven leak)
|
||||||
HeatSinkAttributeID, // @0x164 linkedSinks (link to master sink)
|
HeatSinkAttributeID, // @0x164 linkedSinks (link to master sink)
|
||||||
ValveSettingAttributeID, // @0x15C coolantFlowScale (condenser valve slider @2)
|
ValveSettingAttributeID, // @0x15C coolantFlowScale (condenser valve slider @2)
|
||||||
|
// (AUDIO_FIDELITY F6) the binary heat attribute table (16-byte rows
|
||||||
|
// {id, name, off+1, pad} @0x50e438..0x50e4c8, ids 3..12) confirms
|
||||||
|
// EVERY existing binding above [T1] and adds ReportLeak (id 12) ->
|
||||||
|
// +0x138 = coolantActive, the INT leak hysteresis flag UpdateCoolant
|
||||||
|
// (@004adbf8 [0x4e]) drives 1 above draw 0.003 / 0 below 0.0025.
|
||||||
|
// The authored Logical match watchers (19 subsystems, ==1 Start /
|
||||||
|
// ==0 Stop of the looped 3-note leak sequence) fire on it directly.
|
||||||
|
ReportLeakAttributeID,
|
||||||
NextAttributeID
|
NextAttributeID
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -735,9 +735,13 @@ const Mech::IndexEntry
|
|||||||
ATTRIBUTE_ENTRY(Mech, RequestDuckAnimation, attrPad), // 0x33
|
ATTRIBUTE_ENTRY(Mech, RequestDuckAnimation, attrPad), // 0x33
|
||||||
ATTRIBUTE_ENTRY(Mech, UnstablePercentage, attrPad), // 0x34
|
ATTRIBUTE_ENTRY(Mech, UnstablePercentage, attrPad), // 0x34
|
||||||
ATTRIBUTE_ENTRY(Mech, SuperStop, attrPad), // 0x35
|
ATTRIBUTE_ENTRY(Mech, SuperStop, attrPad), // 0x35
|
||||||
ATTRIBUTE_ENTRY(Mech, IncomingLock, attrPad), // 0x36
|
// (AUDIO_FIDELITY F7) real missile-alarm backing: binary ids 54/56 @0x3fc/
|
||||||
|
// 0x400 [T1 table @0x50c0b0/0x50c0d0]; the authored beeper (match 1/0) +
|
||||||
|
// tempo scale (range 100..800 -> tempo 600..10) read these. Driven by
|
||||||
|
// Missile::MoveAndCollide via BTReportIncomingMissile (mech4.cpp).
|
||||||
|
ATTRIBUTE_ENTRY(Mech, IncomingLock, incomingLock), // 0x36
|
||||||
ATTRIBUTE_ENTRY(Mech, DuckState, duckState), // 0x37 (crouch posture, int)
|
ATTRIBUTE_ENTRY(Mech, DuckState, duckState), // 0x37 (crouch posture, int)
|
||||||
ATTRIBUTE_ENTRY(Mech, DistanceToMissile, attrPad) // 0x38
|
ATTRIBUTE_ENTRY(Mech, DistanceToMissile, distanceToMissile) // 0x38
|
||||||
};
|
};
|
||||||
|
|
||||||
Mech::AttributeIndexSet&
|
Mech::AttributeIndexSet&
|
||||||
@@ -850,7 +854,9 @@ Mech::Mech(
|
|||||||
mechNameFilter.Initialize(); // FUN_00435a7c(this+0xdb)
|
mechNameFilter.Initialize(); // FUN_00435a7c(this+0xdb)
|
||||||
masterAlarm = AlarmIndicator(0x21); // FUN_0041b9ec(this+0xe7,0x21)
|
masterAlarm = AlarmIndicator(0x21); // FUN_0041b9ec(this+0xe7,0x21)
|
||||||
stateFlags = 0; // Wword(0xff)
|
stateFlags = 0; // Wword(0xff)
|
||||||
maxSpeed = DAT_005209d0; // FLT_MAX -> Wword(0x100)
|
// (F7 correction) the binary's 0x400 = FLT_MAX init is DistanceToMissile's
|
||||||
|
// "no missile" far default (attr id 56), NOT a maxSpeed -- the old member
|
||||||
|
// is retired; distanceToMissile (init below) owns the slot's meaning.
|
||||||
Wword(0x104) = 0;
|
Wword(0x104) = 0;
|
||||||
Wword(0x106).Construct(0); // FUN_004a4d60 (slot member)
|
Wword(0x106).Construct(0); // FUN_004a4d60 (slot member)
|
||||||
Wword(0x10f).LinkTo(this + 0x61); // FUN_00420ea4
|
Wword(0x10f).LinkTo(this + 0x61); // FUN_00420ea4
|
||||||
@@ -934,6 +940,12 @@ Mech::Mech(
|
|||||||
radarLinearPosition = &localOrigin.linearPosition; // map reads the mech's live world position...
|
radarLinearPosition = &localOrigin.linearPosition; // map reads the mech's live world position...
|
||||||
radarAngularPosition= &localOrigin.angularPosition; // ...and orientation (pointers into the base origin)
|
radarAngularPosition= &localOrigin.angularPosition; // ...and orientation (pointers into the base origin)
|
||||||
duckState = 0; // not crouching
|
duckState = 0; // not crouching
|
||||||
|
// (AUDIO_FIDELITY F7) missile alarm: the binary reset writes 0 / FLT_MAX
|
||||||
|
// (part_012.c:9446-9447; FLT_MAX = "no missile" far default)
|
||||||
|
incomingLock = 0;
|
||||||
|
distanceToMissile = FLT_MAX;
|
||||||
|
incomingLockNext = 0;
|
||||||
|
distanceToMissileNext = FLT_MAX;
|
||||||
|
|
||||||
ZeroBlock(this + 0xca, 6); // this[0xca..0xcf] = 0
|
ZeroBlock(this + 0xca, 6); // this[0xca..0xcf] = 0
|
||||||
ZeroBlock(this + 0x153, 6); // this[0x153..0x158] = 0
|
ZeroBlock(this + 0x153, 6); // this[0x153..0x158] = 0
|
||||||
@@ -1014,7 +1026,9 @@ Mech::Mech(
|
|||||||
SetPerformance(PTR_LAB_0050c0f4); // master performance
|
SetPerformance(PTR_LAB_0050c0f4); // master performance
|
||||||
}
|
}
|
||||||
|
|
||||||
maxSpeed = 0x447a0000; // 1000.0f -> Wword(0x101) (override)
|
// (F7 correction) the old "maxSpeed = 1000.0f override" here targeted
|
||||||
|
// Wword(0x101) = +0x404 -- the binary table says that is RadarRange
|
||||||
|
// (id 47), already initialized as radarRange = 1000.0f above.
|
||||||
Wword(0x102) = 0;
|
Wword(0x102) = 0;
|
||||||
Wword(0x103) = (int)(this + 0x43);
|
Wword(0x103) = (int)(this + 0x43);
|
||||||
|
|
||||||
|
|||||||
@@ -723,8 +723,10 @@ protected:
|
|||||||
//
|
//
|
||||||
protected:
|
protected:
|
||||||
BTVal mechName; // @0x360 this[0xd8] (proxy: .Copy)
|
BTVal mechName; // @0x360 this[0xd8] (proxy: .Copy)
|
||||||
Scalar maxSpeed; // @0x400 this[0x100] = FLT_MAX
|
// (F7) `Scalar maxSpeed @0x400` was a MISREAD -- the binary attribute
|
||||||
int stateFlags; // @0x410 this[0x104]
|
// table names 0x400 DistanceToMissile (id 56; FLT_MAX = far default);
|
||||||
|
// the member is retired in favor of distanceToMissile below.
|
||||||
|
int stateFlags; // @0x410 this[0x104] (binary attr table: RearFiring, id 50)
|
||||||
int throttleState; // @0x4a4 this[0x129] = 2 (initial)
|
int throttleState; // @0x4a4 this[0x129] = 2 (initial)
|
||||||
int heatLevel; // @0x518 this[0x146]
|
int heatLevel; // @0x518 this[0x146]
|
||||||
int heatCapacity; // @0x51c this[0x147] = 0.6 * heatLevel
|
int heatCapacity; // @0x51c this[0x147] = 0.6 * heatLevel
|
||||||
@@ -865,6 +867,19 @@ protected:
|
|||||||
Point3D *radarLinearPosition; // 0x30 RadarLinearPosition
|
Point3D *radarLinearPosition; // 0x30 RadarLinearPosition
|
||||||
Quaternion *radarAngularPosition; // 0x31 RadarAngularPosition
|
Quaternion *radarAngularPosition; // 0x31 RadarAngularPosition
|
||||||
int duckState; // 0x37 DuckState (crouch posture)
|
int duckState; // 0x37 DuckState (crouch posture)
|
||||||
|
// (AUDIO_FIDELITY F7) the incoming-missile alarm attributes. Binary
|
||||||
|
// Mech table [T1]: IncomingLock id 54 @0x3fc (Logical; authored match
|
||||||
|
// ==1 Start / ==0 Stop of the looped beeper), DistanceToMissile id 56
|
||||||
|
// @0x400 (Scalar; authored scale maps range 100..800 -> TEMPO 600..10,
|
||||||
|
// the beep accelerating as the missile closes). The mech reset inits
|
||||||
|
// them 0 / FLT_MAX (part_012.c:9446-9447); the live writer is in an
|
||||||
|
// un-exported gap, so the drive is intent-level [T3]: every homing
|
||||||
|
// Missile reports its target + range per MoveAndCollide tick into the
|
||||||
|
// *Next accumulators; PerformAndWatch latches them each frame.
|
||||||
|
int incomingLock; // 0x36 IncomingLock (1 = missile inbound)
|
||||||
|
Scalar distanceToMissile; // 0x38 DistanceToMissile (FLT_MAX = none)
|
||||||
|
int incomingLockNext; // accumulator (missiles OR into it)
|
||||||
|
Scalar distanceToMissileNext; // accumulator (missiles MIN into it)
|
||||||
|
|
||||||
// --- raw / engine-shim members touched by the ctor slice -------------
|
// --- raw / engine-shim members touched by the ctor slice -------------
|
||||||
void *vtable; // installed Mech vtable ptr
|
void *vtable; // installed Mech vtable ptr
|
||||||
@@ -890,6 +905,15 @@ protected:
|
|||||||
public:
|
public:
|
||||||
int MovementMode() { return (int)GetSimulationState(); }
|
int MovementMode() { return (int)GetSimulationState(); }
|
||||||
void SetMovementMode(int m) { SetSimulationState((unsigned)m); }
|
void SetMovementMode(int m) { SetSimulationState((unsigned)m); }
|
||||||
|
// (AUDIO_FIDELITY F7) called by each homing Missile per MoveAndCollide
|
||||||
|
// tick; PerformAndWatch latches the accumulators into the published
|
||||||
|
// IncomingLock/DistanceToMissile attributes each frame.
|
||||||
|
void ReportIncomingMissile(Scalar range)
|
||||||
|
{
|
||||||
|
incomingLockNext = 1;
|
||||||
|
if (range < distanceToMissileNext)
|
||||||
|
distanceToMissileNext = range;
|
||||||
|
}
|
||||||
// (the members below were and stay PUBLIC -- the recon TUs
|
// (the members below were and stay PUBLIC -- the recon TUs
|
||||||
// (btplayer/dmgtable/mechmppr/emitter) reach them directly)
|
// (btplayer/dmgtable/mechmppr/emitter) reach them directly)
|
||||||
int movementFlags;
|
int movementFlags;
|
||||||
|
|||||||
@@ -5274,6 +5274,15 @@ void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (AUDIO_FIDELITY F7) latch the incoming-missile report accumulated by
|
||||||
|
// Missile::MoveAndCollide since our last frame, then re-arm. The authored
|
||||||
|
// beeper matches incomingLock 1/0 and the tempo scale reads the range --
|
||||||
|
// both polled by ExecuteWatchers below.
|
||||||
|
incomingLock = incomingLockNext;
|
||||||
|
distanceToMissile = distanceToMissileNext;
|
||||||
|
incomingLockNext = 0;
|
||||||
|
distanceToMissileNext = FLT_MAX;
|
||||||
|
|
||||||
if (getenv("BT_AUDIO_LOG")) { static int s_wd=0; if ((s_wd++ % 300)==0)
|
if (getenv("BT_AUDIO_LOG")) { static int s_wd=0; if ((s_wd++ % 300)==0)
|
||||||
DEBUG_STREAM << "[audio] mech watcher poll: delayed=" << (int)AreWatchersDelayed() << " audioWatchers=" << DebugAudioWatcherCount()
|
DEBUG_STREAM << "[audio] mech watcher poll: delayed=" << (int)AreWatchersDelayed() << " audioWatchers=" << DebugAudioWatcherCount()
|
||||||
<< " simFlags=0x" << std::hex << (unsigned)simulationFlags << std::dec
|
<< " simFlags=0x" << std::hex << (unsigned)simulationFlags << std::dec
|
||||||
@@ -5971,3 +5980,19 @@ void
|
|||||||
<< ") rgb=(" << r << "," << g << "," << b << ")" << std::endl;
|
<< ") rgb=(" << r << "," << g << "," << b << ")" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//###########################################################################
|
||||||
|
// BTReportIncomingMissile -- complete-type bridge (F7)
|
||||||
|
//
|
||||||
|
// Missile::MoveAndCollide (missile.cpp, forward-declared Mech only) reports
|
||||||
|
// its target + range each tick; the missile-alarm attributes latch in
|
||||||
|
// Mech::PerformAndWatch. Seeker targets are always mechs in this game
|
||||||
|
// (the launcher's lock); null-guarded.
|
||||||
|
//###########################################################################
|
||||||
|
void BTReportIncomingMissile(Entity *target, Scalar range)
|
||||||
|
{
|
||||||
|
if (target != 0)
|
||||||
|
{
|
||||||
|
((Mech *)target)->ReportIncomingMissile(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -123,16 +123,14 @@ const MechWeapon::IndexEntry
|
|||||||
// binary's (layout static_assert-locked); TriggerState stays the streamed
|
// binary's (layout static_assert-locked); TriggerState stays the streamed
|
||||||
// fire-button binding (id 0x13 PINNED).
|
// fire-button binding (id 0x13 PINNED).
|
||||||
//
|
//
|
||||||
// The five PADS fill our chain-vs-binary id gap (0x0D..0x11) with valid,
|
// The PADS fill our chain-vs-binary id gap (now 0x0F..0x11) with valid,
|
||||||
// named, never-bound entries (the binary's own ids here are the powered/
|
// named, never-bound entries (the binary's own ids here are the powered/
|
||||||
// aux-screen family we don't publish); target = rechargeLevel, harmless.
|
// aux-screen family we don't publish); target = rechargeLevel, harmless.
|
||||||
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 0, "MechWeaponPad0E",
|
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 0, "MechWeaponPad0F",
|
||||||
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
||||||
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 1, "MechWeaponPad0F",
|
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 1, "MechWeaponPad10",
|
||||||
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
||||||
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 2, "MechWeaponPad10",
|
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 2, "MechWeaponPad11",
|
||||||
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
|
||||||
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 3, "MechWeaponPad11",
|
|
||||||
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
||||||
ATTRIBUTE_ENTRY(MechWeapon, PercentDone, rechargeLevel), // 0x12 @0x320
|
ATTRIBUTE_ENTRY(MechWeapon, PercentDone, rechargeLevel), // 0x12 @0x320
|
||||||
ATTRIBUTE_ENTRY(MechWeapon, TriggerState, fireImpulse), // 0x13 @0x31C
|
ATTRIBUTE_ENTRY(MechWeapon, TriggerState, fireImpulse), // 0x13 @0x31C
|
||||||
|
|||||||
@@ -184,12 +184,14 @@ class CockpitHud;
|
|||||||
// is a latent AV (gotcha #11; the old pinned table survived on
|
// is a latent AV (gotcha #11; the old pinned table survived on
|
||||||
// heap luck -- the renumber reshuffled allocations and it fired
|
// heap luck -- the renumber reshuffled allocations and it fired
|
||||||
// live in WeaponCluster's "PercentDone" resolve). Pads below fill
|
// live in WeaponCluster's "PercentDone" resolve). Pads below fill
|
||||||
// ids 0x0E..0x11 (the mech.cpp attrPad idiom). F15: the base
|
// ids 0x0F..0x11 (the mech.cpp attrPad idiom). F15: the base
|
||||||
// MechSubsystem now publishes ConfigureActivePress (binary id 2),
|
// MechSubsystem now publishes ConfigureActivePress (binary id 2),
|
||||||
// shifting the parent chain end 0x0D -> 0x0E -- which matches the
|
// shifting the parent chain end 0x0D -> 0x0E -- which matches the
|
||||||
// binary's own numbering (the old 0x0D chain was one LOW because
|
// binary's own numbering (the old 0x0D chain was one LOW because
|
||||||
// the base attribute was missing). One pad absorbed.
|
// the base attribute was missing). One pad absorbed. F6: HeatSink
|
||||||
MechWeaponPadFirstAttributeID = 0x0E, // == PoweredSubsystem::NextAttributeID (locked below)
|
// now publishes ReportLeak (binary id 12) -> 0x0E -> 0x0F; another
|
||||||
|
// pad absorbed (each authentic parent attr closes the gap by one).
|
||||||
|
MechWeaponPadFirstAttributeID = 0x0F, // == PoweredSubsystem::NextAttributeID (locked below)
|
||||||
PercentDoneAttributeID = 0x12, // @0x320 rechargeLevel
|
PercentDoneAttributeID = 0x12, // @0x320 rechargeLevel
|
||||||
TriggerStateAttributeID, // 0x13 @0x31C (PINNED -- the fire-button binding)
|
TriggerStateAttributeID, // 0x13 @0x31C (PINNED -- the fire-button binding)
|
||||||
DistanceToTargetAttributeID, // 0x14 @0x324 rangeToTarget
|
DistanceToTargetAttributeID, // 0x14 @0x324 rangeToTarget
|
||||||
|
|||||||
@@ -219,6 +219,17 @@ void Missile::MoveAndCollide(Scalar time_slice)
|
|||||||
if (thruster != 0)
|
if (thruster != 0)
|
||||||
thruster->MissileThrusterSimulation(time_slice); // bleed burnTimeRemaining
|
thruster->MissileThrusterSimulation(time_slice); // bleed burnTimeRemaining
|
||||||
|
|
||||||
|
// (AUDIO_FIDELITY F7) report the threat to the homing target: the mech's
|
||||||
|
// IncomingLock/DistanceToMissile attributes (binary @0x3fc/0x400) drive
|
||||||
|
// the authored missile-alarm beeper whose TEMPO rises as we close.
|
||||||
|
if (seeker != 0 && seeker->targetEntity != 0 && (simulationFlags & 1) == 0)
|
||||||
|
{
|
||||||
|
extern void BTReportIncomingMissile(Entity *target, Scalar range);
|
||||||
|
Vector3D to_target;
|
||||||
|
to_target.Subtract(seeker->targetPosition, localOrigin.linearPosition);
|
||||||
|
BTReportIncomingMissile(seeker->targetEntity, to_target.Length());
|
||||||
|
}
|
||||||
|
|
||||||
// --- guidance: build steering toward the Seeker's lead point ----------
|
// --- guidance: build steering toward the Seeker's lead point ----------
|
||||||
Vector3D forward;
|
Vector3D forward;
|
||||||
GetForward(forward); // FUN_0040d150(.., +0x100)
|
GetForward(forward); // FUN_0040d150(.., +0x100)
|
||||||
|
|||||||
Reference in New Issue
Block a user