Audio Phase 1 (AUDIO_FIDELITY F3/F4/F10/F15/F18/F20 + KB): the quick wins

F3 distance: alDistanceModel(AL_NONE); restored the commented authored
  distance multiply in Dynamic3D::CalculateSourceVolumeScale, added the same
  override to Static3D, dropped the (now inert) AL_MAX_DISTANCE writes.  Far
  battle audio follows the authored knee/rolloff curve again, and the volume
  cull / voice steal / ducking chains are distance-aware.
F4 volume law: AL_GAIN = volume_scale^2 at all 3 per-frame sites (Direct/
  Dyn3D/Static3D) -- the GM CC7 squared curve; linear was ~+6 dB at mids.
F10 doppler: alDopplerFactor(0) (AL's model ran wrong constants + sign-
  inverted velocity: approaching sources pitched DOWN); the AUTHORED
  dopplerCents (AUDIO.INI range/speed-of-sound model, decomp-proven consumer
  part_008.c:7466) now adds into the Dynamic3D pitch chain.
F15 ConfigureActivePress: published at the MechSubsystem BASE (binary id 2,
  descriptor @0x50de5c -> +0x110); renamed the misnamed vitalSubsystemIndex
  member (the weapon ConfigureMappables handler already drives it 0/-1).
  Removed the invented Sensor/Myomers duplicates and RESTORED their byte-
  exact layouts (0x328/0x358 allocs + asserts).  MechWeapon's pinned-id pad
  absorbed the +1 chain shift -- which matches the binary's own numbering.
F18 cook-off warning: AmmoBin FireCountdownStarted -> the existing
  cookOffArmed @0x18C (binary table @0x512600); the countdown klaxon can fire.
F20 zoom blip: L4MechControlsMapper publishes TargetRangeExponent -> the live
  @0x1a4 zoom member (own table chained to MechControlsMapper).
KB: replaced the bogus divisionParameters+0x10 rate read with
  SystemClock::GetTicksPerSecond() (FUN_0044e19c is GetFrameRate -- original
  audio frames were CLOCK TICKS).

Regression (35s drive+fire): stable; ConfigureActivePress binds real on all 9
subsystems (idle -1, zero pad redirects); FireCountdownStarted +
TargetRangeExponent bind live members; attrnull 53 -> 41; chirp still dead;
footfalls still fire (gain now correctly squared).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-16 10:43:38 -05:00
co-authored by Claude Opus 4.8
parent 05cb3f5549
commit fc7f311771
16 changed files with 162 additions and 81 deletions
+9 -2
View File
@@ -95,8 +95,15 @@ void
}
headEntitySocket.Add(entity);
alDistanceModel(AL_LINEAR_DISTANCE);
alDopplerFactor(0.3f);
// FIDELITY (AUDIO_FIDELITY.md F3/F10): the engine computes the AUTHORED
// distance-attenuation curve (AUDIO.INI amplitude_rolloff knee/exponent ->
// AudioLocation::distanceVolumeScale) and the authored doppler-cents model.
// Disable OpenAL's own models so they can't double-apply / fight them:
// AL_LINEAR_DISTANCE made far battle audio fade to zero on a straight line
// (-6 dB vs authored at 300u), and AL doppler ran with the wrong constants
// AND a sign-inverted velocity feed (approaching sources pitched DOWN).
alDistanceModel(AL_NONE);
alDopplerFactor(0.0f);
#if 0
//
+34 -18
View File
@@ -1106,8 +1106,7 @@ void
<< " vol=" << volume_scale << "\n" << std::flush; }
for (int i=0; i < channelSet.count; i++)
{
alSourcef(channelSet.sources[i],AL_MAX_DISTANCE,audio_location->getMaxDistance(audio_head));
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale);
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale * volume_scale); // FIDELITY F4: CC7 squared law (linear was ~+6 dB at mid volumes)
}
}
@@ -1439,6 +1438,13 @@ void
pitch_offset = CalculateSourcePitchOffset();
// FIDELITY (AUDIO_FIDELITY.md F10): the AUTHORED doppler (AUDIO.INI
// doppler_range/speed_of_sound -> AudioLocation::dopplerCents, computed each
// spatial update) -- the decomp proves the original added it to the pitch
// cents on THIS dynamic path (part_008.c:7466). AL's own doppler is now
// disabled (it ran with wrong constants and a sign-inverted velocity feed).
pitch_offset += GetAudioLocation()->GetDopplerCents();
double relativePitch = pow(2.0,pitch_offset/1200.0);
Clamp(relativePitch,0.5,2.0);
{ // apply the combined control-chain + note pitch per frame
@@ -1456,9 +1462,8 @@ void
for (int i=0; i < channelSet.count; i++)
{
alSource3f(channelSet.sources[i],AL_POSITION,pos.x,pos.y,pos.z);
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale);
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale * volume_scale); // FIDELITY F4: CC7 squared law (linear was ~+6 dB at mid volumes)
alSource3f(channelSet.sources[i],AL_VELOCITY,-relative_velocity.x,-relative_velocity.y,-relative_velocity.z);
alSourcef(channelSet.sources[i],AL_MAX_DISTANCE,audio_location->getMaxDistance(audio_head));
}
}
@@ -1477,22 +1482,18 @@ AudioControlValue
//
Scalar
volume_scale = L4AudioSource::CalculateSourceVolumeScale();
return volume_scale;
//
// Update the spatial model that will result in the value
// for distance related volume attenuation
//
/*Check(application);
Check(application->GetAudioRenderer());
UpdateSpatialModel(application->GetAudioRenderer()->GetAudioHead());
//
// Apply distance attenuation to the volume scale
//
// FIDELITY (AUDIO_FIDELITY.md F3): apply the AUTHORED distance attenuation
// (AUDIO.INI knee/rolloff curve, computed into distanceVolumeScale on every
// spatial update). This multiply was commented out and AL_LINEAR_DISTANCE
// substituted -- far sounds faded on a straight line to zero instead of the
// authored 1/(1+(k(d-knee))^2) curve, and the volume-based cull / voice
// steal / ducking chains were distance-blind. AL's model is now AL_NONE.
//
Check(GetAudioLocation());
volume_scale *= GetAudioLocation()->GetDistanceVolumeScale();
return volume_scale;*/
return volume_scale;
}
//#############################################################################
@@ -1682,6 +1683,22 @@ void
// StartRequest(this);
}
//
//#############################################################################
//#############################################################################
//
AudioControlValue
Static3DPatchSource::CalculateSourceVolumeScale()
{
Check(this);
// FIDELITY (AUDIO_FIDELITY.md F3): same authored distance attenuation as the
// dynamic path -- the spatial model computes distanceVolumeScale per execute.
Scalar volume_scale = L4AudioSource::CalculateSourceVolumeScale();
Check(GetAudioLocation());
volume_scale *= GetAudioLocation()->GetDistanceVolumeScale();
return volume_scale;
}
//
//#############################################################################
//#############################################################################
@@ -1992,9 +2009,8 @@ void
//Static models have their position freely available as relative positions and stand still
for (int i=0; i < channelSet.count; i++)
{
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale);
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale * volume_scale); // FIDELITY F4: CC7 squared law (linear was ~+6 dB at mid volumes)
alSource3f(channelSet.sources[i],AL_POSITION,relative_position.x,relative_position.y,relative_position.z);
alSourcef(channelSet.sources[i],AL_MAX_DISTANCE,audio_location->getMaxDistance(audio_head));
}
//
+4
View File
@@ -552,6 +552,10 @@ public:
// State implementations
//
public:
// FIDELITY (AUDIO_FIDELITY.md F3): statics get the authored distance curve too
AudioControlValue
CalculateSourceVolumeScale();
void
StartImplementation();
void
+2 -1
View File
@@ -101,7 +101,8 @@ Receiver::MessageHandlerSet AmmoBin::MessageHandlers;
const AmmoBin::IndexEntry
AmmoBin::AttributePointers[]=
{
ATTRIBUTE_ENTRY(AmmoBin, AmmoState, ammoAlarm) // @0x194 (0x54 StateIndicator-compatible feed alarm)
ATTRIBUTE_ENTRY(AmmoBin, AmmoState, ammoAlarm), // @0x194 (0x54 StateIndicator-compatible feed alarm)
ATTRIBUTE_ENTRY(AmmoBin, FireCountdownStarted, cookOffArmed) // F18 @0x18C -- ammo cook-off warning gate
};
Simulation::AttributeIndexSet AmmoBin::AttributeIndex(
+4
View File
@@ -120,6 +120,10 @@
// was a bare, unchained index, so even SimulationState resolved to NULL.
enum {
AmmoStateAttributeID = HeatWatcher::NextAttributeID,
FireCountdownStartedAttributeID, // F18: the ammo COOK-OFF warning (binary
// AmmoBin table @0x512600 -> +0x18C); the 4
// authored start/stop match watchers gate the
// cook-off countdown klaxon on it
NextAttributeID
};
static const IndexEntry AttributePointers[];
+13 -19
View File
@@ -280,27 +280,21 @@ BTL4Application::SharedData
}
//
// FUN_0044e19c read the sample rate as a float out of the division
// parameter block (@+0x10). In WinTesla that block is the public
// L4Application::divisionParameters char*; fall back to 1000.0f (the
// RP default) when it is absent. Second arg is the mission-review
// flag (the 1995 binary hard-coded it off; DAT_004fd550 == 0).
// AUDIO CLOCK RATE (AUDIO_FIDELITY.md KB correction): FUN_0044e19c is
// ApplicationManager::GetFrameRate() -- the ORIGINAL audio "frames" were
// system CLOCK TICKS (the DOS 18.2/28 Hz timer), not a sample rate. The
// old port read a float from divisionParameters+0x10 (a raw 1995-layout
// offset = garbage, -1.6e14 measured). The Windows equivalent of the
// original semantic is the system tick rate: AudioHead::Execute stamps
// audioFrameCount from SystemClock ticks, so calibrating the renderer to
// the same tick rate keeps every AudioTime conversion unit-consistent.
//
RendererRate sample_rate =
divisionParameters
? (RendererRate)*reinterpret_cast<float*>(divisionParameters + 0x10)
: (RendererRate)1000.0f;
// DATABINDING GUARD (task #50): divisionParameters is a raw engine block
// pointer and +0x10 is a 1995-layout offset; on the port it read GARBAGE
// (-1.6e14 measured), poisoning calibrationRate -> every AudioTime
// conversion (sequence event scheduling, compression durations) broke,
// which is why AudioControlSequence timeline events (footstep volumes!)
// never landed. Sanity-clamp to the authored 1000 frames/sec default.
if (!(sample_rate > 0.0f && sample_rate <= 100000.0f))
sample_rate = (RendererRate)1000.0f;
long ticks_per_second = SystemClock::GetTicksPerSecond();
if (ticks_per_second <= 0) ticks_per_second = 1000; // GetTickCount ms (static not yet measured)
RendererRate sample_rate = (RendererRate)ticks_per_second;
if (getenv("BT_AUDIO_LOG"))
DEBUG_STREAM << "[audio] renderer sample_rate=" << sample_rate
<< " (divisionParameters=" << (void*)divisionParameters << ")" << "\n" << std::flush;
DEBUG_STREAM << "[audio] renderer calibration rate=" << sample_rate
<< " (SystemClock ticks/sec)" << "\n" << std::flush;
return
new BTL4AudioRenderer(
+21 -1
View File
@@ -244,11 +244,31 @@ static void
//#############################################################################
// Shared Data Support
//
// TargetRangeExponent -> the live @0x1a4 zoom member (AUDIO_FIDELITY.md F20):
// the authored AudioScalarDeltaTrigger blips per zoom step; it bound NULL until
// this publication. Chained to MechControlsMapper's dense index.
const L4MechControlsMapper::IndexEntry
L4MechControlsMapper::AttributePointers[]=
{
ATTRIBUTE_ENTRY(L4MechControlsMapper, TargetRangeExponent, targetRangeExponent) // @0x1a4
};
L4MechControlsMapper::AttributeIndexSet&
L4MechControlsMapper::GetAttributeIndex()
{
static L4MechControlsMapper::AttributeIndexSet attributeIndex(
ELEMENTS(L4MechControlsMapper::AttributePointers),
L4MechControlsMapper::AttributePointers,
MechControlsMapper::GetAttributeIndex()
);
return attributeIndex;
}
L4MechControlsMapper::SharedData
L4MechControlsMapper::DefaultData(
L4MechControlsMapper::GetClassDerivations(),
L4MechControlsMapper::GetMessageHandlers(),
L4MechControlsMapper::GetAttributeIndex(), // inherited from MechControlsMapper
L4MechControlsMapper::GetAttributeIndex(), // own table -> chained to MechControlsMapper
L4MechControlsMapper::StateCount
);
+14
View File
@@ -159,6 +159,20 @@
);
~L4MechControlsMapper(); // @004d1814
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support (AUDIO_FIDELITY.md F20): the authored zoom-blip
// AudioScalarDeltaTrigger binds ControlsMapper/TargetRangeExponent -- the
// live @0x1a4 member that slews every frame. Chained to the parent index;
// Thrustmaster/RIO inherit this accessor.
//
public:
enum {
TargetRangeExponentAttributeID = MechControlsMapper::NextAttributeID,
L4NextAttributeID
};
static const IndexEntry AttributePointers[];
static AttributeIndexSet& GetAttributeIndex();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected data (object grows to >= 0x1bc)
//
+21 -3
View File
@@ -89,11 +89,29 @@ static const StatusNameEntry StatusNameTable[] =
//#############################################################################
// Shared Data Support
//
// ConfigureActivePress -> the +0x110 session flag (AUDIO_FIDELITY.md F15).
const MechSubsystem::IndexEntry
MechSubsystem::AttributePointers[]=
{
ATTRIBUTE_ENTRY(MechSubsystem, ConfigureActivePress, configureActivePress) // id 2 @0x110
};
MechSubsystem::AttributeIndexSet&
MechSubsystem::GetAttributeIndex()
{
static MechSubsystem::AttributeIndexSet attributeIndex(
ELEMENTS(MechSubsystem::AttributePointers),
MechSubsystem::AttributePointers,
Simulation::GetAttributeIndex()
);
return attributeIndex;
}
MechSubsystem::SharedData
MechSubsystem::DefaultData(
&MechSubsystem::ClassDerivations,
ReconMessageHandlers,
ReconAttributeIndex,
MechSubsystem::GetAttributeIndex(),
MechSubsystem::StateCount
);
@@ -132,7 +150,7 @@ MechSubsystem::MechSubsystem(
criticalReference = 0; // this[0x42]
collisionCriticalHitWeight = 0; // this[0x43]
printSimulationState = 0; // this[0x41]
vitalSubsystemIndex = -1; // this[0x44]
configureActivePress = -1; // this[0x44] configure-session idle
damageZone = (ReconDamageZone *)new DamageZone(this, 0); // this[0x38] = FUN_0041de1c(new 0x160, this, 0)
}
@@ -162,7 +180,7 @@ MechSubsystem::MechSubsystem(
controlDestination = 0; // this[0x3a]=param_6 (ctor pass-through;
controlMessageID = 0; // this[0x3b]=param_7 weapons override -- task #6)
resource = subsystem_resource; // this[0x3c]
vitalSubsystemIndex = -1; // this[0x44]
configureActivePress = -1; // this[0x44] configure-session idle
vitalSubsystem = (subsystem_resource->vitalSubsystemIndex == 1); // res+0x48==1
BindName(refCount, subsystem_resource->videoObjectName); // res+0x4c
+19 -1
View File
@@ -137,6 +137,21 @@ class Damage;
static Recon MessageHandlers; // SharedData ctor operand
enum { StateCount = 7 }; // TechStatusTypeCount
// Attribute Support (AUDIO_FIDELITY.md F15): the binary registers
// ConfigureActivePress as a MechSubsystem-BASE attribute (id 2,
// descriptor @0x50de5c -> subsystem+0x110) -- the configure-session
// flag every weapon's ConfigureMappables handler drives (0 open /
// -1 idle) and the authored configure-ticker audio watches at
// thresh=-1. Publishing here makes it resolve on EVERY subsystem
// (each reads its own +0x110) and restores the binary-authentic
// dense id numbering (children start at 3, not 2).
enum {
ConfigureActivePressAttributeID = Simulation::NextAttributeID, // 2
NextAttributeID // 3
};
static const IndexEntry AttributePointers[];
static AttributeIndexSet& GetAttributeIndex();
// alarm-changed callback (vtable slot +0x34) + host back-pointer
void OnAlarmChanged();
Mech *owner; // owning mech (== hostEntity)
@@ -307,7 +322,10 @@ class Damage;
int printSimulationState; // @0x104 this[0x41]
Scalar criticalReference; // @0x108 this[0x42]
Scalar collisionCriticalHitWeight; // @0x10C this[0x43]
int vitalSubsystemIndex; // @0x110 this[0x44] (default -1)
int configureActivePress; // @0x110 this[0x44] (default -1) -- the
// configure-session flag (was misnamed
// vitalSubsystemIndex; the reader is the
// authored audio configure-ticker, F15)
};
#endif
+7 -9
View File
@@ -126,15 +126,13 @@ const MechWeapon::IndexEntry
// The five PADS fill our chain-vs-binary id gap (0x0D..0x11) with valid,
// named, never-bound entries (the binary's own ids here are the powered/
// aux-screen family we don't publish); target = rechargeLevel, harmless.
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 0, "MechWeaponPad0D",
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 0, "MechWeaponPad0E",
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 1, "MechWeaponPad0E",
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 1, "MechWeaponPad0F",
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 2, "MechWeaponPad0F",
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 2, "MechWeaponPad10",
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 3, "MechWeaponPad10",
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 4, "MechWeaponPad11",
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 3, "MechWeaponPad11",
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
ATTRIBUTE_ENTRY(MechWeapon, PercentDone, rechargeLevel), // 0x12 @0x320
ATTRIBUTE_ENTRY(MechWeapon, TriggerState, fireImpulse), // 0x13 @0x31C
@@ -183,7 +181,7 @@ MechWeapon::SharedData
// Release: close the session (mode restored, temp layer stripped).
// The +0x110 write (0 open / -1 idle) is the binary's config-session flag
// (ctor default -1, part_012.c:15775); the port field carries the older name
// vitalSubsystemIndex -- no confirmed reader yet (read-site survey pending).
// configureActivePress -- the reader is the authored audio configure ticker (F15).
//
void
MechWeapon::ConfigureMappablesMessageHandler(
@@ -205,11 +203,11 @@ void
if (value < 1)
{
mapper->ExitConfiguration(element); // vtbl+0x3C
vitalSubsystemIndex = -1; // this+0x110 -> idle
configureActivePress = -1; // this+0x110 -> idle (audio ticker OFF)
}
else
{
vitalSubsystemIndex = 0; // this+0x110 -> session open
configureActivePress = 0; // this+0x110 -> session open (audio ticker ON)
mapper->EnterConfiguration( // vtbl+0x38
element,
(ControlsButton *)&fireImpulse, // this+0x31C (TriggerState)
+6 -2
View File
@@ -184,8 +184,12 @@ class CockpitHud;
// is a latent AV (gotcha #11; the old pinned table survived on
// heap luck -- the renumber reshuffled allocations and it fired
// live in WeaponCluster's "PercentDone" resolve). Pads below fill
// ids 0x0D..0x11 (the mech.cpp attrPad idiom).
MechWeaponPadFirstAttributeID = 0x0D, // == PoweredSubsystem::NextAttributeID (locked below)
// ids 0x0E..0x11 (the mech.cpp attrPad idiom). F15: the base
// MechSubsystem now publishes ConfigureActivePress (binary id 2),
// shifting the parent chain end 0x0D -> 0x0E -- which matches the
// binary's own numbering (the old 0x0D chain was one LOW because
// the base attribute was missing). One pad absorbed.
MechWeaponPadFirstAttributeID = 0x0E, // == PoweredSubsystem::NextAttributeID (locked below)
PercentDoneAttributeID = 0x12, // @0x320 rechargeLevel
TriggerStateAttributeID, // 0x13 @0x31C (PINNED -- the fire-button binding)
DistanceToTargetAttributeID, // 0x14 @0x324 rangeToTarget
+3 -6
View File
@@ -102,8 +102,7 @@ Myomers::AttributeIndexSet&
ATTRIBUTE_ENTRY(Myomers, MinSeekVoltageIndex, minSeekVoltageIndex), // 0x15 @0x328
ATTRIBUTE_ENTRY(Myomers, MaxSeekVoltageIndex, maxSeekVoltageIndex), // 0x16 @0x32C
ATTRIBUTE_ENTRY(Myomers, SeekVoltage, seekVoltage), // 0x17 @0x330 (array base)
ATTRIBUTE_ENTRY(Myomers, OutputVoltage, outputVoltage), // 0x18 @0x344
ATTRIBUTE_ENTRY(Myomers, ConfigureActivePress, configureActivePress) // 0x19 audio configure-ticker gate
ATTRIBUTE_ENTRY(Myomers, OutputVoltage, outputVoltage) // 0x18 @0x344
};
static Myomers::AttributeIndexSet attributeIndex(
ELEMENTS(entries), entries,
@@ -165,7 +164,6 @@ Myomers::Myomers(
// vtable @005117dc installed by the compiler here.
speedEffect = 1.0f; // @0x31C
configureActivePress = -1; // APPENDED: no configure button held
heatRange = failureTemperature - degradationTemperature; // @0x348 (this[0x11C]-this[0x118])
heatRangeSquared = heatRange * heatRange; // @0x34C
velocityEfficiency = resource->velocityEfficiency; // @0x350 res+0x190
@@ -571,7 +569,7 @@ struct MyomersLayoutCheck
// .. accelerationEfficiency@0x354) land exactly at 0x31C..0x358.
static_assert(offsetof(Myomers, speedEffect) == 0x31C, "Myomers::speedEffect @0x31C (attr 0x12)");
static_assert(offsetof(Myomers, seekVoltage) == 0x330, "Myomers::seekVoltage @0x330 (attr 0x17)");
static_assert(sizeof(Myomers) == 0x35C, "sizeof(Myomers) 0x358 binary + 4 appended (alloc bumped in CreateMyomersSubsystem)");
static_assert(sizeof(Myomers) == 0x358, "sizeof(Myomers) 0x358 (factory alloc, byte-exact)");
};
@@ -586,7 +584,6 @@ struct MyomersLayoutCheck
//===========================================================================//
Subsystem *CreateMyomersSubsystem(Mech *owner, int id, void *seg)
{
// 0x35C = the 0x358 binary object + 4 appended (configureActivePress; sizeof lock bumped too)
return (Subsystem *) new (Memory::Allocate(0x35C))
return (Subsystem *) new (Memory::Allocate(0x358))
Myomers(owner, id, (Myomers::SubsystemResource *)seg);
}
+1 -7
View File
@@ -162,8 +162,7 @@ class Mech;
MaxSeekVoltageIndexAttributeID, // 0x16
SeekVoltageAttributeID, // 0x17
OutputVoltageAttributeID, // 0x18
ConfigureActivePressAttributeID, // 0x19 audio configure-ticker gate (idle -1)
NextAttributeID // 0x1a
NextAttributeID // 0x19
};
private:
@@ -341,11 +340,6 @@ class Mech;
Scalar heatRangeSquared; // @0x34C ctor = heatRange*heatRange (degradation-curve denominator)
Scalar velocityEfficiency; // @0x350 resource +0x190
Scalar accelerationEfficiency; // @0x354 resource +0x194
int configureActivePress; // @0x358 APPENDED (audio): configure held-button
// index; -1 = none. The audio configure-ticker gates
// on > -1; the inert-pad 0 ticked forever (the chirp).
// Alloc + sizeof lock bumped 0x358 -> 0x35C together.
friend struct MyomersLayoutCheck;
};
+3 -6
View File
@@ -117,8 +117,7 @@ const Sensor::IndexEntry
{
ATTRIBUTE_ENTRY(Sensor, RadarPercent, radarPercent), // @0x31C (map capabilities ratio)
ATTRIBUTE_ENTRY(Sensor, SelfTest, selfTest),
ATTRIBUTE_ENTRY(Sensor, BadVoltage, badVoltage),
ATTRIBUTE_ENTRY(Sensor, ConfigureActivePress, configureActivePress) // audio configure-ticker gate
ATTRIBUTE_ENTRY(Sensor, BadVoltage, badVoltage)
};
Sensor::AttributeIndexSet
@@ -163,7 +162,6 @@ Sensor::Sensor(
radarPercent = RadarBaseline; // @0x31C = 1.0f
selfTest = False; // @0x320 = 0
badVoltage = False; // @0x324 = 0
configureActivePress = -1; // APPENDED: no configure button held (audio ticker OFF)
// this[0x28] |= 0x8 -- flag "has an active per-frame Performance".
SetHasPerformanceFlag(); // param_1[10] |= 8
@@ -412,7 +410,7 @@ struct SensorLayoutCheck
static_assert(offsetof(Sensor, radarPercent) == 0x31C, "Sensor::radarPercent @0x31C (attr 0x12)");
static_assert(offsetof(Sensor, selfTest) == 0x320, "Sensor::selfTest @0x320");
static_assert(offsetof(Sensor, badVoltage) == 0x324, "Sensor::badVoltage @0x324");
static_assert(sizeof(Sensor) == 0x32C, "sizeof(Sensor) 0x328 binary + 4 appended (alloc bumped in CreateSensorSubsystem)");
static_assert(sizeof(Sensor) == 0x328, "sizeof(Sensor) 0x328 (factory alloc, byte-exact)");
};
@@ -426,7 +424,6 @@ struct SensorLayoutCheck
//===========================================================================//
Subsystem *CreateSensorSubsystem(Mech *owner, int id, void *seg)
{
// 0x32C = the 0x328 binary object + 4 appended (configureActivePress; sizeof lock bumped too)
return (Subsystem *) new (Memory::Allocate(0x32C))
return (Subsystem *) new (Memory::Allocate(0x328))
Sensor(owner, id, (Sensor::SubsystemResource *)seg);
}
+1 -6
View File
@@ -149,7 +149,6 @@
RadarPercentAttributeID = PoweredSubsystem::NextAttributeID,
SelfTestAttributeID,
BadVoltageAttributeID,
ConfigureActivePressAttributeID, // audio configure-ticker gate (idle -1)
NextAttributeID
};
@@ -167,11 +166,7 @@
Logical
selfTest, // @0x320 ctor init 0
badVoltage; // @0x324 ctor init 0
int
configureActivePress; // APPENDED (audio): the cockpit-configure held-button
// index; -1 = none. The audio config gates the
// configure-mode ticker on this > -1 -- the inert-pad 0
// read as "button 0 held" and ticked FOREVER (the chirp).
//##########################################################################