3313 lines
110 KiB
C++
3313 lines
110 KiB
C++
//
|
|
// audio/audPlaneAudioEntity.cpp
|
|
//
|
|
// Copyright (C) 1999-2006 Rockstar Games. All Rights Reserved.
|
|
//
|
|
#include "audioengine/engine.h"
|
|
#include "audio/northaudioengine.h"
|
|
#include "audiosoundtypes/envelopesound.h"
|
|
#include "audiosoundtypes/simplesound.h"
|
|
#include "audiohardware/submix.h"
|
|
#include "audioeffecttypes/waveshapereffect.h"
|
|
|
|
#include "Camera/CamInterface.h"
|
|
#include "Camera/Cinematic/CinematicDirector.h"
|
|
|
|
#include "control/replay/Replay.h"
|
|
|
|
#include "planeaudioentity.h"
|
|
#include "scriptaudioentity.h"
|
|
#include "Vehicles/Planes.h"
|
|
#include "game/weather.h"
|
|
#include "speechmanager.h"
|
|
#include "scene/playerswitch/PlayerSwitchInterface.h"
|
|
|
|
u32 g_audPlaneLoopReleaseTime = 300;
|
|
f32 g_PlaneVolumeTrims[PLANE_LOOPS_MAX];
|
|
|
|
const u32 g_DefaultTyreSqueal = ATSTRINGHASH("TYRE_LAND_RANDOM", 0x67A8D590);
|
|
|
|
extern u32 g_SuperDummyRadiusSq;
|
|
extern const u32 g_TemperatureVariableHash;
|
|
extern CWeather g_weather;
|
|
extern AircraftWarningSettings* g_AircraftWarningSettings;
|
|
extern CPlayerSwitchInterface g_PlayerSwitch;
|
|
AmbientRadioLeakage g_AircraftPositionedPlayerVehicleRadioLeakage = LEAKAGE_CRAZY_LOUD;
|
|
|
|
#if __BANK
|
|
bool g_ShowDebugInfo = false;
|
|
bool g_ShowEngineCooling = false;
|
|
bool g_ShowFlyby = false;
|
|
bool g_ShowEngineInfo = false;
|
|
bool g_ShowEnginePosition = false;
|
|
bool g_ShowExhaustPosition = false;
|
|
bool g_ShowPropPosition = false;
|
|
bool g_PlanesEnabled = true;
|
|
bool g_DebugPlaneSuspension = false;
|
|
bool g_ForceFlightMode = false;
|
|
|
|
bool g_UseDebugPlaneTracker = false;
|
|
f32 g_DebugTrackerFlybyEngineSpeed = 0.75f;
|
|
f32 g_DebugTrackerFlybyTime = 50.0f;
|
|
f32 g_DebugTrackerFlybyDist = 2000.0f;
|
|
f32 g_DebugTrackerFlybyHeight = 200.0f;
|
|
f32 g_DebugTrackerTimer = 0.0f;
|
|
f32 g_ForcedFlightModeValue = 0.0f;
|
|
|
|
float g_OverRideEngineDamage[2] = {-1.0f, -1.0f};
|
|
bool g_ApplyEngineDamage = false;
|
|
|
|
bool g_ForceStallWarningOn = false;
|
|
f32 g_ForcedStallWarningSeverity = 0.0f;
|
|
|
|
extern f32 g_PositionedPlayerVehicleRadioReverbSmall;
|
|
extern f32 g_PositionedPlayerVehicleRadioReverbMedium;
|
|
extern f32 g_PositionedPlayerVehicleRadioReverbLarge;
|
|
extern bool g_PositionedPlayerVehicleRadioEnabled;
|
|
#endif
|
|
|
|
bank_float g_MinClosingRateForFlyby = 0.5f;
|
|
bank_float g_MinClosingRateForFlybyAway = -0.2f;
|
|
bank_float g_FlyingAwayDistanceToTrigger = 75.0f;
|
|
|
|
bank_float g_NpcEngineSpeedForAfterBurner = 0.75f;
|
|
|
|
bank_float g_MinSpeedForJetFlyby = 20.0f;
|
|
bank_float g_MinSpeedForPropFlyby = 10.0f; // some prop planes flying around 15.0f
|
|
|
|
bank_u32 g_TireSquealAttack = 30;
|
|
bank_u32 g_TireSquealDecay = 0;
|
|
bank_u32 g_TireSquealSustain = 100;
|
|
bank_u32 g_TireSquealHold = 100;
|
|
bank_s32 g_TireSquealRelease = 50;
|
|
|
|
static bank_u32 g_RadioOnDelay = 4000;
|
|
|
|
#define PEELING_ROLL_LIMIT 90.0f
|
|
#define PEELING_PITCH_LIMIT 90.0f
|
|
#define PEELING_PITCH_UP_LIMIT 30.0f
|
|
#define PEELING_STICK_DEFLECTION 0.9f
|
|
|
|
audCurve audPlaneAudioEntity::sm_BankingAngleToWindNoiseVolumeCurve;
|
|
audCurve audPlaneAudioEntity::sm_BankingAngleToWindNoisePitchCurve;
|
|
audCurve audPlaneAudioEntity::sm_SuspensionVolCurve;
|
|
audCurve audPlaneAudioEntity::sm_JetClosingToFlybyDistance;
|
|
audCurve audPlaneAudioEntity::sm_PropClosingToFlybyDistance;
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
// audPlaneAudioEntity constructor
|
|
// ----------------------------------------------------------------
|
|
audPlaneAudioEntity::audPlaneAudioEntity() :
|
|
audVehicleAudioEntity()
|
|
{
|
|
for(u32 loop = 0; loop < PLANE_LOOPS_MAX; loop++)
|
|
{
|
|
m_PlaneLoops[loop] = NULL;
|
|
}
|
|
|
|
for(int i=0; i<NUM_VEH_CWHEELS_MAX; i++)
|
|
{
|
|
m_SuspensionSounds[i] = NULL;
|
|
m_LastCompressionChange[i] = 0.0f;
|
|
}
|
|
|
|
m_WindSound = NULL;
|
|
m_EngineCoolingSound = NULL;
|
|
m_VehicleType = AUD_VEHICLE_PLANE;
|
|
m_StallWarning = NULL;
|
|
m_LandingGearDeploy = NULL;
|
|
m_LandingGearRetract = NULL;
|
|
m_CropDustingSound = NULL;
|
|
m_NextMissFireSoundTime = 0;
|
|
m_BackFireTime = 0;
|
|
m_FakeEngineSpeed = -10.0f;
|
|
|
|
m_LastDownwashTime = 0;
|
|
m_DownwashSound = NULL;
|
|
m_DownwashHash = g_NullSoundHash;
|
|
m_DownwashVolume = -100.0f;
|
|
m_DownwashHeight = -1.0f;
|
|
|
|
m_DiveSoundPitch = 0;
|
|
m_DiveSoundVolumeLin = 0.0f;
|
|
|
|
m_DiveSound = NULL;
|
|
m_FlybySound = NULL;
|
|
m_IgnitionSound = NULL;
|
|
m_VTOLModeSwitchSound = NULL;
|
|
m_GliderSound = NULL;
|
|
m_ClosingRate = 0.0f;
|
|
m_LastDistanceFromListener = 5000000.0f;
|
|
m_DistanceFromListener = 500000.0f;
|
|
m_SpeechSlotId = -1;
|
|
m_NumClosingSamples = 0;
|
|
m_TimeLastClosingRateUpdated = 0;
|
|
m_ClosingRateAccum = 0.0f;
|
|
m_FlybyStartTime = 0;
|
|
m_FlybyComingAtYou = true;
|
|
m_InARecording = false;
|
|
m_HasPlayedShutdownSound = false;
|
|
m_IsUsingStealthMicrolightGameobject = false;
|
|
|
|
m_IgnitionTime = -1;
|
|
|
|
for(u32 loop = 0; loop < m_LastControlSurfaceRotation.GetMaxCount(); loop++)
|
|
{
|
|
m_LastControlSurfaceRotation[loop] = 0.0f;
|
|
}
|
|
m_ControlSurfaceMovementSound[0] = NULL;
|
|
m_ControlSurfaceMovementSound[1] = NULL;
|
|
m_ControlSurfaceMovementSound[2] = NULL;
|
|
|
|
|
|
for(u32 loop = 0; loop < PLANE_NUM_PROPELLERS; loop++)
|
|
{
|
|
m_PropellorSpeedMult[loop] = 0.0f;
|
|
}
|
|
|
|
m_AirSpeed = 0.0f;
|
|
|
|
#if __BANK
|
|
m_DebugDivePitchLoops = 0;
|
|
m_DebugVertAirSpeed = 0.0f;
|
|
m_DebugDivingRate = 0.001f;
|
|
m_DebugOcclusion = 0.0f;
|
|
#endif
|
|
|
|
}
|
|
|
|
audPlaneAudioEntity::~audPlaneAudioEntity()
|
|
{
|
|
StopEngine(true);
|
|
StopAndForgetSounds(m_DownwashSound, m_WindSound, m_EngineCoolingSound, m_FlybySound, m_DiveSound);
|
|
FreeSpeechSlot();
|
|
}
|
|
|
|
void audPlaneAudioEntity::InitClass()
|
|
{
|
|
StaticConditionalWarning(sm_BankingAngleToWindNoiseVolumeCurve.Init(ATSTRINGHASH("PLANE_BANKING_ANGLE_TO_WIND_NOISE_VOL", 0xAE5BFDF5)), "Invalid AIR_SPEED_TO_WIND_NOISE_VOLUME_CURVE");
|
|
StaticConditionalWarning(sm_BankingAngleToWindNoisePitchCurve.Init(ATSTRINGHASH("PLANE_BANKING_ANGLE_TO_WIND_NOISE_PITCH", 0x5E7EB1A7)), "Invalid PLANE_AIR_SPEED_TO_WIND_NOISE_PITCH");
|
|
StaticConditionalWarning(sm_SuspensionVolCurve.Init(ATSTRINGHASH("HELI_SUSPENSION_COMPRESSION_TO_VOL",0xD9991BE)), "Invalid SuspVolCurve");
|
|
StaticConditionalWarning(sm_JetClosingToFlybyDistance.Init(ATSTRINGHASH("JETS_CLOSING_RATE_TO_FLYBY_DISTANCE", 0x7EA21C78)), "Invalid JETS_CLOSING_RATE_TO_FLYBY_DISTANCE Curve");
|
|
StaticConditionalWarning(sm_PropClosingToFlybyDistance.Init(ATSTRINGHASH("PROP_CLOSING_RATE_TO_FLYBY_DISTANCE", 0x8857DE09)), "Invalid PROP_CLOSING_RATE_TO_FLYBY_DISTANCE Curve");
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the plane settings data
|
|
// ----------------------------------------------------------------
|
|
PlaneAudioSettings* audPlaneAudioEntity::GetPlaneAudioSettings()
|
|
{
|
|
PlaneAudioSettings* settings = NULL;
|
|
|
|
if(g_AudioEngine.IsAudioEnabled())
|
|
{
|
|
if(m_ForcedGameObject != 0u)
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<PlaneAudioSettings>(m_ForcedGameObject);
|
|
m_ForcedGameObject = 0u;
|
|
}
|
|
|
|
if(!settings)
|
|
{
|
|
// Special case GO for microlight stealth propellor mod
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("MICROLIGHT", 0x96E24857))
|
|
{
|
|
const u8 modIndex = m_Vehicle->GetVariationInstance().GetModIndex(VMT_EXHAUST);
|
|
|
|
if(modIndex == 2)
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<PlaneAudioSettings>(ATSTRINGHASH("MICROLIGHT_STEALTHY", 0x34D5AB02));
|
|
m_IsUsingStealthMicrolightGameobject = true;
|
|
}
|
|
else
|
|
{
|
|
m_IsUsingStealthMicrolightGameobject = false;
|
|
}
|
|
}
|
|
|
|
if(!settings && m_Vehicle->GetVehicleModelInfo()->GetAudioNameHash() != 0)
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<PlaneAudioSettings>(m_Vehicle->GetVehicleModelInfo()->GetAudioNameHash());
|
|
}
|
|
|
|
if(!settings)
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<PlaneAudioSettings>(GetVehicleModelNameHash());
|
|
}
|
|
}
|
|
|
|
if(!audVerifyf(settings, "Couldn't find plane settings for plane: %s", GetVehicleModelName()))
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
if(plane)
|
|
{
|
|
if(m_IsJet)
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<PlaneAudioSettings>(ATSTRINGHASH("DEFAULT_JET", 0xA7351714));
|
|
}
|
|
else
|
|
{
|
|
settings = audNorthAudioEngine::GetObject<PlaneAudioSettings>(ATSTRINGHASH("DEFAULT_PROP_PLANE", 0xE924FA7));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return settings;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the vehicle collision settings
|
|
// ----------------------------------------------------------------
|
|
VehicleCollisionSettings* audPlaneAudioEntity::GetVehicleCollisionSettings() const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return audNorthAudioEngine::GetObject<VehicleCollisionSettings>(m_PlaneAudioSettings->VehicleCollisions);
|
|
}
|
|
|
|
return audVehicleAudioEntity::GetVehicleCollisionSettings();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Initialise the plane settings
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::Reset()
|
|
{
|
|
audVehicleAudioEntity::Reset();
|
|
|
|
for(u32 loop = 0; loop < PLANE_LOOPS_MAX; loop++)
|
|
{
|
|
m_PlaneLoopHashes[loop] = g_NullSoundHash;
|
|
g_PlaneVolumeTrims[loop] = 0.0f;
|
|
m_PlaneLoopTypes[loop] = AUD_VEHICLE_SOUND_UNKNOWN;
|
|
}
|
|
|
|
m_PlaneLoopTypes[PLANE_LOOP_ENGINE] = AUD_VEHICLE_SOUND_ENGINE;
|
|
m_PlaneLoopTypes[PLANE_LOOP_EXHAUST] = AUD_VEHICLE_SOUND_EXHAUST;
|
|
|
|
m_PlaneAudioSettings = NULL;
|
|
m_PlaneStatus = AUD_PLANE_OFF;
|
|
m_TimeInAir = 0.0f;
|
|
m_StallWarningOn = false;
|
|
m_StallWarningEnabled = true;
|
|
m_IsPeeling = false;
|
|
m_IsJet = false;
|
|
m_OnGround = false;
|
|
m_EngineSpeedSmoother.Reset();
|
|
|
|
for(s32 i = 0; i < MAX_PLANE_WHEELS; i++)
|
|
{
|
|
m_WheelInAir[i] = false;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Initialise the plane settings
|
|
// ----------------------------------------------------------------
|
|
bool audPlaneAudioEntity::InitVehicleSpecific()
|
|
{
|
|
#if __BANK
|
|
if(!g_PlanesEnabled)
|
|
return false;
|
|
#endif
|
|
|
|
for(u32 loop = 0; loop < PLANE_LOOPS_MAX; loop++)
|
|
{
|
|
m_PlaneLoopHashes[loop] = g_NullSoundHash;
|
|
g_PlaneVolumeTrims[loop] = 0.0f;
|
|
}
|
|
|
|
m_PropellorHealthFactorLastFrame = 0.0f;
|
|
m_PeelingFactor = 0.0f;
|
|
m_BankingAngle = 0.0f;
|
|
m_EngineSpeed = 0.0f;
|
|
m_FakeEngineSpeed = -10.0f;
|
|
m_PlaneAudioSettings = NULL;
|
|
m_StallWarning = NULL;
|
|
m_LandingGearDeploy = NULL;
|
|
m_LandingGearRetract = NULL;
|
|
m_CropDustingSound = NULL;
|
|
m_PlaneStatus = AUD_PLANE_OFF;
|
|
m_TimeInAir = 0.0f;
|
|
m_StallWarningOn = false;
|
|
m_IsPeeling = false;
|
|
m_IsJet = false;
|
|
m_OnGround = false;
|
|
m_EngineInstantOnOff = false;
|
|
m_EngineOffTemperature = 100.0f;
|
|
m_ClosingRate = 0.0f;
|
|
m_LastDistanceFromListener = 5000000.0f;
|
|
m_TimeStallStarted = 0;
|
|
|
|
for(s32 i = 0; i < MAX_PLANE_WHEELS; i++)
|
|
{
|
|
m_WheelInAir[i] = false;
|
|
}
|
|
|
|
m_PlaneAudioSettings = GetPlaneAudioSettings();
|
|
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
m_PlaneLoopHashes[PLANE_LOOP_ENGINE] = m_PlaneAudioSettings->EngineLoop;
|
|
m_PlaneLoopHashes[PLANE_LOOP_EXHAUST] = m_PlaneAudioSettings->ExhaustLoop;
|
|
m_PlaneLoopHashes[PLANE_LOOP_PROPELLOR] = m_PlaneAudioSettings->PropellorLoop;
|
|
m_PlaneLoopHashes[PLANE_LOOP_IDLE] = m_PlaneAudioSettings->IdleLoop;
|
|
m_PlaneLoopHashes[PLANE_LOOP_DISTANCE] = m_PlaneAudioSettings->DistanceLoop;
|
|
m_PlaneLoopHashes[PLANE_LOOP_BANKING] = m_PlaneAudioSettings->BankingLoop;
|
|
m_PlaneLoopHashes[PLANE_LOOP_AFTERBURNER] = m_PlaneAudioSettings->AfterburnerLoop;
|
|
m_PlaneLoopHashes[PLANE_LOOP_DAMAGE] = m_PlaneAudioSettings->JetDamageLoop;
|
|
|
|
SetUpVolumeCurves();
|
|
|
|
ConditionalWarning(m_PlaneLoopVolumeCurves[PLANE_LOOP_ENGINE].Init(m_PlaneAudioSettings->EngineThrottleVolumeCurve), "Invalid EngineThrottleVolumeCurve");
|
|
ConditionalWarning(m_PlaneLoopPitchCurves[PLANE_LOOP_ENGINE].Init(m_PlaneAudioSettings->EngineThrottlePitchCurve), "Invalid EngineThrottlePitchCurve");
|
|
ConditionalWarning(m_PlaneLoopVolumeCurves[PLANE_LOOP_EXHAUST].Init(m_PlaneAudioSettings->ExhaustThrottleVolumeCurve), "Invalid ExhaustThrottleVolumeCurve");
|
|
ConditionalWarning(m_PlaneLoopPitchCurves[PLANE_LOOP_EXHAUST].Init(m_PlaneAudioSettings->ExhaustThrottlePitchCurve), "Invalid ExhaustThrottlePitchCurve");
|
|
ConditionalWarning(m_PlaneLoopVolumeCurves[PLANE_LOOP_PROPELLOR].Init(m_PlaneAudioSettings->PropellorThrottleVolumeCurve), "Invalid PropellorThrottleVolumeCurve");
|
|
ConditionalWarning(m_PlaneLoopPitchCurves[PLANE_LOOP_PROPELLOR].Init(m_PlaneAudioSettings->PropellorThrottlePitchCurve), "Invalid PropellorThrottlePitchCurve");
|
|
ConditionalWarning(m_PlaneLoopVolumeCurves[PLANE_LOOP_IDLE].Init(m_PlaneAudioSettings->IdleThrottleVolumeCurve), "Invalid IdleThrottleVolumeCurve");
|
|
ConditionalWarning(m_PlaneLoopPitchCurves[PLANE_LOOP_IDLE].Init(m_PlaneAudioSettings->IdleThrottlePitchCurve), "Invalid IdleThrottlePitchCurve");
|
|
ConditionalWarning(m_PlaneLoopVolumeCurves[PLANE_LOOP_DISTANCE].Init(m_PlaneAudioSettings->DistanceThrottleVolumeCurve), "Invalid DistanceThrottleVolumeCurve");
|
|
ConditionalWarning(m_PlaneLoopPitchCurves[PLANE_LOOP_DISTANCE].Init(m_PlaneAudioSettings->DistanceThrottlePitchCurve), "Invalid DistanceThrottlePitchCurve");
|
|
ConditionalWarning(m_PlaneLoopVolumeCurves[PLANE_LOOP_BANKING].Init(m_PlaneAudioSettings->BankingThrottleVolumeCurve), "Invalid BankingThrottleVolumeCurve");
|
|
ConditionalWarning(m_PlaneLoopPitchCurves[PLANE_LOOP_BANKING].Init(m_PlaneAudioSettings->BankingThrottlePitchCurve), "Invalid BankingThrottlePitchCurve");
|
|
ConditionalWarning(m_PlaneLoopVolumeCurves[PLANE_LOOP_AFTERBURNER].Init(m_PlaneAudioSettings->AfterburnerThrottleVolCurve), "Invalid AfterburnerThrottleVolCurve");
|
|
ConditionalWarning(m_PlaneLoopPitchCurves[PLANE_LOOP_AFTERBURNER].Init(m_PlaneAudioSettings->AfterburnerThrottlePitchCurve), "Invalid AfterburnerThrottlePitchCurve");
|
|
ConditionalWarning(m_PlaneLoopVolumeCurves[PLANE_LOOP_DAMAGE].Init(m_PlaneAudioSettings->DamageEngineSpeedVolumeCurve), "Invalid DamageEngineSpeedVolumeCurve");
|
|
ConditionalWarning(m_PlaneLoopPitchCurves[PLANE_LOOP_DAMAGE].Init(m_PlaneAudioSettings->DamageEngineSpeedPitchCurve), "Invalid DamageEngineSpeedPitchCurve");
|
|
ConditionalWarning(m_BankingAngleVolCurve.Init(m_PlaneAudioSettings->BankingAngleVolCurve), "Invalid BankingAngleVolCurve");
|
|
ConditionalWarning(m_PeelingPitchCurve.Init(m_PlaneAudioSettings->PeelingPitchCurve), "Invalid PeelingPitchCurve");
|
|
|
|
// Distance just has the one volume curve
|
|
ConditionalWarning(m_DistanceEffectVolCurve.Init(m_PlaneAudioSettings->DistanceVolumeCurve), "Invalid DistanceVolumeCurve");
|
|
ConditionalWarning(m_DamageVolumeCurve.Init(m_PlaneAudioSettings->DamageHealthVolumeCurve), "Invalid PLANE_JET_DAMAGE_VOL Curve");
|
|
m_VehicleSpeedToHullSlapVol.Init(m_PlaneAudioSettings->IdleHullSlapSpeedToVol);
|
|
|
|
SetEnvironmentGroupSettings(true, audNorthAudioEngine::GetOcclusionManager()->GetMaxOcclusionPathDepth());
|
|
|
|
if(AUD_GET_TRISTATE_VALUE(m_PlaneAudioSettings->Flags, FLAG_ID_PLANEAUDIOSETTINGS_HASMISSILELOCKSYSTEM) == AUD_TRISTATE_TRUE)
|
|
{
|
|
m_HasMissileLockWarningSystem = true;
|
|
}
|
|
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
if((plane && plane->GetNumPropellors() == 0) || (AUD_GET_TRISTATE_VALUE(m_PlaneAudioSettings->Flags, FLAG_ID_PLANEAUDIOSETTINGS_ISJET) == AUD_TRISTATE_TRUE))
|
|
{
|
|
m_IsJet = true;
|
|
}
|
|
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("STARLING", 0x9A9EB7DE))
|
|
{
|
|
m_IsJet = true;
|
|
m_EngineInstantOnOff = true;
|
|
}
|
|
|
|
if(plane)
|
|
{
|
|
Vector3 planePosition = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
Vector3 planeToListener = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(0)) - planePosition;
|
|
m_DistanceFromListener = planeToListener.Mag();
|
|
m_LastDistanceFromListener = m_DistanceFromListener;
|
|
}
|
|
|
|
m_angularVelocitySmoother.Init(0.1f);
|
|
|
|
float divingRate = (float)m_PlaneAudioSettings->DivingFactor;
|
|
if(divingRate > 100.0f)
|
|
divingRate = 1.0f;
|
|
static bank_float pullupRateMult = 2.5f;
|
|
m_angleBasedPitchLoopSmoother.Init(divingRate, divingRate*pullupRateMult, 0.0f, (float)m_PlaneAudioSettings->MaxDivePitch);
|
|
|
|
static bank_float volIncRate = 0.01f;
|
|
m_angleBasedVolumeSmoother.Init(volIncRate, volIncRate*pullupRateMult, 0.0f, 1.0f);
|
|
m_angleBasedPitchSmoother.Init(divingRate, divingRate*pullupRateMult, 0.0f, (float)m_PlaneAudioSettings->MaxDivePitch);
|
|
|
|
#if __BANK
|
|
m_DebugDivingRate = divingRate;
|
|
#endif
|
|
m_peelingPitchSmoother.Init(0.001f, true);
|
|
m_EngineSpeedSmoother.Init(m_PlaneAudioSettings->NPCEngineSmoothAmount, true);
|
|
static bank_float upRate = 0.75f;
|
|
static bank_float downRate = 0.25f;
|
|
m_DistantSoundVolumeSmoother.Init(upRate, downRate, -100.0f, 0.0f);
|
|
static bank_float dopplerRate = 0.01f;
|
|
m_DopplerSmoother.Init(dopplerRate, true);
|
|
|
|
|
|
#if NA_RADIO_ENABLED
|
|
m_AmbientRadioDisabled = (AUD_GET_TRISTATE_VALUE(m_PlaneAudioSettings->Flags, FLAG_ID_PLANEAUDIOSETTINGS_DISABLEAMBIENTRADIO) == AUD_TRISTATE_TRUE);
|
|
m_RadioType = (RadioType)m_PlaneAudioSettings->RadioType;
|
|
m_RadioGenre = (RadioGenre)m_PlaneAudioSettings->RadioGenre;
|
|
#endif
|
|
|
|
// GTAV specific fix for new DLC VTOL aircraft
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
|
|
if(modelNameHash == ATSTRINGHASH("HYDRA", 0x39D6E83F))
|
|
{
|
|
m_VTOLThrusterSoundset.Init(ATSTRINGHASH("HYDRA_THRUSTERS_SOUNDSET", 0x6B68804C));
|
|
}
|
|
else if(modelNameHash == ATSTRINGHASH("TULA", 0x3E2E4F8A))
|
|
{
|
|
m_VTOLThrusterSoundset.Init(ATSTRINGHASH("DLC_Smuggler_Tula_Sounds", 0xA569570B));
|
|
}
|
|
else if(modelNameHash == ATSTRINGHASH("AVENGER", 0x81BD2ED0))
|
|
{
|
|
m_VTOLThrusterSoundset.Init(ATSTRINGHASH("DLC_Christmas2017_Avenger_Sounds", 0x2FDD8496));
|
|
}
|
|
|
|
m_KersSystem.Init(this);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void audPlaneAudioEntity::PostUpdate()
|
|
{
|
|
audVehicleAudioEntity::PostUpdate();
|
|
|
|
#if __BANK
|
|
if(IsReal() || m_PlaneStatus == AUD_PLANE_STOPPING)
|
|
{
|
|
ShowDebugInfo(m_DebugPlaneValues);
|
|
}
|
|
#endif
|
|
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("MICROLIGHT", 0x96E24857))
|
|
{
|
|
const u8 modIndex = m_Vehicle->GetVariationInstance().GetModIndex(VMT_EXHAUST);
|
|
|
|
if((modIndex == 2 && !m_IsUsingStealthMicrolightGameobject) || (modIndex != 2 && m_IsUsingStealthMicrolightGameobject))
|
|
{
|
|
m_ForcedGameObjectResetRequired = true;
|
|
m_IsUsingStealthMicrolightGameobject = modIndex == 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Acquire a wave slot
|
|
// ----------------------------------------------------------------
|
|
bool audPlaneAudioEntity::AcquireWaveSlot()
|
|
{
|
|
if(m_IsFocusVehicle && GetVehicleModelNameHash() == ATSTRINGHASH("STARLING", 0x9A9EB7DE))
|
|
{
|
|
m_RequiresSFXBank = true;
|
|
RequestSFXWaveSlot(ATSTRINGHASH("DLC_SMUGGLER_STARLING_ROCKET_THRUST_BANK", 0x122AB4CB), true);
|
|
}
|
|
else if(m_IsFocusVehicle && m_KersSystem.GetKersSoundSetName() != 0u)
|
|
{
|
|
m_RequiresSFXBank = true;
|
|
RequestSFXWaveSlot(ATSTRINGHASH("DLC_SMUGGLER_PLAYER_JATO_ROCKET_THRUST", 0x70BA015), true);
|
|
}
|
|
else if(GetVehicleModelNameHash() == ATSTRINGHASH("AVENGER", 0x81BD2ED0))
|
|
{
|
|
m_RequiresSFXBank = true;
|
|
RequestSFXWaveSlot(m_PlaneAudioSettings->PropellorLoop, false);
|
|
}
|
|
else
|
|
{
|
|
m_RequiresSFXBank = false;
|
|
}
|
|
|
|
if(m_RequiresSFXBank && !m_SFXWaveSlot)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(m_PlaneAudioSettings->SimpleSoundForLoading != g_NullSoundHash)
|
|
{
|
|
RequestWaveSlot(&audVehicleAudioEntity::sm_StandardWaveSlotManager, m_PlaneAudioSettings->SimpleSoundForLoading);
|
|
}
|
|
else
|
|
{
|
|
RequestWaveSlot(&audVehicleAudioEntity::sm_StandardWaveSlotManager, m_PlaneAudioSettings->BankingLoop);
|
|
}
|
|
|
|
if(m_RequiresSFXBank)
|
|
{
|
|
// If we didn't manage to acquire a primary wave slot, release the SFX slot so we don't hog it
|
|
if(m_SFXWaveSlot && !m_EngineWaveSlot)
|
|
{
|
|
audWaveSlotManager::FreeWaveSlot(m_SFXWaveSlot, this);
|
|
}
|
|
|
|
return m_SFXWaveSlot != NULL && m_EngineWaveSlot != NULL;
|
|
}
|
|
else
|
|
{
|
|
return m_EngineWaveSlot != NULL;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// OnFocusVehicleChanged
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::OnFocusVehicleChanged()
|
|
{
|
|
if(m_SFXWaveSlot && !m_IsFocusVehicle)
|
|
{
|
|
audWaveSlotManager::FreeWaveSlot(m_SFXWaveSlot, this);
|
|
}
|
|
else if(m_IsFocusVehicle && m_EngineWaveSlot && !m_SFXWaveSlot)
|
|
{
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("STARLING", 0x9A9EB7DE))
|
|
{
|
|
RequestSFXWaveSlot(ATSTRINGHASH("DLC_SMUGGLER_STARLING_ROCKET_THRUST_BANK", 0x122AB4CB), true);
|
|
}
|
|
else if(m_KersSystem.GetKersSoundSetName() != 0u)
|
|
{
|
|
RequestSFXWaveSlot(ATSTRINGHASH("DLC_SMUGGLER_PLAYER_JATO_ROCKET_THRUST", 0x70BA015), true);
|
|
}
|
|
}
|
|
|
|
StopAndForgetSounds(m_GliderSound);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Set up the volume curves
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::SetUpVolumeCurves()
|
|
{
|
|
Vec3V frontConeDir = Vec3V(V_Y_AXIS_WZERO);
|
|
Vec3V rearConeDir = -Vec3V(V_Y_AXIS_WZERO);
|
|
// Vec3V upConeDir = Vec3V(V_Z_AXIS_WZERO);
|
|
// Vec3V downConeDir = -Vec3V(V_Z_AXIS_WZERO);
|
|
|
|
m_PlaneLoopVolumeCones[PLANE_LOOP_ENGINE].Init(frontConeDir, m_PlaneAudioSettings->EngineConeAtten/100.f, m_PlaneAudioSettings->EngineConeFrontAngle, m_PlaneAudioSettings->EngineConeRearAngle);
|
|
m_PlaneLoopVolumeCones[PLANE_LOOP_EXHAUST].Init(rearConeDir, m_PlaneAudioSettings->ExhaustConeAtten/100.f, m_PlaneAudioSettings->ExhaustConeFrontAngle, m_PlaneAudioSettings->ExhaustConeRearAngle);
|
|
m_PlaneLoopVolumeCones[PLANE_LOOP_PROPELLOR].Init(frontConeDir, m_PlaneAudioSettings->PropellorConeAtten/100.f, m_PlaneAudioSettings->PropellorConeFrontAngle, m_PlaneAudioSettings->PropellorConeRearAngle);
|
|
m_PlaneLoopVolumeCones[PLANE_LOOP_IDLE].Init(frontConeDir, 0.0f, 0.0f, 0.0f);
|
|
m_PlaneLoopVolumeCones[PLANE_LOOP_DISTANCE].Init(frontConeDir, 0.0f, 0.0f, 0.0f);
|
|
m_PlaneLoopVolumeCones[PLANE_LOOP_BANKING].Init(frontConeDir, 0.0f, 0.0f, 0.0f);
|
|
m_PlaneLoopVolumeCones[PLANE_LOOP_AFTERBURNER].Init(rearConeDir, m_PlaneAudioSettings->ExhaustConeAtten/100.f, m_PlaneAudioSettings->ExhaustConeFrontAngle, m_PlaneAudioSettings->ExhaustConeRearAngle);
|
|
m_PlaneLoopVolumeCones[PLANE_LOOP_DAMAGE].Init(frontConeDir, m_PlaneAudioSettings->EngineConeAtten/100.f, m_PlaneAudioSettings->EngineConeFrontAngle, m_PlaneAudioSettings->EngineConeRearAngle);
|
|
}
|
|
|
|
void audPlaneAudioEntity::SetTracker(audSoundInitParams &initParams)
|
|
{
|
|
initParams.TrackEntityPosition = true;
|
|
#if __BANK
|
|
if(g_UseDebugPlaneTracker)
|
|
{
|
|
initParams.Tracker = &m_DebugTracker;
|
|
initParams.TrackEntityPosition = false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if the engine is on
|
|
// ----------------------------------------------------------------
|
|
bool audPlaneAudioEntity::IsEngineOn() const
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
static f32 minEngineSpeed = 0.09f;
|
|
bool engineOn = m_Vehicle->m_nVehicleFlags.bEngineOn || (!m_EngineInstantOnOff && plane && plane->GetEngineSpeed() > minEngineSpeed) || (!m_EngineInstantOnOff && !m_IsPlayerVehicle && m_EngineSpeed > minEngineSpeed);
|
|
|
|
if(plane && m_PlaneAudioSettings)
|
|
{
|
|
// For planes with the engines attached to the wings, we want to stop the engine sounds as soon as either the wings or the engines fall off
|
|
if(AUD_GET_TRISTATE_VALUE(m_PlaneAudioSettings->Flags, FLAG_ID_PLANEAUDIOSETTINGS_ENGINESATTACHEDTOWINGS) == AUD_TRISTATE_TRUE)
|
|
{
|
|
if((plane->GetAircraftDamage().HasSectionBrokenOff(plane, CAircraftDamage::ENGINE_L) || plane->GetAircraftDamage().HasSectionBrokenOff(plane, CAircraftDamage::WING_L)) &&
|
|
(plane->GetAircraftDamage().HasSectionBrokenOff(plane, CAircraftDamage::ENGINE_R) || plane->GetAircraftDamage().HasSectionBrokenOff(plane, CAircraftDamage::WING_R)))
|
|
{
|
|
engineOn = false;
|
|
}
|
|
}
|
|
// Other planes have engines either built into the main body of the aircraft or attached to the body by some point other than the wings, so just check the engines themselves
|
|
else
|
|
{
|
|
if(plane->GetAircraftDamage().HasSectionBrokenOff(plane, CAircraftDamage::ENGINE_L) &&
|
|
plane->GetAircraftDamage().HasSectionBrokenOff(plane, CAircraftDamage::ENGINE_R))
|
|
{
|
|
engineOn = false;
|
|
}
|
|
}
|
|
|
|
if(m_Vehicle->GetStatus() == STATUS_WRECKED)
|
|
{
|
|
engineOn = false;
|
|
}
|
|
|
|
//#if __BANK
|
|
// if(g_ShowDebugInfo)
|
|
// {
|
|
// static float size = 1.0f;
|
|
// grcDebugDraw::Sphere(m_Vehicle->GetVehiclePosition(), size, engineOn?Color_green:Color_red);
|
|
// static float offset = -8.0f;
|
|
// grcDebugDraw::Sphere(m_Vehicle->GetVehiclePosition() + Vec3V(0.f,0.f, offset), size, engineOn?Color_green:Color_red);
|
|
// }
|
|
//#endif
|
|
}
|
|
|
|
return engineOn;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audPlaneAudioEntity::GetPropellorHealthFactor
|
|
// ----------------------------------------------------------------
|
|
f32 audPlaneAudioEntity::GetPropellorHealthFactor() const
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
#if __BANK
|
|
if(plane && g_ApplyEngineDamage)
|
|
{
|
|
if(g_OverRideEngineDamage[0] != -1.0f)
|
|
{
|
|
if(plane->GetNumPropellors() > 1)
|
|
plane->GetAircraftDamage().SetSectionHealth(CAircraftDamage::ENGINE_L, g_OverRideEngineDamage[0]);
|
|
else
|
|
plane->GetVehicleDamage()->SetEngineHealth(g_OverRideEngineDamage[0]);
|
|
}
|
|
if(plane->GetNumPropellors() > 0 && g_OverRideEngineDamage[1] != -1.0f)
|
|
{
|
|
plane->GetAircraftDamage().SetSectionHealth(CAircraftDamage::ENGINE_R, g_OverRideEngineDamage[1]);
|
|
}
|
|
g_ApplyEngineDamage = false;
|
|
}
|
|
#endif
|
|
|
|
f32 propellorHealthFactor = 1.0f;
|
|
|
|
if(plane->GetNumPropellors() > 0 && !m_IsJet)
|
|
{
|
|
propellorHealthFactor = 0.0f;
|
|
|
|
for(u32 loop = 0; loop < plane->GetNumPropellors(); loop++)
|
|
{
|
|
if(m_PropellorSpeedMult[loop] > 0.0f)
|
|
{
|
|
propellorHealthFactor += 1.0f;
|
|
}
|
|
}
|
|
|
|
propellorHealthFactor /= plane->GetNumPropellors();
|
|
}
|
|
|
|
return propellorHealthFactor;
|
|
}
|
|
|
|
void audPlaneAudioEntity::SetPropellorSpeedMult(s32 index, f32 mult)
|
|
{
|
|
if(index >= 0 && index < PLANE_NUM_PROPELLERS)
|
|
{
|
|
m_PropellorSpeedMult[index] = mult;
|
|
}
|
|
}
|
|
|
|
void audPlaneAudioEntity::AdjustControlSurface(int partId, f32 newRotation)
|
|
{
|
|
if(partId < PLANE_RUDDER || partId > PLANE_AILERON_R)
|
|
return;
|
|
|
|
int partIndex = partId - PLANE_RUDDER;
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
static bank_float surfaceMovementFactor = 0.7f;
|
|
if(fabs(m_LastControlSurfaceRotation[partIndex] - newRotation) > surfaceMovementFactor)
|
|
{
|
|
m_LastControlSurfaceRotation[partIndex] = newRotation;
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
|
|
if(!m_OnGround)
|
|
{
|
|
static bank_float volume = -6.0f;
|
|
initParams.Volume = volume;
|
|
}
|
|
|
|
switch(partIndex)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
if(!m_ControlSurfaceMovementSound[0])
|
|
{
|
|
if(!plane->GetAircraftDamage().HasSectionBrokenOff(plane, partIndex == 0? CAircraftDamage::RUDDER : CAircraftDamage::RUDDER_2))
|
|
{
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->Rudder, &m_ControlSurfaceMovementSound[0], &initParams);
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
if(!m_ControlSurfaceMovementSound[1])
|
|
{
|
|
if(!plane->GetAircraftDamage().HasSectionBrokenOff(plane, partIndex == 2? CAircraftDamage::ELEVATOR_L : CAircraftDamage::ELEVATOR_R))
|
|
{
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->Elevator, &m_ControlSurfaceMovementSound[1], &initParams);
|
|
}
|
|
}
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
if(!m_ControlSurfaceMovementSound[2])
|
|
{
|
|
if(!plane->GetAircraftDamage().HasSectionBrokenOff(plane, partIndex == 4? CAircraftDamage::AILERON_L : CAircraftDamage::AILERON_R))
|
|
{
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->Aileron, &m_ControlSurfaceMovementSound[2], &initParams);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool audPlaneAudioEntity::IsPlayingStartupSequence() const
|
|
{
|
|
if(m_IgnitionSound || (m_IgnitionTime > 0 && !m_Vehicle->m_nVehicleFlags.bSkipEngineStartup))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
u32 audPlaneAudioEntity::GetTurretSoundSet() const
|
|
{
|
|
return ATSTRINGHASH("Plane_Turret_Sounds", 0xC96E8DD7);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update anything plane specific
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateVehicleSpecific(audVehicleVariables& UNUSED_PARAM(vehicleVariables), audVehicleDSPSettings& dspSettings)
|
|
{
|
|
audPlaneValues planeValues;
|
|
f32 propellorHealthFactor = GetPropellorHealthFactor();
|
|
|
|
if(IsReal() || m_PlaneStatus == AUD_PLANE_STOPPING)
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
bool engineOn = IsEngineOn();
|
|
|
|
m_EngineSpeed = plane->GetEngineSpeed();
|
|
if(!m_IsPlayerVehicle && m_Vehicle->m_nVehicleFlags.bKeepEngineOnWhenAbandoned)
|
|
{
|
|
static bank_float fakeEngineSpeed = 0.5f;
|
|
m_EngineSpeed = fakeEngineSpeed;
|
|
}
|
|
// planes can have some very erratic throttle/engine speeds
|
|
if(m_IsPlayerVehicle || (!m_IsJet && m_PlaneStatus == AUD_PLANE_STOPPING))
|
|
{
|
|
static bank_float playerEngineSmoother = 0.01f;
|
|
m_EngineSpeedSmoother.SetRate(playerEngineSmoother);
|
|
}
|
|
else
|
|
{
|
|
m_EngineSpeedSmoother.SetRate(m_PlaneAudioSettings->NPCEngineSmoothAmount);
|
|
}
|
|
#if GTA_REPLAY
|
|
if(!CReplayMgr::IsEditModeActive())
|
|
#endif
|
|
{
|
|
m_EngineSpeed = m_EngineSpeedSmoother.CalculateValue(m_EngineSpeed);
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_UseDebugPlaneTracker)
|
|
{
|
|
m_EngineSpeed = g_DebugTrackerFlybyEngineSpeed;
|
|
}
|
|
#endif
|
|
m_BankingAngle = AcosfSafe(Dot(m_Vehicle->GetTransform().GetC(), Vec3V(V_Z_AXIS_WZERO)).Getf()) * RtoD;
|
|
|
|
f32 entityVariableThrottle = 0.0f;
|
|
f32 entityVariableRevs = 0.0f;
|
|
f32 fakeEngineFactor = 0.0f;
|
|
|
|
if(HasEntityVariableBlock())
|
|
{
|
|
entityVariableThrottle = GetEntityVariableValue(ATSTRINGHASH("fakethrottle", 0xEB27990));
|
|
entityVariableRevs = GetEntityVariableValue(ATSTRINGHASH("fakerevs", 0xCEB98BEB));
|
|
|
|
// Reduce this each frame so that that the behavior gets canceled even if a sound forgets to do so
|
|
fakeEngineFactor = GetEntityVariableValue(ATSTRINGHASH("usefakeengine", 0x91DF7F97));
|
|
SetEntityVariable(ATSTRINGHASH("usefakeengine", 0x91DF7F97), Clamp(fakeEngineFactor - 0.1f, 0.0f, 1.0f));
|
|
}
|
|
|
|
if(fakeEngineFactor > 0.1f)
|
|
{
|
|
m_EngineSpeed = entityVariableThrottle;
|
|
m_BankingAngle = entityVariableRevs;
|
|
m_InARecording = true;
|
|
m_Vehicle->m_nVehicleFlags.bForceActiveDuringPlayback = true;
|
|
}
|
|
else
|
|
{
|
|
m_InARecording = false;
|
|
}
|
|
|
|
|
|
// This check is needed to avoid us missing the frame that the engine turns on, and therefore having an incorrect m_WasEngineOnLastFrame
|
|
// flag (causing us to use the wrong attack time, miss the ignition, etc.). Basically, GetPropellorSpeedMult() (used by GetPropellorHealthFactor()) only returns
|
|
// values > 0.0f once the engine speed is > 0.0f, so shouldn't be relied upon until the engine has actually started.
|
|
u32 currentTime = fwTimer::GetTimeInMilliseconds();
|
|
if(engineOn && propellorHealthFactor == 0.0f && m_EngineSpeed > 0.0f)
|
|
{
|
|
if(!plane->m_Transmission.GetCurrentlyMissFiring() && currentTime > (m_BackFireTime + 1000))
|
|
engineOn = false;
|
|
}
|
|
|
|
planeValues.propellorHealthFactor = propellorHealthFactor;
|
|
|
|
switch(m_PlaneStatus)
|
|
{
|
|
case AUD_PLANE_OFF:
|
|
if(engineOn)
|
|
{
|
|
if(m_EngineWaveSlot && m_EngineWaveSlot->IsLoaded())
|
|
{
|
|
StartEngine();
|
|
|
|
if(m_PlaneStatus != AUD_PLANE_OFF)
|
|
{
|
|
UpdateEngineOn(planeValues);
|
|
}
|
|
}
|
|
m_DiveSoundVolumeLin = 0.0f;
|
|
}
|
|
break;
|
|
|
|
case AUD_PLANE_STARTING:
|
|
m_PlaneStatus = AUD_PLANE_ON;
|
|
if(m_EngineSpeed <= m_FakeEngineSpeed)
|
|
{
|
|
m_EngineSpeed = m_FakeEngineSpeed;
|
|
}
|
|
//fall through
|
|
|
|
case AUD_PLANE_ON:
|
|
if(engineOn)
|
|
{
|
|
m_EngineOffTemperature = 100.0f;
|
|
|
|
//check if we have a jet shutting down
|
|
if(!m_Vehicle->m_nVehicleFlags.bEngineOn && m_IsJet)
|
|
{
|
|
m_PlaneStatus = AUD_PLANE_STOPPING;
|
|
// get the starting engine speed
|
|
m_FakeEngineSpeed = m_EngineSpeed;
|
|
m_EngineOffTemperature = m_Vehicle->m_EngineTemperature;
|
|
}
|
|
else if(m_EngineSpeed <= m_FakeEngineSpeed)
|
|
{
|
|
m_EngineSpeed = m_FakeEngineSpeed;
|
|
ShutdownJetEngine(); // this keeps adjusting the m_FakeEngineSpeed until they match
|
|
}
|
|
else
|
|
{
|
|
m_FakeEngineSpeed = -10.0f;
|
|
}
|
|
|
|
if(!m_IsJet && m_Vehicle->m_nVehicleFlags.bEngineOn && !m_WasEngineOnLastFrame && currentTime > (m_BackFireTime + 2000))
|
|
{
|
|
// engine was off and is restarting, but no restart sound. We get a black puff from engines, so give a backfire sound to match.
|
|
TriggerBackFire();
|
|
}
|
|
|
|
UpdateStallWarning(planeValues);
|
|
UpdateEngineOn(planeValues);
|
|
UpdateTricks();
|
|
}
|
|
else
|
|
{
|
|
if(m_IsJet)
|
|
{
|
|
// get the starting engine speed
|
|
m_FakeEngineSpeed = m_EngineSpeed;
|
|
}
|
|
m_PlaneStatus = AUD_PLANE_STOPPING;
|
|
m_EngineOffTemperature = m_Vehicle->m_EngineTemperature;
|
|
}
|
|
break;
|
|
case AUD_PLANE_STOPPING:
|
|
if(m_Vehicle->GetStatus() == STATUS_WRECKED)
|
|
{
|
|
m_DiveSoundVolumeLin = 0.0f;
|
|
if(m_IsJet && m_Vehicle->GetIsInWater())
|
|
{
|
|
ShutdownJetEngine();
|
|
m_EngineSpeed = m_FakeEngineSpeed;
|
|
UpdateEngineOn(planeValues);
|
|
}
|
|
else
|
|
{
|
|
StopEngine();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_Vehicle->m_nVehicleFlags.bEngineOn)
|
|
{
|
|
if(m_EngineWaveSlot && m_EngineWaveSlot->IsLoaded())
|
|
{
|
|
StartEngine();
|
|
}
|
|
}
|
|
if(m_IsJet)
|
|
{
|
|
ShutdownJetEngine();
|
|
m_EngineSpeed = m_FakeEngineSpeed;
|
|
}
|
|
else
|
|
{
|
|
static bank_float minEngineSpeedToStop = 0.03f;
|
|
if(m_EngineSpeed < minEngineSpeedToStop || m_EngineInstantOnOff)
|
|
{
|
|
StopEngine();
|
|
}
|
|
|
|
}
|
|
UpdateEngineOn(planeValues);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(m_PlaneStatus != AUD_PLANE_OFF)
|
|
{
|
|
if(planeValues.haveBeenCalculated)
|
|
{
|
|
UpdateSounds(planeValues);
|
|
|
|
f32 throttle = plane->GetThrottle();
|
|
|
|
if(!m_IsPlayerVehicle && m_EngineSpeed > g_NpcEngineSpeedForAfterBurner)
|
|
{
|
|
throttle = 1.0f;
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_UseDebugPlaneTracker)
|
|
{
|
|
throttle = 1.0f;
|
|
}
|
|
#endif
|
|
dspSettings.AddDSPParameter(atHashString("Throttle", 0xEA0151DC), throttle);
|
|
dspSettings.AddDSPParameter(atHashString("RPM", 0x5B924509), m_Vehicle->m_Transmission.GetRevRatio());
|
|
|
|
if(m_IsJet)
|
|
{
|
|
dspSettings.enginePostSubmixAttenuation = planeValues.postSubmixVolumes[PLANE_LOOP_ENGINE];
|
|
}
|
|
else
|
|
{
|
|
dspSettings.enginePostSubmixAttenuation = planeValues.postSubmixVolumes[PLANE_LOOP_PROPELLOR];
|
|
}
|
|
|
|
dspSettings.exhaustPostSubmixAttenuation = planeValues.postSubmixVolumes[PLANE_LOOP_EXHAUST];
|
|
}
|
|
}
|
|
|
|
UpdateSuspension(); // must be done before tyre squeals so we can check m_TimeInAir before it goes 0
|
|
UpdateTyreSqueals();
|
|
UpdateWindNoise(planeValues);
|
|
UpdateControlSurfaces();
|
|
UpdateDiveSound(planeValues);
|
|
UpdateGliding();
|
|
m_KersSystem.Update();
|
|
|
|
m_DownwashVolume = planeValues.loopVolumes[PLANE_LOOP_ENGINE];
|
|
if(m_LastDownwashTime + 300 < currentTime && m_DownwashSound)
|
|
{
|
|
m_DownwashSound->StopAndForget();
|
|
}
|
|
|
|
if(m_IsPlayerVehicle && m_IsPlayerSeatedInVehicle && m_Vehicle->GetStatus() != STATUS_WRECKED)
|
|
{
|
|
if(m_IgnitionTime > 0)
|
|
{
|
|
m_IgnitionTime -= fwTimer::GetTimeStepInMilliseconds();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!m_IsPlayerSeatedInVehicle)
|
|
{
|
|
m_IgnitionTime = g_RadioOnDelay;
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
UpdateDebug();
|
|
SetUpVolumeCurves();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
m_IgnitionTime = g_RadioOnDelay;
|
|
StopAndForgetSounds(m_WindSound, m_DownwashSound, m_FlybySound, m_DiveSound, m_GliderSound);
|
|
m_KersSystem.StopAllSounds();
|
|
}
|
|
|
|
UpdateVTOL();
|
|
UpdateEngineCooling();
|
|
UpdateFlyby();
|
|
|
|
if(IsSeaPlane())
|
|
{
|
|
if(IsReal() || IsDummy())
|
|
{
|
|
UpdateSeaPlane();
|
|
}
|
|
}
|
|
|
|
if(!m_FlybySound)
|
|
{
|
|
FreeSpeechSlot();
|
|
}
|
|
#if __BANK
|
|
if(g_ShowEngineInfo)
|
|
{
|
|
char tempString[128];
|
|
formatf(tempString, "Occ %4.2f Dop %4.2f ESpd %4.2f EON %d AEON %d", m_DebugOcclusion, m_DopplerSmoother.GetLastValue(), m_EngineSpeed, m_Vehicle->m_nVehicleFlags.bEngineOn, IsEngineOn());
|
|
grcDebugDraw::Text(m_Vehicle->GetTransform().GetPosition(), Color_green, tempString);
|
|
}
|
|
|
|
m_DebugPlaneValues = planeValues;
|
|
#endif
|
|
|
|
m_DownwashHeight = -1.0f;
|
|
|
|
m_PropellorHealthFactorLastFrame = propellorHealthFactor;
|
|
|
|
SetEnvironmentGroupSettings(true, audNorthAudioEngine::GetOcclusionManager()->GetMaxOcclusionPathDepth());
|
|
}
|
|
|
|
void audPlaneAudioEntity::UpdateControlSurfaces()
|
|
{
|
|
if(IsReal())
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
AdjustControlSurface(PLANE_RUDDER, plane->GetYaw());
|
|
AdjustControlSurface(PLANE_RUDDER_2, plane->GetYaw());
|
|
|
|
// Elevators (pitch)
|
|
AdjustControlSurface(PLANE_ELEVATOR_L, plane->GetPitch());
|
|
AdjustControlSurface(PLANE_ELEVATOR_R, plane->GetPitch());
|
|
|
|
// Ailerons (roll)
|
|
AdjustControlSurface(PLANE_AILERON_L, plane->GetRoll());
|
|
AdjustControlSurface(PLANE_AILERON_R, plane->GetRoll());
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the desired lod for the vehicle
|
|
// ----------------------------------------------------------------
|
|
audVehicleLOD audPlaneAudioEntity::GetDesiredLOD(f32 UNUSED_PARAM(fwdSpeedRatio), u32 distFromListenerSq, bool UNUSED_PARAM(visibleBySniper))
|
|
{
|
|
if(m_IsFocusVehicle || m_Vehicle->m_nVehicleFlags.bUsedForPilotSchool)
|
|
{
|
|
return AUD_VEHICLE_LOD_REAL;
|
|
}
|
|
else if(RequiresWaveSlot())
|
|
{
|
|
if(m_IsFocusVehicle || (distFromListenerSq < (m_PlaneAudioSettings->IsRealLODRange * sm_ActivationRangeScale)) )
|
|
{
|
|
return AUD_VEHICLE_LOD_REAL;
|
|
}
|
|
}
|
|
|
|
return distFromListenerSq < g_SuperDummyRadiusSq ? AUD_VEHICLE_LOD_SUPER_DUMMY : AUD_VEHICLE_LOD_DISABLED;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Turn on the engines
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::StartEngine()
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
if(plane)
|
|
{
|
|
m_NumClosingSamples = 0;
|
|
m_TimeLastClosingRateUpdated = fwTimer::GetTimeInMilliseconds();
|
|
m_ClosingRateAccum = 0.0f;
|
|
|
|
if(m_Vehicle && !m_Vehicle->m_nVehicleFlags.bSkipEngineStartup && !m_WasEngineOnLastFrame && !m_PlaneLoops[PLANE_LOOP_ENGINE])
|
|
{
|
|
if(m_IgnitionSound)
|
|
{
|
|
m_IgnitionSound->StopAndForget();
|
|
}
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->Ignition, &m_IgnitionSound, &initParams);
|
|
}
|
|
|
|
for(u32 loop = 0; loop < PLANE_LOOPS_MAX; loop++)
|
|
{
|
|
if(!m_PlaneLoops[loop] && m_PlaneLoopHashes[loop] != g_NullSoundHash &&
|
|
loop != PLANE_LOOP_AFTERBURNER) // Afterburner stops/starts as required, rather than constantly playing
|
|
{
|
|
if((loop == PLANE_LOOP_ENGINE && m_IsJet) ||
|
|
(loop == PLANE_LOOP_PROPELLOR && !m_IsJet))
|
|
{
|
|
Assign(initParams.EffectRoute, GetEngineEffectRoute());
|
|
}
|
|
else if(loop == PLANE_LOOP_EXHAUST || loop == PLANE_LOOP_AFTERBURNER )
|
|
{
|
|
Assign(initParams.EffectRoute, GetExhaustEffectRoute());
|
|
}
|
|
else
|
|
{
|
|
initParams.EffectRoute = 0;
|
|
}
|
|
|
|
// We missed the engine actually starting (probably because we were set to disabled) so fade in
|
|
u32 defaultPlaneAttackTime = 1000;
|
|
#if GTA_REPLAY
|
|
// always use a quick fade in for replay player vehicle
|
|
if(CReplayMgr::IsPlaying())
|
|
{
|
|
m_WasScheduledCreation = false;
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
defaultPlaneAttackTime = 0;
|
|
}
|
|
}
|
|
#endif
|
|
if(m_Vehicle->m_nVehicleFlags.bSkipEngineStartup || m_WasScheduledCreation || m_WasEngineOnLastFrame)
|
|
{
|
|
static bank_u32 fadeInTime = 8000;
|
|
initParams.AttackTime = m_WasScheduledCreation ? fadeInTime : defaultPlaneAttackTime;
|
|
}
|
|
else
|
|
{
|
|
initParams.AttackTime = defaultPlaneAttackTime; // default plane attack time, helps us hear startup sound
|
|
}
|
|
|
|
CreateAndPlaySound_Persistent(m_PlaneLoopHashes[loop], &m_PlaneLoops[loop], &initParams);
|
|
|
|
if(m_PlaneLoops[loop])
|
|
{
|
|
BANK_ONLY(if(!g_UseDebugPlaneTracker))
|
|
{
|
|
audVehicleSounds vehicleSoundType = AUD_VEHICLE_SOUND_ENGINE;
|
|
|
|
if(loop == PLANE_LOOP_EXHAUST ||
|
|
loop == PLANE_LOOP_AFTERBURNER)
|
|
{
|
|
vehicleSoundType = AUD_VEHICLE_SOUND_EXHAUST;
|
|
}
|
|
|
|
m_PlaneLoops[loop]->SetUpdateEntity(true);
|
|
m_PlaneLoops[loop]->SetClientVariable((u32)vehicleSoundType);
|
|
}
|
|
}
|
|
//else
|
|
//{
|
|
// StopEngine();
|
|
// return;
|
|
//}
|
|
}
|
|
}
|
|
|
|
m_PlaneStatus = AUD_PLANE_STARTING;
|
|
}
|
|
|
|
m_WasScheduledCreation = false;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Update gliding
|
|
// -------------------------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateGliding()
|
|
{
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
|
|
if(modelNameHash == ATSTRINGHASH("STARLING", 0x9A9EB7DE))
|
|
{
|
|
const bool shouldPlayGliderSound = !m_OnGround && !m_Vehicle->IsRocketBoosting();
|
|
|
|
if(shouldPlayGliderSound)
|
|
{
|
|
if(!m_GliderSound)
|
|
{
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = m_IsFocusVehicle? ATSTRINGHASH("DLC_Smuggler_Starling_Sounds", 0xC99D5122) : ATSTRINGHASH("DLC_Smuggler_Starling_NPC_Sounds", 0x1C2ADE23);
|
|
const u32 soundFieldName = ATSTRINGHASH("glide", 0xF9209D38);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound_Persistent(soundset.Find(soundFieldName), &m_GliderSound, &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSoundPersistant(soundsetName, soundFieldName, &initParams, m_GliderSound, GetOwningEntity()));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_GliderSound)
|
|
{
|
|
m_GliderSound->StopAndForget(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update the plane sounds
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateSounds(audPlaneValues& planeValues)
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
u32 currentTime = fwTimer::GetTimeInMilliseconds();
|
|
|
|
if(plane && m_PlaneAudioSettings)
|
|
{
|
|
bool playerInInterior = audNorthAudioEngine::GetGtaEnvironment()->AreWeInAnInterior();
|
|
if(!m_IsPlayerVehicle && playerInInterior)
|
|
{
|
|
f32 exteriorOcclusionFactor = audNorthAudioEngine::GetOcclusionManager()->GetExteriorOcclusionFor3DPosition(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()));
|
|
static bank_float maxOcclusion = 0.25f;
|
|
exteriorOcclusionFactor = Clamp(exteriorOcclusionFactor, 0.0f, maxOcclusion);
|
|
BANK_ONLY(m_DebugOcclusion = exteriorOcclusionFactor;)
|
|
if(m_EnvironmentGroup)
|
|
{
|
|
m_EnvironmentGroup->SetExtraOcclusionValue(exteriorOcclusionFactor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_EnvironmentGroup)
|
|
{
|
|
m_EnvironmentGroup->SetExtraOcclusionValue(0.0f);
|
|
}
|
|
BANK_ONLY(m_DebugOcclusion = 0.0f;)
|
|
}
|
|
|
|
if(m_IsJet)
|
|
{
|
|
static bank_float afterburnerStartThrottle = 0.0f;
|
|
float throttle = plane->GetThrottle();
|
|
|
|
if(!m_IsPlayerVehicle && m_EngineSpeed > g_NpcEngineSpeedForAfterBurner)
|
|
{
|
|
throttle = 1.0f;
|
|
}
|
|
if(throttle > afterburnerStartThrottle && m_PlaneStatus != AUD_PLANE_STOPPING && m_PlaneStatus != AUD_PLANE_OFF && !m_Vehicle->m_nVehicleFlags.bIsDrowning BANK_ONLY( || g_UseDebugPlaneTracker) )
|
|
{
|
|
if(!m_PlaneLoops[PLANE_LOOP_AFTERBURNER] && m_EngineWaveSlot)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
Assign(initParams.EffectRoute, GetExhaustEffectRoute());
|
|
#if __BANK
|
|
if(g_UseDebugPlaneTracker)
|
|
{
|
|
initParams.EffectRoute = 0;
|
|
}
|
|
#endif
|
|
CreateSound_PersistentReference(m_PlaneLoopHashes[PLANE_LOOP_AFTERBURNER], &m_PlaneLoops[PLANE_LOOP_AFTERBURNER], &initParams);
|
|
|
|
if(m_PlaneLoops[PLANE_LOOP_AFTERBURNER])
|
|
{
|
|
m_PlaneLoops[PLANE_LOOP_AFTERBURNER]->SetUpdateEntity(true);
|
|
m_PlaneLoops[PLANE_LOOP_AFTERBURNER]->SetClientVariable((u32)AUD_VEHICLE_SOUND_EXHAUST);
|
|
m_PlaneLoops[PLANE_LOOP_AFTERBURNER]->PrepareAndPlay(m_EngineWaveSlot->waveSlot,false,15000);
|
|
}
|
|
}
|
|
}
|
|
else if(m_PlaneLoops[PLANE_LOOP_AFTERBURNER])
|
|
{
|
|
m_PlaneLoops[PLANE_LOOP_AFTERBURNER]->Stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
static bank_float distanceForDoppler = 200.0f;
|
|
|
|
// Fix for Distant plane sounds pitching up after being deleted from the world. Speed goes to 0 and thus the pitch goes up(when the plane is flying away from you).
|
|
// Doppler now smooths back to 1 as the plane approaches.
|
|
f32 doppler = m_DopplerSmoother.CalculateValue(m_DistanceFromListener > distanceForDoppler ? 0.0f : 1.0f);
|
|
if(fwTimer::IsGamePaused() || (m_IsPlayerVehicle && !camInterface::GetCinematicDirector().IsRenderingAnyInVehicleCinematicCamera()))
|
|
doppler = 0.0f;
|
|
for(u32 loop = 0; loop < PLANE_LOOPS_MAX; loop++)
|
|
{
|
|
if(m_PlaneLoops[loop])
|
|
{
|
|
m_PlaneLoops[loop]->SetRequestedVolume(planeValues.loopVolumes[loop]);
|
|
m_PlaneLoops[loop]->SetRequestedPitch(planeValues.loopPitches[loop]);
|
|
m_PlaneLoops[loop]->SetRequestedPostSubmixVolumeAttenuation(planeValues.postSubmixVolumes[loop]);
|
|
m_PlaneLoops[loop]->SetRequestedDopplerFactor(doppler);
|
|
|
|
if(NetworkInterface::IsGameInProgress())
|
|
{
|
|
if(loop == PLANE_LOOP_ENGINE || loop == PLANE_LOOP_EXHAUST || loop == PLANE_LOOP_PROPELLOR || loop == PLANE_LOOP_AFTERBURNER)
|
|
{
|
|
m_PlaneLoops[loop]->FindAndSetVariableValue(ATSTRINGHASH("BoostAmount", 0x5EADB832), m_Vehicle->GetBoostAmount());
|
|
m_PlaneLoops[loop]->FindAndSetVariableValue(ATSTRINGHASH("BoostTimer", 0x4925EC4E), m_Vehicle->GetSpeedUpBoostDuration());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool stallWarningOn = m_StallWarningOn && m_StallWarningEnabled && AreWarningSoundsValid();
|
|
|
|
#if __BANK
|
|
if(g_ForceStallWarningOn)
|
|
{
|
|
stallWarningOn = true;
|
|
}
|
|
#endif
|
|
|
|
if(stallWarningOn)
|
|
{
|
|
if(!m_StallWarning)
|
|
{
|
|
CreateSound_PersistentReference(m_PlaneAudioSettings->StallWarning, &m_StallWarning);
|
|
|
|
if(m_StallWarning)
|
|
{
|
|
m_StallWarning->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_StallWarning);
|
|
}
|
|
|
|
if(m_StallWarning)
|
|
{
|
|
Vector3 velocity = m_CachedVehicleVelocity;
|
|
|
|
if(velocity.z < 0.0f)
|
|
{
|
|
velocity.z = 0.0f;
|
|
}
|
|
|
|
f32 airSpeed = velocity.Mag();
|
|
f32 stallSeverity = Clamp(1.0f - (airSpeed/25.0f), 0.0f, 1.0f);
|
|
|
|
#if __BANK
|
|
if(g_ForceStallWarningOn)
|
|
{
|
|
stallSeverity = g_ForcedStallWarningSeverity;
|
|
}
|
|
#endif
|
|
m_StallWarning->FindAndSetVariableValue(ATSTRINGHASH("StallSeverity", 0x573A0501), stallSeverity);
|
|
}
|
|
|
|
if( plane->m_Transmission.GetCurrentlyMissFiring() && currentTime > (m_BackFireTime + 2000))
|
|
{
|
|
TriggerBackFire();
|
|
}
|
|
|
|
// prop plane miss fire
|
|
if(!m_IsJet)
|
|
{
|
|
if(plane->m_Transmission.GetCurrentlyRecoveringFromMissFiring())
|
|
{
|
|
f32 engineSpeed = Clamp(m_EngineSpeed, 0.0f, 1.0f);
|
|
s32 predelay = -1;
|
|
f32 volume = -6.0f;
|
|
|
|
static bank_float missFireBelowEngineSpeed = 0.4f;
|
|
if(engineSpeed < missFireBelowEngineSpeed && engineSpeed > 0.0f)
|
|
{
|
|
if(m_NextMissFireSoundTime > (currentTime + 1000))
|
|
{
|
|
m_NextMissFireSoundTime = currentTime;
|
|
}
|
|
if(currentTime > m_NextMissFireSoundTime)
|
|
{
|
|
static bank_s32 divFactor = 1;
|
|
predelay = (s32)((missFireBelowEngineSpeed - engineSpeed) * 1000.0f)/divFactor;
|
|
predelay = Clamp(predelay, 0, 1000);
|
|
|
|
static bank_float volFactor = 0.6f;
|
|
f32 linearVolume = Clamp(volFactor - engineSpeed, 0.0f, 1.0f);
|
|
volume = audDriverUtil::ComputeDbVolumeFromLinear(linearVolume);
|
|
}
|
|
}
|
|
else if(engineSpeed >= missFireBelowEngineSpeed)
|
|
{
|
|
if(currentTime > m_NextMissFireSoundTime && currentTime > (m_BackFireTime + 2000))
|
|
{
|
|
f32 health = m_Vehicle->GetVehicleDamage()->GetEngineHealth();
|
|
s32 multFactor = (s32)(health / 100.0f);
|
|
s32 maxRange = (s32)((engineSpeed) * 1000.0f)*multFactor;
|
|
predelay = audEngineUtil::GetRandomNumberInRange(maxRange/2, maxRange);
|
|
|
|
if(audEngineUtil::GetRandomFloat() > 0.75f)
|
|
{
|
|
TriggerBackFire();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(predelay != -1)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.Volume = volume;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(m_PlaneAudioSettings->EngineMissFire, &initParams);
|
|
m_NextMissFireSoundTime = fwTimer::GetTimeInMilliseconds() + predelay;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Calculate if the plane is in the water
|
|
// ----------------------------------------------------------------
|
|
bool audPlaneAudioEntity::CalculateIsInWater() const
|
|
{
|
|
if(IsSeaPlane())
|
|
{
|
|
return m_Vehicle->GetIsInWater();
|
|
}
|
|
|
|
return audVehicleAudioEntity::CalculateIsInWater();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the idle hull slap volume
|
|
// ----------------------------------------------------------------
|
|
f32 audPlaneAudioEntity::GetIdleHullSlapVolumeLinear(f32 speed) const
|
|
{
|
|
return m_VehicleSpeedToHullSlapVol.CalculateValue(speed);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audPlaneAudioEntity GetIdleHullSlapSound
|
|
// ----------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetIdleHullSlapSound() const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->IdleHullSlapLoop;
|
|
}
|
|
|
|
return audVehicleAudioEntity::GetIdleHullSlapSound();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audPlaneAudioEntity GetLeftWaterSound
|
|
// ----------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetLeftWaterSound() const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->LeftWaterSound;
|
|
}
|
|
|
|
return audVehicleAudioEntity::GetLeftWaterSound();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audPlaneAudioEntity GetWaveHitSound
|
|
// ----------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetWaveHitSound() const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->WaveHitSound;
|
|
}
|
|
|
|
return audVehicleAudioEntity::GetWaveHitSound();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audPlaneAudioEntity GetWaveHitBigSound
|
|
// ----------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetWaveHitBigSound() const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->WaveHitBigAirSound;
|
|
}
|
|
|
|
return audVehicleAudioEntity::GetWaveHitBigSound();
|
|
}
|
|
|
|
#if __BANK
|
|
void audPlaneAudioEntity::ShowDebugInfo(audPlaneValues& planeValues)
|
|
{
|
|
#define NEXT_LINE grcDebugDraw::Text(Vector2(0.1f, lineBase), Color32(255,255,255), tempString ); lineBase += lineInc;
|
|
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
if(g_ShowDebugInfo && (m_IsPlayerVehicle || plane == g_pFocusEntity))
|
|
{
|
|
char tempString[2048];
|
|
static bank_float lineInc = 0.015f;
|
|
f32 lineBase = 0.1f;
|
|
formatf(tempString, " VOLUME PITCH SUBMIX_VOL"); NEXT_LINE
|
|
formatf(tempString, "ENGINE %8.4f %5d %8.4f", planeValues.loopVolumes[0], planeValues.loopPitches[0], planeValues.postSubmixVolumes[0]); NEXT_LINE
|
|
formatf(tempString, "EXHAUST %8.4f %5d %8.4f", planeValues.loopVolumes[1], planeValues.loopPitches[1], planeValues.postSubmixVolumes[1]); NEXT_LINE
|
|
formatf(tempString, "IDLE %8.4f %5d %8.4f", planeValues.loopVolumes[2], planeValues.loopPitches[2], planeValues.postSubmixVolumes[2]); NEXT_LINE
|
|
formatf(tempString, "DISTANT %8.4f %5d %8.4f", planeValues.loopVolumes[3], planeValues.loopPitches[3], planeValues.postSubmixVolumes[3]); NEXT_LINE
|
|
formatf(tempString, "PROP %8.4f %5d %8.4f", planeValues.loopVolumes[4], planeValues.loopPitches[4], planeValues.postSubmixVolumes[4]); NEXT_LINE
|
|
formatf(tempString, "BANKING %8.4f %5d %8.4f", planeValues.loopVolumes[5], planeValues.loopPitches[5], planeValues.postSubmixVolumes[5]); NEXT_LINE
|
|
formatf(tempString, "AFTER %8.4f %5d %8.4f", planeValues.loopVolumes[6], planeValues.loopPitches[6], planeValues.postSubmixVolumes[6]); NEXT_LINE
|
|
formatf(tempString, "DAM %8.4f %5d %8.4f", planeValues.loopVolumes[7], planeValues.loopPitches[7], planeValues.postSubmixVolumes[7]); NEXT_LINE
|
|
formatf(tempString, "DIVING L %8.4f %5d %8.4f", 0.0f, m_DebugDivePitchLoops, 0.0f); NEXT_LINE
|
|
formatf(tempString, "DIVING S %8.4f %5d %8.4f %8.4f", audDriverUtil::ComputeDbVolumeFromLinear(m_DiveSoundVolumeLin) + planeValues.loopVolumes[PLANE_LOOP_ENGINE], m_DiveSoundPitch, 0.0f, m_DiveSoundVolumeLin); NEXT_LINE
|
|
formatf(tempString, "VERT_SPD %8.4f SPEED %8.4f CLOSING %8.4f", m_DebugVertAirSpeed, m_AirSpeed, m_ClosingRate); NEXT_LINE
|
|
formatf(tempString, "NUM_PROPS %d IS_JET %d ON_GRND %d CONTACT %d", plane->GetNumPropellors(), m_IsJet, m_OnGround, m_Vehicle->HasContactWheels()); NEXT_LINE
|
|
formatf(tempString, "DOWNWASH HEIGHT %8.4f", m_DownwashHeight); NEXT_LINE
|
|
formatf(tempString, "THROTTLE %8.4f", static_cast<CPlane*>(m_Vehicle)->GetThrottle()); NEXT_LINE
|
|
formatf(tempString, "THROTTLE CONTROL %8.4f", static_cast<CPlane*>(m_Vehicle)->GetThrottleControl()); NEXT_LINE
|
|
formatf(tempString, "BOOST TIMER %8.4f BOOST AMOUNT %8.4f", m_Vehicle->GetSpeedUpBoostDuration(), m_Vehicle->GetBoostAmount()); NEXT_LINE
|
|
formatf(tempString, "ENG SPEED %8.4f ENG_ON %d AUD_ENG_ON %d", m_EngineSpeed, m_Vehicle->m_nVehicleFlags.bEngineOn, IsEngineOn()); NEXT_LINE
|
|
formatf(tempString, "ENG HEALTH %8.4f MISSFIRE %d RECOVER_MISSFIRE %d TIME %8.4f",
|
|
m_Vehicle->GetVehicleDamage()->GetEngineHealth(), plane->m_Transmission.GetCurrentlyMissFiring(),
|
|
plane->m_Transmission.GetCurrentlyRecoveringFromMissFiring(),
|
|
plane->m_Transmission.GetOverrideMissFireTime()); NEXT_LINE
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update the engine sounds
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateEngineOn(audPlaneValues& planeValues)
|
|
{
|
|
const Mat34V mat = m_Vehicle->GetMatrix();
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
f32 engineSpeed = Clamp(m_EngineSpeed, 0.0f, 1.0f);
|
|
|
|
f32 pitchAngle = AcosfSafe(Dot(m_Vehicle->GetTransform().GetB(), Vec3V(V_Z_AXIS_WZERO)).Getf()) * RtoD;
|
|
|
|
if(pitchAngle < 90.0f)
|
|
{
|
|
pitchAngle = 90.0f;
|
|
}
|
|
|
|
pitchAngle -= 90.0f;
|
|
f32 pitchProportion = 1.0f - ((90.0f - pitchAngle)/90.0f);
|
|
|
|
m_AirSpeed = m_CachedVehicleVelocity.Mag();
|
|
f32 airSpeedZ = m_CachedVehicleVelocity.z;
|
|
|
|
// only dive bomb if going fast and height is dropping
|
|
static bank_float resetPitchProportion = 0.2f;
|
|
if(pitchProportion < resetPitchProportion && (m_AirSpeed < m_PlaneAudioSettings->DiveAirSpeedThreshold || airSpeedZ > m_PlaneAudioSettings->DivingRateApproachingGround))
|
|
pitchProportion = 0.0f;
|
|
|
|
float divingRate = (float)m_PlaneAudioSettings->DivingFactor;
|
|
if(divingRate > 100.0f)
|
|
divingRate = 1.0f;
|
|
s32 diveBombPitchChangeLoops = (s32)(m_angleBasedPitchLoopSmoother.CalculateValue(divingRate * m_PlaneAudioSettings->MaxDivePitch * pitchProportion));
|
|
|
|
m_DiveSoundPitch = (s32)(m_angleBasedPitchSmoother.CalculateValue((f32)m_PlaneAudioSettings->DivingSoundPitchFactor * m_PlaneAudioSettings->MaxDiveSoundPitch * pitchProportion));
|
|
|
|
m_DiveSoundVolumeLin = m_angleBasedVolumeSmoother.CalculateValue((f32)m_PlaneAudioSettings->DivingSoundVolumeFactor * pitchProportion);
|
|
m_DiveSoundVolumeLin = Clamp(m_DiveSoundVolumeLin, 0.0f, 1.0f);
|
|
|
|
#if __BANK
|
|
m_DebugDivePitchLoops = diveBombPitchChangeLoops;
|
|
m_DebugVertAirSpeed = airSpeedZ;
|
|
|
|
if(divingRate != m_DebugDivingRate)
|
|
{
|
|
static bank_float pullupRateMult = 2.5f;
|
|
m_angleBasedPitchLoopSmoother.Init(divingRate, divingRate*pullupRateMult, 0.0f, (float)m_PlaneAudioSettings->MaxDivePitch);
|
|
m_angleBasedPitchSmoother.Init(divingRate, divingRate*pullupRateMult, 0.0f, (float)m_PlaneAudioSettings->MaxDivePitch);
|
|
m_DebugDivingRate = divingRate;
|
|
|
|
static bank_float incRate = 0.01f;
|
|
m_angleBasedVolumeSmoother.Init(divingRate*incRate, divingRate*incRate*pullupRateMult, 0.0f, 1.0f);
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
for(u32 loop = 0; loop < PLANE_LOOPS_MAX; loop++)
|
|
{
|
|
f32 adjustedEngineSpeed = engineSpeed;
|
|
|
|
if(loop == PLANE_LOOP_ENGINE || loop == PLANE_LOOP_EXHAUST || loop == PLANE_LOOP_PROPELLOR)
|
|
{
|
|
adjustedEngineSpeed *= planeValues.propellorHealthFactor;
|
|
}
|
|
|
|
planeValues.loopPitches[loop] = (s32) m_PlaneLoopPitchCurves[loop].CalculateValue(adjustedEngineSpeed);
|
|
planeValues.loopPitches[loop] += diveBombPitchChangeLoops;
|
|
planeValues.loopVolumes[loop] = m_PlaneLoopVolumeCurves[loop].CalculateValue(adjustedEngineSpeed);
|
|
planeValues.postSubmixVolumes[loop] = m_PlaneLoopVolumeCones[loop].ComputeAttenuation(mat);
|
|
planeValues.postSubmixVolumes[loop] += g_PlaneVolumeTrims[loop];
|
|
|
|
if(loop == PLANE_LOOP_BANKING)
|
|
{
|
|
if(m_PlaneAudioSettings->BankingStyle == kRotationAngle)
|
|
{
|
|
planeValues.loopVolumes[loop] += m_BankingAngleVolCurve.CalculateValue(m_BankingAngle);
|
|
}
|
|
if(!m_IsJet || m_PlaneAudioSettings->BankingStyle == kRotationSpeed)
|
|
{
|
|
f32 angularVelocity = GetCachedAngularVelocity().Mag();
|
|
|
|
// Treat peeling in the same way as spinning
|
|
if(m_IsPeeling && !m_OnGround)
|
|
{
|
|
angularVelocity += 5.0f;
|
|
|
|
static bank_float fPeelingInc = 0.009f;
|
|
m_PeelingFactor += fPeelingInc;
|
|
}
|
|
else
|
|
{
|
|
if(m_PeelingFactor > 0.5f)
|
|
m_PeelingFactor = 0.5f;
|
|
static bank_float fPeelingDec = 0.008f;
|
|
m_PeelingFactor -= fPeelingDec;
|
|
}
|
|
m_PeelingFactor = Clamp(m_PeelingFactor, 0.0f, 1.0f);
|
|
//Displayf("Peeling %f", m_PeelingFactor);
|
|
planeValues.loopPitches[PLANE_LOOP_ENGINE] += (s32)m_PeelingPitchCurve.CalculateValue(m_PeelingFactor);
|
|
planeValues.loopPitches[PLANE_LOOP_EXHAUST] += (s32)m_PeelingPitchCurve.CalculateValue(m_PeelingFactor);
|
|
planeValues.loopPitches[PLANE_LOOP_BANKING] += (s32)m_PeelingPitchCurve.CalculateValue(m_PeelingFactor);
|
|
planeValues.loopPitches[PLANE_LOOP_PROPELLOR] += (s32)m_PeelingPitchCurve.CalculateValue(m_PeelingFactor);
|
|
|
|
planeValues.loopPitches[PLANE_LOOP_AFTERBURNER] += (s32)(m_PeelingPitchCurve.CalculateValue(m_PeelingFactor) * m_PlaneAudioSettings->PeelingAfterburnerPitchScalingFactor);
|
|
|
|
f32 angularVelocitySmoothed = m_angularVelocitySmoother.CalculateValue(angularVelocity);
|
|
if(m_InARecording)
|
|
{
|
|
planeValues.loopVolumes[loop] += m_BankingAngleVolCurve.CalculateValue(m_BankingAngle);
|
|
}
|
|
else
|
|
{
|
|
planeValues.loopVolumes[loop] += m_BankingAngleVolCurve.CalculateValue(angularVelocitySmoothed);
|
|
}
|
|
}
|
|
}
|
|
else if(loop == PLANE_LOOP_AFTERBURNER)
|
|
{
|
|
f32 throttle = 0.0f;
|
|
if(m_Vehicle->m_nVehicleFlags.bEngineOn && IsEngineOn())
|
|
{
|
|
throttle = plane->GetThrottle();
|
|
|
|
if(!m_IsPlayerVehicle && m_EngineSpeed > g_NpcEngineSpeedForAfterBurner)
|
|
{
|
|
throttle = 1.0f;
|
|
}
|
|
}
|
|
#if __BANK
|
|
if(g_UseDebugPlaneTracker)
|
|
{
|
|
throttle = 0.5f;
|
|
}
|
|
#endif
|
|
planeValues.loopVolumes[loop] = m_PlaneLoopVolumeCurves[loop].CalculateValue(throttle);
|
|
//Displayf("throttle %f abvol %f", throttle, planeValues.loopVolumes[loop]);
|
|
}
|
|
else if(loop == PLANE_LOOP_DISTANCE)
|
|
{
|
|
Vector3 planePosition = BANK_ONLY(g_UseDebugPlaneTracker? (Vector3) m_DebugTracker.GetPosition() : )VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
Vector3 planeToListener = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(0)) - planePosition;
|
|
m_DistanceFromListener = planeToListener.Mag();
|
|
planeValues.loopVolumes[loop] += m_DistanceEffectVolCurve.CalculateValue(m_DistanceFromListener);
|
|
|
|
if(!m_IsPlayerVehicle BANK_ONLY(|| g_UseDebugPlaneTracker))
|
|
{
|
|
static f32 maxDist = 100.0f;
|
|
static f32 minDist = 0.0f;
|
|
static f32 maxPitch = 10.0f;
|
|
static f32 minPitch = 0.0f;
|
|
|
|
static const audThreePointPiecewiseLinearCurve pitchCurve(minDist, maxPitch, maxDist/2.0f, maxPitch/2.0f, maxDist, minPitch);
|
|
|
|
planeValues.loopPitches[loop] = (s32) pitchCurve.CalculateValue(m_DistanceFromListener);
|
|
}
|
|
}
|
|
else if(loop == PLANE_LOOP_DAMAGE)
|
|
{
|
|
if(m_IsJet)
|
|
{
|
|
f32 vehicleHealth = m_Vehicle->GetVehicleDamage()->GetEngineHealth();
|
|
planeValues.loopVolumes[loop] += audDriverUtil::ComputeDbVolumeFromLinear( m_DamageVolumeCurve.CalculateValue(vehicleHealth) );
|
|
}
|
|
else
|
|
{
|
|
planeValues.loopVolumes[loop] = g_SilenceVolume;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// we turn off the prop sound for jets that the player is flying. This sound is used for distant jet sounds.
|
|
if(m_IsJet && (m_IsPlayerVehicle || m_PlaneStatus != AUD_PLANE_ON))
|
|
{
|
|
planeValues.loopVolumes[PLANE_LOOP_PROPELLOR] = -100.0f;
|
|
}
|
|
|
|
static bank_float downwashHeight = 0.2f;
|
|
static bank_float airSpeedToTurnOnRoar = 30.0f;
|
|
if(m_IsJet && !m_IsPlayerVehicle && ((m_OnGround && m_AirSpeed < airSpeedToTurnOnRoar) || (m_DownwashHeight > 0.0f && m_DownwashHeight < downwashHeight) || m_AirSpeed == 0.0f))
|
|
{
|
|
if(m_OnGround && m_AirSpeed > airSpeedToTurnOnRoar)
|
|
{
|
|
planeValues.loopVolumes[PLANE_LOOP_DISTANCE] = m_DistantSoundVolumeSmoother.CalculateValue(planeValues.loopVolumes[PLANE_LOOP_DISTANCE]);
|
|
if(m_IsJet) // jets use the prop slot for up close in air roaring sound, need to smooth this as we get off the ground
|
|
{
|
|
planeValues.loopVolumes[PLANE_LOOP_PROPELLOR] += planeValues.loopVolumes[PLANE_LOOP_DISTANCE]; // this will fade out the jet flyby sweetner sound when on ground
|
|
}
|
|
}
|
|
else
|
|
{
|
|
planeValues.loopVolumes[PLANE_LOOP_DISTANCE] = m_DistantSoundVolumeSmoother.CalculateValue(-100.0f);
|
|
planeValues.loopVolumes[PLANE_LOOP_PROPELLOR] += planeValues.loopVolumes[PLANE_LOOP_DISTANCE]; // this will fade out the jet flyby sweetner sound when on ground
|
|
}
|
|
}
|
|
else
|
|
{
|
|
planeValues.loopVolumes[PLANE_LOOP_DISTANCE] = m_DistantSoundVolumeSmoother.CalculateValue(planeValues.loopVolumes[PLANE_LOOP_DISTANCE]);
|
|
if(m_IsJet) // jets use the prop slot for up close in air roaring sound, need to smooth this as we get off the ground
|
|
{
|
|
planeValues.loopVolumes[PLANE_LOOP_PROPELLOR] += planeValues.loopVolumes[PLANE_LOOP_DISTANCE]; // this will fade out the jet flyby sweetner sound when on ground
|
|
}
|
|
}
|
|
|
|
planeValues.haveBeenCalculated = true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update the flight mode for VTOL planes
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateVTOL()
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
// Only update these variable whilst the engine is on
|
|
if(plane->GetVerticalFlightModeAvaliable() && m_Vehicle->m_nVehicleFlags.bEngineOn)
|
|
{
|
|
f32 flightMode = plane->GetVerticalFlightModeRatio();
|
|
|
|
#if __BANK
|
|
if(g_ForceFlightMode)
|
|
{
|
|
flightMode = g_ForcedFlightModeValue;
|
|
}
|
|
else
|
|
{
|
|
g_ForcedFlightModeValue = flightMode;
|
|
}
|
|
#endif
|
|
|
|
f32 downwashHeight = m_DownwashHeight >= 0.0f? m_DownwashHeight : 1.0f;
|
|
f32 throttle = plane->GetThrottleControl();
|
|
|
|
if(m_PlaneLoops[PLANE_LOOP_ENGINE])
|
|
{
|
|
m_PlaneLoops[PLANE_LOOP_ENGINE]->FindAndSetVariableValue(ATSTRINGHASH("flightmode", 0x1DFCE7B5), flightMode);
|
|
m_PlaneLoops[PLANE_LOOP_ENGINE]->FindAndSetVariableValue(ATSTRINGHASH("distancetoground", 0x2A4943B4), downwashHeight);
|
|
m_PlaneLoops[PLANE_LOOP_ENGINE]->FindAndSetVariableValue(ATSTRINGHASH("throttle", 0xEA0151DC), throttle);
|
|
}
|
|
|
|
if(m_PlaneLoops[PLANE_LOOP_EXHAUST])
|
|
{
|
|
m_PlaneLoops[PLANE_LOOP_EXHAUST]->FindAndSetVariableValue(ATSTRINGHASH("flightmode", 0x1DFCE7B5), flightMode);
|
|
m_PlaneLoops[PLANE_LOOP_EXHAUST]->FindAndSetVariableValue(ATSTRINGHASH("distancetoground", 0x2A4943B4), downwashHeight);
|
|
m_PlaneLoops[PLANE_LOOP_EXHAUST]->FindAndSetVariableValue(ATSTRINGHASH("throttle", 0xEA0151DC), throttle);
|
|
}
|
|
|
|
if(m_PlaneLoops[PLANE_LOOP_AFTERBURNER])
|
|
{
|
|
m_PlaneLoops[PLANE_LOOP_AFTERBURNER]->FindAndSetVariableValue(ATSTRINGHASH("flightmode", 0x1DFCE7B5), flightMode);
|
|
m_PlaneLoops[PLANE_LOOP_AFTERBURNER]->FindAndSetVariableValue(ATSTRINGHASH("distancetoground", 0x2A4943B4), downwashHeight);
|
|
m_PlaneLoops[PLANE_LOOP_AFTERBURNER]->FindAndSetVariableValue(ATSTRINGHASH("throttle", 0xEA0151DC), throttle);
|
|
}
|
|
|
|
if(m_PlaneLoops[PLANE_LOOP_IDLE])
|
|
{
|
|
m_PlaneLoops[PLANE_LOOP_IDLE]->FindAndSetVariableValue(ATSTRINGHASH("flightmode", 0x1DFCE7B5), flightMode);
|
|
}
|
|
|
|
if(m_PlaneLoops[PLANE_LOOP_PROPELLOR])
|
|
{
|
|
m_PlaneLoops[PLANE_LOOP_PROPELLOR]->FindAndSetVariableValue(ATSTRINGHASH("flightmode", 0x1DFCE7B5), flightMode);
|
|
}
|
|
|
|
if(m_PlaneLoops[PLANE_LOOP_BANKING])
|
|
{
|
|
m_PlaneLoops[PLANE_LOOP_BANKING]->FindAndSetVariableValue(ATSTRINGHASH("flightmode", 0x1DFCE7B5), flightMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update sea plane specific stuff
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateSeaPlane()
|
|
{
|
|
if(CalculateIsInWater())
|
|
{
|
|
if(!m_WaterTurbulenceSound)
|
|
{
|
|
if(m_PlaneAudioSettings->WaterTurbulenceSound != g_NullSoundHash)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->WaterTurbulenceSound, &m_WaterTurbulenceSound, &initParams);
|
|
}
|
|
}
|
|
}
|
|
else if(m_WaterTurbulenceSound)
|
|
{
|
|
m_WaterTurbulenceSound->StopAndForget();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Called when the the
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::OnVerticalFlightModeChanged(f32 newFlightModeRatio)
|
|
{
|
|
if(m_VTOLThrusterSoundset.IsInitialised())
|
|
{
|
|
if(m_VTOLModeSwitchSound)
|
|
{
|
|
m_VTOLModeSwitchSound->StopAndForget();
|
|
}
|
|
|
|
audMetadataRef switchSound = m_VTOLThrusterSoundset.Find(newFlightModeRatio == 1.0f? ATSTRINGHASH("thrusters_up", 0xA4515F19) : ATSTRINGHASH("thrusters_down", 0x5C8C8AC0));
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound_Persistent(switchSound, &m_VTOLModeSwitchSound, &initParams);
|
|
|
|
if(m_VTOLModeSwitchSound)
|
|
{
|
|
m_VTOLModeSwitchSound->SetUpdateEntity(true);
|
|
m_VTOLModeSwitchSound->SetClientVariable((u32)AUD_VEHICLE_SOUND_ENGINE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void audPlaneAudioEntity::UpdateEngineCooling()
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
if(plane)
|
|
{
|
|
static bank_float engineCooldownTemperatureRange = 20.0f;
|
|
const f32 baseTemperature = g_weather.GetTemperature(m_Vehicle->GetTransform().GetPosition());
|
|
const bool shouldEngineCoolingStop = (m_Vehicle->m_nVehicleFlags.bIsDrowning || m_Vehicle->m_nVehicleFlags.bEngineOn || m_Vehicle->m_EngineTemperature <= m_EngineOffTemperature - engineCooldownTemperatureRange);
|
|
const bool shouldEngineCoolingStart = (!m_Vehicle->m_nVehicleFlags.bIsDrowning && ((m_PlaneStatus == AUD_PLANE_OFF || m_PlaneStatus == AUD_PLANE_STOPPING) && m_Vehicle->m_EngineTemperature > baseTemperature + 30.f));
|
|
f32 engineCoolingProgress = Clamp((engineCooldownTemperatureRange - (m_EngineOffTemperature - m_Vehicle->m_EngineTemperature))/engineCooldownTemperatureRange, 0.0f, 1.0f);
|
|
if(m_Vehicle->m_nVehicleFlags.bEngineOn)
|
|
{
|
|
engineCoolingProgress = 1.0f;
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_ShowEngineCooling)
|
|
{
|
|
char tempString[128];
|
|
formatf(tempString, "Cooling Progress %4.2f OffTemp %4.2f Temp:%4.2f Base:%4.2f Occ %4.2f", engineCoolingProgress, m_EngineOffTemperature, m_Vehicle->m_EngineTemperature, baseTemperature, m_DebugOcclusion);
|
|
grcDebugDraw::Text(m_Vehicle->GetTransform().GetPosition(), Color_green, tempString);
|
|
}
|
|
#endif
|
|
|
|
if(m_EngineCoolingSound)
|
|
{
|
|
if(shouldEngineCoolingStop)
|
|
{
|
|
m_EngineCoolingSound->StopAndForget();
|
|
}
|
|
else
|
|
{
|
|
((audSound*)m_EngineCoolingSound)->FindAndSetVariableValue(g_TemperatureVariableHash, engineCoolingProgress);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(shouldEngineCoolingStart && !shouldEngineCoolingStop)
|
|
{
|
|
audSoundInitParams initParams;
|
|
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateSound_PersistentReference(ATSTRINGHASH("HEAT_STRESS_HEAT_TICK_LOOP", 0x578B87D4), &m_EngineCoolingSound, &initParams);
|
|
|
|
if(m_EngineCoolingSound)
|
|
{
|
|
m_EngineCoolingSound->SetUpdateEntity(true);
|
|
m_EngineCoolingSound->SetClientVariable((u32)AUD_VEHICLE_SOUND_ENGINE);
|
|
((audSound*)m_EngineCoolingSound)->FindAndSetVariableValue(g_TemperatureVariableHash, engineCoolingProgress);
|
|
|
|
m_EngineCoolingSound->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Stop all the sounds
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::StopEngine(bool fadeOut)
|
|
{
|
|
static bank_u32 fadeOutTime = 5000;
|
|
for(u32 loop = 0; loop < PLANE_LOOPS_MAX; loop++)
|
|
{
|
|
if(m_PlaneLoops[loop])
|
|
{
|
|
if(!m_PlaneLoops[loop]->IsBeingReleased())
|
|
{
|
|
if(fadeOut)
|
|
{
|
|
m_PlaneLoops[loop]->SetRequestedDopplerFactor(0.0f);
|
|
m_PlaneLoops[loop]->SetReleaseTime(fadeOutTime);
|
|
}
|
|
else
|
|
{
|
|
static bank_u32 defaultFadeOut = 1000;
|
|
m_PlaneLoops[loop]->SetReleaseTime(defaultFadeOut);
|
|
}
|
|
}
|
|
|
|
if(m_PlaneLoops[loop])
|
|
{
|
|
m_PlaneLoops[loop]->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_StallWarning)
|
|
{
|
|
if(fadeOut)
|
|
{
|
|
m_StallWarning->SetReleaseTime(fadeOutTime);
|
|
}
|
|
|
|
StopAndForgetSounds(m_StallWarning);
|
|
}
|
|
|
|
if(m_WindSound)
|
|
{
|
|
m_WindSound->StopAndForget();
|
|
}
|
|
|
|
if(m_DiveSound)
|
|
{
|
|
m_DiveSound->StopAndForget();
|
|
}
|
|
|
|
m_HasPlayedShutdownSound = false;
|
|
m_PlaneStatus = AUD_PLANE_OFF;
|
|
}
|
|
|
|
void audPlaneAudioEntity::ShutdownJetEngine()
|
|
{
|
|
if(!m_HasPlayedShutdownSound)
|
|
{
|
|
// GTA special case for the Starling - extra shutdown behaviour
|
|
if(m_PlaneStatus != AUD_PLANE_OFF && GetVehicleModelNameHash() == ATSTRINGHASH("STARLING", 0x9A9EB7DE))
|
|
{
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = m_IsFocusVehicle? ATSTRINGHASH("DLC_Smuggler_Starling_Sounds", 0xC99D5122) : ATSTRINGHASH("DLC_Smuggler_Starling_NPC_Sounds", 0x1C2ADE23);
|
|
const u32 soundFieldName = ATSTRINGHASH("shutdown", 0xE99B0DCB);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(soundset.Find(soundFieldName), &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundsetName, soundFieldName, &initParams, GetOwningEntity()));
|
|
}
|
|
}
|
|
|
|
m_HasPlayedShutdownSound = true;
|
|
}
|
|
|
|
if(m_FakeEngineSpeed == -10.0f)
|
|
return;
|
|
|
|
if(m_FakeEngineSpeed > -10.0f && m_FakeEngineSpeed < 0.0f)
|
|
{
|
|
m_FakeEngineSpeed = -10.0f;
|
|
if(m_PlaneStatus != AUD_PLANE_ON) // don't stop the engine sound when we are just getting the fake engine to match the real engine
|
|
{
|
|
StopEngine();
|
|
}
|
|
}
|
|
else if(!m_OnGround && m_FakeEngineSpeed < 0.03f && m_PlaneStatus == AUD_PLANE_STOPPING && !IsEngineOn()) // this is for gliding, detects when we are at the lowest point in engine speed
|
|
{
|
|
StopEngine();
|
|
}
|
|
else
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
if(!m_OnGround && m_FakeEngineSpeed < plane->GetEngineSpeed())
|
|
{
|
|
m_FakeEngineSpeed = plane->GetEngineSpeed();
|
|
}
|
|
else
|
|
{
|
|
static bank_float instantOnOffDecTime = 0.05f;
|
|
|
|
if(m_OnGround || !m_IsPlayerVehicle)
|
|
{
|
|
if(m_Vehicle->m_nVehicleFlags.bIsDrowning)
|
|
{
|
|
static bank_float decInAir = 0.01f;
|
|
m_FakeEngineSpeed -= m_EngineInstantOnOff? instantOnOffDecTime : decInAir;
|
|
}
|
|
else
|
|
{
|
|
static bank_float decOnGround = 0.0005f;
|
|
m_FakeEngineSpeed -= m_EngineInstantOnOff? instantOnOffDecTime : decOnGround;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_Vehicle->m_nVehicleFlags.bIsDrowning)
|
|
{
|
|
static bank_float decInAir = 0.01f;
|
|
m_FakeEngineSpeed -= m_EngineInstantOnOff? instantOnOffDecTime : decInAir;
|
|
}
|
|
else
|
|
{
|
|
static bank_float decInAir = 0.004f;
|
|
m_FakeEngineSpeed -= m_EngineInstantOnOff? instantOnOffDecTime : decInAir;
|
|
}
|
|
}
|
|
//Displayf("Engine Speed %f", m_FakeEngineSpeed);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Convert the plane to disabled
|
|
// -------------------------------------------------------------------------------
|
|
void audPlaneAudioEntity::ConvertToDisabled()
|
|
{
|
|
if(m_PlaneStatus != AUD_PLANE_OFF && m_PlaneStatus != AUD_PLANE_STOPPING)
|
|
{
|
|
StopEngine(true);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update stall warning
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateStallWarning(audPlaneValues& UNUSED_PARAM(planeValues))
|
|
{
|
|
u32 currentTime = g_AudioEngine.GetTimeInMilliseconds();
|
|
|
|
f32 airSpeed = m_CachedVehicleVelocity.Mag();
|
|
f32 airSpeedZ = m_CachedVehicleVelocity.z;
|
|
f32 pitchAngle = AcosfSafe(Dot(m_Vehicle->GetTransform().GetB(), Vec3V(V_Z_AXIS_WZERO)).Getf()) * RtoD;
|
|
|
|
if(!m_StallWarningOn)
|
|
{
|
|
// Don't warn during takeoff
|
|
if(m_IsPlayerVehicle &&
|
|
m_TimeInAir > 5.0f)
|
|
{
|
|
if(pitchAngle < 37.5f)
|
|
{
|
|
if(airSpeedZ < 17.5f)
|
|
{
|
|
m_StallWarningOn = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(g_PlayerSwitch.IsActive())
|
|
{
|
|
m_StallWarningOn = false;
|
|
}
|
|
|
|
if(m_StallWarningOn)
|
|
{
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
if(m_TimeStallStarted == 0)
|
|
{
|
|
m_TimeStallStarted = currentTime;
|
|
}
|
|
else if(currentTime - m_TimeStallStarted > (g_AircraftWarningSettings ? g_AircraftWarningSettings->PlaneWarningStall.MinTimeInStateToTrigger : 1500) )
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_PLANE_WARNING_STALL);
|
|
}
|
|
}
|
|
|
|
if(airSpeed > 25.0f )
|
|
{
|
|
if(pitchAngle < 40.0f &&
|
|
airSpeedZ < 0.0f)
|
|
{
|
|
// Case where the plane has picked up speed but only because its falling vertically backwards - need
|
|
// to keep stall warning on in this situation
|
|
}
|
|
else
|
|
{
|
|
m_StallWarningOn = false;
|
|
}
|
|
}
|
|
else if(pitchAngle > 90.0f ||
|
|
m_TimeInAir <= 5.0f) // Crashed!
|
|
{
|
|
m_StallWarningOn = false;
|
|
}
|
|
}
|
|
else if(m_IsPlayerVehicle)
|
|
{
|
|
m_TimeStallStarted = 0;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Get the engine submix synth def
|
|
// -------------------------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetEngineSubmixSynth() const
|
|
{
|
|
if(ShouldUseDSPEffects() && m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->EngineSynthDef;
|
|
}
|
|
else
|
|
{
|
|
return audVehicleAudioEntity::GetEngineSubmixSynth();
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Get the engine submix synth preset
|
|
// -------------------------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetEngineSubmixSynthPreset() const
|
|
{
|
|
if(ShouldUseDSPEffects() && m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->EngineSynthPreset;
|
|
}
|
|
else
|
|
{
|
|
return audVehicleAudioEntity::GetEngineSubmixSynthPreset();
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Get the exhaust submix synth def
|
|
// -------------------------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetExhaustSubmixSynth() const
|
|
{
|
|
if(ShouldUseDSPEffects() && m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->ExhaustSynthDef;
|
|
}
|
|
else
|
|
{
|
|
return audVehicleAudioEntity::GetExhaustSubmixSynth();
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Get the exhaust submix synth preset
|
|
// -------------------------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetExhaustSubmixSynthPreset() const
|
|
{
|
|
if(ShouldUseDSPEffects() && m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->ExhaustSynthPreset;
|
|
}
|
|
else
|
|
{
|
|
return audVehicleAudioEntity::GetExhaustSubmixSynthPreset();
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Get the engine submix voice
|
|
// -------------------------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetEngineSubmixVoice() const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->EngineSubmixVoice;
|
|
}
|
|
else
|
|
{
|
|
return audVehicleAudioEntity::GetEngineSubmixVoice();
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Get the exhaust submix voice
|
|
// -------------------------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetExhaustSubmixVoice() const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->ExhaustSubmixVoice;
|
|
}
|
|
else
|
|
{
|
|
return audVehicleAudioEntity::GetExhaustSubmixVoice();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audPlaneAudioEntity GetCabinToneSound
|
|
// ----------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetCabinToneSound() const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return m_PlaneAudioSettings->CabinToneLoop;
|
|
}
|
|
|
|
return audVehicleAudioEntity::GetCabinToneSound();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a tyre squeal when the wheel hits the ground
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateTyreSqueals()
|
|
{
|
|
bool planeInAir = true;
|
|
|
|
bool contactWheels = m_Vehicle->HasContactWheels();
|
|
|
|
static bank_float distanceToFilterInstantInAirs = 400.0f;
|
|
|
|
// For every wheel...
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels() && i < MAX_PLANE_WHEELS; i++)
|
|
{
|
|
bool wheelInAir = !(m_Vehicle->GetWheel(i)->GetIsTouching() || m_Vehicle->GetWheel(i)->GetWasTouching());
|
|
|
|
// If the wheel is not in the air...
|
|
if(!wheelInAir && contactWheels)
|
|
{
|
|
planeInAir = false;
|
|
|
|
// And the wheel was previously in the air...
|
|
if(m_WheelInAir[i])
|
|
{
|
|
// Then play our skid touchdown sound if we're traveling at a reasonable speed
|
|
static bank_float fSkidVelocity = 0.15f;
|
|
if(m_DistanceFromListener < distanceToFilterInstantInAirs && m_CachedVehicleVelocity.Mag() > fSkidVelocity && !m_Vehicle->GetIsInWater())
|
|
{
|
|
audEnvelopeSound* squealSound = NULL;
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Predelay = audEngineUtil::GetRandomNumberInRange(0, 200);
|
|
SetTracker(initParams);
|
|
u32 mainSkidHash = (m_CachedMaterialSettings?m_CachedMaterialSettings->MainSkid:g_DefaultTyreSqueal);
|
|
if(mainSkidHash == g_NullSoundHash)
|
|
mainSkidHash = g_DefaultTyreSqueal;
|
|
|
|
CreateSound_LocalReference(ATSTRINGHASH("WHEEL_SKID_ENVELOPE", 0xEBABCAB5),(audSound**)&squealSound, &initParams);
|
|
if(squealSound)
|
|
{
|
|
squealSound->SetRequestedEnvelope(g_TireSquealAttack, g_TireSquealDecay, g_TireSquealSustain, g_TireSquealHold, g_TireSquealRelease);
|
|
squealSound->SetChildSoundReference(mainSkidHash);
|
|
squealSound->SetClientVariable(GetWheelSoundUpdateClientVar(i));
|
|
squealSound->SetUpdateEntity(true);
|
|
squealSound->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
|
|
m_WheelInAir[i] = false;
|
|
}
|
|
}
|
|
|
|
// Wheels only count as being in the air if every wheel on the whole plane is also in the air - this prevents lots of skidding
|
|
// sounds playing when wheels are quickly bumping along the surface, or when the physics is being indecisive
|
|
if(planeInAir)
|
|
{
|
|
static bank_float minTimeToBeConsideredInAir = 0.5f;
|
|
if(m_TimeInAir > minTimeToBeConsideredInAir)
|
|
{
|
|
for(s32 i = 0; i < MAX_PLANE_WHEELS; i++)
|
|
{
|
|
m_WheelInAir[i] = true;
|
|
}
|
|
}
|
|
|
|
m_TimeInAir += fwTimer::GetTimeStep();
|
|
}
|
|
else
|
|
{
|
|
m_TimeInAir = 0.0f;
|
|
}
|
|
|
|
// check if we are far away and only in air for a tiny amount of time, this is likely the planes doing weird stuff on the collision
|
|
//static bank_float distanceToFilterInstantInAirs = 250.0f;
|
|
//static bank_float farAwayMinTimeToBeConsideredInAir = 1.0f;
|
|
if(contactWheels) //planeInAir && m_DistanceFromListener > distanceToFilterInstantInAirs && m_TimeInAir < farAwayMinTimeToBeConsideredInAir)
|
|
{
|
|
m_OnGround = true;
|
|
}
|
|
else
|
|
{
|
|
m_OnGround = !planeInAir;
|
|
}
|
|
}
|
|
|
|
|
|
void audPlaneAudioEntity::UpdateSuspension()
|
|
{
|
|
// suspension sounds
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
Vector3 pos;
|
|
GetWheelPosition(i, pos);
|
|
|
|
f32 compressionChange = m_Vehicle->GetWheel(i)->GetCompressionChange() * fwTimer::GetInvTimeStep();
|
|
|
|
// use the max of the previous frame and this frame, since physics is double stepped otherwise we'll miss some
|
|
f32 compression = Max(m_Vehicle->GetWheel(i)->GetCompression()-m_Vehicle->GetWheel(i)->GetCompressionChange(),m_Vehicle->GetWheel(i)->GetCompression());
|
|
|
|
if(m_Vehicle->m_nVehicleFlags.bIsAsleep)
|
|
{
|
|
// ignore physics if asleep or the wheel isn't touching anything
|
|
compressionChange = 0.0f;
|
|
compression = 0.0f;
|
|
}
|
|
|
|
const f32 absCompressionChange = Abs(compressionChange);
|
|
f32 damageFactor = 1.0f - m_Vehicle->GetWheel(i)->GetSuspensionHealth() * SUSPENSION_HEALTH_DEFAULT_INV;
|
|
|
|
f32 ratio = Clamp((absCompressionChange - m_PlaneAudioSettings->MinSuspCompThresh) / (m_PlaneAudioSettings->MaxSuspCompThres - m_PlaneAudioSettings->MinSuspCompThresh - (damageFactor*2.f)), 0.0f,1.0f);
|
|
|
|
//if(m_IsPlayerVehicle)
|
|
// Displayf("Suspension Compression %f LinearVol %f change %f", ratio, (f32)sm_SuspensionVolCurve.CalculateValue(ratio), compressionChange);
|
|
|
|
#if __BANK
|
|
if(g_DebugPlaneSuspension)
|
|
{
|
|
static f32 peakComp = 0.0f;
|
|
if(absCompressionChange > peakComp)
|
|
{
|
|
peakComp= absCompressionChange;
|
|
Displayf("Peak Suspension Compression %f LinearVol %f", peakComp, (f32)sm_SuspensionVolCurve.CalculateValue(ratio));
|
|
}
|
|
}
|
|
#endif
|
|
if(m_SuspensionSounds[i])
|
|
{
|
|
// Disabling volume update so that we hear the whole one shot rather than it being played then immediately muted
|
|
// m_SuspensionSounds[i]->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(sm_SuspensionVolCurve.CalculateValue(ratio)));
|
|
m_SuspensionSounds[i]->SetRequestedPosition(pos);
|
|
}
|
|
|
|
static bank_float wtfThatsTooHigh = 2.0f;
|
|
static bank_float minTimeInAir = 1.0f;
|
|
if(absCompressionChange > m_PlaneAudioSettings->MinSuspCompThresh && compressionChange < wtfThatsTooHigh && m_TimeInAir > minTimeInAir )
|
|
{
|
|
if(!m_SuspensionSounds[i])
|
|
{
|
|
// trigger a suspension sound
|
|
if(compressionChange > 0)
|
|
{
|
|
BANK_ONLY(if(g_DebugPlaneSuspension) Displayf("Suspension Down");)
|
|
|
|
u32 soundHash = m_PlaneAudioSettings->SuspensionDown;
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Position = pos;
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(sm_SuspensionVolCurve.CalculateValue(ratio));
|
|
CreateAndPlaySound_Persistent(soundHash, &m_SuspensionSounds[i], &initParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bank_float suspensionUpThreshold = -0.1f;
|
|
if(compressionChange < suspensionUpThreshold)
|
|
{
|
|
u32 soundHash = m_PlaneAudioSettings->SuspensionUp;
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Position = pos;
|
|
|
|
static bank_float fudge = 0.5f;
|
|
f32 vol = Clamp(ratio+fudge, 0.0f, 1.0f);
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(sm_SuspensionVolCurve.CalculateValue(vol));
|
|
CreateAndPlaySound(soundHash, &initParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the volume trim on the road noise
|
|
// ----------------------------------------------------------------
|
|
f32 audPlaneAudioEntity::GetRoadNoiseVolumeScale() const
|
|
{
|
|
static bank_float roadNoiseVolumeScale = 1.0f;
|
|
return roadNoiseVolumeScale;
|
|
}
|
|
|
|
u32 audPlaneAudioEntity::GetNPCRoadNoiseSound() const
|
|
{
|
|
return ATSTRINGHASH("NPC_ROADNOISE_PASSES_DEFAULT", 0xC3F6AD5);
|
|
}
|
|
|
|
void audPlaneAudioEntity::UpdateDiveSound(audPlaneValues& planeValues)
|
|
{
|
|
if(m_DiveSoundVolumeLin > 0.01f && m_Vehicle->GetStatus() != STATUS_WRECKED)
|
|
{
|
|
if(!m_DiveSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->DivingSound, &m_DiveSound, &initParams);
|
|
}
|
|
if(m_DiveSound)
|
|
{
|
|
m_DiveSound->SetRequestedPitch(m_DiveSoundPitch);
|
|
m_DiveSound->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(m_DiveSoundVolumeLin) + planeValues.loopVolumes[PLANE_LOOP_ENGINE]);
|
|
m_DiveSound->SetRequestedPostSubmixVolumeAttenuation(planeValues.postSubmixVolumes[PLANE_LOOP_ENGINE]);
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_DiveSound)
|
|
m_DiveSound->StopAndForget(true);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Play some wind noise when plane is in the air and has no engines
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateWindNoise(audPlaneValues& planeValues)
|
|
{
|
|
f32 airSpeed = m_CachedVehicleVelocity.Mag();
|
|
f32 engineSpeed = Clamp(m_EngineSpeed, 0.0f, 1.0f);
|
|
static bank_float minAirSpeedForWind = 0.05f;
|
|
if(m_IsPlayerVehicle && !m_OnGround && !m_Vehicle->HasContactWheels() && !m_Vehicle->GetIsInWater() && m_TimeInAir > 1.0f && (engineSpeed < 0.3f || planeValues.propellorHealthFactor <= 0.5f) && airSpeed > minAirSpeedForWind)
|
|
{
|
|
if(!m_WindSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->WindNoise, &m_WindSound, &initParams);
|
|
}
|
|
|
|
if(m_WindSound)
|
|
{
|
|
f32 volume = sm_BankingAngleToWindNoiseVolumeCurve.CalculateValue(m_BankingAngle);
|
|
m_WindSound->SetRequestedVolume(volume);
|
|
f32 pitch = sm_BankingAngleToWindNoisePitchCurve.CalculateValue(m_BankingAngle);
|
|
m_WindSound->SetRequestedPitch((s32)pitch);
|
|
//Displayf("%f", m_BankingAngle);
|
|
}
|
|
}
|
|
else if(m_WindSound)
|
|
{
|
|
m_WindSound->StopAndForget();
|
|
}
|
|
}
|
|
|
|
|
|
void audPlaneAudioEntity::BreakOffSection(int nHitSection)
|
|
{
|
|
// play a little wind noise when a part breaks off in mid air
|
|
switch(nHitSection)
|
|
{
|
|
case CAircraftDamage::ELEVATOR_L:
|
|
case CAircraftDamage::ELEVATOR_R:
|
|
case CAircraftDamage::AILERON_L:
|
|
case CAircraftDamage::AILERON_R:
|
|
case CAircraftDamage::RUDDER:
|
|
case CAircraftDamage::RUDDER_2:
|
|
case CAircraftDamage::AIRBRAKE_L:
|
|
case CAircraftDamage::AIRBRAKE_R:
|
|
{
|
|
static bank_float minAirSpeedForWindPuff = 25.0f;
|
|
if(!m_OnGround && m_IsPlayerVehicle && m_TimeInAir > 5.0f && m_CachedVehicleVelocity.Mag() > minAirSpeedForWindPuff)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
CreateAndPlaySound("FRAGMENT_WIND_NOISE", &initParams);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void audPlaneAudioEntity::TriggerPropBreak()
|
|
{
|
|
if(m_PlaneAudioSettings == NULL)
|
|
return;
|
|
|
|
CreateDeferredSound(m_PlaneAudioSettings->PropellorBreakOneShot, m_Vehicle, NULL, true, true);
|
|
}
|
|
|
|
|
|
void audPlaneAudioEntity::TriggerBackFire()
|
|
{
|
|
if(m_PlaneAudioSettings == NULL)
|
|
return;
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
|
|
if(m_IsJet)
|
|
{
|
|
CreateAndPlaySound(m_PlaneAudioSettings->EngineMissFire, &initParams);
|
|
}
|
|
else
|
|
{
|
|
const u32 vehicleName = GetVehicleModelNameHash();
|
|
|
|
if (vehicleName != ATSTRINGHASH("MICROLIGHT", 0x96E24857) && vehicleName == ATSTRINGHASH("MICROLIGHT_STEALTHY", 0x34D5AB02))
|
|
{
|
|
CreateAndPlaySound(ATSTRINGHASH("PROP_PLANE_BACKFIRE", 0x63D0699C), &initParams);
|
|
}
|
|
}
|
|
|
|
m_BackFireTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
|
|
void audPlaneAudioEntity::TriggerDownwash(const u32 soundHash, const Vector3 &pos, const f32 distEvo, const f32 speedEvo)
|
|
{
|
|
//veh_air_turbulance_default
|
|
//veh_air_turbulance_sand
|
|
//veh_air_turbulance_dirt
|
|
//veh_air_turbulance_water
|
|
//veh_air_turbulance_foliage
|
|
|
|
SetDownwashHeightFactor(distEvo);
|
|
|
|
if(!m_DownwashSound || m_DownwashHash != soundHash)
|
|
{
|
|
if(m_DownwashSound)
|
|
{
|
|
m_DownwashSound->StopAndForget();
|
|
}
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound_Persistent(soundHash, &m_DownwashSound, &initParams);
|
|
m_DownwashHash = soundHash;
|
|
}
|
|
|
|
m_LastDownwashTime = fwTimer::GetTimeInMilliseconds();
|
|
|
|
if(m_DownwashSound)
|
|
{
|
|
#if __BANK
|
|
if(g_UseDebugPlaneTracker)
|
|
m_DownwashSound->SetRequestedPosition(m_DebugTracker.GetPosition());
|
|
else
|
|
#endif
|
|
m_DownwashSound->SetRequestedPosition(pos);
|
|
|
|
const f32 dbVol = audDriverUtil::ComputeDbVolumeFromLinear(speedEvo * Min(1.f, 2.f*(1.f-distEvo)));
|
|
m_DownwashSound->SetRequestedVolume(dbVol + m_DownwashVolume);
|
|
|
|
//Displayf("downwash vol %f + %f = %f", dbVol, m_DownwashVolume, dbVol+m_DownwashVolume);
|
|
}
|
|
}
|
|
|
|
void audPlaneAudioEntity::UpdateFlyby()
|
|
{
|
|
f32 distanceFromListener = m_DistanceFromListener;
|
|
|
|
if(distanceFromListener > 2000.0f || m_LastDistanceFromListener > 2000.0f)
|
|
{
|
|
m_LastDistanceFromListener = distanceFromListener;
|
|
return;
|
|
}
|
|
|
|
if(m_IsPlayerVehicle && camInterface::GetCinematicDirector().IsRenderingAnyInVehicleCinematicCamera())
|
|
{
|
|
distanceFromListener = g_audEnvironment->ComputeDistanceToPanningListener(m_Vehicle->GetVehiclePosition());
|
|
}
|
|
|
|
m_ClosingRateAccum += (m_LastDistanceFromListener - distanceFromListener);
|
|
u32 currentTime = fwTimer::GetTimeInMilliseconds();
|
|
m_NumClosingSamples++;
|
|
if(currentTime > m_TimeLastClosingRateUpdated + 1000)
|
|
{
|
|
m_ClosingRate = m_ClosingRateAccum / m_NumClosingSamples;
|
|
m_NumClosingSamples = 0;
|
|
m_ClosingRateAccum = 0.0f;
|
|
}
|
|
m_LastDistanceFromListener = distanceFromListener;
|
|
|
|
f32 distanceToTrigger = 150.0f;
|
|
f32 minAirSpeed = g_MinSpeedForJetFlyby;
|
|
if(m_IsJet && sm_JetClosingToFlybyDistance.IsValid())
|
|
{
|
|
distanceToTrigger = sm_JetClosingToFlybyDistance.CalculateValue(m_ClosingRate);
|
|
}
|
|
else if(sm_PropClosingToFlybyDistance.IsValid())
|
|
{
|
|
minAirSpeed = g_MinSpeedForPropFlyby;
|
|
distanceToTrigger = sm_PropClosingToFlybyDistance.CalculateValue(m_ClosingRate);
|
|
}
|
|
|
|
static bank_float minClosingRateForInVehicleConematicCam = 0.2f;
|
|
static bank_float tooCloseDistance = 15.0f;
|
|
static bank_float minEngineSpeed = 0.25f;
|
|
f32 minClosingRate = g_MinClosingRateForFlyby;
|
|
if(m_IsPlayerVehicle && camInterface::GetCinematicDirector().IsRenderingAnyInVehicleCinematicCamera())
|
|
minClosingRate = minClosingRateForInVehicleConematicCam;
|
|
if(!m_FlybySound && m_Vehicle->m_nVehicleFlags.bEngineOn && (m_EngineSpeed > minEngineSpeed) && (!m_IsPlayerVehicle || camInterface::GetCinematicDirector().IsRenderingAnyInVehicleCinematicCamera()) &&
|
|
!m_OnGround && (m_DownwashHeight == -1.0f || m_DownwashHeight > 1.0f) &&
|
|
m_AirSpeed > minAirSpeed && m_ClosingRate > minClosingRate && distanceFromListener < distanceToTrigger)
|
|
{
|
|
m_FlybyComingAtYou = true;
|
|
TriggerFlyby();
|
|
}
|
|
else if(!m_FlybySound && m_Vehicle->m_nVehicleFlags.bEngineOn && (m_EngineSpeed > minEngineSpeed) && m_IsPlayerVehicle && camInterface::GetCinematicDirector().IsRenderingAnyInVehicleCinematicCamera() &&
|
|
!m_OnGround && (m_DownwashHeight == -1.0f || m_DownwashHeight > 1.0f) &&
|
|
m_AirSpeed > minAirSpeed && (m_ClosingRate > -10.0f && m_ClosingRate < g_MinClosingRateForFlybyAway) && (distanceFromListener > tooCloseDistance && distanceFromListener < g_FlyingAwayDistanceToTrigger))
|
|
{
|
|
m_FlybyComingAtYou = false;
|
|
TriggerFlyby();
|
|
}
|
|
|
|
if(m_FlybySound)
|
|
{
|
|
static bank_u32 closingRateThresholdTime = 2500;
|
|
static bank_s32 defaultRelease = 5000;
|
|
static bank_s32 quickRelease = 1000;
|
|
s32 release = defaultRelease;
|
|
if(currentTime < (m_FlybyStartTime + closingRateThresholdTime))
|
|
{
|
|
release = quickRelease;
|
|
}
|
|
|
|
static bank_float distanceToStop = 150.0f;
|
|
if(!m_Vehicle->m_nVehicleFlags.bEngineOn || m_OnGround || (m_FlybyComingAtYou && !m_IsPlayerVehicle && m_ClosingRate <= 0.0f) || (m_IsPlayerVehicle && (distanceFromListener > distanceToStop || distanceFromListener < tooCloseDistance)) || (m_IsPlayerVehicle && !camInterface::GetCinematicDirector().IsRenderingAnyInVehicleCinematicCamera()))
|
|
{
|
|
m_FlybySound->SetReleaseTime(release);
|
|
m_FlybySound->StopAndForget();
|
|
}
|
|
}
|
|
if(!m_FlybySound)
|
|
{
|
|
FreeSpeechSlot();
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_ShowFlyby && (!m_IsPlayerVehicle || camInterface::GetCinematicDirector().IsRenderingAnyInVehicleCinematicCamera()))
|
|
{
|
|
Vector3 planePosition = BANK_ONLY(g_UseDebugPlaneTracker? (Vector3) m_DebugTracker.GetPosition() : )VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
Vector3 listener = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(0));
|
|
if(m_IsPlayerVehicle && camInterface::GetCinematicDirector().IsRenderingAnyInVehicleCinematicCamera())
|
|
{
|
|
listener = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerPosition(0));
|
|
}
|
|
grcDebugDraw::Line(listener, planePosition, m_FlybySound ? Color_green : (distanceFromListener < distanceToTrigger ? Color_blue : Color_red));
|
|
|
|
char tempString[128];
|
|
formatf(tempString, "Closing %4.2f Dist %4.2f ListDist %4.2f", m_ClosingRate, distanceToTrigger, distanceFromListener);
|
|
grcDebugDraw::Text(m_Vehicle->GetTransform().GetPosition(), m_FlybySound ? Color_green : Color_red, tempString);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
//void audPlaneAudioEntity::TriggerFlyby2()
|
|
//{
|
|
// audSoundInitParams initParams;
|
|
// initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
// SetTracker(initParams);
|
|
// //CreateAndPlaySound_Persistent(m_PlaneAudioSettings->FlybySound, &m_FlybySound, &initParams);
|
|
// CreateAndPlaySound_Persistent(ATSTRINGHASH("SPL_RPG_DIST_FLIGHT_MASTER", 0xE8ED5661), &m_FlybySound, &initParams);
|
|
//}
|
|
|
|
void audPlaneAudioEntity::TriggerFlyby()
|
|
{
|
|
// Only allow if there are lots of slots free, and we're not already playing the sound
|
|
if((g_SpeechManager.GetNumVacantAmbientSlots() <= 3) || m_FlybySound)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(m_Vehicle->m_nVehicleFlags.bIsDrowning)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Try to grab a free ambient speech slot at low priority
|
|
s32 speechSlotId = g_SpeechManager.GetAmbientSpeechSlot(NULL, NULL, -1.0f);
|
|
|
|
if(speechSlotId >= 0)
|
|
{
|
|
audWaveSlot* speechSlot = g_SpeechManager.GetAmbientWaveSlotFromId(speechSlotId);
|
|
|
|
// Success! Use this slot to load and play our asset
|
|
if(speechSlot)
|
|
{
|
|
audSoundInitParams initParams;
|
|
m_SpeechSlotId = speechSlotId;
|
|
initParams.WaveSlot = speechSlot;
|
|
initParams.AllowLoad = true;
|
|
initParams.PrepareTimeLimit = 5000;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
g_SpeechManager.PopulateAmbientSpeechSlotWithPlayingSpeechInfo(speechSlotId, 0,
|
|
#if __BANK
|
|
"JET_PLANE_FLYBY",
|
|
#endif
|
|
0);
|
|
|
|
if(m_FlybyComingAtYou && !m_IsPlayerVehicle)
|
|
{
|
|
if(m_PlaneAudioSettings->FlybySound == g_NullSoundHash && m_IsJet)
|
|
{
|
|
u32 soundHash = ATSTRINGHASH("JetFlyby", 0xB05301CB);
|
|
CreateAndPlaySound_Persistent(audVehicleAudioEntity::GetExtrasSoundSet()->Find(soundHash), &m_FlybySound, &initParams);
|
|
}
|
|
else
|
|
{
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->FlybySound, &m_FlybySound, &initParams);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CreateAndPlaySound_Persistent(m_PlaneAudioSettings->FlyAwaySound, &m_FlybySound, &initParams);
|
|
}
|
|
m_FlybyStartTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
else
|
|
{
|
|
g_SpeechManager.FreeAmbientSpeechSlot(speechSlotId, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void audPlaneAudioEntity::FreeSpeechSlot()
|
|
{
|
|
if(m_SpeechSlotId >= 0)
|
|
{
|
|
g_SpeechManager.FreeAmbientSpeechSlot(m_SpeechSlotId, true);
|
|
m_SpeechSlotId = -1;
|
|
}
|
|
}
|
|
|
|
|
|
#if __BANK
|
|
// ----------------------------------------------------------------
|
|
// Update debug stuff
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateDebug()
|
|
{
|
|
// If this is enabled, we fudge the tracker position to simulate the plane flying overhead every x seconds
|
|
if(g_UseDebugPlaneTracker)
|
|
{
|
|
const ScalarV distanceTravelled = ScalarV((g_DebugTrackerFlybyDist/2.0f) - (g_DebugTrackerFlybyDist * (g_DebugTrackerTimer/g_DebugTrackerFlybyTime)));
|
|
const Vec3V height(0.0f, 0.0f, g_DebugTrackerFlybyHeight);
|
|
Vec3V newPosition = m_Vehicle->GetTransform().GetPosition() + (m_Vehicle->GetTransform().GetForward() * distanceTravelled);
|
|
newPosition = newPosition + height;
|
|
m_DebugTracker.SetPosition(RCC_VECTOR3(newPosition));
|
|
|
|
for(u32 loop = 0; loop < PLANE_LOOPS_MAX; loop++)
|
|
{
|
|
if(m_PlaneLoops[loop])
|
|
{
|
|
m_PlaneLoops[loop]->SetRequestedPosition(newPosition);
|
|
}
|
|
}
|
|
|
|
m_ExhaustOffsetPos = newPosition;
|
|
m_EngineOffsetPos = newPosition;
|
|
|
|
//Displayf("Position: %f, %f, %f", newPosition.x, newPosition.y, newPosition.z);
|
|
|
|
g_DebugTrackerTimer += fwTimer::GetTimeStep();
|
|
|
|
if(g_DebugTrackerTimer > g_DebugTrackerFlybyTime)
|
|
{
|
|
g_DebugTrackerTimer = 0.0f;
|
|
}
|
|
|
|
static bank_float size = 1.0f;
|
|
grcDebugDraw::Sphere(newPosition, size, Color_red);
|
|
|
|
}
|
|
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
if(plane && g_ShowDebugInfo && (m_IsPlayerVehicle || plane == g_pFocusEntity))
|
|
{
|
|
f32 rollAngle = m_Vehicle->GetTransform().GetRoll() * RtoD;
|
|
f32 bankingAngle = AcosfSafe(Dot(m_Vehicle->GetTransform().GetC(), Vec3V(V_Z_AXIS_WZERO)).Getf()) * RtoD;
|
|
f32 pitchAngle = AcosfSafe(Dot(m_Vehicle->GetTransform().GetB(), Vec3V(V_Z_AXIS_WZERO)).Getf()) * RtoD;
|
|
f32 yawAngle = m_Vehicle->GetTransform().GetHeading() * RtoD;
|
|
f32 angularVelocity = GetCachedAngularVelocity().Mag();
|
|
f32 airSpeed = m_CachedVehicleVelocity.Mag();
|
|
|
|
char tempString[64];
|
|
formatf(tempString, "Roll:%.02f Banking:%.02f Pitch:%.02f Yaw:%.02f Ang:%.02f Spd:%.02f", rollAngle, bankingAngle, pitchAngle, yawAngle, angularVelocity, airSpeed);
|
|
grcDebugDraw::Text(Vector2(0.25f, 0.05f), Color32(255,255,255), tempString );
|
|
|
|
static const char *meterNames[] = {"Vel0", "Vel1", "Vel2", "Speed", "Engn", "REngn", "Roll", "Pitch", "Yaw" };
|
|
static audMeterList meterList;
|
|
static f32 meterValues[9];
|
|
|
|
const Vector3 angVelocity = GetCachedAngularVelocity();
|
|
meterValues[0] = Abs(angVelocity[0]);
|
|
meterValues[1] = Abs(angVelocity[1]);
|
|
meterValues[2] = Abs(angVelocity[2]);
|
|
meterValues[3] = angVelocity.Mag();
|
|
meterValues[4] = m_EngineSpeed;
|
|
meterValues[5] = plane->GetEngineSpeed();
|
|
meterValues[6] = Abs(rollAngle/500.0f);
|
|
meterValues[7] = pitchAngle/500.0f;
|
|
meterValues[8] = yawAngle/500.0f;
|
|
|
|
meterList.left = 740.f;
|
|
meterList.bottom = 420.f;
|
|
meterList.width = 400.f;
|
|
meterList.height = 200.f;
|
|
meterList.values = &meterValues[0];
|
|
meterList.names = meterNames;
|
|
meterList.numValues = sizeof(meterNames)/sizeof(meterNames[0]);
|
|
audNorthAudioEngine::DrawLevelMeters(&meterList);
|
|
}
|
|
|
|
static bank_float length = 10.0f;
|
|
Vec3V position = m_Vehicle->GetTransform().GetPosition();
|
|
if(g_ShowEnginePosition)
|
|
{
|
|
if(m_PlaneAudioSettings->EngineConeFrontAngle > 90)
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->EngineConeFrontAngle - 90)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position - (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_green, false, false);
|
|
}
|
|
else
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->EngineConeFrontAngle)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position + (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_green, false, false);
|
|
}
|
|
|
|
if(m_PlaneAudioSettings->EngineConeRearAngle > 90)
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->EngineConeRearAngle - 90)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position - (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_red, false, false);
|
|
}
|
|
else
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->EngineConeRearAngle)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position + (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_red, false, false);
|
|
}
|
|
}
|
|
if(g_ShowExhaustPosition)
|
|
{
|
|
if(m_PlaneAudioSettings->ExhaustConeFrontAngle > 90)
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->ExhaustConeFrontAngle - 90)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position + (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_green, false, false);
|
|
}
|
|
else
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->ExhaustConeFrontAngle)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position - (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_green, false, false);
|
|
}
|
|
|
|
if(m_PlaneAudioSettings->ExhaustConeRearAngle > 90)
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->ExhaustConeRearAngle - 90)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position + (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_red, false, false);
|
|
}
|
|
else
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->ExhaustConeRearAngle)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position - (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_red, false, false);
|
|
}
|
|
}
|
|
if(g_ShowPropPosition)
|
|
{
|
|
if(m_PlaneAudioSettings->PropellorConeFrontAngle > 90)
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->PropellorConeFrontAngle - 90)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position - (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_green, false, false);
|
|
}
|
|
else
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->PropellorConeFrontAngle)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position + (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_green, false, false);
|
|
}
|
|
|
|
if(m_PlaneAudioSettings->PropellorConeRearAngle > 90)
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->PropellorConeRearAngle - 90)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position - (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_red, false, false);
|
|
}
|
|
else
|
|
{
|
|
f32 radius = tan((m_PlaneAudioSettings->PropellorConeRearAngle)*DtoR) * length;
|
|
grcDebugDraw::Cone(position, position + (m_Vehicle->GetTransform().GetForward() * ScalarV(length)), radius, Color_red, false, false);
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update 'tricks'
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::UpdateTricks()
|
|
{
|
|
f32 pitchAngle = AcosfSafe(Dot(m_Vehicle->GetTransform().GetB(), Vec3V(V_Z_AXIS_WZERO)).Getf()) * RtoD;
|
|
f32 rollAngle = m_Vehicle->GetTransform().GetRoll() * RtoD;
|
|
f32 yawAngle = m_Vehicle->GetTransform().GetHeading() * RtoD;
|
|
UNUSED_VAR(yawAngle);
|
|
m_IsPeeling = false;
|
|
|
|
// If we're doing a Top-Gun style horizontal peel, we rotate the aircraft sideways, keep its pitch level, then quickly pull away
|
|
static bank_float fRollAngleLimit = PEELING_ROLL_LIMIT;
|
|
if(fabs(rollAngle) > 90.0f - fRollAngleLimit && fabs(rollAngle) < 90.0f + fRollAngleLimit)
|
|
{
|
|
static bank_float fPeelingPitchLimit = PEELING_PITCH_LIMIT;
|
|
static bank_float fPeelingPitchUpLimit = PEELING_PITCH_UP_LIMIT;
|
|
if(fabs(pitchAngle) > 90.0f - fPeelingPitchUpLimit && fabs(pitchAngle) < 90.0f + fPeelingPitchLimit)
|
|
{
|
|
CPlane* plane = static_cast<CPlane*>(m_Vehicle);
|
|
|
|
static bank_float fPitchControl = PEELING_STICK_DEFLECTION;
|
|
if(plane->GetPitchControl() >= fPitchControl)
|
|
{
|
|
m_IsPeeling = true;
|
|
|
|
#if __BANK
|
|
if(g_ShowDebugInfo)
|
|
{
|
|
char tempString[64];
|
|
formatf(tempString, "PEELING");
|
|
grcDebugDraw::Text(Vector2(0.5f, 0.5f), Color32(255,255,255), tempString);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a door open sound
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::TriggerDoorOpenSound(eHierarchyId doorId)
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
TriggerDoorSound(m_PlaneAudioSettings->DoorOpen, doorId);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a door shut sound
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::TriggerDoorCloseSound(eHierarchyId doorId, const bool UNUSED_PARAM(isBroken))
|
|
{
|
|
// if it's the player vehicle, and they're pissed off - slam the door. Note that this'll have his passengers slam the door too - oh well.
|
|
f32 volumeOffset = 0.0f;
|
|
|
|
if (m_Vehicle && m_IsPlayerVehicle &&
|
|
CGameWorld::GetMainPlayerInfo()->PlayerIsPissedOff())
|
|
{
|
|
if (doorId == VEH_DOOR_DSIDE_F ||
|
|
doorId == VEH_DOOR_DSIDE_R ||
|
|
doorId == VEH_DOOR_PSIDE_F ||
|
|
doorId == VEH_DOOR_PSIDE_R)
|
|
{
|
|
volumeOffset = 6.0f;
|
|
}
|
|
}
|
|
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
TriggerDoorSound(m_PlaneAudioSettings->DoorClose, doorId, volumeOffset);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger door open sound
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::TriggerDoorFullyOpenSound(eHierarchyId doorId)
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
TriggerDoorSound(m_PlaneAudioSettings->DoorLimit, doorId);
|
|
}
|
|
}
|
|
|
|
void audPlaneAudioEntity::TriggerDoorStartOpenSound(eHierarchyId doorIndex)
|
|
{
|
|
if(m_PlaneAudioSettings && m_Vehicle->GetStatus() != STATUS_WRECKED)
|
|
{
|
|
if(m_PlaneAudioSettings->DoorStartOpen == g_NullSoundHash)
|
|
{
|
|
TriggerDoorSound(m_PlaneAudioSettings->DoorOpen, doorIndex);
|
|
}
|
|
TriggerDoorSound(m_PlaneAudioSettings->DoorStartOpen, doorIndex);
|
|
}
|
|
}
|
|
|
|
void audPlaneAudioEntity::TriggerDoorStartCloseSound(eHierarchyId doorIndex)
|
|
{
|
|
if(m_PlaneAudioSettings && m_Vehicle->GetStatus() != STATUS_WRECKED)
|
|
{
|
|
TriggerDoorSound(m_PlaneAudioSettings->DoorStartClose, doorIndex);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audPlaneAudioEntity GetVehicleRainSound
|
|
// ----------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetVehicleRainSound(bool interiorView) const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
if(interiorView)
|
|
{
|
|
return m_PlaneAudioSettings->VehicleRainSoundInterior;
|
|
}
|
|
else
|
|
{
|
|
return m_PlaneAudioSettings->VehicleRainSound;
|
|
}
|
|
}
|
|
|
|
return audVehicleAudioEntity::GetVehicleRainSound(interiorView);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Deploy landing gear
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::DeployLandingGear()
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
StopAndForgetSounds(m_LandingGearRetract, m_LandingGearDeploy);
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
|
|
CreateSound_PersistentReference(m_PlaneAudioSettings->LandingGearDeploy, &m_LandingGearDeploy, &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSoundPersistant(m_PlaneAudioSettings->LandingGearDeploy, &initParams, m_LandingGearDeploy, m_Vehicle, eNoGlobalSoundEntity);)
|
|
|
|
if(m_LandingGearDeploy)
|
|
{
|
|
m_LandingGearDeploy->SetUpdateEntity(true);
|
|
m_LandingGearDeploy->SetClientVariable((u32)AUD_VEHICLE_SOUND_UNKNOWN);
|
|
m_LandingGearDeploy->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Retract landing gear
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::RetractLandingGear()
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
if(m_PlaneAudioSettings->LandingGearRetract == g_NullSoundHash)
|
|
return;
|
|
|
|
StopAndForgetSounds(m_LandingGearRetract, m_LandingGearDeploy);
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
|
|
CreateSound_PersistentReference(m_PlaneAudioSettings->LandingGearRetract, &m_LandingGearRetract, &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSoundPersistant(m_PlaneAudioSettings->LandingGearRetract, &initParams, m_LandingGearRetract, m_Vehicle, eNoGlobalSoundEntity);)
|
|
|
|
if(m_LandingGearRetract)
|
|
{
|
|
m_LandingGearRetract->SetUpdateEntity(true);
|
|
m_LandingGearRetract->SetClientVariable((u32)AUD_VEHICLE_SOUND_UNKNOWN);
|
|
m_LandingGearRetract->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Set the crop dusting active or not
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::SetCropDustingActive(bool active)
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
if(!active)
|
|
{
|
|
StopAndForgetSounds(m_CropDustingSound);
|
|
}
|
|
else
|
|
{
|
|
if(!m_CropDustingSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
SetTracker(initParams);
|
|
|
|
CreateSound_PersistentReference(sm_ExtrasSoundSet.Find(ATSTRINGHASH("CropDuster_SprayLoop", 1764320963)), &m_CropDustingSound, &initParams);
|
|
|
|
if(m_CropDustingSound)
|
|
{
|
|
m_CropDustingSound->SetUpdateEntity(true);
|
|
m_CropDustingSound->SetClientVariable((u32)AUD_VEHICLE_SOUND_UNKNOWN);
|
|
m_CropDustingSound->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Set the stall warning sound enabled or not
|
|
// ----------------------------------------------------------------
|
|
void audPlaneAudioEntity::SetStallWarningEnabled(bool enabled)
|
|
{
|
|
m_StallWarningEnabled = enabled;
|
|
|
|
if(!m_StallWarningEnabled)
|
|
{
|
|
StopAndForgetSounds(m_StallWarning);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get a sound from the object data
|
|
// ----------------------------------------------------------------
|
|
u32 audPlaneAudioEntity::GetSoundFromObjectData(u32 fieldHash) const
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
u32 *ret = (u32 *)m_PlaneAudioSettings->GetFieldPtr(fieldHash);
|
|
return (ret) ? *ret : 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool audPlaneAudioEntity::AircraftWarningVoiceIsMale()
|
|
{
|
|
if(m_PlaneAudioSettings)
|
|
{
|
|
return AUD_GET_TRISTATE_VALUE(m_PlaneAudioSettings->Flags, FLAG_ID_PLANEAUDIOSETTINGS_AIRCRAFTWARNINGVOICEISMALE) == AUD_TRISTATE_TRUE;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
AmbientRadioLeakage audPlaneAudioEntity::GetPositionalPlayerRadioLeakage() const
|
|
{
|
|
return g_AircraftPositionedPlayerVehicleRadioLeakage;
|
|
}
|
|
|
|
#if __BANK
|
|
void audPlaneAudioEntity::AddWidgets(bkBank &bank)
|
|
{
|
|
bank.PushGroup("Planes", false);
|
|
bank.AddToggle("Planes Enabled", &g_PlanesEnabled);
|
|
bank.AddToggle("Show Debug Info", &g_ShowDebugInfo);
|
|
bank.AddToggle("Show Engine Cooling", &g_ShowEngineCooling);
|
|
bank.AddToggle("Show Flyby", &g_ShowFlyby);
|
|
bank.AddToggle("Show Engine Info", &g_ShowEngineInfo);
|
|
|
|
bank.PushGroup("Flyby", false);
|
|
bank.AddSlider("Min Closing Rate", &g_MinClosingRateForFlyby, 0.0f, 10.0f, 0.1f);
|
|
bank.AddSlider("Min Jet Speed To Trigger", &g_MinSpeedForJetFlyby, 0.0f, 100.0f, 0.5f);
|
|
bank.AddSlider("Min Prop Speed To Trigger", &g_MinSpeedForPropFlyby, 0.0f, 100.0f, 0.5f);
|
|
bank.PopGroup();
|
|
|
|
bank.PushGroup("Cones", false);
|
|
bank.AddToggle("Show Engine Cone", &g_ShowEnginePosition);
|
|
bank.AddToggle("Show Exhaust Cone", &g_ShowExhaustPosition);
|
|
bank.AddToggle("Show Prop Cone", &g_ShowPropPosition);
|
|
bank.PopGroup();
|
|
|
|
bank.PushGroup("Flight Mode", false);
|
|
bank.AddToggle("Force Flight Mode", &g_ForceFlightMode);
|
|
bank.AddSlider("Forced Flight Mode", &g_ForcedFlightModeValue, 0.0f, 10.0f, 0.1f);
|
|
bank.PopGroup();
|
|
|
|
bank.PushGroup("Passenger Radio", false);
|
|
bank.AddToggle("Positioned Player Vehicle Radio Enabled", &g_PositionedPlayerVehicleRadioEnabled);
|
|
bank.AddSlider("Reverb Small", &g_PositionedPlayerVehicleRadioReverbSmall, 0.0f, 1.0f, 0.01f);
|
|
bank.AddSlider("Reverb Medium", &g_PositionedPlayerVehicleRadioReverbMedium, 0.0f, 1.0f, 0.01f);
|
|
bank.AddSlider("Reverb Large", &g_PositionedPlayerVehicleRadioReverbLarge, 0.0f, 1.0f, 0.01f);
|
|
const char *leakageNames[NUM_AMBIENTRADIOLEAKAGE];
|
|
for(s32 l = LEAKAGE_BASSY_LOUD; l < NUM_AMBIENTRADIOLEAKAGE; l++)
|
|
{
|
|
leakageNames[l] = AmbientRadioLeakage_ToString((AmbientRadioLeakage)l);
|
|
}
|
|
bank.AddCombo("Passenger Radio Leakage", (s32*)&g_AircraftPositionedPlayerVehicleRadioLeakage, NUM_AMBIENTRADIOLEAKAGE, leakageNames);
|
|
bank.PopGroup();
|
|
|
|
bank.AddToggle("g_DebugPlaneSuspension", &g_DebugPlaneSuspension);
|
|
bank.AddToggle("Force Stall Warning", &g_ForceStallWarningOn);
|
|
bank.AddSlider("Stall Warning Severity", &g_ForcedStallWarningSeverity, 0.0f, 1.0f, 0.1f);
|
|
bank.AddSlider("Engine Volume Trim", &g_PlaneVolumeTrims[PLANE_LOOP_ENGINE], -100.0f, 0.0f, 0.5f);
|
|
bank.AddSlider("Exhaust Volume Trim", &g_PlaneVolumeTrims[PLANE_LOOP_EXHAUST], -100.0f, 0.0f, 0.5f);
|
|
bank.AddSlider("Propellor Volume Trim", &g_PlaneVolumeTrims[PLANE_LOOP_PROPELLOR], -100.0f, 0.0f, 0.5f);
|
|
bank.AddSlider("Idle Volume Trim", &g_PlaneVolumeTrims[PLANE_LOOP_IDLE], -100.0f, 0.0f, 0.5f);
|
|
bank.AddSlider("Distance Volume Trim", &g_PlaneVolumeTrims[PLANE_LOOP_DISTANCE], -100.0f, 0.0f, 0.5f);
|
|
bank.AddSlider("Banking Volume Trim", &g_PlaneVolumeTrims[PLANE_LOOP_BANKING], -100.0f, 0.0f, 0.5f);
|
|
bank.AddSlider("Afterburner Volume Trim", &g_PlaneVolumeTrims[PLANE_LOOP_AFTERBURNER], -100.0f, 0.0f, 0.5f);
|
|
|
|
bank.PushGroup("Tyre Squeal", false);
|
|
bank.AddSlider("Attack", &g_TireSquealAttack, 0, 1000, 1);
|
|
bank.AddSlider("Decay", &g_TireSquealDecay, 0, 1000, 1);
|
|
bank.AddSlider("Sustain", &g_TireSquealSustain, 0, 255, 1);
|
|
bank.AddSlider("Hold", &g_TireSquealHold, 0, 1000, 1);
|
|
bank.AddSlider("Release", &g_TireSquealRelease, 0, 1000, 1);
|
|
bank.PopGroup();
|
|
|
|
bank.PushGroup("Debug Flybys", false);
|
|
bank.AddToggle("Enable Debug Flybys", &g_UseDebugPlaneTracker);
|
|
bank.AddSlider("Flyby Engine Speed", &g_DebugTrackerFlybyEngineSpeed, 0.0f, 1.0f, 0.01f);
|
|
bank.AddSlider("Flyby Time", &g_DebugTrackerFlybyTime, 0.0f, 1000.0f, 0.5f);
|
|
bank.AddSlider("Flyby Distance", &g_DebugTrackerFlybyDist, 0.0f, 10000.0f, 10.0f);
|
|
bank.AddSlider("Flyby Height", &g_DebugTrackerFlybyHeight, 0.0f, 10000.0f, 10.0f);
|
|
bank.PopGroup();
|
|
|
|
bank.PushGroup("Players Plane", false);
|
|
bank.AddSlider("Override Engine Damage Left(Main)", &g_OverRideEngineDamage[0], -1.0f, 1000.0f, 1.0f);
|
|
bank.AddSlider("Override Engine Damage Right", &g_OverRideEngineDamage[1], -1.0f, 1000.0f, 1.0f);
|
|
bank.AddToggle("Apply Damage", &g_ApplyEngineDamage);
|
|
bank.PopGroup();
|
|
|
|
|
|
bank.PopGroup();
|
|
}
|
|
#endif
|