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:
co-authored by
Claude Opus 4.8
parent
05cb3f5549
commit
fc7f311771
@@ -95,8 +95,15 @@ void
|
|||||||
}
|
}
|
||||||
headEntitySocket.Add(entity);
|
headEntitySocket.Add(entity);
|
||||||
|
|
||||||
alDistanceModel(AL_LINEAR_DISTANCE);
|
// FIDELITY (AUDIO_FIDELITY.md F3/F10): the engine computes the AUTHORED
|
||||||
alDopplerFactor(0.3f);
|
// 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
|
#if 0
|
||||||
//
|
//
|
||||||
|
|||||||
+34
-18
@@ -1106,8 +1106,7 @@ void
|
|||||||
<< " vol=" << volume_scale << "\n" << std::flush; }
|
<< " vol=" << volume_scale << "\n" << std::flush; }
|
||||||
for (int i=0; i < channelSet.count; i++)
|
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 * volume_scale); // FIDELITY F4: CC7 squared law (linear was ~+6 dB at mid volumes)
|
||||||
alSourcef(channelSet.sources[i], AL_GAIN, volume_scale);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1439,6 +1438,13 @@ void
|
|||||||
|
|
||||||
pitch_offset = CalculateSourcePitchOffset();
|
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);
|
double relativePitch = pow(2.0,pitch_offset/1200.0);
|
||||||
Clamp(relativePitch,0.5,2.0);
|
Clamp(relativePitch,0.5,2.0);
|
||||||
{ // apply the combined control-chain + note pitch per frame
|
{ // apply the combined control-chain + note pitch per frame
|
||||||
@@ -1456,9 +1462,8 @@ void
|
|||||||
for (int i=0; i < channelSet.count; i++)
|
for (int i=0; i < channelSet.count; i++)
|
||||||
{
|
{
|
||||||
alSource3f(channelSet.sources[i],AL_POSITION,pos.x,pos.y,pos.z);
|
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);
|
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
|
Scalar
|
||||||
volume_scale = L4AudioSource::CalculateSourceVolumeScale();
|
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());
|
Check(GetAudioLocation());
|
||||||
volume_scale *= GetAudioLocation()->GetDistanceVolumeScale();
|
volume_scale *= GetAudioLocation()->GetDistanceVolumeScale();
|
||||||
return volume_scale;*/
|
return volume_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#############################################################################
|
//#############################################################################
|
||||||
@@ -1682,6 +1683,22 @@ void
|
|||||||
// StartRequest(this);
|
// 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
|
//Static models have their position freely available as relative positions and stand still
|
||||||
for (int i=0; i < channelSet.count; i++)
|
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);
|
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -552,6 +552,10 @@ public:
|
|||||||
// State implementations
|
// State implementations
|
||||||
//
|
//
|
||||||
public:
|
public:
|
||||||
|
// FIDELITY (AUDIO_FIDELITY.md F3): statics get the authored distance curve too
|
||||||
|
AudioControlValue
|
||||||
|
CalculateSourceVolumeScale();
|
||||||
|
|
||||||
void
|
void
|
||||||
StartImplementation();
|
StartImplementation();
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ Receiver::MessageHandlerSet AmmoBin::MessageHandlers;
|
|||||||
const AmmoBin::IndexEntry
|
const AmmoBin::IndexEntry
|
||||||
AmmoBin::AttributePointers[]=
|
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(
|
Simulation::AttributeIndexSet AmmoBin::AttributeIndex(
|
||||||
|
|||||||
@@ -120,6 +120,10 @@
|
|||||||
// was a bare, unchained index, so even SimulationState resolved to NULL.
|
// was a bare, unchained index, so even SimulationState resolved to NULL.
|
||||||
enum {
|
enum {
|
||||||
AmmoStateAttributeID = HeatWatcher::NextAttributeID,
|
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
|
NextAttributeID
|
||||||
};
|
};
|
||||||
static const IndexEntry AttributePointers[];
|
static const IndexEntry AttributePointers[];
|
||||||
|
|||||||
@@ -280,27 +280,21 @@ BTL4Application::SharedData
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// FUN_0044e19c read the sample rate as a float out of the division
|
// AUDIO CLOCK RATE (AUDIO_FIDELITY.md KB correction): FUN_0044e19c is
|
||||||
// parameter block (@+0x10). In WinTesla that block is the public
|
// ApplicationManager::GetFrameRate() -- the ORIGINAL audio "frames" were
|
||||||
// L4Application::divisionParameters char*; fall back to 1000.0f (the
|
// system CLOCK TICKS (the DOS 18.2/28 Hz timer), not a sample rate. The
|
||||||
// RP default) when it is absent. Second arg is the mission-review
|
// old port read a float from divisionParameters+0x10 (a raw 1995-layout
|
||||||
// flag (the 1995 binary hard-coded it off; DAT_004fd550 == 0).
|
// 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 =
|
long ticks_per_second = SystemClock::GetTicksPerSecond();
|
||||||
divisionParameters
|
if (ticks_per_second <= 0) ticks_per_second = 1000; // GetTickCount ms (static not yet measured)
|
||||||
? (RendererRate)*reinterpret_cast<float*>(divisionParameters + 0x10)
|
RendererRate sample_rate = (RendererRate)ticks_per_second;
|
||||||
: (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;
|
|
||||||
if (getenv("BT_AUDIO_LOG"))
|
if (getenv("BT_AUDIO_LOG"))
|
||||||
DEBUG_STREAM << "[audio] renderer sample_rate=" << sample_rate
|
DEBUG_STREAM << "[audio] renderer calibration rate=" << sample_rate
|
||||||
<< " (divisionParameters=" << (void*)divisionParameters << ")" << "\n" << std::flush;
|
<< " (SystemClock ticks/sec)" << "\n" << std::flush;
|
||||||
|
|
||||||
return
|
return
|
||||||
new BTL4AudioRenderer(
|
new BTL4AudioRenderer(
|
||||||
|
|||||||
@@ -244,11 +244,31 @@ static void
|
|||||||
//#############################################################################
|
//#############################################################################
|
||||||
// Shared Data Support
|
// 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::SharedData
|
||||||
L4MechControlsMapper::DefaultData(
|
L4MechControlsMapper::DefaultData(
|
||||||
L4MechControlsMapper::GetClassDerivations(),
|
L4MechControlsMapper::GetClassDerivations(),
|
||||||
L4MechControlsMapper::GetMessageHandlers(),
|
L4MechControlsMapper::GetMessageHandlers(),
|
||||||
L4MechControlsMapper::GetAttributeIndex(), // inherited from MechControlsMapper
|
L4MechControlsMapper::GetAttributeIndex(), // own table -> chained to MechControlsMapper
|
||||||
L4MechControlsMapper::StateCount
|
L4MechControlsMapper::StateCount
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -159,6 +159,20 @@
|
|||||||
);
|
);
|
||||||
~L4MechControlsMapper(); // @004d1814
|
~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)
|
// Protected data (object grows to >= 0x1bc)
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -89,11 +89,29 @@ static const StatusNameEntry StatusNameTable[] =
|
|||||||
//#############################################################################
|
//#############################################################################
|
||||||
// Shared Data Support
|
// 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::SharedData
|
||||||
MechSubsystem::DefaultData(
|
MechSubsystem::DefaultData(
|
||||||
&MechSubsystem::ClassDerivations,
|
&MechSubsystem::ClassDerivations,
|
||||||
ReconMessageHandlers,
|
ReconMessageHandlers,
|
||||||
ReconAttributeIndex,
|
MechSubsystem::GetAttributeIndex(),
|
||||||
MechSubsystem::StateCount
|
MechSubsystem::StateCount
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -132,7 +150,7 @@ MechSubsystem::MechSubsystem(
|
|||||||
criticalReference = 0; // this[0x42]
|
criticalReference = 0; // this[0x42]
|
||||||
collisionCriticalHitWeight = 0; // this[0x43]
|
collisionCriticalHitWeight = 0; // this[0x43]
|
||||||
printSimulationState = 0; // this[0x41]
|
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)
|
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;
|
controlDestination = 0; // this[0x3a]=param_6 (ctor pass-through;
|
||||||
controlMessageID = 0; // this[0x3b]=param_7 weapons override -- task #6)
|
controlMessageID = 0; // this[0x3b]=param_7 weapons override -- task #6)
|
||||||
resource = subsystem_resource; // this[0x3c]
|
resource = subsystem_resource; // this[0x3c]
|
||||||
vitalSubsystemIndex = -1; // this[0x44]
|
configureActivePress = -1; // this[0x44] configure-session idle
|
||||||
vitalSubsystem = (subsystem_resource->vitalSubsystemIndex == 1); // res+0x48==1
|
vitalSubsystem = (subsystem_resource->vitalSubsystemIndex == 1); // res+0x48==1
|
||||||
|
|
||||||
BindName(refCount, subsystem_resource->videoObjectName); // res+0x4c
|
BindName(refCount, subsystem_resource->videoObjectName); // res+0x4c
|
||||||
|
|||||||
@@ -137,6 +137,21 @@ class Damage;
|
|||||||
static Recon MessageHandlers; // SharedData ctor operand
|
static Recon MessageHandlers; // SharedData ctor operand
|
||||||
enum { StateCount = 7 }; // TechStatusTypeCount
|
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
|
// alarm-changed callback (vtable slot +0x34) + host back-pointer
|
||||||
void OnAlarmChanged();
|
void OnAlarmChanged();
|
||||||
Mech *owner; // owning mech (== hostEntity)
|
Mech *owner; // owning mech (== hostEntity)
|
||||||
@@ -307,7 +322,10 @@ class Damage;
|
|||||||
int printSimulationState; // @0x104 this[0x41]
|
int printSimulationState; // @0x104 this[0x41]
|
||||||
Scalar criticalReference; // @0x108 this[0x42]
|
Scalar criticalReference; // @0x108 this[0x42]
|
||||||
Scalar collisionCriticalHitWeight; // @0x10C this[0x43]
|
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
|
#endif
|
||||||
|
|||||||
@@ -126,15 +126,13 @@ const MechWeapon::IndexEntry
|
|||||||
// The five PADS fill our chain-vs-binary id gap (0x0D..0x11) with valid,
|
// 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/
|
// 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, "MechWeaponPad0D",
|
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 0, "MechWeaponPad0E",
|
||||||
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
||||||
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 1, "MechWeaponPad0E",
|
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 1, "MechWeaponPad0F",
|
||||||
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
||||||
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 2, "MechWeaponPad0F",
|
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 2, "MechWeaponPad10",
|
||||||
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
||||||
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 3, "MechWeaponPad10",
|
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 3, "MechWeaponPad11",
|
||||||
(Simulation::AttributePointer)&MechWeapon::rechargeLevel },
|
|
||||||
{ (int)MechWeapon::MechWeaponPadFirstAttributeID + 4, "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
|
||||||
@@ -183,7 +181,7 @@ MechWeapon::SharedData
|
|||||||
// Release: close the session (mode restored, temp layer stripped).
|
// Release: close the session (mode restored, temp layer stripped).
|
||||||
// The +0x110 write (0 open / -1 idle) is the binary's config-session flag
|
// 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
|
// (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
|
void
|
||||||
MechWeapon::ConfigureMappablesMessageHandler(
|
MechWeapon::ConfigureMappablesMessageHandler(
|
||||||
@@ -205,11 +203,11 @@ void
|
|||||||
if (value < 1)
|
if (value < 1)
|
||||||
{
|
{
|
||||||
mapper->ExitConfiguration(element); // vtbl+0x3C
|
mapper->ExitConfiguration(element); // vtbl+0x3C
|
||||||
vitalSubsystemIndex = -1; // this+0x110 -> idle
|
configureActivePress = -1; // this+0x110 -> idle (audio ticker OFF)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vitalSubsystemIndex = 0; // this+0x110 -> session open
|
configureActivePress = 0; // this+0x110 -> session open (audio ticker ON)
|
||||||
mapper->EnterConfiguration( // vtbl+0x38
|
mapper->EnterConfiguration( // vtbl+0x38
|
||||||
element,
|
element,
|
||||||
(ControlsButton *)&fireImpulse, // this+0x31C (TriggerState)
|
(ControlsButton *)&fireImpulse, // this+0x31C (TriggerState)
|
||||||
|
|||||||
@@ -184,8 +184,12 @@ 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 0x0D..0x11 (the mech.cpp attrPad idiom).
|
// ids 0x0E..0x11 (the mech.cpp attrPad idiom). F15: the base
|
||||||
MechWeaponPadFirstAttributeID = 0x0D, // == PoweredSubsystem::NextAttributeID (locked below)
|
// 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
|
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
|
||||||
|
|||||||
@@ -102,8 +102,7 @@ Myomers::AttributeIndexSet&
|
|||||||
ATTRIBUTE_ENTRY(Myomers, MinSeekVoltageIndex, minSeekVoltageIndex), // 0x15 @0x328
|
ATTRIBUTE_ENTRY(Myomers, MinSeekVoltageIndex, minSeekVoltageIndex), // 0x15 @0x328
|
||||||
ATTRIBUTE_ENTRY(Myomers, MaxSeekVoltageIndex, maxSeekVoltageIndex), // 0x16 @0x32C
|
ATTRIBUTE_ENTRY(Myomers, MaxSeekVoltageIndex, maxSeekVoltageIndex), // 0x16 @0x32C
|
||||||
ATTRIBUTE_ENTRY(Myomers, SeekVoltage, seekVoltage), // 0x17 @0x330 (array base)
|
ATTRIBUTE_ENTRY(Myomers, SeekVoltage, seekVoltage), // 0x17 @0x330 (array base)
|
||||||
ATTRIBUTE_ENTRY(Myomers, OutputVoltage, outputVoltage), // 0x18 @0x344
|
ATTRIBUTE_ENTRY(Myomers, OutputVoltage, outputVoltage) // 0x18 @0x344
|
||||||
ATTRIBUTE_ENTRY(Myomers, ConfigureActivePress, configureActivePress) // 0x19 audio configure-ticker gate
|
|
||||||
};
|
};
|
||||||
static Myomers::AttributeIndexSet attributeIndex(
|
static Myomers::AttributeIndexSet attributeIndex(
|
||||||
ELEMENTS(entries), entries,
|
ELEMENTS(entries), entries,
|
||||||
@@ -165,7 +164,6 @@ Myomers::Myomers(
|
|||||||
// vtable @005117dc installed by the compiler here.
|
// vtable @005117dc installed by the compiler here.
|
||||||
|
|
||||||
speedEffect = 1.0f; // @0x31C
|
speedEffect = 1.0f; // @0x31C
|
||||||
configureActivePress = -1; // APPENDED: no configure button held
|
|
||||||
heatRange = failureTemperature - degradationTemperature; // @0x348 (this[0x11C]-this[0x118])
|
heatRange = failureTemperature - degradationTemperature; // @0x348 (this[0x11C]-this[0x118])
|
||||||
heatRangeSquared = heatRange * heatRange; // @0x34C
|
heatRangeSquared = heatRange * heatRange; // @0x34C
|
||||||
velocityEfficiency = resource->velocityEfficiency; // @0x350 res+0x190
|
velocityEfficiency = resource->velocityEfficiency; // @0x350 res+0x190
|
||||||
@@ -571,7 +569,7 @@ struct MyomersLayoutCheck
|
|||||||
// .. accelerationEfficiency@0x354) land exactly at 0x31C..0x358.
|
// .. accelerationEfficiency@0x354) land exactly at 0x31C..0x358.
|
||||||
static_assert(offsetof(Myomers, speedEffect) == 0x31C, "Myomers::speedEffect @0x31C (attr 0x12)");
|
static_assert(offsetof(Myomers, speedEffect) == 0x31C, "Myomers::speedEffect @0x31C (attr 0x12)");
|
||||||
static_assert(offsetof(Myomers, seekVoltage) == 0x330, "Myomers::seekVoltage @0x330 (attr 0x17)");
|
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)
|
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(0x358))
|
||||||
return (Subsystem *) new (Memory::Allocate(0x35C))
|
|
||||||
Myomers(owner, id, (Myomers::SubsystemResource *)seg);
|
Myomers(owner, id, (Myomers::SubsystemResource *)seg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,8 +162,7 @@ class Mech;
|
|||||||
MaxSeekVoltageIndexAttributeID, // 0x16
|
MaxSeekVoltageIndexAttributeID, // 0x16
|
||||||
SeekVoltageAttributeID, // 0x17
|
SeekVoltageAttributeID, // 0x17
|
||||||
OutputVoltageAttributeID, // 0x18
|
OutputVoltageAttributeID, // 0x18
|
||||||
ConfigureActivePressAttributeID, // 0x19 audio configure-ticker gate (idle -1)
|
NextAttributeID // 0x19
|
||||||
NextAttributeID // 0x1a
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -341,11 +340,6 @@ class Mech;
|
|||||||
Scalar heatRangeSquared; // @0x34C ctor = heatRange*heatRange (degradation-curve denominator)
|
Scalar heatRangeSquared; // @0x34C ctor = heatRange*heatRange (degradation-curve denominator)
|
||||||
Scalar velocityEfficiency; // @0x350 resource +0x190
|
Scalar velocityEfficiency; // @0x350 resource +0x190
|
||||||
Scalar accelerationEfficiency; // @0x354 resource +0x194
|
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;
|
friend struct MyomersLayoutCheck;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -117,8 +117,7 @@ const Sensor::IndexEntry
|
|||||||
{
|
{
|
||||||
ATTRIBUTE_ENTRY(Sensor, RadarPercent, radarPercent), // @0x31C (map capabilities ratio)
|
ATTRIBUTE_ENTRY(Sensor, RadarPercent, radarPercent), // @0x31C (map capabilities ratio)
|
||||||
ATTRIBUTE_ENTRY(Sensor, SelfTest, selfTest),
|
ATTRIBUTE_ENTRY(Sensor, SelfTest, selfTest),
|
||||||
ATTRIBUTE_ENTRY(Sensor, BadVoltage, badVoltage),
|
ATTRIBUTE_ENTRY(Sensor, BadVoltage, badVoltage)
|
||||||
ATTRIBUTE_ENTRY(Sensor, ConfigureActivePress, configureActivePress) // audio configure-ticker gate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Sensor::AttributeIndexSet
|
Sensor::AttributeIndexSet
|
||||||
@@ -163,7 +162,6 @@ Sensor::Sensor(
|
|||||||
radarPercent = RadarBaseline; // @0x31C = 1.0f
|
radarPercent = RadarBaseline; // @0x31C = 1.0f
|
||||||
selfTest = False; // @0x320 = 0
|
selfTest = False; // @0x320 = 0
|
||||||
badVoltage = False; // @0x324 = 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".
|
// this[0x28] |= 0x8 -- flag "has an active per-frame Performance".
|
||||||
SetHasPerformanceFlag(); // param_1[10] |= 8
|
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, radarPercent) == 0x31C, "Sensor::radarPercent @0x31C (attr 0x12)");
|
||||||
static_assert(offsetof(Sensor, selfTest) == 0x320, "Sensor::selfTest @0x320");
|
static_assert(offsetof(Sensor, selfTest) == 0x320, "Sensor::selfTest @0x320");
|
||||||
static_assert(offsetof(Sensor, badVoltage) == 0x324, "Sensor::badVoltage @0x324");
|
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)
|
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(0x328))
|
||||||
return (Subsystem *) new (Memory::Allocate(0x32C))
|
|
||||||
Sensor(owner, id, (Sensor::SubsystemResource *)seg);
|
Sensor(owner, id, (Sensor::SubsystemResource *)seg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,6 @@
|
|||||||
RadarPercentAttributeID = PoweredSubsystem::NextAttributeID,
|
RadarPercentAttributeID = PoweredSubsystem::NextAttributeID,
|
||||||
SelfTestAttributeID,
|
SelfTestAttributeID,
|
||||||
BadVoltageAttributeID,
|
BadVoltageAttributeID,
|
||||||
ConfigureActivePressAttributeID, // audio configure-ticker gate (idle -1)
|
|
||||||
NextAttributeID
|
NextAttributeID
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -167,11 +166,7 @@
|
|||||||
Logical
|
Logical
|
||||||
selfTest, // @0x320 ctor init 0
|
selfTest, // @0x320 ctor init 0
|
||||||
badVoltage; // @0x324 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).
|
|
||||||
|
|
||||||
|
|
||||||
//##########################################################################
|
//##########################################################################
|
||||||
|
|||||||
Reference in New Issue
Block a user