14350 lines
495 KiB
C++
14350 lines
495 KiB
C++
//
|
|
// audio/vehicleaudioentity.cpp
|
|
//
|
|
// Copyright (C) 1999-2006 Rockstar Games. All Rights Reserved.
|
|
//
|
|
#include "debugaudio.h"
|
|
|
|
#include "audio/ambience/ambientaudioentity.h"
|
|
#include "audio/environment/environment.h"
|
|
#include "audio/environment/environmentgroup.h"
|
|
#include "caraudioentity.h"
|
|
#include "heliaudioentity.h"
|
|
#include "trainaudioentity.h"
|
|
#include "boataudioentity.h"
|
|
#include "planeaudioentity.h"
|
|
#include "traileraudioentity.h"
|
|
#include "dynamicmixer.h"
|
|
#include "frontendaudioentity.h"
|
|
#include "northaudioengine.h"
|
|
#include "policescanner.h"
|
|
#include "radioaudioentity.h"
|
|
#include "scriptaudioentity.h"
|
|
#include "vehicleaudioentity.h"
|
|
#include "vehiclereflectionsaudioentity.h"
|
|
#include "camera/helpers/switch/BaseSwitchHelper.h"
|
|
#include "vfx/systems/VfxWater.h"
|
|
|
|
#include "vehicleengine/vehicleengine.h"
|
|
#include "vehicles/Trailer.h"
|
|
#include "audioengine/engine.h"
|
|
#include "control/record.h"
|
|
#include "control/replay/replay.h"
|
|
#include "control/replay/audio/SoundPacket.h"
|
|
#include "control/replay/Audio/CollisionAudioPacket.h"
|
|
#include "modelinfo/ModelSeatInfo.h"
|
|
#include "debug/DebugScene.h"
|
|
#include "game/weather.h"
|
|
#include "weatheraudioentity.h"
|
|
#include "animation/MoveVehicle.h"
|
|
#include "audiohardware/device.h"
|
|
#include "audiohardware/driver.h"
|
|
#include "audiohardware/driverdefs.h"
|
|
#include "audiohardware/driverutil.h"
|
|
#include "game/ModelIndices.h"
|
|
#include "vehicleAi/VehicleIntelligence.h"
|
|
#include "Vehicles/vehicle.h"
|
|
#include "Vehicles/VehicleFactory.h"
|
|
#include "Vehicles/Automobile.h"
|
|
#include "Vehicles/Submarine.h"
|
|
#include "Vehicles/VehicleGadgets.h"
|
|
#include "glassaudioentity.h"
|
|
#include "Peds/ped.h"
|
|
#include "Peds/PedIntelligence.h"
|
|
#include "Peds/PedHelmetComponent.h"
|
|
#include "renderer/Water.h"
|
|
#include "radiostation.h"
|
|
#include "vehicles/train.h"
|
|
#include "Vehicles/planes.h"
|
|
#include "scene/streamer/SceneStreamerMgr.h"
|
|
#include "task/Vehicle/TaskEnterVehicle.h"
|
|
#include "task/Vehicle/TaskExitVehicle.h"
|
|
#include "vehicleai/task/taskvehicleanimation.h"
|
|
#include "Vehicles/VehicleDefines.h"
|
|
#include "Vehicles/AmphibiousAutomobile.h"
|
|
#include "vehicles/Metadata/VehicleSeatInfo.h"
|
|
#include "audiosynth/synthcore.h"
|
|
#include "renderer/River.h"
|
|
#include "system/nelem.h"
|
|
#include "vfx/systems/VfxWheel.h"
|
|
#include "camera/CamInterface.h"
|
|
#include "camera/cinematic/CinematicDirector.h"
|
|
#include "scene/playerswitch/PlayerSwitchInterface.h"
|
|
#include "script/script_hud.h"
|
|
#include "network/Events/NetworkEventTypes.h"
|
|
#include "control/replay/Vehicle/VehiclePacket.h"
|
|
|
|
|
|
AUDIO_VEHICLES_OPTIMISATIONS()
|
|
|
|
EXT_PF_GROUP(VehicleAudioTimings);
|
|
PF_TIMER(UpdateRoadNoise, VehicleAudioTimings);
|
|
EXT_PF_GROUP(VehicleAudioEntity);
|
|
PF_COUNTER(NumNPCRoadNoise, VehicleAudioEntity);
|
|
PF_COUNTER(NumRealVehicles, VehicleAudioEntity);
|
|
PF_COUNTER(NumDisabledVehicles, VehicleAudioEntity);
|
|
PF_COUNTER(NumSuperDummyVehicles, VehicleAudioEntity);
|
|
PF_COUNTER(NumDummyVehicles, VehicleAudioEntity);
|
|
PF_VALUE_INT(NumGranularEnginesLastFrame, VehicleAudioEntity);
|
|
PF_VALUE_INT(NumEnginesUsingSubmixesLastFrame, VehicleAudioEntity);
|
|
PF_VALUE_INT(NumVehiclesInActivationRange, VehicleAudioEntity);
|
|
PF_VALUE_INT(NumVehiclesInGranularRange, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(RealRadiusScalar, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(GranularRadiusScalar, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(RainRadiusScalarQ1, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(RainRadiusScalarQ2, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(RainRadiusScalarQ3, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(RainRadiusScalarQ4, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(WaterSlapRadiusScalarQ1, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(WaterSlapRadiusScalarQ2, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(WaterSlapRadiusScalarQ3, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(WaterSlapRadiusScalarQ4, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(DummyRadiusScalarQ1, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(DummyRadiusScalarQ2, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(DummyRadiusScalarQ3, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(DummyRadiusScalarQ4, VehicleAudioEntity);
|
|
|
|
PF_VALUE_FLOAT(FrontWheelSteeringAngle, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(FrontWheelSlipAngle, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(DriftAngle, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(UndersteerFactor, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(ClatterRatioValue, VehicleAudioEntity);
|
|
PF_VALUE_FLOAT(ClatterAcceleration, VehicleAudioEntity);
|
|
|
|
audWaveSlotManager audVehicleAudioEntity::sm_StandardWaveSlotManager;
|
|
audWaveSlotManager audVehicleAudioEntity::sm_HighQualityWaveSlotManager;
|
|
audWaveSlotManager audVehicleAudioEntity::sm_LowLatencyWaveSlotManager;
|
|
audVehicleAudioEntity::audVehicleSubmix audVehicleAudioEntity::sm_VehicleEngineSubmixes[EFFECT_ROUTE_VEHICLE_ENGINE_MAX - EFFECT_ROUTE_VEHICLE_ENGINE_MIN + 1];
|
|
audVehicleAudioEntity::audVehicleSubmix audVehicleAudioEntity::sm_VehicleExhaustSubmixes[EFFECT_ROUTE_VEHICLE_EXHAUST_MAX - EFFECT_ROUTE_VEHICLE_EXHAUST_MIN + 1];
|
|
audSmoother audVehicleAudioEntity::sm_HighSpeedSceneApplySmoother;
|
|
audSmoother audVehicleAudioEntity::sm_OpennessSmoother;
|
|
|
|
bool audVehicleAudioEntity::sm_IsSpectatorModeActive = false;
|
|
bool audVehicleAudioEntity::sm_TriggerStuntRaceSpeedBoostScene = false;
|
|
bool audVehicleAudioEntity::sm_TriggerStuntRaceSlowDownScene = false;
|
|
bool audVehicleAudioEntity::sm_IsInCarMeet = false;
|
|
audSoundSet audVehicleAudioEntity::sm_VehiclesInWaterSoundset;
|
|
f32 audVehicleAudioEntity::sm_DownSpeedThreshold = 4.f;
|
|
f32 audVehicleAudioEntity::sm_FwdSpeedThreshold = 1.f;
|
|
f32 audVehicleAudioEntity::sm_SizeThreshold = 7.f;
|
|
f32 audVehicleAudioEntity::sm_BigSizeThreshold = 100.f;
|
|
f32 audVehicleAudioEntity::sm_CombineSpeedThreshold = 300.f;
|
|
f32 audVehicleAudioEntity::sm_BicycleCombineSpeedMediumThreshold = 150.f;
|
|
f32 audVehicleAudioEntity::sm_BicycleCombineSpeedBigThreshold = 300.f;
|
|
|
|
u32 audVehicleAudioEntity::sm_TimeTargetLockStarted = 0;
|
|
u32 audVehicleAudioEntity::sm_TimeMissleFiredStarted = 0;
|
|
u32 audVehicleAudioEntity::sm_TimeAllClearStarted = 0;
|
|
u32 audVehicleAudioEntity::sm_TimeAcquiringTargetStarted = 0;
|
|
u32 audVehicleAudioEntity::sm_TimeATargetAcquiredStarted = 0;
|
|
|
|
f32 audVehicleAudioEntity::sm_HighSpeedReqVehicleVelocity = 50.0f;
|
|
u32 audVehicleAudioEntity::sm_HighSpeedMaxGearOffset = 1;
|
|
f32 audVehicleAudioEntity::sm_HighSpeedApplyStart = 0.85f;
|
|
f32 audVehicleAudioEntity::sm_HighSpeedApplyEnd = 0.95f;
|
|
u32 audVehicleAudioEntity::sm_InvHighSpeedSmootherIncreaseRate = 10000;
|
|
u32 audVehicleAudioEntity::sm_InvHighSpeedSmootherDecreaseRate = 100;
|
|
u32 audVehicleAudioEntity::sm_AlarmIntervalInMs = 400;
|
|
u32 audVehicleAudioEntity::sm_ScriptVehicleRequest = 0;
|
|
s32 audVehicleAudioEntity::sm_ScriptVehicleRequestScriptID = -1;
|
|
audDynamicWaveSlot* audVehicleAudioEntity::sm_ScriptVehicleWaveSlot = NULL;
|
|
|
|
CVehicle* audVehicleAudioEntity::sm_PlayerPedTargetVehicle = NULL;
|
|
audScene* audVehicleAudioEntity::sm_HighSpeedScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_ExhaustProximityScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_VehicleInteriorScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_VehicleGeneralScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_VehicleBonnetCamScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_VehicleFirstPersonTurretScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_OnMovingTrainScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_StuntTunnelScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_StuntRaceSpeedUpScene = NULL;
|
|
audScene* audVehicleAudioEntity::sm_StuntRaceSlowDownScene = NULL;
|
|
audVehicleType audVehicleAudioEntity::sm_StuntRaceVehicleType = AUD_VEHICLE_CAR;
|
|
|
|
f32 audVehicleAudioEntity::sm_PlayerVehicleOpenness = 1.0f;
|
|
f32 audVehicleAudioEntity::sm_PlayerVehicleProximityRatio = 0.0f;
|
|
f32 audVehicleAudioEntity::sm_CheapDistance = 30.0f;
|
|
f32 audVehicleAudioEntity::sm_DoorConeInnerAngleScaling = 0.666f;
|
|
f32 audVehicleAudioEntity::sm_DoorConeOuterAngle = 110.0f;
|
|
audCurve audVehicleAudioEntity::sm_InteriorOpenToCutoffCurve;
|
|
audCurve audVehicleAudioEntity::sm_RoofToOpennessCurve;
|
|
audCurve audVehicleAudioEntity::sm_InteriorOpenToVolumeCurve;
|
|
audSoundSet audVehicleAudioEntity::sm_ExtrasSoundSet;
|
|
audSoundSet audVehicleAudioEntity::sm_LightsSoundSet;
|
|
audSoundSet audVehicleAudioEntity::sm_MissileLockSoundSet;
|
|
audCurve audVehicleAudioEntity::sm_RoadNoiseDetailVolCurve, audVehicleAudioEntity::sm_RoadNoiseFastVolCurve, audVehicleAudioEntity::sm_RoadNoiseSteeringAngleToAttenuation, audVehicleAudioEntity::sm_RoadNoiseSteeringAngleCRToVolume;
|
|
audCurve audVehicleAudioEntity::sm_RoadNoisePitchCurve, audVehicleAudioEntity::sm_RoadNoiseSingleVolCurve, audVehicleAudioEntity::sm_RoadNoiseBicycleVolCurve;
|
|
audCurve audVehicleAudioEntity::sm_SkidSpeedRatioToPitch, audVehicleAudioEntity::sm_SkidDriftAngleToVolume, audVehicleAudioEntity::sm_RecentSpeedToSettleVolume, audVehicleAudioEntity::sm_RecentSpeedToSettleReleaseTime;
|
|
audCurve audVehicleAudioEntity::sm_SkidFwdSlipToMainVol;
|
|
audCurve audVehicleAudioEntity::sm_SlipToUndersteerVol;
|
|
audSoundSet audVehicleAudioEntity::sm_TarmacSkidSounds;
|
|
audSoundSet audVehicleAudioEntity::sm_ClatterSoundSet;
|
|
audSoundSet audVehicleAudioEntity::sm_ChassisStressSoundSet;
|
|
audCurve audVehicleAudioEntity::sm_NPCRoadNoiseRelativeSpeedToVol;
|
|
f32 audVehicleAudioEntity::sm_FrequencySmoothingRate = 18.f;
|
|
u32 g_SuperDummyRadiusSq = 50 * 50;
|
|
|
|
audSound* audVehicleAudioEntity::sm_InCarViewWind = NULL;
|
|
|
|
// time in seconds - for when the vehicle isn't going to start this time
|
|
f32 audVehicleAudioEntity::sm_IgnitionMinHold = 0.8f;
|
|
f32 audVehicleAudioEntity::sm_IgnitionMaxHold = 1.3f;
|
|
// and these ones for when it is
|
|
f32 audVehicleAudioEntity::sm_StartingIgnitionMinHold = 0.3f;
|
|
f32 audVehicleAudioEntity::sm_StartingIgnitionMaxHold = 0.6f;
|
|
|
|
u32 audVehicleAudioEntity::sm_LodSwitchFadeTime = 2000;
|
|
u32 audVehicleAudioEntity::sm_ScheduledVehicleSpawnFadeTime = 5000;
|
|
u32 audVehicleAudioEntity::sm_NumVehiclesInGranularActivationRange = 0;
|
|
u32 audVehicleAudioEntity::sm_NumVehiclesInGranularActivationRangeLastFrame = 0;
|
|
f32 audVehicleAudioEntity::sm_GranularActivationRangeScale = 1.0f;
|
|
u32 audVehicleAudioEntity::sm_NumVehiclesInActivationRange = 0;
|
|
u32 audVehicleAudioEntity::sm_NumVehiclesInActivationRangeLastFrame = 0;
|
|
u32 audVehicleAudioEntity::sm_NumDummyVehiclesLastFrame = 0;
|
|
u32 audVehicleAudioEntity::sm_NumDummyVehiclesCounter = 0;
|
|
f32 audVehicleAudioEntity::sm_ActivationRangeScale = 1.0f;
|
|
u32 audVehicleAudioEntity::sm_NumVehiclesInDummyRange[NumQuadrants];
|
|
f32 audVehicleAudioEntity::sm_DummyRangeScale[NumQuadrants];
|
|
s32 audVehicleAudioEntity::sm_FramesSincePlayerVehicleStarvation = 0;
|
|
u32 audVehicleAudioEntity::sm_NumVehiclesInRainRadius[NumQuadrants];
|
|
f32 audVehicleAudioEntity::sm_RainRadiusScalar[NumQuadrants];
|
|
u32 audVehicleAudioEntity::sm_NumVehiclesInWaterSlapRadius[NumQuadrants];
|
|
f32 audVehicleAudioEntity::sm_WaterSlapRadiusScalar[NumQuadrants];
|
|
|
|
f32 audVehicleAudioEntity::sm_VehDeltaSpeedForCollision = 90.f;
|
|
|
|
// Can't have more real vehicles than submixes
|
|
u32 g_MaxVehicleSubmixes = EFFECT_ROUTE_VEHICLE_ENGINE_MAX - EFFECT_ROUTE_VEHICLE_ENGINE_MIN + 1;
|
|
u32 g_MaxDummyVehicles = 8;
|
|
u32 g_MaxDumyVehiclesPerQuadrant = g_MaxDummyVehicles/4;
|
|
f32 g_MaxDummyRangeScale = 30.0f;
|
|
f32 g_MaxGranularRangeScale = 6.0f;
|
|
f32 g_MaxRealRangeScale = 3.0f;
|
|
u32 g_NPCRoadNoiseAttackTime = 1000;
|
|
u32 g_NPCRoadNoiseReleaseTime = 500;
|
|
f32 g_GranularActivationScaleIncreaseRate = 2.0f;
|
|
f32 g_GranularActivationScaleDecreaseRate = 2.0f;
|
|
f32 g_ActivationScaleIncreaseRate = 2.0f;
|
|
f32 g_ActivationScaleDecreaseRate = 2.0f;
|
|
f32 g_DummyActivationScaleIncreaseRate = 2.0f;
|
|
f32 g_DummyActivationScaleDecreaseRate = 2.0f;
|
|
f32 g_MinTimeAtDesiredLOD = 0.2f;
|
|
f32 g_MinTimeAtCurrentLOD = 0.5f;
|
|
f32 g_SqdDistThresholdForWaveImpact = 900.f;
|
|
f32 g_DistThresholdToTriggerVehSplashes = 10000.f;
|
|
u32 g_MaxWaterSlapVehiclesPerQuadrant = 1;
|
|
f32 g_HydraulicsChassisStressSensitivityMultiplier = 2.0f;
|
|
u8 g_NumHydraulicActivationDelayFrames = 1;
|
|
|
|
f32 g_WheelDirtinessIncreaseSmoothRate = 0.0015f;
|
|
f32 g_WheelDirtinessDecreaseSmoothRate = 0.00075f;
|
|
f32 g_WheelGlassinessIncreaseSmoothRate = 1.0f;
|
|
f32 g_WheelGlassinessDecreaseSmoothRate = 0.001f;
|
|
f32 g_GlassAreaDepletionRate = 0.25f;
|
|
f32 g_ModdedRadioVehicleOpenness = 0.3f;
|
|
u32 g_HydraulicsModifiedTimeoutMs = 1250;
|
|
u32 g_ModShopDoorRecentlyUsedTime = 500;
|
|
u32 g_MinSubRudderRepeatTime = 250;
|
|
|
|
extern bool g_NoHeadlightSmashAudio;
|
|
extern bool g_BonnetCamStereoEffectEnabled;
|
|
extern u32 g_FakeWaveHitDistanceSq;
|
|
extern bool g_AllowSynthsOnNetworkVehicles;
|
|
extern bool g_PositionedPlayerVehicleRadioEnabled;
|
|
|
|
bool g_DebugDrawFocusVehicleRadioOcclusion = false;
|
|
bool g_DisablePlayerVehicleDSP = false;
|
|
bool g_DisableNPCVehicleDSP = false;
|
|
bool g_DisableBurnoutSkidsInReverse = false;
|
|
bool g_ForceAmphibiousBoatMode = false;
|
|
bool g_EnableStereoSirens = true;
|
|
f32 g_CopsAndCrooksForceSirenSmashDamage = 0.75f;
|
|
f32 g_CopsAndCrooksForceSirenSmashProbability = 0.2f;
|
|
|
|
extern bool g_ForceUpgradeRadio;
|
|
extern float g_SubmersibleUnderwaterCutoff;
|
|
extern AircraftWarningSettings* g_AircraftWarningSettings;
|
|
|
|
BANK_ONLY(char g_CRFilter[128]={0};)
|
|
BANK_ONLY(f32 g_WaveSlotStreamingDelayTime = 0.0f;)
|
|
BANK_ONLY(bool g_AuditionVehExplosions = false;);
|
|
f32 g_VehHealthThreshold = 100.f;
|
|
#if __BANK
|
|
PARAM(disablegranular, "Disable the granular engine system");
|
|
#endif
|
|
|
|
XPARAM(audiodesigner);
|
|
|
|
#if __BANK
|
|
extern bool g_ForceUpgradeEngine;
|
|
extern f32 g_ForcedEngineUpgradeLevel;
|
|
extern bool g_ForceUpgradeExhaust;
|
|
extern f32 g_ForcedExhaustUpgradeLevel;
|
|
extern bool g_ForceUpgradeEngineBay[3];
|
|
extern f32 g_ForcedEngineBayUpgradeLevel[3];
|
|
extern bool g_ForceUpgradeTransmission;
|
|
extern f32 g_ForcedTransmissionUpgradeLevel;
|
|
extern bool g_ForceUpgradeTurbo;
|
|
extern f32 g_ForcedTurboUpgradeLevel;
|
|
extern bool g_ForceUpgradeRadio;
|
|
extern f32 g_ForcedRadioUpgradeLevel;
|
|
bool g_ForceGlassySurface;
|
|
bool g_ForceDirtySurface;
|
|
bool g_ShowCarsPlayingRainLoops = false;
|
|
bool g_OverrideMissileStatus = false;
|
|
bool g_DebugMissileLockStatus = false;
|
|
bool g_UndersteerAffectsMainSkidVol = true;
|
|
bool g_ShowDoorRatios = false;
|
|
extern bool g_ForceNPCHydraulicSounds;
|
|
extern bool g_DebugDrawVehicleWater;
|
|
extern bool g_ForceDamage;
|
|
extern bool g_ForceRealLodOnFocusEntity;
|
|
extern f32 g_ForcedDamageFactor;
|
|
extern bool g_ForceSynthsOnAllEngines;
|
|
extern bool g_SimulateDrowning;
|
|
extern bool g_ShowEngineStates;
|
|
extern bool g_DrawSuperDummyRadius;
|
|
extern bool g_ShowFocusVehicle;
|
|
extern bool g_DrawLinesToRealCars;
|
|
extern bool g_DrawLinesToVehiclesWithWaveSlots;
|
|
extern bool g_DrawVehiclesInModShop;
|
|
extern bool g_DrawLinesToVehiclesWithSubmixVoices;
|
|
extern bool g_OverrideHydraulicSuspensionDamage;
|
|
extern f32 g_OverridenHydraulicSuspensionDamage;
|
|
|
|
s32 g_SimulatedMissileState = 0;
|
|
f32 g_SimulatedMissileDistance = 0.5f;
|
|
extern bool g_ForceShallowWater;
|
|
extern bool g_DisableClatter;
|
|
extern bool g_DisplayRidgedSurfaceInfo;
|
|
extern bool g_UseDebugPlaneTracker;
|
|
extern bool g_UseDebugHeliTracker;
|
|
extern bool g_DisableHorns;
|
|
extern CPlayerSwitchInterface g_PlayerSwitch;
|
|
|
|
bool g_SmashPlayerSiren = false;
|
|
bool g_FixPlayerSiren = false;
|
|
|
|
bool g_OverrideFocusVehicleOpenness = false;
|
|
f32 g_OverriddenVehicleOpenness = 0.f;
|
|
|
|
bool g_OverrideFocusVehicleLeakage;
|
|
AmbientRadioLeakage g_OverriddenVehicleRadioLeakage = LEAKAGE_BASSY_LOUD;
|
|
|
|
audioCarRecordingInfo audVehicleAudioEntity::sm_DebugCarRecording;
|
|
|
|
f32 audVehicleAudioEntity::sm_CRCurrentTime = 0.f;
|
|
f32 audVehicleAudioEntity::sm_CRProgress = 0.f;
|
|
f32 audVehicleAudioEntity::sm_CRJumpTimeInMs = 1000.f;
|
|
bool audVehicleAudioEntity::sm_UpdateCRTime = false;
|
|
bool audVehicleAudioEntity::sm_PauseGame = false;
|
|
bool audVehicleAudioEntity::sm_EnableCREditor = false;
|
|
bool audVehicleAudioEntity::sm_ManualTimeSet = false;
|
|
bool audVehicleAudioEntity::sm_DrawCREvents = false;
|
|
bool audVehicleAudioEntity::sm_DrawCRName = false;
|
|
bool audVehicleAudioEntity::sm_LoadExistingCR = false;
|
|
bool audVehicleAudioEntity::sm_VehCreated = false;
|
|
char audVehicleAudioEntity::sm_CRAudioSettingsCreator[128];
|
|
char audVehicleAudioEntity::sm_RecordingName[64];
|
|
u32 audVehicleAudioEntity::sm_RecordingIndex = 0;
|
|
rage::bkGroup* audVehicleAudioEntity::sm_CRWidgetGroup(NULL);
|
|
#endif
|
|
|
|
#if NA_RADIO_ENABLED
|
|
bank_float g_RadioLPFCutoffs[NUM_AMBIENTRADIOLEAKAGE][2] =
|
|
{
|
|
{50.f, 5000.f}, // Bassy/Loud
|
|
{300.f, 5000.f}, // Bassy/Medium
|
|
{1000.f, 5000.f}, // Mids/Loud
|
|
{1000.f, 5000.f}, // Mids/Medium
|
|
{1000.f, 5000.f}, // Mids/Quiet
|
|
{50.f, 250.f}, // CrazyLoud
|
|
{550.f, 4000.f}, // Modded
|
|
{550.f, 1200.f}, // PartyBus
|
|
};
|
|
|
|
float g_RadioLPFLinear[NUM_AMBIENTRADIOLEAKAGE][2];
|
|
|
|
bank_u32 g_RadioHPFCutoffs[NUM_AMBIENTRADIOLEAKAGE] =
|
|
{
|
|
0, // Bassy/Loud
|
|
30, // Bassy/Medium
|
|
500, // Mids/Loud
|
|
500, // Mids/Medium
|
|
1000, // Mids/Quiet
|
|
0, // CrazyLoud
|
|
0, // Modded
|
|
0, // PartyBus
|
|
};
|
|
|
|
bank_float g_RadioOpennessVols[NUM_AMBIENTRADIOLEAKAGE][2] =
|
|
{
|
|
{5.0f, 1.25f}, // Bassy/Loud
|
|
{2.5f, 1.f}, // Bassy/Medium
|
|
{2.82f, 1.41f}, // Mids/Loud
|
|
{1.41f, 1.41f}, // Mids/Medium
|
|
{1.27f, 1.41f}, // Mids/Quiet
|
|
{7.0f, 8.5f}, // Crazy/Loud
|
|
{5.0f, 4.0f}, // Modded
|
|
{5.0f, 13.0f}, // PartyBus
|
|
};
|
|
|
|
bank_float g_RadioRolloffs[NUM_AMBIENTRADIOLEAKAGE][2] =
|
|
{
|
|
{2.0f, 1.f}, // Bassy/Loud
|
|
{1.5f, 1.f}, // Bassy/Medium
|
|
{1.0f, 1.f}, // Mids/Loud
|
|
{1.0f, 1.f}, // Mids/Medium
|
|
{1.1f, 1.f}, // Mids/Quiet
|
|
{5.f, 5.f}, // CrazyLoud
|
|
{3.f, 3.f}, // Modded
|
|
{3.f, 4.f}, // PartyBus
|
|
};
|
|
|
|
bank_float g_MaxRadiusForAmbientRadio2[NUM_AMBIENTRADIOLEAKAGE] =
|
|
{
|
|
(50.f * 50.f), // Bassy/Loud
|
|
(40.f * 40.f), // Bassy/Medium
|
|
(25.f * 25.f), // Mids/Loud
|
|
(25.f * 25.f), // Mids/Medium
|
|
(25.f * 25.f), // Mids/Quiet
|
|
(65.f * 65.f), // CrazyLoud
|
|
(65.f * 65.f), // Modded
|
|
(350.f * 350.f), // PartyBus
|
|
};
|
|
|
|
#if __BANK
|
|
bool g_OverrideFocusVehicleLeakageParams = false;
|
|
bool g_CopyOverridenLeakageFromCurrentSettings = false;
|
|
f32 g_OverridenLeakageVolMin = 0.f;
|
|
f32 g_OverridenLeakageVolMax = 0.f;
|
|
f32 g_OverridenLeakageLpfLinearMin = 0.f;
|
|
f32 g_OverridenLeakageLpfLinearMax = 0.f;
|
|
f32 g_OverridenLeakageRolloffMin = 0.f;
|
|
f32 g_OverridenLeakageRolloffMax = 0.f;
|
|
u32 g_OverridenLeakageHPFCutoff = 0;
|
|
f32 g_OverridenLeakageMaxRadius = 0;
|
|
#endif
|
|
|
|
bank_float g_LoudVehicleRadioOffset = 4.f;
|
|
bank_float g_AmbientVehicleRadioOffset = 5.f;
|
|
#endif //NA_RADIO_ENABLED
|
|
|
|
const char * g_MissileLockOnStates[5] = {
|
|
"No Lock",
|
|
"Acquired/Acquiring",
|
|
"Missile Fired",
|
|
"Acquiring Target",
|
|
"Target Acquired",
|
|
};
|
|
|
|
extern s32 g_ForcePlayerVehicleLOD;
|
|
|
|
const eHierarchyId g_DoorHierarchyIds[] =
|
|
{
|
|
VEH_INVALID_ID,// FRONT
|
|
VEH_INVALID_ID,// BACK
|
|
VEH_DOOR_DSIDE_F,
|
|
VEH_DOOR_PSIDE_F,
|
|
VEH_DOOR_DSIDE_R,
|
|
VEH_DOOR_PSIDE_R,
|
|
VEH_INVALID_ID,
|
|
VEH_INVALID_ID
|
|
};
|
|
|
|
const eHierarchyId audVehicleAudioEntity::sm_WindowHierarchyIds[NumWindowHierarchyIds] =
|
|
{
|
|
VEH_WINDSCREEN,
|
|
VEH_WINDSCREEN_R,
|
|
VEH_WINDOW_LF,
|
|
VEH_WINDOW_RF,
|
|
VEH_WINDOW_LR,
|
|
VEH_WINDOW_RR,
|
|
VEH_WINDOW_LM,
|
|
VEH_WINDOW_RM,
|
|
};
|
|
|
|
const f32 g_WindowOpenContribs[] =
|
|
{
|
|
0.5f, // VEH_WINDSCREEN
|
|
0.45f, // VEH_WINDSCREEN_R
|
|
0.3f, // VEH_WINDOW_LF
|
|
0.3f, // VEH_WINDOW_RF
|
|
0.2f, // VEH_WINDOW_LR
|
|
0.2f, // VEH_WINDOW_RR
|
|
0.2f, // VEH_WINDOW_LM
|
|
0.2f, // VEH_WINDOW_RM
|
|
};
|
|
|
|
const f32 g_WindowOutSign[] =
|
|
{
|
|
1.0f, // VEH_WINDSCREEN
|
|
-1.0f, // VEH_WINDSCREEN_R
|
|
-1.0f, // VEH_WINDOW_LF
|
|
1.0f, // VEH_WINDOW_RF
|
|
-1.0f, // VEH_WINDOW_LR
|
|
1.0f, // VEH_WINDOW_RR
|
|
-1.0f, // VEH_WINDOW_LM
|
|
1.0f, // VEH_WINDOW_RM
|
|
};
|
|
|
|
const f32 g_DoorOutSign[] =
|
|
{
|
|
1.0f, // VEH_INVALID_ID
|
|
1.0f, // VEH_INVALID_ID
|
|
-1.0f, // VEH_DOOR_DSIDE_F
|
|
1.0f, // VEH_DOOR_PSIDE_F
|
|
-1.0f, // VEH_DOOR_DSIDE_R
|
|
1.0f, // VEH_DOOR_PSIDE_R
|
|
1.0f, //VEH_INVALID_ID
|
|
1.0f //VEH_INVALID_ID
|
|
};
|
|
|
|
bool g_RenderSlotManager = false;
|
|
bool g_ShowRadioGenres = false;
|
|
bool g_BreakOnVehicleUpdate = false;
|
|
bool g_DebugVehicleOpenness = false;
|
|
bool g_DebugVehicleSkids = false;
|
|
bool g_DebugDSPParams = false;
|
|
bool g_DebugHighSpeedEffect = false;
|
|
bool g_DisableEngineExhaustDSP = false;
|
|
s32 g_OverridenSkidPitchOffset = 0;
|
|
|
|
char g_DrivingMaterialName[64] = "";
|
|
audCategory *g_SkidCategory, *g_RoadNoiseCategory;
|
|
extern const u32 g_VariationVariableHash = ATSTRINGHASH("variation", 0x0cff74a31);
|
|
audCurve g_FreewayBumpSpeedToVol, g_FreewayBumpSpeedToPitch;
|
|
audCurve g_PlayerRoadNoiseFastVolCurve;
|
|
audCurve g_RoadNoiseWetRoadVolCurve;
|
|
audCurve g_VehicleMassToRumbleVol;
|
|
audCurve g_IceVanTempoScalingCurve;
|
|
bank_u32 g_TimeToPlaySiren = 350;
|
|
u32 g_StuntBoostIntensityTimeout = 3000;
|
|
u32 g_RechargeIntensityTimeout = 3000;
|
|
u32 g_IceVanTune = 0;
|
|
u32 g_IceVanTuneTextId = 1;
|
|
f32 g_ExhaustProximityEffectRange = 1.5f;
|
|
f32 g_PlayerHornOffset = 0.f;
|
|
f32 g_UpperVehDynamicImpactThreshold = -5.f;
|
|
f32 g_LowerVehDynamicImpactThreshold = -10.f;
|
|
u32 g_audVehicleLoopReleaseTime = 1500;
|
|
f32 g_NPCRoadNoiseInnerAngle = 0.0f;
|
|
f32 g_NPCRoadNoiseOuterAngle = 160.0f;
|
|
f32 g_SpeedForSpinDebris = 0.2f;
|
|
f32 g_ClatterMaxAcceleration = 80.0f;
|
|
f32 g_ChassisStressMaxAcceleration = 10.0f;
|
|
f32 g_SpinRatioForDebris = 3.5f;
|
|
u32 g_MaxRainVehiclesPerQuadrant = 1;
|
|
float g_BodyDamageFactorForDebris = 0.4f;
|
|
float g_BodyDamageFactorForHydraulicDebris = 0.15f;
|
|
bool g_GranularEnabled = true;
|
|
bool g_InteriorEngineExhaustAtListener = true;
|
|
bool g_InteriorEngineExhaustPanned = true;
|
|
|
|
f32 g_LateralSkidSmootherIncrease = 0.6f;
|
|
f32 g_LateralSkidSmootherDecrease = 6.f;
|
|
f32 g_MainSkidSmootherIncrease = 3.5f;
|
|
f32 g_MainSkidSmootherDecrease = 3.3f;
|
|
|
|
bool g_DebugSubmarineDiveHorn = false;
|
|
bool g_ForceTriggerSubmarineDiveHorn = false;
|
|
f32 g_MinSubDiveHoldTime = 0.25f;
|
|
f32 g_SubDiveHornVelocity = 1.f;
|
|
f32 g_SubDiveHornSubmergeThreshold = 0.5f;
|
|
f32 g_SubDiveHornSubmergeRetriggerThreshold = 0.3f;
|
|
f32 g_SubDiveHornSubmergeRetriggerThresholdNoDriver = 0.55f;
|
|
|
|
const f32 g_MaxDoorOpenAngle = 70.0f;
|
|
const u32 g_MaxDoors = NELEM(g_DoorHierarchyIds);
|
|
const f32 g_NumDoorsScalar = 1.f / (f32)g_MaxDoors;
|
|
|
|
CompileTimeAssert(NELEM(g_WindowOpenContribs) == audVehicleAudioEntity::NumWindowHierarchyIds);
|
|
CompileTimeAssert(NELEM(g_DoorOutSign) == g_MaxDoors);
|
|
CompileTimeAssert(NELEM(g_WindowOpenContribs) == audVehicleAudioEntity::NumWindowHierarchyIds);
|
|
|
|
extern audCategory* g_EngineDamageCategory;
|
|
extern CWeather g_weather;
|
|
extern phMaterialMgr::Id g_PedMaterialId;
|
|
extern bool g_DisplayGroundMaterial;
|
|
extern bool g_DisplayDirtGlassInfo;
|
|
extern bool g_ShowEngineExhaust;
|
|
extern bool g_AllowDummyVehicleRoadNoise;
|
|
extern f32 g_EngineVolumeTrim;
|
|
extern f32 g_ExhaustVolumeTrim;
|
|
extern f32 g_GearboxVolumeTrim;
|
|
extern f32 g_TurboVolumeTrim;
|
|
extern f32 g_StereoEffectEngineVolumeTrim;
|
|
extern f32 g_StereoEffectExhaustVolumeTrim;
|
|
extern Vector3 g_HydrantSprayPos;
|
|
extern bool g_IsHydrantSpraying;
|
|
extern u32 g_MaxGranularEngines;
|
|
extern u32 g_StuntBoostIntensityIncreaseDelay;
|
|
extern u32 g_RechargeIntensityIncreaseDelay;
|
|
|
|
BANK_ONLY(extern bool g_TreatAsPedCar);
|
|
BANK_ONLY(extern bool g_DisableRoadNoise);
|
|
BANK_ONLY(extern bool g_ShowNPCRoadNoiseState);
|
|
BANK_ONLY(extern bool g_DisableNPCRoadNoise);
|
|
BANK_ONLY(extern bool g_AutoReapplyDSPPresets);
|
|
BANK_ONLY(extern bool g_ShowVehiclesWithWaveSlots);
|
|
BANK_ONLY(extern bool g_EngineVolumeCaptureActive);
|
|
|
|
const u32 g_MainTarmacSkid = ATSTRINGHASH("VEHICLES_WHEEL_LOOPS_MAIN_TARMAC_SKID", 0x0ef01c293);
|
|
const u32 g_MainTarmacSkidBicycle = ATSTRINGHASH("BICYCLE_SKIDS", 0x00503a04a);
|
|
const u32 g_SideTarmacSkid = ATSTRINGHASH("VEHICLES_WHEEL_LOOPS_SIDE_TARMAC_SKID", 0x04346c124);
|
|
const u32 g_ScrapeTarmacSkid = ATSTRINGHASH("VEHICLES_WHEEL_LOOPS_TARMAC_SCRAPE", 0x01491e0de);
|
|
const u32 g_FastConcreteTyreRollHash = ATSTRINGHASH("VEHICLES_WHEEL_LOOPS_FAST_CONCRETE", 0x06ae284f4);
|
|
|
|
#if __WIN32
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4355) // 'this' used in base member initializer list
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity constructor
|
|
// ----------------------------------------------------------------
|
|
audVehicleAudioEntity::audVehicleAudioEntity() : m_CollisionAudio(this)
|
|
{
|
|
m_VehicleLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
m_VehicleType = AUD_VEHICLE_NONE;
|
|
m_EngineWaveSlot = NULL;
|
|
m_LowLatencyWaveSlot = NULL;
|
|
m_SFXWaveSlot = NULL;
|
|
m_Vehicle = NULL;
|
|
m_VehicleClatter = NULL;
|
|
m_SpecialFlightModeTransformSound = NULL;
|
|
m_LandingGearSound = NULL;
|
|
m_JumpRecharge = NULL;
|
|
m_ChassisStressLoop = NULL;
|
|
m_EnvironmentGroup = NULL;
|
|
m_HornSound = NULL;
|
|
m_AlarmSound = NULL;
|
|
m_MissileApproachingSound = NULL;
|
|
m_MissileApproachingSoundImminent = NULL;
|
|
m_AcquiringTargetSound = NULL;
|
|
m_AllClearSound = NULL;
|
|
m_BeingTargetedSound = NULL;
|
|
m_DrowningRadioSound = NULL;
|
|
m_WeaponChargeSound = NULL;
|
|
m_SirenLoop = NULL;
|
|
m_SirenBlip = NULL;
|
|
m_ParachuteLoop = NULL;
|
|
m_IdleHullSlapSound = NULL;
|
|
m_ReverseWarning = NULL;
|
|
m_DoorOpenWarning = NULL;
|
|
m_RoadNoiseFast = NULL;
|
|
m_RoadNoiseRidged = NULL;
|
|
m_RoadNoiseRidgedPulse = NULL;
|
|
m_ExhastProximityPulseSound = NULL;
|
|
m_DirtyWheelLoop = NULL;
|
|
m_GlassyWheelLoop = NULL;
|
|
m_RoadNoiseWet = NULL;
|
|
m_RoadNoiseHeavy = NULL;
|
|
m_WheelDetailLoop = NULL;
|
|
m_RoadNoiseNPC = NULL;
|
|
m_RainLoop = NULL;
|
|
m_CaterpillarTrackLoop = NULL;
|
|
m_DetachedBonnetSound = NULL;
|
|
m_WaterLappingSound = NULL;
|
|
m_VehicleCabinTone = NULL;
|
|
m_SubTurningSweetener = NULL;
|
|
m_SubPropSound = NULL;
|
|
m_SubExtrasSound = NULL;
|
|
m_SubmersibleCreakSound = NULL;
|
|
m_WaterDiveSound = NULL;
|
|
m_MainSkidLoop = m_SideSkidLoop = m_UndersteerSkidLoop = m_WheelSpinLoop = m_WetWheelSpinLoop = NULL;
|
|
m_SurfaceSettleSound = NULL;
|
|
m_WetSkidLoop = NULL;
|
|
m_DriveWheelSlipLoop = NULL;
|
|
m_ClothSound = NULL;
|
|
m_CinematicTireSweetener = NULL;
|
|
m_StuntTunnelSound = NULL;
|
|
m_WaterTurbulenceSound = NULL;
|
|
m_RadioStation = NULL;
|
|
m_LastRadioStation = NULL;
|
|
m_ReapplyDSPEffects = false;
|
|
|
|
m_FranklinSpecialPassby = m_FranklinSpecialTraction = NULL;
|
|
m_DamageWarningSound = NULL;
|
|
m_SkidPitchOffset = 0;
|
|
|
|
m_CachedMaterialSettings = NULL;
|
|
m_SubAngularVelocityMag = 0.0f;
|
|
m_ForcedGameObject = 0u;
|
|
m_EngineSubmixIndex = -1;
|
|
m_ExhaustSubmixIndex = -1;
|
|
m_PlayerHornOn = false;
|
|
m_PlaySirenWithNoNetworkPlayerDriver = false;
|
|
m_WasAlarmActive = false;
|
|
m_WasScheduledCreation = false;
|
|
m_OverrideHorn = false;
|
|
m_OverridenHornHash = g_NullSoundHash;
|
|
m_BulletHitCount = 0;
|
|
m_TimeSinceLastBulletHit = 0;
|
|
m_LastSurfaceChangeClatterTime = 0u;
|
|
|
|
for(u32 i = 0; i < NUM_VEH_CWHEELS_MAX; i++)
|
|
{
|
|
m_ShallowWaterSounds[i] = NULL;
|
|
}
|
|
|
|
for (u32 i = 0; i < CVehicle::MAX_NUM_WEAPON_BLADES; i++)
|
|
{
|
|
m_BladeImpactSound[i] = NULL;
|
|
}
|
|
|
|
m_ShallowWaterEnterSound = NULL;
|
|
m_LastDriftAngleDelta = m_LastDriftAngle = 0.f;
|
|
m_LastDriftChirpTime = 0;
|
|
|
|
m_NetworkCachedRadioStationIndex = g_NullRadioStation;
|
|
}
|
|
|
|
#if __WIN32
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity reset
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::Reset()
|
|
{
|
|
m_EngineWaterDepth = 0.0f;
|
|
m_RidgedSurfaceDirectionMatch = 0.0f;
|
|
m_LastHydraulicSuspensionStateChangeTime = 0u;
|
|
m_LastCaterpillarTrackValidTime = 0u;
|
|
m_LastHydraulicEngageDisengageTime = 0u;
|
|
m_FakeAudioHealth = 1000.0f;
|
|
m_FwdSpeedLastFrame = 0.0f;
|
|
m_PrevDirtinessVolume = 0.0f;
|
|
m_PrevGlassinessVolume = 0.0f;
|
|
m_MissileApproachTimer = 0.0f;
|
|
m_InAirRotationalForceX = 0.0f;
|
|
m_CachedNonCameraRelativeOpenness = 0.0f;
|
|
m_CachedCameraRelativeOpenness = 0.0f;
|
|
m_InAirRotationalForceXLastFrame = 0.0f;
|
|
m_InAirRotationalForceY = 0.0f;
|
|
m_InAirRotationalForceYLastFrame = 0.0f;
|
|
m_SteeringAngleLastFrame = 0.0f;
|
|
m_OutOfWaterTimer = 0.f;
|
|
m_WheelRetractRate = 0.f;
|
|
m_InWaterTimer = 0.f;
|
|
m_LastSubCarRudderTurnSoundTime = 0u;
|
|
m_SubmarineTransformSoundHash = 0u;
|
|
m_ShouldStopSubTransformSound = false;
|
|
m_IsLandingGearRetracting = false;
|
|
m_ShouldPlayLandingGearSound = false;
|
|
m_ShouldStopLandingGearSound = false;
|
|
m_WasSuspensionDropped = false;
|
|
m_WasReducedSuspensionForceSet = false;
|
|
m_SpecialFlightModeWingsDeployed = false;
|
|
m_SuppressHorn = false;
|
|
m_RequiresSFXBank = false;
|
|
m_IsWaitingOnActivatedJumpLand = false;
|
|
m_HasTriggeredSubmarineDiveHorn = false;
|
|
m_HasTriggeredSubmarineSurface = true;
|
|
m_TriggerDeferredSubmarineDiveHorn = false;
|
|
m_TriggerDeferredSubmarineSurface = false;
|
|
m_SubmarineDiveHoldTime = 0.f;
|
|
m_TriggerFastSubCarTransformSound = false;
|
|
m_ForceReverseWarning = false;
|
|
m_ResetDSPEffects = false;
|
|
m_ReapplyDSPPresets = false;
|
|
m_IsScriptTriggeredHorn = false;
|
|
m_IsBeingNetworkSpectated = false;
|
|
m_IsVehicleBeingStopped = false;
|
|
m_WasInWaterLastFrame = true;
|
|
m_IsPlayerPedInFullyOpenSeat = false;
|
|
m_ShouldPlayBonnetDetachSound = false;
|
|
m_ShouldTriggerHydraulicBounce = false;
|
|
m_ShouldTriggerHydraulicActivate = false;
|
|
m_ShouldTriggerHydraulicDeactivate = false;
|
|
m_IsPersonalVehicle = false;
|
|
m_HydraulicActivationDelayFrames = 0u;
|
|
m_ScriptPriority = AUD_VEHICLE_SCRIPT_PRIORITY_NONE;
|
|
m_ScriptPriortyVehicleThreadID = THREAD_INVALID;
|
|
m_DummyLODValid = false;
|
|
m_VehicleModelSoundHash = m_VehicleMakeSoundHash = m_VehicleCategorySoundHash = m_ScannerVehicleSettingsHash = 0;
|
|
m_HasMissileLockWarningSystem = false;
|
|
m_GpsType = GPS_TYPE_NONE;
|
|
m_GpsVoice = GPS_VOICE_FEMALE;
|
|
m_RadioType = RADIO_TYPE_NONE;
|
|
m_RadioLeakage = LEAKAGE_MIDS_MEDIUM;
|
|
m_RadioOpennessVol = 0.f;
|
|
#if NA_RADIO_ENABLED
|
|
m_RadioLPFCutoff = (u32)g_RadioLPFCutoffs[m_RadioLeakage][0];
|
|
m_RadioHPFCutoff = g_RadioHPFCutoffs[m_RadioLeakage];
|
|
m_RadioRolloffFactor = g_RadioRolloffs[m_RadioLeakage][0];
|
|
m_AmbientRadioDisabled = false;
|
|
m_RadioDisabled = false;
|
|
m_HasLoudRadio = false;
|
|
m_ScriptForcedRadio = false;
|
|
m_ScriptRequestedRadioStation = false;
|
|
#endif
|
|
|
|
m_VehicleLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
m_PrevDesiredLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
m_TimeAtDesiredLOD = 10.0f;
|
|
m_NextClatterTime = 0;
|
|
m_ScriptEngineDamageFactor = 0.0f;
|
|
m_ScriptBodyDamageFactor = 0.0f;
|
|
m_SpecialFlightModeReplayAngularVelocity = 0.0f;
|
|
m_DistanceFromListener2LastFrame = 0u;
|
|
m_DistanceFromListener2 = 0u;
|
|
m_ForcedGameObjectResetRequired = false;
|
|
m_PreserveEnvironmentGroupOnShutdown = false;
|
|
REPLAY_ONLY(m_ReplayRevs = 0.0f;)
|
|
m_RadioStation = NULL;
|
|
m_IsRadioOff = false;
|
|
m_PlayedDiveSound = false;
|
|
m_TimeAtCurrentLOD = 10.0f;
|
|
m_TimeStationary = 0.0f;
|
|
m_LastRadioStation = NULL;
|
|
m_CachedMaterialSettings = NULL;
|
|
m_BurnoutPitch = 0.0f;
|
|
m_LastRevLimiterTime = 0;
|
|
m_LastScriptDoorModifyTime = 0;
|
|
m_LastHitByRocketTime = 0;
|
|
m_LastWaveHitTime = 0;
|
|
m_LastBigWaveHitTime = 0;
|
|
m_LastWaterLeaveTime = 0;
|
|
m_WeaponChargeBone = -1;
|
|
m_WeaponChargeLevel = 0.f;
|
|
m_PrevFastRoadNoiseHash = g_NullSoundHash;
|
|
m_PrevDetailRoadNoiseHash = g_NullSoundHash;
|
|
m_SpecialFlightModeTransformSoundToTrigger = 0u;
|
|
m_HasScannerDescribedModel = false;
|
|
m_HasScannerDescribedManufacturer = false;
|
|
m_HasScannerDescribedColour = false;
|
|
m_HasScannerDescribedCategory = false;
|
|
m_IsFastRoadNoiseDisabled = false;
|
|
m_InCarModShop = false;
|
|
m_WasInCarModShop = false;
|
|
m_HornType = 0;
|
|
m_HornHeldDownTime = 0;
|
|
m_LastSirenChangeTime = 0;
|
|
m_SirenState = AUD_SIREN_OFF;
|
|
m_IsSirenFucked = false;
|
|
m_IsSirenForcedOn = false;
|
|
m_SirenBypassMPDriverCheck = false;
|
|
m_UseSirenForHorn = true;
|
|
m_IsIndicatorRequestedOn = false;
|
|
m_ParkingBeepEnabled = false;
|
|
m_KeepSirenOn = false;
|
|
m_IsReversing = false;
|
|
m_HasIndicatorRequest = false;
|
|
m_LastSplashTime = 0;
|
|
m_LastHeliRotorSplashTime = 0;
|
|
m_LastTimeOnGround = 0;
|
|
m_LastTimeTwoWheeling = 0;
|
|
m_LastTimeInAir = 0;
|
|
m_LastTimeExploded = 0;
|
|
m_LastTimeExplodedVehicle = 0;
|
|
m_HasSmashedWindow = false;
|
|
m_IsHornPermanentlyOn = false;
|
|
m_WasHornPermanentlyOn = false;
|
|
m_IsHornEnabled = true;
|
|
m_HeadlightsSwitched = false;
|
|
m_WasMissileApproaching = false;
|
|
m_WasBeingTargeted = false;
|
|
m_WasAcquiringTarget = false;
|
|
m_HadAcquiredTarget = false;
|
|
m_SirenControlledByConductor = true;
|
|
m_MustPlaySiren = true;
|
|
m_LastPlayerVehicle = false;
|
|
m_ShouldPlayPlayerVehSiren = true;
|
|
m_WantsToPlaySiren = false;
|
|
m_IsSirenOn = false;
|
|
m_IsWaitingToInit = true;
|
|
m_IsPlayerSeatedInVehicle = false;
|
|
m_IsNetworkPlayerSeatedInVehicle = false;
|
|
m_PlayerHornOn = false;
|
|
m_IsInAirCached = false;
|
|
m_IsPlayerVehicle = false;
|
|
m_IsFocusVehicle = false;
|
|
m_IsPlayerDrivingVehicle = false;
|
|
m_OverrideHorn = false;
|
|
m_OverridenHornHash = g_NullSoundHash;
|
|
m_WasWrecked = false;
|
|
m_DrowningFactor = 0.f;
|
|
m_IgnitionHoldTime = 1.0f;
|
|
m_TimeToPlaySiren = 0;
|
|
m_LastCREventProcessed = 0;
|
|
m_PrevAverageDriveWheelSpeed = 1.0f;
|
|
m_TyreChirpAccelPlayed = false;
|
|
m_TyreChirpBrakePlayed = false;
|
|
m_OnStairs = false;
|
|
m_WasOnStairs = false;
|
|
m_ReapplyDSPEffects = false;
|
|
|
|
m_DriftFactorSmoother.Init(1.0f, 0.05f, true);
|
|
m_WheelDirtinessSmoother.Init(0.001f, 0.001f, true);
|
|
m_WheelGlassinessSmoother.Init(0.001f, 0.001f, true);
|
|
m_ChassisStressSmoother.Init(10.f, 2.41f/1000.f, true);
|
|
m_HydraulicSuspensionInputSmoother.Init(0.1f, 0.1f, true);
|
|
m_HydraulicSuspensionAngleSmoother.Init(0.0075f, 0.1f, true);
|
|
m_DrowningFactorSmoother.Init(GetDrowningSpeed()/1000.0f, 0.2f/1000.0f, true);
|
|
m_SirensVolumeSmoother.Init(0.001f,true);
|
|
m_RainLoopVolSmoother.Init(0.1f,true);
|
|
m_NPCRoadNoiseSmoother.Init(0.01f);
|
|
m_WheelSpinSmoother.Init(1.0f, 0.001f);
|
|
m_VisibilitySmoother.Init(0.001f, 0.0001f);
|
|
m_SubAngularVelocitySmoother.Init(0.01f);
|
|
m_ShouldStopSiren = false;
|
|
m_SirensDesireLinVol = 1.f;
|
|
m_NearestNodeAddress.SetEmpty();
|
|
|
|
m_EngineEffectWetSmoother.Init(0.0006f);
|
|
m_EngineEffectWetSmoother.CalculateValue(0.0f, fwTimer::GetTimeInMilliseconds());
|
|
|
|
for(u32 i = 0; i < NUM_VEH_CWHEELS_MAX; i++)
|
|
{
|
|
m_LastMaterialIds[i] = ~0U;
|
|
m_LastTyreBumpTimes[i] = 0;
|
|
m_LastSlipAngle[i] = 0.f;
|
|
}
|
|
|
|
for (u32 i = 0; i < CVehicle::MAX_NUM_WEAPON_BLADES; i++)
|
|
{
|
|
m_IsWeaponBladeColliding[i] = false;
|
|
m_LastWeaponBladeCollisionTime[i] = 0u;
|
|
m_LastWeaponBladeCollisionIsPed[i] = false;
|
|
}
|
|
|
|
m_MainSkidSmoother.Init(g_MainSkidSmootherIncrease * 0.001f,g_MainSkidSmootherDecrease * 0.001f,0.0f,2.5f);
|
|
m_LateralSkidSmoother.Init(g_LateralSkidSmootherIncrease * 0.001f,g_LateralSkidSmootherDecrease * 0.001f,0.f, 1.f);
|
|
m_BurnoutSmoother.Init(0.001f, true);
|
|
m_SurfaceSettleSmoother.Init(0.1f);
|
|
|
|
m_RoadNoiseLeftCone.Init(-Vec3V(V_X_AXIS_WZERO), 0.5f, g_NPCRoadNoiseInnerAngle, g_NPCRoadNoiseOuterAngle);
|
|
m_RoadNoiseRightCone.Init(Vec3V(V_X_AXIS_WZERO), 0.5f, g_NPCRoadNoiseInnerAngle, g_NPCRoadNoiseOuterAngle);
|
|
|
|
m_CachedVehicleVelocity.Zero();
|
|
m_CachedVehicleVelocityLastFrame.Zero();
|
|
m_CachedAngularVelocity.Zero();
|
|
m_PrevHydraulicsInputAxis.Zero();
|
|
m_HydraulicsInputAxis.Zero();
|
|
m_PrevHydraulicsSuspensionAngle.Zero();
|
|
m_HydraulicsSuspensionAngle.Zero();
|
|
|
|
for(s32 loop = 0; loop < m_VehicleGadgets.GetCount(); loop++)
|
|
{
|
|
m_VehicleGadgets[loop]->Reset();
|
|
}
|
|
|
|
m_BulletHitCount = 0;
|
|
m_TimeSinceLastBulletHit = 0;
|
|
|
|
m_PlayerVehicleMixGroupIndex = -1;
|
|
|
|
m_PlayerVehicleAlarmBehaviour = false;
|
|
|
|
m_NetworkCachedRadioStationIndex = g_NullRadioStation;
|
|
|
|
for(s32 i = 0; i < NumWindowHierarchyIds; i++)
|
|
{
|
|
m_HasWindowToSmashCache.Set(i);
|
|
}
|
|
|
|
if(m_RainLoop)
|
|
{
|
|
m_RainLoop->StopAndForget();
|
|
}
|
|
}
|
|
|
|
#if __DEV
|
|
void audVehicleAudioEntity::PoolFullCallback(void* pItem)
|
|
{
|
|
static const char *pPopTypeNames[] =
|
|
{
|
|
"POPTYPE_UNKNOWN",
|
|
"POPTYPE_RANDOM_PERMANENT",
|
|
"POPTYPE_RANDOM_PARKED",
|
|
"POPTYPE_RANDOM_PATROL",
|
|
"POPTYPE_RANDOM_SCENARIO",
|
|
"POPTYPE_RANDOM_AMBIENT",
|
|
"POPTYPE_PERMANENT",
|
|
"POPTYPE_MISSION",
|
|
"POPTYPE_REPLAY",
|
|
"POPTYPE_CACHE",
|
|
"POPTYPE_TOOL"
|
|
};
|
|
|
|
static const char *pVehicleTypeNames[] =
|
|
{
|
|
"AUD_VEHICLE_TRAIN",
|
|
"AUD_VEHICLE_PLANE",
|
|
"AUD_VEHICLE_HELI",
|
|
"AUD_VEHICLE_CAR",
|
|
"AUD_VEHICLE_BOAT",
|
|
"AUD_VEHICLE_BICYCLE",
|
|
"AUD_VEHICLE_TRAILER",
|
|
"AUD_VEHICLE_ANY",
|
|
};
|
|
|
|
if (!pItem)
|
|
{
|
|
Printf("ERROR - audVehicleAudioEntity Pool FULL!\n");
|
|
}
|
|
else
|
|
{
|
|
audVehicleAudioEntity* vehicleAudioEntity = static_cast<audVehicleAudioEntity*>(pItem);
|
|
const char *pName = vehicleAudioEntity->GetVehicleModelName();
|
|
float fTimeSinceCreation = (fwTimer::GetTimeInMilliseconds() - vehicleAudioEntity->GetVehicle()->m_TimeOfCreation) * 0.001f;
|
|
|
|
Displayf(" \"%s\", memory address %p, type %s, pop type %s, time since creation %3.2f",
|
|
pName, vehicleAudioEntity, pVehicleTypeNames[vehicleAudioEntity->GetAudioVehicleType()], pPopTypeNames[vehicleAudioEntity->GetVehicle()->m_nDEflags.nPopType], fTimeSinceCreation);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity FixSiren
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::FixSiren()
|
|
{
|
|
m_IsSirenFucked = false;
|
|
if(m_SirenLoop)
|
|
{
|
|
m_SirenLoop->StopAndForget();
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity destructor
|
|
// ----------------------------------------------------------------
|
|
audVehicleAudioEntity::~audVehicleAudioEntity()
|
|
{
|
|
for(s32 loop = 0; loop < m_VehicleGadgets.GetCount(); loop++)
|
|
{
|
|
delete m_VehicleGadgets[loop];
|
|
}
|
|
|
|
m_VehicleGadgets.clear();
|
|
ShutdownPrivate();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity Shutdown
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::Shutdown()
|
|
{
|
|
ShutdownPrivate();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity ShutdownPrivate
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ShutdownPrivate()
|
|
{
|
|
// If this is a priority vehicle, make sure we unregister it from the script that originally modified the status
|
|
if(m_ScriptPriority > AUD_VEHICLE_SCRIPT_PRIORITY_NONE)
|
|
{
|
|
g_ScriptAudioEntity.SetVehicleScriptPriority(this, AUD_VEHICLE_SCRIPT_PRIORITY_NONE, m_ScriptPriortyVehicleThreadID);
|
|
}
|
|
|
|
g_ReflectionsAudioEntity.DetachFromVehicle(this);
|
|
|
|
for(s32 loop = 0; loop < m_VehicleGadgets.GetCount(); loop++)
|
|
{
|
|
m_VehicleGadgets[loop]->StopAllSounds();
|
|
}
|
|
|
|
if(m_Vehicle)
|
|
{
|
|
DYNAMICMIXER.RemoveEntityFromMixGroup(m_Vehicle);
|
|
}
|
|
|
|
if(!m_PreserveEnvironmentGroupOnShutdown)
|
|
{
|
|
RemoveEnvironmentGroup(naAudioEntity::SHUTDOWN);
|
|
}
|
|
|
|
#if NA_RADIO_ENABLED
|
|
if(m_Vehicle != NULL)
|
|
{
|
|
g_RadioAudioEntity.StopVehicleRadio(m_Vehicle);
|
|
}
|
|
m_RadioStation = NULL;
|
|
#endif
|
|
|
|
if(GetShockwaveID() != kInvalidShockwaveId)
|
|
{
|
|
audNorthAudioEngine::GetGtaEnvironment()->FreeShockwave(GetShockwaveID());
|
|
SetShockwaveID(kInvalidShockwaveId);
|
|
}
|
|
|
|
if(camInterface::IsFadedOut())
|
|
{
|
|
StopAllSounds(false);
|
|
}
|
|
|
|
NA_POLICESCANNER_ENABLED_ONLY(g_AudioScannerManager.CancelAnySentencesFromEntity(this));
|
|
SetLOD(AUD_VEHICLE_LOD_DISABLED);
|
|
m_VehicleFireAudio.StopAllSounds();
|
|
naAudioEntity::Shutdown();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Initialise a gadgets associated with this vehicle
|
|
// ----------------------------------------------------------------
|
|
audVehicleGadget* audVehicleAudioEntity::CreateVehicleGadget(audVehicleGadget::audVehicleGadgetType type)
|
|
{
|
|
for(u32 i = 0; i < m_VehicleGadgets.GetCount(); i++)
|
|
{
|
|
if(m_VehicleGadgets[i]->GetType() == type)
|
|
{
|
|
return m_VehicleGadgets[i];
|
|
}
|
|
}
|
|
|
|
audVehicleGadget* newGadget = NULL;
|
|
|
|
switch(type)
|
|
{
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_FORKS:
|
|
newGadget = rage_new audVehicleForks;
|
|
break;
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_ROOF:
|
|
newGadget = rage_new audVehicleConvertibleRoof;
|
|
break;
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_TURRET:
|
|
newGadget = rage_new audVehicleTurret;
|
|
break;
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_DIGGER:
|
|
newGadget = rage_new audVehicleDigger;
|
|
break;
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_TOWTRUCK_ARM:
|
|
newGadget = rage_new audVehicleTowTruckArm;
|
|
break;
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_HANDLER_FRAME:
|
|
newGadget = rage_new audVehicleHandlerFrame;
|
|
break;
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_GRAPPLING_HOOK:
|
|
newGadget = rage_new audVehicleGrapplingHook;
|
|
break;
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_MAGNET:
|
|
newGadget = rage_new audVehicleGadgetMagnet;
|
|
break;
|
|
case audVehicleGadget::AUD_VEHICLE_GADGET_DYNAMIC_SPOILER:
|
|
newGadget = rage_new audVehicleGadgetDynamicSpoiler;
|
|
break;
|
|
default:
|
|
audAssertf(false, "Unsupported vehicle gadget type!");
|
|
break;
|
|
}
|
|
|
|
if(newGadget)
|
|
{
|
|
newGadget->Init(this);
|
|
m_VehicleGadgets.PushAndGrow(newGadget);
|
|
}
|
|
|
|
return newGadget;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity update rain
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateRain(audVehicleVariables& params)
|
|
{
|
|
f32 actualRainVol = -100.f;
|
|
if(g_weather.IsRaining() &&
|
|
!m_Vehicle->IsBikeOrQuad() &&
|
|
!m_Vehicle->InheritsFromBicycle() &&
|
|
!m_Vehicle->m_nFlags.bInMloRoom &&
|
|
m_EnvironmentGroup &&
|
|
!m_EnvironmentGroup->IsUnderCover()
|
|
&& m_Vehicle->GetIsVisible())
|
|
{
|
|
actualRainVol = g_WeatherAudioEntity.GetRainVolume();
|
|
}
|
|
|
|
f32 hydrantRainVol = -100.f;
|
|
if(g_IsHydrantSpraying)
|
|
{
|
|
const f32 dist2 = (g_HydrantSprayPos - VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition())).Mag2();
|
|
if(dist2 < (12.f*12.f))
|
|
{
|
|
const f32 dist = Sqrtf(dist2);
|
|
const f32 linearVol = 1.f - (dist * (1.f/12.f));
|
|
bank_float LinearVolMult = 3.f;
|
|
hydrantRainVol = audDriverUtil::ComputeDbVolumeFromLinear(linearVol * LinearVolMult);
|
|
}
|
|
}
|
|
|
|
if(CScriptHud::bUsingMissionCreator && !m_Vehicle->IsCollisionEnabled())
|
|
{
|
|
actualRainVol = -100.0f;
|
|
hydrantRainVol = -100.0f;
|
|
}
|
|
|
|
f32 rainVol = Max(hydrantRainVol, actualRainVol);
|
|
rainVol = audDriverUtil::ComputeDbVolumeFromLinear(m_RainLoopVolSmoother.CalculateValue(Min(m_VehRainInWaterVol, audDriverUtil::ComputeLinearVolumeFromDb(rainVol)),audNorthAudioEngine::GetTimeStepInMs()));
|
|
f32 distanceFromListenerSq = 0.0f;
|
|
|
|
if(rainVol > -100.f)
|
|
{
|
|
Vector3 vehPos = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
Vector3 listenerPos = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition());
|
|
Vector3 dirToVeh = vehPos - listenerPos;
|
|
distanceFromListenerSq = dirToVeh.Mag2();
|
|
u32 vehicleQuadrant = GetVehicleQuadrant();
|
|
|
|
if(m_RainLoop && m_WasInInteriorViewLastFrame != params.isInFirstPersonCam)
|
|
{
|
|
m_RainLoop->StopAndForget();
|
|
}
|
|
|
|
if(m_IsPlayerVehicle || distanceFromListenerSq < (g_SuperDummyRadiusSq * sm_RainRadiusScalar[vehicleQuadrant]) * 0.5f)
|
|
{
|
|
if(!m_IsPlayerVehicle)
|
|
{
|
|
sm_NumVehiclesInRainRadius[vehicleQuadrant]++;
|
|
}
|
|
|
|
if(!m_RainLoop)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.StartOffset = audEngineUtil::GetRandomNumberInRange(0,99);
|
|
initParams.IsStartOffsetPercentage = true;
|
|
u32 vehicleRainSound = GetVehicleRainSound(params.isInFirstPersonCam);
|
|
|
|
if(vehicleRainSound == g_NullSoundHash)
|
|
{
|
|
audMetadataRef rainSoundRef = params.isInFirstPersonCam? sm_ExtrasSoundSet.Find(ATSTRINGHASH("Vehicle_RainSoundInterior", 0x2C1D8B68)) : sm_ExtrasSoundSet.Find(ATSTRINGHASH("Vehicle_RainSound", 0x69294653));
|
|
|
|
// No interior specific sound? Fallback to exterior
|
|
if(params.isInFirstPersonCam && rainSoundRef == g_NullSoundRef)
|
|
{
|
|
rainSoundRef = sm_ExtrasSoundSet.Find(ATSTRINGHASH("Vehicle_RainSound", 0x69294653));
|
|
}
|
|
|
|
CreateAndPlaySound_Persistent(rainSoundRef, &m_RainLoop, &initParams);
|
|
}
|
|
else
|
|
{
|
|
CreateAndPlaySound_Persistent(vehicleRainSound, &m_RainLoop, &initParams);
|
|
}
|
|
|
|
}
|
|
}
|
|
else if(m_RainLoop && m_RainLoop->GetCurrentPlayTime(g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0)) > 500)
|
|
{
|
|
m_RainLoop->StopAndForget();
|
|
}
|
|
|
|
if(m_RainLoop)
|
|
{
|
|
m_RainLoop->SetRequestedVolume(rainVol);
|
|
}
|
|
}
|
|
else if(m_RainLoop)
|
|
{
|
|
m_RainLoop->StopAndForget();
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_ShowCarsPlayingRainLoops)
|
|
{
|
|
if(m_RainLoop)
|
|
{
|
|
grcDebugDraw::Sphere(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), 2.f, Color32(0,0,255,128));
|
|
}
|
|
|
|
if(rainVol > -100.0f && distanceFromListenerSq < g_SuperDummyRadiusSq)
|
|
{
|
|
char buf[32];
|
|
formatf(buf, "Q%d", (u32)GetVehicleQuadrant());
|
|
grcDebugDraw::Text(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), Color32(255,255,255), buf);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity init
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::StopAllRoofLoops()
|
|
{
|
|
for(s32 loop = 0; loop < m_VehicleGadgets.GetCount(); loop++)
|
|
{
|
|
if(m_VehicleGadgets[loop]->GetType() == audVehicleGadget::AUD_VEHICLE_GADGET_ROOF)
|
|
{
|
|
m_VehicleGadgets[loop]->StopAllSounds();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity init
|
|
// ----------------------------------------------------------------
|
|
u32 audVehicleAudioEntity::CalculateNumVehiclesUsingSubmixes(audVehicleType type, bool engineSubmix, bool granularOnly)
|
|
{
|
|
u32 count = 0;
|
|
|
|
if(engineSubmix)
|
|
{
|
|
for(u32 loop = 0; loop < EFFECT_ROUTE_VEHICLE_ENGINE_MAX - EFFECT_ROUTE_VEHICLE_ENGINE_MIN + 1; loop++)
|
|
{
|
|
if(sm_VehicleEngineSubmixes[loop].vehicleType == type || (sm_VehicleEngineSubmixes[loop].vehicleType != AUD_VEHICLE_NONE && type == AUD_VEHICLE_ANY))
|
|
{
|
|
if(!granularOnly || sm_VehicleEngineSubmixes[loop].isGranular)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(u32 loop = 0; loop < EFFECT_ROUTE_VEHICLE_EXHAUST_MAX - EFFECT_ROUTE_VEHICLE_EXHAUST_MIN + 1; loop++)
|
|
{
|
|
if(sm_VehicleExhaustSubmixes[loop].vehicleType == type || (sm_VehicleExhaustSubmixes[loop].vehicleType != AUD_VEHICLE_NONE && type == AUD_VEHICLE_ANY))
|
|
{
|
|
if(!granularOnly || sm_VehicleExhaustSubmixes[loop].isGranular)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity init
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::Init(CVehicle *vehicle)
|
|
{
|
|
Reset();
|
|
naAudioEntity::Init();
|
|
audEntity::SetName("VehicleAudioEntity");
|
|
m_Vehicle = vehicle;
|
|
m_WasEngineOnLastFrame = m_Vehicle->m_nVehicleFlags.bEngineOn;
|
|
m_LastVehicleDriver = m_Vehicle->GetDriver();
|
|
m_VehicleFireAudio.Init(this);
|
|
|
|
#if NA_RADIO_ENABLED
|
|
m_RadioEmitter.SetEmitter(vehicle);
|
|
#endif
|
|
m_FreewayBumpPitch = static_cast<s16>(audEngineUtil::GetRandomNumberInRange(-400,400));
|
|
m_EnginePitchOffset = static_cast<s16>(audEngineUtil::GetRandomNumberInRange(-250,100));
|
|
|
|
// 60% chance of normal horn
|
|
if(ENTITY_SEED_PROB(m_Vehicle->GetRandomSeed(), 0.6f))
|
|
{
|
|
m_AlarmType = AUD_CAR_ALARM_TYPE_HORN;
|
|
}
|
|
else
|
|
{
|
|
m_AlarmType = (audCarAlarmType)(1 + (m_Vehicle->GetRandomSeed() % AUD_NUM_CAR_ALARM_TYPES-2));
|
|
}
|
|
|
|
m_CRSettings = NULL;
|
|
for (u32 i = 0; i < CarRecordingAudioSettings::MAX_PERSISTENTMIXERSCENES; i ++)
|
|
{
|
|
m_CarRecordingPersistentScenes[i] = NULL;
|
|
}
|
|
m_TimeCreated = fwTimer::GetTimeInMilliseconds();
|
|
m_LastTimeAlarmPlayed = 0;
|
|
m_RandomAlarmInterval = 0;
|
|
m_LastClatterUpVel = 0.f;
|
|
m_LastClatterAcceleration = 0.f;
|
|
m_HasToTriggerAlarm = false;
|
|
m_WasInInteriorViewLastFrame = false;
|
|
m_OverrideHorn = false;
|
|
m_OverridenHornHash = g_NullSoundHash;
|
|
m_JustCameOutOfWater= false;
|
|
|
|
#if GTA_REPLAY
|
|
m_ReplayIsInWater = false;
|
|
m_ReplayVehiclePhysicsInWater = false;
|
|
#endif
|
|
|
|
m_HornSoundIndex = -1;
|
|
m_FakeEngineHealth = -1;
|
|
m_FakeBodyHealth = 0;
|
|
for(u32 i = 0 ; i < AUD_MAX_WHEEL_WATER_SOUNDS; i ++)
|
|
{
|
|
m_WaveImpactSounds[i] = NULL;
|
|
}
|
|
m_WasOnFreeWayLastFrame = false;
|
|
|
|
m_VehRainInWaterVol = 1.f;
|
|
m_VehicleCaterpillarTrackSpeed = 0.f;
|
|
m_LastTimeTerrainProbeHit = 0;
|
|
m_LastTimeTerrainProbeNotHit = 0;
|
|
m_LastTimeGroundProbeNotHit = 0;
|
|
m_TimeOfLastAircraftOverspeedWarning = 0;
|
|
m_LastTimeAircraftDamageReported = 0;
|
|
m_TimeOfLastAircraftLowFuelWarning = 0;
|
|
m_TimeOfLastAircraftLowDamageWarning = 0;
|
|
m_TimeOfLastAircraftHighDamageWarning = 0;
|
|
m_TimeOfLastAircraftEngineDamageWarning = 0;
|
|
m_TimeEnteredFreeway = 0;
|
|
m_TimeExitedFreeway = 0;
|
|
m_LastStuntRaceSpeedBoostTime = 0;
|
|
m_LastStuntRaceSpeedBoostIntensityIncreaseTime = 0;
|
|
m_LastRechargeIntensityIncreaseTime = 0;
|
|
m_SpeedBoostIntensity = 0;
|
|
m_RechargeIntensity = 0;
|
|
|
|
m_HasPlayedEngineOnFire1 = false;
|
|
m_HasPlayedEngineOnFire2 = false;
|
|
m_HasPlayedEngineOnFire3 = false;
|
|
m_HasPlayedEngineOnFire4 = false;
|
|
m_TriggeredDispatchEnteredFreeway = true;
|
|
m_TriggeredDispatchExitedFreeway = true;
|
|
REPLAY_ONLY(m_ReplayRevLimiter = false;)
|
|
|
|
m_VehicleUnderCover = false;
|
|
|
|
if(!GetEnvironmentGroup())
|
|
{
|
|
InitOcclusion();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity InitClass
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::InitClass()
|
|
{
|
|
CompileTimeAssert(kMaxAudioWeaponBlades == CVehicle::MAX_NUM_WEAPON_BLADES);
|
|
|
|
char slotName[32];
|
|
for(u32 i = 0; i < g_audMaxEngineSlots; i++)
|
|
{
|
|
formatf(slotName, sizeof(slotName), "STREAM_ENGINE_%d", i+1);
|
|
|
|
if(!sm_StandardWaveSlotManager.AddWaveSlot(slotName, "ENGINE"))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(u32 i = 0; i < g_audMaxEngineSlots; i++)
|
|
{
|
|
formatf(slotName, sizeof(slotName), "STREAM_ENGINE_GRANULAR_HI_%d", i+1);
|
|
|
|
if(!sm_HighQualityWaveSlotManager.AddWaveSlot(slotName, "ENGINE"))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(u32 i = 0; i < g_audMaxEngineSlots; i++)
|
|
{
|
|
formatf(slotName, sizeof(slotName), "STREAM_ENGINE_LOW_LATENCY_%d", i+1);
|
|
|
|
if(!sm_LowLatencyWaveSlotManager.AddWaveSlot(slotName, "ENGINE"))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(u32 i = 0; i < NumQuadrants; i++)
|
|
{
|
|
sm_NumVehiclesInDummyRange[i] = 0;
|
|
sm_DummyRangeScale[i] = 2.0f;
|
|
sm_NumVehiclesInRainRadius[i] = 0;
|
|
sm_RainRadiusScalar[i] = 1.0f;
|
|
sm_NumVehiclesInWaterSlapRadius[i] = 0;
|
|
sm_WaterSlapRadiusScalar[i] = 1.0f;
|
|
}
|
|
|
|
for(u32 loop = 0; loop < EFFECT_ROUTE_VEHICLE_ENGINE_MAX - EFFECT_ROUTE_VEHICLE_ENGINE_MIN + 1; loop++)
|
|
{
|
|
sm_VehicleEngineSubmixes[loop].submixSound = NULL;
|
|
sm_VehicleEngineSubmixes[loop].vehicleType = AUD_VEHICLE_NONE;
|
|
sm_VehicleEngineSubmixes[loop].isGranular = false;
|
|
}
|
|
|
|
for(u32 loop = 0; loop < EFFECT_ROUTE_VEHICLE_EXHAUST_MAX - EFFECT_ROUTE_VEHICLE_EXHAUST_MIN + 1; loop++)
|
|
{
|
|
sm_VehicleExhaustSubmixes[loop].submixSound = NULL;
|
|
sm_VehicleExhaustSubmixes[loop].vehicleType = AUD_VEHICLE_NONE;
|
|
sm_VehicleExhaustSubmixes[loop].isGranular = false;
|
|
}
|
|
|
|
#if __BANK
|
|
if(PARAM_disablegranular.Get())
|
|
{
|
|
g_GranularEnabled = false;
|
|
}
|
|
sm_DebugCarRecording.nameHash = atHashString();
|
|
sm_DebugCarRecording.eventList.Reset();
|
|
sm_DebugCarRecording.settings = NULL;
|
|
sm_DebugCarRecording.modelId = fwModelId::MI_INVALID;
|
|
|
|
audDisplayf("Size of naAudioEntity: %" SIZETFMT "d", sizeof(naAudioEntity));
|
|
audDisplayf("Size of audVehicleAudioEntity: %" SIZETFMT "d", sizeof(audVehicleAudioEntity));
|
|
audDisplayf("Size of audCarAudioEntity: %" SIZETFMT "d", sizeof(audCarAudioEntity));
|
|
audDisplayf("Size of audHeliAudioEntity: %" SIZETFMT "d", sizeof(audHeliAudioEntity));
|
|
audDisplayf("Size of audTrainAudioEntity: %" SIZETFMT "d", sizeof(audTrainAudioEntity));
|
|
audDisplayf("Size of audBoatAudioEntity: %" SIZETFMT "d", sizeof(audBoatAudioEntity));
|
|
audDisplayf("Size of audPlaneAudioEntity: %" SIZETFMT "d", sizeof(audPlaneAudioEntity));
|
|
audDisplayf("Size of audTrailerAudioEntity: %" SIZETFMT "d", sizeof(audTrailerAudioEntity));
|
|
audDisplayf("Size of audVehicleEngine: %" SIZETFMT "d", sizeof(audVehicleEngine));
|
|
#endif
|
|
|
|
g_SkidCategory = g_AudioEngine.GetCategoryManager().GetCategoryPtr(ATSTRINGHASH("VEHICLES_WHEELS_SKIDS", 0x3C43E428));
|
|
g_RoadNoiseCategory = g_AudioEngine.GetCategoryManager().GetCategoryPtr(ATSTRINGHASH("VEHICLES_WHEELS_ROAD_NOISE", 0x2EED1D0A));
|
|
|
|
StaticConditionalWarning(g_PlayerRoadNoiseFastVolCurve.Init(ATSTRINGHASH("ROAD_NOISE_FAST_VOL_PLAYER", 0xB3F915D9)), "Invalid road noise player curve");
|
|
StaticConditionalWarning(g_FreewayBumpSpeedToVol.Init(ATSTRINGHASH("FREEWAY_BUMPS_SPEED_TO_VOL", 0x75D3133D)), "Invalid freeway bump speed to vol curve");
|
|
StaticConditionalWarning(g_FreewayBumpSpeedToPitch.Init(ATSTRINGHASH("FREEWAY_BUMPS_SPEED_TO_PITCH", 0x2E6AE968)), "Invalid freeway bump speed to pitch curve");
|
|
StaticConditionalWarning(g_IceVanTempoScalingCurve.Init(ATSTRINGHASH("ICEVAN_TEMPO_SCALING", 0x5167AC58)), "Invalid ICEVAN_TEMPO_SCALING");
|
|
StaticConditionalWarning(sm_ExtrasSoundSet.Init(ATSTRINGHASH("VehicleExtras", 0xF68247A0)), "Failed to find VehicleExtras sound set");
|
|
StaticConditionalWarning(sm_LightsSoundSet.Init(ATSTRINGHASH("VehicleLights", 0x9A9F9DD0)), "Failed to find VehicleLights sound set");
|
|
StaticConditionalWarning(sm_MissileLockSoundSet .Init(ATSTRINGHASH("CNC_PLANE_DROP_SOUNDSET", 0xCE1684EE)), "Failed to find CNC_PLANE_DROP_SOUNDSET sound set");
|
|
StaticConditionalWarning(sm_InteriorOpenToCutoffCurve.Init(ATSTRINGHASH("VEHICLE_INTERIOR_OPEN_TO_CUTOFF", 0xC162E536)), "Failed to initialise VEHICLE_INTERIOR_OPEN_TO_CUTOFF");
|
|
StaticConditionalWarning(sm_InteriorOpenToVolumeCurve.Init(ATSTRINGHASH("VEHICLE_INTERIOR_OPEN_TO_VOL", 0x281883D8)), "Failed to initialise VEHICLE_INTERIOR_OPEN_TO_VOL");
|
|
StaticConditionalWarning(sm_RoadNoiseDetailVolCurve.Init(ATSTRINGHASH("ROAD_NOISE_DETAIL_VOL", 0x9679D859)), "Invalid RoadNoiseDetailVolCurve");
|
|
StaticConditionalWarning(sm_RoadNoiseFastVolCurve.Init(ATSTRINGHASH("ROAD_NOISE_FAST_VOL", 0xCDC720A4)), "Invalid RoadNoiseFastVol");
|
|
StaticConditionalWarning(sm_RoadNoiseSteeringAngleToAttenuation.Init(ATSTRINGHASH("ROAD_NOISE_STEERING_ANGLE_TO_ATTENUATION", 0x3A94E0F5)), "Invalid ROAD_NOISE_STEERING_ANGLE_TO_ATTENUATION curve");
|
|
StaticConditionalWarning(sm_RoadNoiseSteeringAngleCRToVolume.Init(ATSTRINGHASH("ROAD_NOISE_STEERING_ANGLE_CR_TO_VOL", 0x81A22045)), "Invalid ROAD_NOISE_STEERING_ANGLE_CR_TO_VOL curve");
|
|
StaticConditionalWarning(sm_RoadNoisePitchCurve.Init(ATSTRINGHASH("ROAD_NOISE_PITCH", 0xF450D2B)), "Invalid RoadNoisePitch");
|
|
StaticConditionalWarning(sm_RoadNoiseSingleVolCurve.Init(ATSTRINGHASH("ROAD_NOISE_SINGLE_VOL", 0xFB08DFAB)), "Invalid RoadNoise single vol");
|
|
StaticConditionalWarning(sm_RoadNoiseBicycleVolCurve.Init(ATSTRINGHASH("ROAD_NOISE_BICYCLE_VOL", 0x3C5A0803)), "Invalid RoadNoise bicycle vol");
|
|
StaticConditionalWarning(sm_SkidSpeedRatioToPitch.Init(ATSTRINGHASH("SKID_CURVES_SPEED_RATIO_TO_PITCH", 0x73EF5C32)), "Failed to initialise SKID_CURVES_SPEED_RATIO_TO_PITCH");
|
|
StaticConditionalWarning(sm_SkidDriftAngleToVolume.Init(ATSTRINGHASH("SKID_CURVES_DRIFT_ANGLE_TO_VOL", 0x44BEB5ED)), "Failed to initialise SKID_CURVES_DRIFT_ANGLE_TO_VOL");
|
|
StaticConditionalWarning(sm_RecentSpeedToSettleVolume.Init(ATSTRINGHASH("RECENT_SPEED_TO_SETTLE_VOL", 0x7439F09E)), "Failed to initialise RECENT_SPEED_TO_SETTLE_VOL");
|
|
StaticConditionalWarning(sm_RecentSpeedToSettleReleaseTime.Init(ATSTRINGHASH("RECENT_SPEED_TO_SETTLE_RELEASE_TIME", 0xE116BA10)), "Failed to initialise RECENT_SPEED_TO_SETTLE_RELEASE_TIME");
|
|
StaticConditionalWarning(sm_SkidFwdSlipToMainVol.Init(ATSTRINGHASH("SKID_CURVES_FWD_SLIP_TO_MAIN_VOL", 0x82AEB645)), "invalid fwd slip to main");
|
|
StaticConditionalWarning(sm_NPCRoadNoiseRelativeSpeedToVol.Init(ATSTRINGHASH("NPC_ROAD_NOISE_RELATIVE_SPEED_TO_VOL", 0x97D711AE)), "invalid sm_NPCRoadNoiseRelativeSpeedToVol");
|
|
StaticConditionalWarning(g_RoadNoiseWetRoadVolCurve.Init(ATSTRINGHASH("ROAD_NOISE_WET_VOL", 0xCF73CEB7)), "invalid road noise wet vol curve");
|
|
StaticConditionalWarning(g_VehicleMassToRumbleVol.Init(ATSTRINGHASH("VEHICLE_MASS_TO_HEAVY_VOL", 0xA2E7D5A)), "invalid veh mass to heavy vol");
|
|
StaticConditionalWarning(sm_RoofToOpennessCurve.Init(ATSTRINGHASH("VEHICLE_ROOF_OPENNESS", 0x57254724)), "invalid vehicle roof openness curve");
|
|
StaticConditionalWarning(sm_SlipToUndersteerVol.Init(ATSTRINGHASH("SKID_CURVES_FWD_SLIP_TO_UNDERSTEER_VOL", 0x3EFA4444)), "invalid understeer curve");
|
|
|
|
StaticConditionalWarning(sm_TarmacSkidSounds.Init(ATSTRINGHASH("TARMAC_TRACTION_SOUNDS", 0xBA04BFF)), "Couldn't find tarmac skid soundset");
|
|
StaticConditionalWarning(sm_ClatterSoundSet.Init(ATSTRINGHASH("ClatterTypes", 0x3E19B4D8)), "Failed to find ClatterTypes sound set");
|
|
StaticConditionalWarning(sm_ChassisStressSoundSet.Init(ATSTRINGHASH("ChassStressTypes", 0x8D1C6834)), "Failed to find ChassStressTypes sound set");
|
|
StaticConditionalWarning(sm_VehiclesInWaterSoundset.Init(ATSTRINGHASH("VEHICLE_WATER_SPLASH_SOUNDSET", 0xCE24C102)), "Failed to find VEHICLE_WATER_SPLASH_SOUNDSET sound set");
|
|
|
|
sm_HighSpeedSceneApplySmoother.Init(1.0f/sm_InvHighSpeedSmootherIncreaseRate, 1.0f/sm_InvHighSpeedSmootherDecreaseRate, 0.0f, 1.0f);
|
|
sm_OpennessSmoother.Init(0.01f, 0.0002f, 0.0f, 1.0f);
|
|
|
|
// precompute linear filter values to interpolate
|
|
for(s32 i = 0 ; i < NUM_AMBIENTRADIOLEAKAGE; i++)
|
|
{
|
|
g_RadioLPFLinear[i][0] = audDriverUtil::ComputeLinearFromHzFrequency(g_RadioLPFCutoffs[i][0]);
|
|
g_RadioLPFLinear[i][1] = audDriverUtil::ComputeLinearFromHzFrequency(g_RadioLPFCutoffs[i][1]);
|
|
}
|
|
|
|
#if __BANK
|
|
g_OverridenLeakageVolMin = g_RadioOpennessVols[LEAKAGE_MODDED][0];
|
|
g_OverridenLeakageVolMax = g_RadioOpennessVols[LEAKAGE_MODDED][1];
|
|
g_OverridenLeakageLpfLinearMin = g_RadioLPFLinear[LEAKAGE_MODDED][0];
|
|
g_OverridenLeakageLpfLinearMax = g_RadioLPFLinear[LEAKAGE_MODDED][1];
|
|
g_OverridenLeakageRolloffMin = g_RadioRolloffs[LEAKAGE_MODDED][0];
|
|
g_OverridenLeakageRolloffMax = g_RadioRolloffs[LEAKAGE_MODDED][1];
|
|
g_OverridenLeakageHPFCutoff = g_RadioHPFCutoffs[LEAKAGE_MODDED];
|
|
g_OverridenLeakageMaxRadius = Sqrtf(g_MaxRadiusForAmbientRadio2[LEAKAGE_MODDED]);
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity ShutdownClass
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ShutdownClass()
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity CalculateVehicleQuadrant
|
|
// ----------------------------------------------------------------
|
|
audQuadrants audVehicleAudioEntity::GetVehicleQuadrant()
|
|
{
|
|
// Quadrant 0 Fdot + Rdot -
|
|
if(m_QuadrantDirty)
|
|
{
|
|
const Vec3V vehPos = m_Vehicle->GetTransform().GetPosition();
|
|
const Vec3V listenerPos = g_AudioEngine.GetEnvironment().GetVolumeListenerPosition();
|
|
const Vec3V dirToVehicle = Normalize(vehPos - listenerPos);
|
|
|
|
const ScalarV fDot = Dot(g_AudioEngine.GetEnvironment().GetVolumeListenerMatrix().b(), dirToVehicle);
|
|
const ScalarV rDot = Dot(g_AudioEngine.GetEnvironment().GetVolumeListenerMatrix().a(), dirToVehicle);
|
|
|
|
const BoolV fDotGreaterThanEqualZero = IsGreaterThanOrEqual(fDot, ScalarV(V_ZERO));
|
|
const BoolV rDotGreaterThanEqualZero = IsGreaterThanOrEqual(rDot, ScalarV(V_ZERO));
|
|
|
|
const ScalarV quadrantV = SelectFT(fDotGreaterThanEqualZero, SelectFT(rDotGreaterThanEqualZero, ScalarV(V_ONE), ScalarV(V_TWO)), SelectFT(rDotGreaterThanEqualZero, ScalarV(V_ZERO), ScalarV(V_THREE)));
|
|
const audQuadrants quadrant = (audQuadrants)(FloatToIntRaw<0>(quadrantV).Geti());
|
|
m_VehicleQuadrant = quadrant;
|
|
return quadrant;
|
|
}
|
|
else
|
|
{
|
|
return m_VehicleQuadrant;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity GetPosition
|
|
// ----------------------------------------------------------------
|
|
Vec3V_Out audVehicleAudioEntity::GetPosition() const
|
|
{
|
|
Assert(m_Vehicle);
|
|
return m_Vehicle->GetVehiclePosition();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity GetOrientation
|
|
// ----------------------------------------------------------------
|
|
audCompressedQuat audVehicleAudioEntity::GetOrientation() const
|
|
{
|
|
Assert(m_Vehicle);
|
|
Assert(m_Vehicle->GetPlaceableTracker());
|
|
return m_Vehicle->GetPlaceableTracker()->GetOrientation();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity AllocateVehicleVariableBlock
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::AllocateVehicleVariableBlock()
|
|
{
|
|
if(!HasEntityVariableBlock())
|
|
{
|
|
AllocateEntityVariableBlock(ATSTRINGHASH("VEHICLE_VARIABLES", 0xBE95634E));
|
|
audAssert(HasEntityVariableBlock());
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Set LOD
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetLOD(audVehicleLOD lod)
|
|
{
|
|
if(lod != m_VehicleLOD)
|
|
{
|
|
if(m_VehicleLOD == AUD_VEHICLE_LOD_DUMMY)
|
|
{
|
|
sm_NumDummyVehiclesCounter--;
|
|
}
|
|
|
|
m_VehicleLOD = lod;
|
|
|
|
if(lod <= AUD_VEHICLE_LOD_DUMMY)
|
|
{
|
|
AllocateVehicleVariableBlock();
|
|
m_LastClatterWorldPos = m_Vehicle->TransformIntoWorldSpace(m_ClatterOffsetPos);
|
|
m_LastTimeInAir = 0;
|
|
m_LastTimeTwoWheeling = 0;
|
|
}
|
|
|
|
if(m_VehicleLOD == AUD_VEHICLE_LOD_DUMMY)
|
|
{
|
|
sm_NumDummyVehiclesCounter++;
|
|
sm_NumDummyVehiclesLastFrame++;
|
|
}
|
|
|
|
if(m_VehicleLOD >= AUD_VEHICLE_LOD_DUMMY)
|
|
{
|
|
StopAndForgetSounds(m_WheelDetailLoop, m_DirtyWheelLoop, m_GlassyWheelLoop, m_MainSkidLoop, m_SideSkidLoop, m_UndersteerSkidLoop, m_WheelSpinLoop, m_WetWheelSpinLoop, m_WetSkidLoop, m_DriveWheelSlipLoop, m_RoadNoiseRidged);
|
|
StopAndForgetSounds(m_RoadNoiseRidgedPulse, m_ExhastProximityPulseSound, m_VehicleCabinTone, m_CaterpillarTrackLoop);
|
|
|
|
for(u32 loop = 0; loop < NUM_VEH_CWHEELS_MAX; loop++)
|
|
{
|
|
StopAndForgetSounds(m_ShallowWaterSounds[loop]);
|
|
}
|
|
}
|
|
|
|
if(m_VehicleLOD >= AUD_VEHICLE_LOD_SUPER_DUMMY)
|
|
{
|
|
// Disabled cars keep their sirens and alarms, but nothing else. Super dummy can play rain and warning sounds too.
|
|
StopAndForgetSounds(m_ReverseWarning, m_SurfaceSettleSound, m_VehicleClatter, m_ChassisStressLoop, m_WaterTurbulenceSound, m_ParachuteLoop, m_JumpRecharge);
|
|
StopAndForgetSounds(m_BeingTargetedSound, m_MissileApproachingSound, m_AcquiringTargetSound, m_AllClearSound, m_MissileApproachingSoundImminent, m_DamageWarningSound);
|
|
StopAndForgetSounds(m_DrowningRadioSound, m_RoadNoiseNPC, m_RoadNoiseFast, m_CinematicTireSweetener, m_RoadNoiseHeavy, m_RoadNoiseWet);
|
|
|
|
for (u32 i = 0; i < CVehicle::MAX_NUM_WEAPON_BLADES; i++)
|
|
{
|
|
StopAndForgetSounds(m_BladeImpactSound[i]);
|
|
}
|
|
|
|
m_SubmarineTransformSoundHash = 0u;
|
|
|
|
if(m_VehicleLOD >= AUD_VEHICLE_LOD_DISABLED)
|
|
{
|
|
for(s32 loop = 0; loop < m_VehicleGadgets.GetCount(); loop++)
|
|
{
|
|
m_VehicleGadgets[loop]->StopAllSounds();
|
|
}
|
|
|
|
for(u32 i = 0; i < AUD_MAX_WHEEL_WATER_SOUNDS; i++)
|
|
{
|
|
if(m_WaveImpactSounds[i])
|
|
{
|
|
m_WaveImpactSounds[i]->StopAndForget();
|
|
}
|
|
}
|
|
|
|
m_ShouldPlayBonnetDetachSound = false;
|
|
m_HasIndicatorRequest = false;
|
|
m_VehicleFireAudio.StopAllSounds();
|
|
StopAndForgetSounds(m_RainLoop, m_DoorOpenWarning, m_WaterLappingSound, m_ClothSound, m_DetachedBonnetSound, m_IdleHullSlapSound, m_LandingGearSound, m_WeaponChargeSound);
|
|
StopSubmersibleSounds();
|
|
}
|
|
}
|
|
|
|
switch(m_VehicleLOD)
|
|
{
|
|
case AUD_VEHICLE_LOD_REAL:
|
|
ConvertFromDummy();
|
|
break;
|
|
case AUD_VEHICLE_LOD_DUMMY:
|
|
ConvertToDummy();
|
|
break;
|
|
case AUD_VEHICLE_LOD_SUPER_DUMMY:
|
|
ConvertToSuperDummy();
|
|
break;
|
|
case AUD_VEHICLE_LOD_DISABLED:
|
|
ConvertToDisabled();
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
|
|
if(m_VehicleLOD != AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
FreeWaveSlot();
|
|
}
|
|
|
|
m_TimeAtCurrentLOD = 0.0f;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Stop all submersible soudns
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::StopSubmersibleSounds()
|
|
{
|
|
StopAndForgetSounds(m_SubTurningSweetener, m_SubExtrasSound, m_SubmersibleCreakSound, m_SubPropSound);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update cloth sounds
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateClothSounds(audVehicleVariables& vehicleVariables)
|
|
{
|
|
// Wind cloth sounds for vehicles
|
|
if(!m_ClothSound && vehicleVariables.distFromListenerSq < 900)
|
|
{
|
|
fragInstGta* pFragInst = (fragInstGta*)m_Vehicle->GetCurrentPhysicsInst();
|
|
Assertf(pFragInst, "Failed to allocate new fragInstGta.");
|
|
if(pFragInst)
|
|
{
|
|
fragCacheEntry *cacheEntry = pFragInst->GetCacheEntry();
|
|
if( cacheEntry )
|
|
{
|
|
fragHierarchyInst* hierInst = cacheEntry->GetHierInst();
|
|
Assert( hierInst );
|
|
if( hierInst->envCloth )
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
CreateAndPlaySound_Persistent(GetWindClothSound(),&m_ClothSound,&initParams);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(vehicleVariables.distFromListenerSq >= 900)
|
|
{
|
|
if(m_ClothSound)
|
|
{
|
|
m_ClothSound->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWaveImpactSounds(audVehicleVariables& vehicleVariables)
|
|
{
|
|
if (vehicleVariables.distFromListenerSq < g_SqdDistThresholdForWaveImpact)
|
|
{
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
CWheel* wheel = m_Vehicle->GetWheel(i);
|
|
if(wheel)
|
|
{
|
|
u32 hierarchyID = wheel->GetHierarchyId();
|
|
if(hierarchyID >= VEH_WHEEL_LF && hierarchyID <= VEH_WHEEL_RR)
|
|
{
|
|
u32 soundIdx = GetAudioWheelIndex(hierarchyID);
|
|
|
|
// We have a valid wheel to play the wave impact sounds.
|
|
if(wheel->GetDynamicFlags().IsFlagSet(WF_INSHALLOWWATER) || wheel->GetDynamicFlags().IsFlagSet(WF_INDEEPWATER))
|
|
{
|
|
Vector3 pos;
|
|
GetCachedWheelPosition(i, pos, vehicleVariables);
|
|
// get the river flow at this position
|
|
Vector2 riverFlow(0.0f, 0.0f);
|
|
River::GetRiverFlowFromPosition(VECTOR3_TO_VEC3V(pos), riverFlow);
|
|
Vec3V vRiverVel = Vec3V(100*riverFlow.x, 100*riverFlow.y, 0.0f);
|
|
vRiverVel.SetZ(ScalarV(V_ZERO));
|
|
float speed = Mag(vRiverVel).Getf();
|
|
|
|
if( speed > 0.f)
|
|
{
|
|
if(!m_WaveImpactSounds[soundIdx])
|
|
{
|
|
// Trigger a wave wet impact.
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.Position = pos;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
CreateAndPlaySound_Persistent(GetVehicleCollisionSettings()->WaveImpactLoop,&m_WaveImpactSounds[soundIdx],&initParams);
|
|
}
|
|
}
|
|
else if(m_WaveImpactSounds[soundIdx])
|
|
{
|
|
m_WaveImpactSounds[soundIdx]->StopAndForget();
|
|
}
|
|
}
|
|
else if(m_WaveImpactSounds[soundIdx])
|
|
{
|
|
m_WaveImpactSounds[soundIdx]->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( u32 i = 0; i < AUD_MAX_WHEEL_WATER_SOUNDS; i ++)
|
|
{
|
|
if(m_WaveImpactSounds[i])
|
|
{
|
|
m_WaveImpactSounds[i]->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------------
|
|
const u32 audVehicleAudioEntity::GetAudioWheelIndex(const u32 wheelId) const
|
|
{
|
|
switch(wheelId)
|
|
{
|
|
case VEH_WHEEL_LF:
|
|
return AUD_VEHICLE_SOUND_WHEEL0 -1;
|
|
case VEH_WHEEL_RF:
|
|
return AUD_VEHICLE_SOUND_WHEEL1 -1;
|
|
case VEH_WHEEL_LR:
|
|
return AUD_VEHICLE_SOUND_WHEEL2 -1;
|
|
case VEH_WHEEL_RR:
|
|
return AUD_VEHICLE_SOUND_WHEEL3 -1;
|
|
default:
|
|
naAssertf(false,"Wrong wheel id when update the wave impacts");
|
|
break;
|
|
}
|
|
return AUD_VEHICLE_SOUND_WHEEL0;
|
|
}
|
|
// ----------------------------------------------------------------
|
|
// SetScriptPriorityVehicle
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::SetScriptPriority(audVehicleScriptPriority priority, scrThreadId scriptThreadID)
|
|
{
|
|
// Only the controlling thread can modify the priority vehicle status
|
|
if(m_ScriptPriority > AUD_VEHICLE_SCRIPT_PRIORITY_NONE)
|
|
{
|
|
if(audVerifyf(m_ScriptPriortyVehicleThreadID == scriptThreadID, "Attempting to set a script as a priority vehicle when another script (%d) already has control!", m_ScriptPriortyVehicleThreadID))
|
|
{
|
|
m_ScriptPriority = priority;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ScriptPriority = priority;
|
|
}
|
|
|
|
m_ScriptPriortyVehicleThreadID = scriptThreadID;
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Calculate engine and exhaust positions
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::CalculateEngineExhaustPositions()
|
|
{
|
|
#if __BANK
|
|
// in this case the engine and exhuast position will be set in planeaudioentity
|
|
if(g_UseDebugPlaneTracker && GetAudioVehicleType() == AUD_VEHICLE_PLANE)
|
|
return;
|
|
if(g_UseDebugHeliTracker && GetAudioVehicleType() == AUD_VEHICLE_HELI)
|
|
return;
|
|
#endif
|
|
|
|
m_EngineOffsetPos = Vec3V(V_ZERO);
|
|
m_ExhaustOffsetPos = Vec3V(V_ZERO);
|
|
m_HornOffsetPos = Vec3V(V_ZERO);
|
|
|
|
bool isSubmarine = m_Vehicle->InheritsFromSubmarine();
|
|
s32 exhaust1BoneId = isSubmarine? m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(SUB_PROPELLER_1) : m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(VEH_EXHAUST);
|
|
s32 exhaust2BoneId = isSubmarine? m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(SUB_PROPELLER_2) : m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(VEH_EXHAUST_2);
|
|
s32 exhaust3BoneId = isSubmarine? m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(SUB_PROPELLER_3) : m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(VEH_EXHAUST_3);
|
|
s32 exhaust4BoneId = isSubmarine? m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(SUB_PROPELLER_4) : m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(VEH_EXHAUST_4);
|
|
s32 exhaust5BoneId = isSubmarine? m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(SUB_PROPELLER_LEFT) : m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(VEH_EXHAUST_5);
|
|
s32 exhaust6BoneId = isSubmarine? m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(SUB_PROPELLER_RIGHT) : m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(VEH_EXHAUST_6);
|
|
s32 afterburner1BoneId = m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(PLANE_AFTERBURNER);
|
|
s32 afterburner2BoneId = m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(PLANE_AFTERBURNER+1);
|
|
s32 afterburner3BoneId = m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(PLANE_AFTERBURNER+2);
|
|
s32 afterburner4BoneId = m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(PLANE_AFTERBURNER+3);
|
|
CompileTimeAssert(PLANE_NUM_AFTERBURNERS == 4);
|
|
s32 bonnetBoneId = m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(VEH_BUMPER_F);
|
|
Vec3V ex1pos = Vec3V(V_ZERO);
|
|
Vec3V ex2pos = Vec3V(V_ZERO);
|
|
Vec3V ex3pos = Vec3V(V_ZERO);
|
|
Vec3V ex4pos = Vec3V(V_ZERO);
|
|
Vec3V ex5pos = Vec3V(V_ZERO);
|
|
Vec3V ex6pos = Vec3V(V_ZERO);
|
|
|
|
u32 numExhausts = 0;
|
|
|
|
if(m_Vehicle->InheritsFromPlane())
|
|
{
|
|
if(afterburner1BoneId>-1)
|
|
{
|
|
ex1pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(afterburner1BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
if(afterburner2BoneId>-1)
|
|
{
|
|
ex2pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(afterburner2BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
if(afterburner3BoneId>-1)
|
|
{
|
|
ex3pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(afterburner3BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
if(afterburner4BoneId>-1)
|
|
{
|
|
ex4pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(afterburner4BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
}
|
|
|
|
if(numExhausts == 0)
|
|
{
|
|
if (exhaust1BoneId>-1)
|
|
{
|
|
ex1pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(exhaust1BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
if(exhaust2BoneId>-1)
|
|
{
|
|
ex2pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(exhaust2BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
if(exhaust3BoneId>-1)
|
|
{
|
|
ex3pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(exhaust3BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
if(exhaust4BoneId>-1)
|
|
{
|
|
ex4pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(exhaust4BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
if(exhaust5BoneId>-1)
|
|
{
|
|
ex5pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(exhaust5BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
if(exhaust6BoneId>-1)
|
|
{
|
|
ex6pos = m_Vehicle->GetSkeletonData().GetDefaultTransform(exhaust6BoneId).d();
|
|
numExhausts++;
|
|
}
|
|
}
|
|
|
|
// use an exhaust position mid way between all exhausts, in local space
|
|
if(numExhausts > 0)
|
|
{
|
|
m_ExhaustOffsetPos = (ex1pos+ex2pos+ex3pos+ex4pos)/ScalarV((f32)numExhausts);
|
|
}
|
|
|
|
s32 engineBoneId = m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(VEH_ENGINE);
|
|
s32 engineBoneLId = m_Vehicle->InheritsFromPlane()? m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(PLANE_ENGINE_L) : VEH_INVALID_ID;
|
|
s32 engineBoneRId = m_Vehicle->InheritsFromPlane()? m_Vehicle->GetVehicleModelInfo()->GetBoneIndex(PLANE_ENGINE_R) : VEH_INVALID_ID;
|
|
|
|
Vec3V engPos = Vec3V(V_ZERO);
|
|
Vec3V engLPos = Vec3V(V_ZERO);
|
|
Vec3V engRPos = Vec3V(V_ZERO);
|
|
Vec3V engExtraPos = Vec3V(V_ZERO);
|
|
|
|
u32 numEngines = 0;
|
|
|
|
if(!m_Vehicle->InheritsFromSubmarine())
|
|
{
|
|
if(m_Vehicle->InheritsFromPlane())
|
|
{
|
|
if(afterburner1BoneId>-1)
|
|
{
|
|
engPos = m_Vehicle->GetSkeletonData().GetDefaultTransform(afterburner1BoneId).d();
|
|
numEngines++;
|
|
}
|
|
if(afterburner2BoneId>-1)
|
|
{
|
|
engLPos = m_Vehicle->GetSkeletonData().GetDefaultTransform(afterburner2BoneId).d();
|
|
numEngines++;
|
|
}
|
|
if(afterburner3BoneId>-1)
|
|
{
|
|
engRPos = m_Vehicle->GetSkeletonData().GetDefaultTransform(afterburner3BoneId).d();
|
|
numEngines++;
|
|
}
|
|
if(afterburner4BoneId>-1)
|
|
{
|
|
engExtraPos = m_Vehicle->GetSkeletonData().GetDefaultTransform(afterburner4BoneId).d();
|
|
numEngines++;
|
|
}
|
|
}
|
|
|
|
if(numEngines == 0)
|
|
{
|
|
if (engineBoneId>-1)
|
|
{
|
|
engPos = m_Vehicle->GetSkeletonData().GetDefaultTransform(engineBoneId).d();
|
|
numEngines++;
|
|
}
|
|
if(engineBoneLId>-1)
|
|
{
|
|
engLPos = m_Vehicle->GetSkeletonData().GetDefaultTransform(engineBoneLId).d();
|
|
numEngines++;
|
|
}
|
|
if(engineBoneRId>-1)
|
|
{
|
|
engRPos = m_Vehicle->GetSkeletonData().GetDefaultTransform(engineBoneRId).d();
|
|
numEngines++;
|
|
}
|
|
}
|
|
|
|
// use an engine position mid way between all engine, in local space
|
|
if(numEngines > 0)
|
|
{
|
|
m_EngineOffsetPos = (engPos+engLPos+engRPos+engExtraPos)/ScalarV((f32)numEngines);
|
|
|
|
// B*3837724 Fix - Plane engines bones are sometimes centered at the left hand propeller, which causes engine sounds to be panned left.
|
|
// Should be safe to assume the engine sound should always central to the plane body unless we come up with some seriously whacky setups!
|
|
if(m_Vehicle->InheritsFromPlane())
|
|
{
|
|
m_EngineOffsetPos.SetXf(0.f);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bonnetBoneId>-1)
|
|
{
|
|
m_HornOffsetPos = m_Vehicle->GetSkeletonData().GetDefaultTransform(bonnetBoneId).d();
|
|
}
|
|
|
|
// If we've got an engine but no exhaust, just set both to the same position
|
|
// in case anything tries to use the exhaust position
|
|
if(numEngines > 0 &&
|
|
numExhausts == 0)
|
|
{
|
|
m_ExhaustOffsetPos = m_EngineOffsetPos;
|
|
}
|
|
|
|
// Likewise for the opposite scenario
|
|
if(numEngines == 0 &&
|
|
numExhausts > 0)
|
|
{
|
|
m_EngineOffsetPos = m_ExhaustOffsetPos;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity InitDSPEffects
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::InitDSPEffects()
|
|
{
|
|
if (!g_AudioEngine.ShouldUseCheapAudioEffects() && m_EngineSubmixIndex >= 0 && m_ExhaustSubmixIndex >= 0)
|
|
{
|
|
ReapplyDSPEffects();
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = GetEnvironmentGroup();
|
|
initParams.UpdateEntity = true;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_UNKNOWN;
|
|
|
|
if(!GetEngineEffectSubmixSound())
|
|
{
|
|
const s32 engineSubmixId = audDriver::GetMixer()->GetSubmixIndex(g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(m_EngineSubmixIndex));
|
|
initParams.SourceEffectSubmixId = (s16) engineSubmixId;
|
|
g_FrontendAudioEntity.CreateAndPlaySound_Persistent(GetEngineSubmixVoice(), &sm_VehicleEngineSubmixes[m_EngineSubmixIndex].submixSound, &initParams);
|
|
sm_VehicleEngineSubmixes[m_EngineSubmixIndex].vehicleType = m_VehicleType;
|
|
sm_VehicleEngineSubmixes[m_EngineSubmixIndex].isGranular = IsUsingGranularEngine();
|
|
}
|
|
|
|
if(!GetExhaustEffectSubmixSound())
|
|
{
|
|
const s32 exhaustSubmixId = audDriver::GetMixer()->GetSubmixIndex(g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(m_ExhaustSubmixIndex));
|
|
initParams.SourceEffectSubmixId = (s16) exhaustSubmixId;
|
|
g_FrontendAudioEntity.CreateAndPlaySound_Persistent(GetExhaustSubmixVoice(), &sm_VehicleExhaustSubmixes[m_ExhaustSubmixIndex].submixSound, &initParams);
|
|
sm_VehicleExhaustSubmixes[m_ExhaustSubmixIndex].vehicleType = m_VehicleType;
|
|
sm_VehicleExhaustSubmixes[m_ExhaustSubmixIndex].isGranular = IsUsingGranularEngine();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Request a wave slot
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::RequestWaveSlot(audWaveSlotManager* waveSlotManager, u32 soundID, bool dspEffectsRequired)
|
|
{
|
|
if(waveSlotManager)
|
|
{
|
|
if(dspEffectsRequired)
|
|
{
|
|
if(m_EngineSubmixIndex == -1)
|
|
{
|
|
m_EngineSubmixIndex = static_cast<s8>(g_AudioEngine.GetEnvironment().AssignVehicleEngineSubmix());
|
|
|
|
if(m_EngineSubmixIndex >= 0)
|
|
{
|
|
if(sm_VehicleEngineSubmixes[m_EngineSubmixIndex].submixSound)
|
|
{
|
|
g_FrontendAudioEntity.StopAndForgetSounds(sm_VehicleEngineSubmixes[m_EngineSubmixIndex].submixSound);
|
|
sm_VehicleEngineSubmixes[m_EngineSubmixIndex].submixSound = NULL;
|
|
sm_VehicleEngineSubmixes[m_EngineSubmixIndex].vehicleType = AUD_VEHICLE_NONE;
|
|
sm_VehicleEngineSubmixes[m_EngineSubmixIndex].isGranular = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_ExhaustSubmixIndex == -1)
|
|
{
|
|
m_ExhaustSubmixIndex = static_cast<s8>(g_AudioEngine.GetEnvironment().AssignVehicleExhaustSubmix());
|
|
|
|
if(m_ExhaustSubmixIndex >= 0)
|
|
{
|
|
if(sm_VehicleExhaustSubmixes[m_ExhaustSubmixIndex].submixSound)
|
|
{
|
|
g_FrontendAudioEntity.StopAndForgetSounds(sm_VehicleExhaustSubmixes[m_ExhaustSubmixIndex].submixSound);
|
|
sm_VehicleExhaustSubmixes[m_ExhaustSubmixIndex].submixSound = NULL;
|
|
sm_VehicleExhaustSubmixes[m_ExhaustSubmixIndex].vehicleType = AUD_VEHICLE_NONE;
|
|
sm_VehicleExhaustSubmixes[m_ExhaustSubmixIndex].isGranular = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(((m_EngineSubmixIndex >= 0 && m_ExhaustSubmixIndex >= 0) || !dspEffectsRequired) && !m_EngineWaveSlot)
|
|
{
|
|
m_EngineWaveSlot = waveSlotManager->LoadBankForSound(soundID, AUD_WAVE_SLOT_ANY, false, this, m_IsFocusVehicle? naWaveLoadPriority::PlayerInteractive : naWaveLoadPriority::General BANK_ONLY(, g_WaveSlotStreamingDelayTime));
|
|
}
|
|
}
|
|
|
|
if(dspEffectsRequired)
|
|
{
|
|
if(m_EngineWaveSlot)
|
|
{
|
|
InitDSPEffects();
|
|
}
|
|
else if(m_VehicleLOD != AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
FreeDSPEffects();
|
|
}
|
|
}
|
|
|
|
return m_EngineWaveSlot != NULL;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Request a low latency wave slot
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::RequestLowLatencyWaveSlot(u32 soundID)
|
|
{
|
|
if(!m_LowLatencyWaveSlot)
|
|
{
|
|
m_LowLatencyWaveSlot = sm_LowLatencyWaveSlotManager.LoadBankForSound(soundID, AUD_WAVE_SLOT_ANY, false, this, m_IsFocusVehicle? naWaveLoadPriority::PlayerInteractive : naWaveLoadPriority::General BANK_ONLY(, g_WaveSlotStreamingDelayTime));
|
|
}
|
|
|
|
return m_LowLatencyWaveSlot != NULL;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Request an sfx wave slot
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::RequestSFXWaveSlot(u32 soundID, bool useHighQualitySlot)
|
|
{
|
|
if(!m_SFXWaveSlot)
|
|
{
|
|
audWaveSlotManager* waveSlotManager = useHighQualitySlot? &sm_HighQualityWaveSlotManager : &sm_StandardWaveSlotManager;
|
|
m_SFXWaveSlot = waveSlotManager->LoadBankForSound(soundID, AUD_WAVE_SLOT_ANY, false, this, m_IsFocusVehicle? naWaveLoadPriority::PlayerInteractive : naWaveLoadPriority::General BANK_ONLY(, g_WaveSlotStreamingDelayTime));
|
|
}
|
|
|
|
return m_SFXWaveSlot != NULL;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Request a wave slot
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::FreeWaveSlot(bool freeDSPEffects)
|
|
{
|
|
if(m_EngineWaveSlot)
|
|
{
|
|
audWaveSlotManager::FreeWaveSlot(m_EngineWaveSlot, this);
|
|
}
|
|
|
|
if(m_LowLatencyWaveSlot)
|
|
{
|
|
audWaveSlotManager::FreeWaveSlot(m_LowLatencyWaveSlot, this);
|
|
}
|
|
|
|
if(m_SFXWaveSlot)
|
|
{
|
|
audWaveSlotManager::FreeWaveSlot(m_SFXWaveSlot, this);
|
|
}
|
|
|
|
if(freeDSPEffects)
|
|
{
|
|
FreeDSPEffects();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update the vehicle filters
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateDSPEffects(audVehicleDSPSettings& dspSettings , audVehicleVariables& vehicleVariables)
|
|
{
|
|
audSound* engineEffectSubmixSound = GetEngineEffectSubmixSound();
|
|
audSound* exhaustEffectSubmixSound = GetExhaustEffectSubmixSound();
|
|
|
|
if(engineEffectSubmixSound && exhaustEffectSubmixSound && engineEffectSubmixSound->GetPlayState() == AUD_SOUND_PLAYING && exhaustEffectSubmixSound->GetPlayState() == AUD_SOUND_PLAYING)
|
|
{
|
|
bool disableDSP = (m_IsFocusVehicle && g_DisablePlayerVehicleDSP) || (!m_IsFocusVehicle && g_DisableNPCVehicleDSP);
|
|
|
|
#if __BANK
|
|
disableDSP |= g_DisableEngineExhaustDSP;
|
|
#endif
|
|
|
|
g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(m_EngineSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::Bypass, disableDSP? 1 : 0);
|
|
g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(m_ExhaustSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::Bypass, disableDSP? 1 : 0);
|
|
|
|
if(IsSafeToApplyDSPChanges())
|
|
{
|
|
if(m_ResetDSPEffects)
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(m_EngineSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::CompiledSynthNameHash, GetEngineSubmixSynth());
|
|
g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(m_ExhaustSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::CompiledSynthNameHash, GetExhaustSubmixSynth());
|
|
m_ResetDSPEffects = false;
|
|
}
|
|
|
|
if(m_ReapplyDSPPresets BANK_ONLY(|| g_AutoReapplyDSPPresets))
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(m_EngineSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::PresetNameHash, GetEngineSubmixSynthPreset());
|
|
g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(m_ExhaustSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::PresetNameHash, GetExhaustSubmixSynthPreset());
|
|
m_ReapplyDSPPresets = false;
|
|
}
|
|
}
|
|
|
|
dspSettings.proximityRatio = ComputeProximityEffectRatio();
|
|
dspSettings.AddDSPParameter(atHashString("Proximity", 0x1C158A61), dspSettings.proximityRatio);
|
|
|
|
f32 proximityVolumeBoost = 0.0f;
|
|
|
|
if(!vehicleVariables.isInFirstPersonCam && !vehicleVariables.isInHoodMountedCam)
|
|
{
|
|
proximityVolumeBoost = dspSettings.proximityRatio * GetExhaustProximityVolumeBoost();
|
|
GranularEngineAudioSettings* granularSettings = GetGranularEngineAudioSettings();
|
|
|
|
bool isExhaustUpgraded = false;
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_CAR)
|
|
{
|
|
isExhaustUpgraded = ((audCarAudioEntity*)this)->IsExhaustUpgraded();
|
|
}
|
|
|
|
if(granularSettings && (AUD_GET_TRISTATE_VALUE(granularSettings->Flags, FLAG_ID_GRANULARENGINEAUDIOSETTINGS_EXHAUSTPROXIMITYMIXERSCENEENABLED) == AUD_TRISTATE_TRUE || isExhaustUpgraded))
|
|
{
|
|
sm_PlayerVehicleProximityRatio = dspSettings.proximityRatio;
|
|
}
|
|
}
|
|
|
|
if(m_IsPlayerVehicle && audNorthAudioEngine::ShouldTriggerPulseHeadset() && sm_PlayerVehicleProximityRatio > 0.0f)
|
|
{
|
|
if(!m_ExhastProximityPulseSound)
|
|
{
|
|
CreateAndPlaySound_Persistent(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("ExhaustProximity", 0x102BBD7)), &m_ExhastProximityPulseSound);
|
|
}
|
|
|
|
if(m_ExhastProximityPulseSound)
|
|
{
|
|
const Vec3V camPos = g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(0);
|
|
const Vec3V exhaustPos = m_Vehicle->TransformIntoWorldSpace(m_ExhaustOffsetPos);
|
|
const Vec3V camToCar = (exhaustPos-camPos);
|
|
m_ExhastProximityPulseSound->FindAndSetVariableValue(ATSTRINGHASH("DistanceToExhaust", 0xBB757FBF), Mag(camToCar).Getf());
|
|
m_ExhastProximityPulseSound->FindAndSetVariableValue(ATSTRINGHASH("Revs", 0x44D3B231), vehicleVariables.revs);
|
|
m_ExhastProximityPulseSound->FindAndSetVariableValue(ATSTRINGHASH("Throttle", 0xEA0151DC), vehicleVariables.throttle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_ExhastProximityPulseSound);
|
|
}
|
|
|
|
for(u32 loop = 0; loop < dspSettings.dspParameters.GetCount(); loop++)
|
|
{
|
|
bool validForEngine = (dspSettings.dspParameters[loop].submixType == audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_BOTH || dspSettings.dspParameters[loop].submixType == audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_ENGINE);
|
|
bool validForExhaust = (dspSettings.dspParameters[loop].submixType == audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_BOTH || dspSettings.dspParameters[loop].submixType == audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_EXHAUST);
|
|
|
|
if(validForEngine)
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(m_EngineSubmixIndex)->SetEffectParam(0, dspSettings.dspParameters[loop].parameterName.GetHash(), dspSettings.dspParameters[loop].parameterValue);
|
|
}
|
|
|
|
if(validForExhaust)
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(m_ExhaustSubmixIndex)->SetEffectParam(0, dspSettings.dspParameters[loop].parameterName.GetHash(), dspSettings.dspParameters[loop].parameterValue);
|
|
}
|
|
}
|
|
|
|
audRequestedSettings *engineReqSets = engineEffectSubmixSound->GetRequestedSettings();
|
|
audRequestedSettings *exhaustReqSets = exhaustEffectSubmixSound->GetRequestedSettings();
|
|
|
|
if(exhaustReqSets && engineReqSets)
|
|
{
|
|
if(m_Vehicle)
|
|
{
|
|
#if __BANK
|
|
if(m_IsPlayerVehicle && ((g_UseDebugPlaneTracker && GetAudioVehicleType() == AUD_VEHICLE_PLANE) || (g_UseDebugHeliTracker && GetAudioVehicleType() == AUD_VEHICLE_HELI)))
|
|
{
|
|
// the absolute positions are set by the debug tracker, both sounds are at the same location but that shouldn't matter for tuning flybys
|
|
engineReqSets->SetPosition(m_EngineOffsetPos);
|
|
exhaustReqSets->SetPosition(m_ExhaustOffsetPos);
|
|
engineReqSets->SetPan(-1);
|
|
exhaustReqSets->SetPan(-1);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if(vehicleVariables.isInFirstPersonCam)
|
|
{
|
|
if(g_InteriorEngineExhaustAtListener)
|
|
{
|
|
const Vec3V listenerPosition = g_AudioEngine.GetEnvironment().GetPanningListenerPosition(0);
|
|
engineReqSets->SetPosition(listenerPosition);
|
|
exhaustReqSets->SetPosition(listenerPosition);
|
|
}
|
|
else
|
|
{
|
|
engineReqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_EngineOffsetPos));
|
|
exhaustReqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_ExhaustOffsetPos));
|
|
}
|
|
|
|
if(g_InteriorEngineExhaustPanned)
|
|
{
|
|
f32 engineDegrees = atan2(m_EngineOffsetPos.GetXf(), m_EngineOffsetPos.GetYf()) * RtoD;
|
|
f32 exhaustDegrees = atan2(m_ExhaustOffsetPos.GetXf(), m_ExhaustOffsetPos.GetYf()) * RtoD;
|
|
|
|
Vec3V vehicleForward = Vec3V(V_Y_AXIS_WZERO);
|
|
Vec3V listenerForward = m_Vehicle->GetTransform().UnTransform(m_Vehicle->GetTransform().GetPosition() + g_AudioEngine.GetEnvironment().GetPanningListenerMatrix().GetCol1());
|
|
listenerForward.SetZ(ScalarV(V_ZERO));
|
|
listenerForward = Normalize(listenerForward);
|
|
|
|
Vec3V forwardCross = Cross(vehicleForward, listenerForward);
|
|
f32 forwardDot = Dot(vehicleForward, listenerForward).Getf();
|
|
f32 headAngleDegrees = AcosfSafe(forwardDot) * RtoD;
|
|
|
|
if(Dot(Vec3V(V_UP_AXIS_WZERO), forwardCross).Getf() < 0.0f)
|
|
{
|
|
headAngleDegrees *= -1.0f;
|
|
}
|
|
|
|
s32 engineAngle = (s32)(engineDegrees + headAngleDegrees) % 360;
|
|
s32 exhaustAngle = (s32)(exhaustDegrees + headAngleDegrees) % 360;
|
|
|
|
if(engineAngle < 0)
|
|
{
|
|
engineAngle += 360;
|
|
}
|
|
|
|
if(exhaustAngle < 0)
|
|
{
|
|
exhaustAngle += 360;
|
|
}
|
|
|
|
engineReqSets->SetPan(engineAngle);
|
|
exhaustReqSets->SetPan(exhaustAngle);
|
|
}
|
|
else
|
|
{
|
|
engineReqSets->SetPan(-1);
|
|
exhaustReqSets->SetPan(-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
engineReqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_EngineOffsetPos));
|
|
exhaustReqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_ExhaustOffsetPos));
|
|
engineReqSets->SetPan(-1);
|
|
exhaustReqSets->SetPan(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static f32 engineExhaustSubmixVolumeTrim = 5.0f;
|
|
|
|
if(g_BonnetCamStereoEffectEnabled && g_ReflectionsAudioEntity.GetActiveVehicle() == this && vehicleVariables.isInFirstPersonCam)
|
|
{
|
|
dspSettings.enginePostSubmixAttenuation += g_StereoEffectEngineVolumeTrim;
|
|
dspSettings.exhaustPostSubmixAttenuation += g_StereoEffectExhaustVolumeTrim;
|
|
}
|
|
|
|
engineReqSets->SetSourceEffectMix(1.0f, 1.0f);
|
|
engineReqSets->SetPostSubmixVolumeAttenuation(dspSettings.enginePostSubmixAttenuation + engineExhaustSubmixVolumeTrim);
|
|
engineReqSets->SetVolumeCurveScale(dspSettings.rolloffScale);
|
|
engineReqSets->SetFrequencySmoothingRate(sm_FrequencySmoothingRate);
|
|
engineReqSets->SetEnvironmentalLoudnessFloat(dspSettings.environmentalLoudness);
|
|
|
|
exhaustReqSets->SetSourceEffectMix(1.0f, 1.0f);
|
|
exhaustReqSets->SetPostSubmixVolumeAttenuation(dspSettings.exhaustPostSubmixAttenuation + engineExhaustSubmixVolumeTrim + proximityVolumeBoost);
|
|
exhaustReqSets->SetVolumeCurveScale(dspSettings.rolloffScale);
|
|
exhaustReqSets->SetFrequencySmoothingRate(sm_FrequencySmoothingRate);
|
|
exhaustReqSets->SetEnvironmentalLoudnessFloat(dspSettings.environmentalLoudness);
|
|
|
|
if(!m_Vehicle->m_nVehicleFlags.bEngineStarting && !m_Vehicle->m_nVehicleFlags.bEngineOn)
|
|
{
|
|
// Mute the submix voices if we want to keep hold of them but aren't actually playing anything through them. Can occur when eg. the player is sitting inside a car that has been switched off by script,
|
|
// such as in the car mod shop
|
|
engineReqSets->SetVolume(audDriver::GetMixer()->GetActiveVoiceCount(g_AudioEngine.GetEnvironment().GetVehicleEngineSubmixId(m_EngineSubmixIndex)) > 0? 0.0f : g_SilenceVolume);
|
|
exhaustReqSets->SetVolume(audDriver::GetMixer()->GetActiveVoiceCount(g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmixId(m_ExhaustSubmixIndex)) > 0? 0.0f : g_SilenceVolume);
|
|
}
|
|
else
|
|
{
|
|
engineReqSets->SetVolume(0.0f);
|
|
exhaustReqSets->SetVolume(0.0f);
|
|
}
|
|
}
|
|
|
|
// This is needed to blend between player/NPC volumes
|
|
m_EngineEffectWetSmoother.CalculateValue(m_IsPlayerSeatedInVehicle?1.0f:0.0f,dspSettings.timeInMs);
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_DebugDSPParams && m_IsPlayerVehicle)
|
|
{
|
|
char tempString[128];
|
|
f32 xCoord = 0.1f;
|
|
f32 yCoord = 0.1f;
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), "DSP Parameters");
|
|
yCoord += 0.02f;
|
|
xCoord += 0.05f;
|
|
|
|
for(u32 loop = 0; loop < dspSettings.dspParameters.GetCount(); loop++)
|
|
{
|
|
sprintf(tempString, "%s: %.02f", dspSettings.dspParameters[loop].parameterName.GetCStr(), dspSettings.dspParameters[loop].parameterValue);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += 0.02f;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if this vehicle should use DSP effects
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::ShouldUseDSPEffects() const
|
|
{
|
|
return BANK_ONLY(g_ForceSynthsOnAllEngines ||) m_IsFocusVehicle || sm_IsInCarMeet || (NetworkInterface::IsGameInProgress() && (m_Vehicle->IsPersonalVehicle() || m_LastPlayerVehicle)) || (g_AllowSynthsOnNetworkVehicles && m_IsNetworkPlayerSeatedInVehicle);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Free any DSP effects so they can be reused
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::FreeDSPEffects()
|
|
{
|
|
audAssert(m_VehicleLOD != AUD_VEHICLE_LOD_REAL);
|
|
|
|
if(m_EngineSubmixIndex >= 0)
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(m_EngineSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::CompiledSynthNameHash, 0);
|
|
g_AudioEngine.GetEnvironment().FreeVehicleEngineSubmix(m_EngineSubmixIndex);
|
|
m_EngineSubmixIndex = -1;
|
|
}
|
|
|
|
if(m_ExhaustSubmixIndex >= 0)
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(m_ExhaustSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::CompiledSynthNameHash, 0);
|
|
g_AudioEngine.GetEnvironment().FreeVehicleExhaustSubmix(m_ExhaustSubmixIndex);
|
|
m_ExhaustSubmixIndex = -1;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Reapply the dsp presets
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ReapplyDSPEffects()
|
|
{
|
|
if(m_EngineSubmixIndex >= 0)
|
|
{
|
|
u32 engineSubmixSynth = GetEngineSubmixSynth();
|
|
|
|
if(engineSubmixSynth == g_NullSoundHash || IsSafeToApplyDSPChanges())
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(m_EngineSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::CompiledSynthNameHash, engineSubmixSynth);
|
|
g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(m_EngineSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::PresetNameHash, GetEngineSubmixSynthPreset());
|
|
}
|
|
else
|
|
{
|
|
m_ResetDSPEffects = true;
|
|
m_ReapplyDSPPresets = true;
|
|
}
|
|
}
|
|
|
|
if(m_ExhaustSubmixIndex >= 0)
|
|
{
|
|
u32 exhaustSubmixSynth = GetExhaustSubmixSynth();
|
|
|
|
if(exhaustSubmixSynth == g_NullSoundHash || IsSafeToApplyDSPChanges())
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(m_ExhaustSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::CompiledSynthNameHash, exhaustSubmixSynth);
|
|
g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(m_ExhaustSubmixIndex)->SetEffectParam(0, synthCorePcmSource::Params::PresetNameHash, GetExhaustSubmixSynthPreset());
|
|
}
|
|
else
|
|
{
|
|
m_ResetDSPEffects = true;
|
|
m_ReapplyDSPPresets = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update damage warning
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateDamageWarning()
|
|
{
|
|
f32 engineHealth = ComputeEffectiveEngineHealth();
|
|
f32 damageRatio = Clamp(1.0f - (engineHealth / CTransmission::GetEngineHealthMax()), 0.0f, 1.0f);
|
|
|
|
if(NetworkInterface::IsGameInProgress() &&
|
|
m_Vehicle->IsTank() &&
|
|
m_IsPlayerVehicle &&
|
|
m_Vehicle->m_nVehicleFlags.bEngineOn &&
|
|
damageRatio > 0.0f &&
|
|
AreWarningSoundsValid())
|
|
{
|
|
if(!m_DamageWarningSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
|
|
if (GetVehicleModelNameHash() == ATSTRINGHASH("MINITANK", 0xB53C6C52))
|
|
{
|
|
audSoundSet soundSet;
|
|
|
|
if (soundSet.Init(m_IsFocusVehicle ? ATSTRINGHASH("ch_vehicle_minitank_player_sounds", 0xCF2B0226) : ATSTRINGHASH("ch_vehicle_minitank_remote_sounds", 0x90AF5388)))
|
|
{
|
|
CreateAndPlaySound_Persistent(soundSet.Find(ATSTRINGHASH("damage_warning", 0xE58B27A1)), &m_DamageWarningSound, &initParams);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CreateAndPlaySound_Persistent(ATSTRINGHASH("TANK_DAMAGE_WARNING_MASTER", 0x1121601B), &m_DamageWarningSound, &initParams);
|
|
}
|
|
}
|
|
|
|
if(m_DamageWarningSound)
|
|
{
|
|
m_DamageWarningSound->FindAndSetVariableValue(ATSTRINGHASH("EngineDamage", 0xC51EB951), damageRatio);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_DamageWarningSound);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update the missile lock on effects
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateMissileLock()
|
|
{
|
|
u32 currentTime = g_AudioEngine.GetTimeInMilliseconds();
|
|
|
|
if(CGameWorld::GetMainPlayerInfo()->AreControlsDisabled())
|
|
{
|
|
return;
|
|
}
|
|
if(m_Vehicle)
|
|
{
|
|
bool isMissileApproaching = false;
|
|
bool isBeingTargeted = false;
|
|
bool isAcquiringTarget = false;
|
|
bool hasTarget = false;
|
|
|
|
if(m_HasMissileLockWarningSystem || g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::EnableMissileLockWarningForAllVehicles))
|
|
{
|
|
bool missileApproachingThisFrame = m_Vehicle->GetHomingProjectileDistance() > 0.0f;
|
|
|
|
if(missileApproachingThisFrame)
|
|
{
|
|
m_MissileApproachTimer += fwTimer::GetTimeStep();
|
|
isMissileApproaching = m_MissileApproachTimer > 0.5f;
|
|
}
|
|
else
|
|
{
|
|
m_MissileApproachTimer = 0.0f;
|
|
}
|
|
|
|
isBeingTargeted = !isMissileApproaching && (m_Vehicle->GetHomingLockedOntoState() == CEntity::HLOnS_ACQUIRED || m_Vehicle->GetHomingLockedOntoState() == CEntity::HLOnS_ACQUIRING);
|
|
isAcquiringTarget = m_Vehicle->GetHomingLockOnState() == CEntity::HLOnS_ACQUIRING;
|
|
hasTarget = m_Vehicle->GetHomingLockOnState() == CEntity::HLOnS_ACQUIRED;
|
|
}
|
|
|
|
if(m_IsPlayerVehicle && m_Vehicle->GetStatus() != STATUS_WRECKED)
|
|
{
|
|
#if __BANK
|
|
if(g_OverrideMissileStatus)
|
|
{
|
|
switch(g_SimulatedMissileState)
|
|
{
|
|
case 0:
|
|
isBeingTargeted = false;
|
|
isMissileApproaching = false;
|
|
isAcquiringTarget = false;
|
|
hasTarget = false;
|
|
break;
|
|
case 1:
|
|
isBeingTargeted = true;
|
|
isMissileApproaching = false;
|
|
isAcquiringTarget = false;
|
|
hasTarget = false;
|
|
break;
|
|
case 2:
|
|
isBeingTargeted = false;
|
|
isMissileApproaching = true;
|
|
isAcquiringTarget = false;
|
|
hasTarget = false;
|
|
break;
|
|
case 3:
|
|
isBeingTargeted = false;
|
|
isMissileApproaching = false;
|
|
isAcquiringTarget = true;
|
|
hasTarget = false;
|
|
break;
|
|
case 4:
|
|
isBeingTargeted = false;
|
|
isMissileApproaching = false;
|
|
isAcquiringTarget = false;
|
|
hasTarget = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(g_DebugMissileLockStatus)
|
|
{
|
|
char tempString[1024];
|
|
const char* lockOnStateNames[] = { "None", "Acquiring", "Acquired" };
|
|
formatf(tempString, "Lock On State: %s", lockOnStateNames[m_Vehicle->GetHomingLockOnState()]);
|
|
safecatf(tempString, "\nLocked Onto State: %s", lockOnStateNames[m_Vehicle->GetHomingLockedOntoState()]);
|
|
|
|
if (m_HasMissileLockWarningSystem)
|
|
{
|
|
safecatf(tempString, "\nBeing Targeted Sound: %s", m_BeingTargetedSound ? "Active" : "Inactive");
|
|
safecatf(tempString, "\nMissile Approaching Sound: %s", m_MissileApproachingSound ? "Active" : "Inactive");
|
|
safecatf(tempString, "\nMissile Approaching Imminent Sound: %s", m_MissileApproachingSoundImminent ? "Active" : "Inactive");
|
|
safecatf(tempString, "\nAll Clear Sound: %s", m_AllClearSound ? "Active" : "Inactive");
|
|
safecatf(tempString, "\nAcquiring Target: %s", m_AcquiringTargetSound && m_Vehicle->GetHomingLockOnState() != CEntity::HLOnS_ACQUIRED ? "Active" : "Inactive");
|
|
safecatf(tempString, "\nTarget Acquired Sound: %s", m_AcquiringTargetSound && m_Vehicle->GetHomingLockOnState() == CEntity::HLOnS_ACQUIRED ? "Active" : "Inactive");
|
|
}
|
|
else
|
|
{
|
|
safecatf(tempString, "\nAudio Missile Lock System Not Enabled");
|
|
}
|
|
|
|
grcDebugDraw::Text(m_Vehicle->GetTransform().GetPosition(), Color_white, tempString, true, -1);
|
|
}
|
|
#endif
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.Pan = 0;
|
|
|
|
if(isBeingTargeted && !isMissileApproaching)
|
|
{
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
sm_TimeMissleFiredStarted = 0;
|
|
sm_TimeAllClearStarted = 0;
|
|
|
|
/*if(sm_TimeTargetLockStarted == 0)
|
|
sm_TimeTargetLockStarted = currentTime;
|
|
else if(currentTime - sm_TimeTargetLockStarted> (g_AircraftWarningSettings ? g_AircraftWarningSettings->TargetedLock.MinTimeInStateToTrigger : 1500) )
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_TARGETED_LOCK);*/
|
|
}
|
|
|
|
if(fwTimer::GetTimeInMilliseconds() - m_LastHitByRocketTime > 1000)
|
|
{
|
|
StopAndForgetSounds(m_MissileApproachingSound);
|
|
|
|
StopAndForgetSounds(m_MissileApproachingSoundImminent);
|
|
|
|
if(!m_BeingTargetedSound && !m_AllClearSound)
|
|
{
|
|
CreateAndPlaySound_Persistent(sm_MissileLockSoundSet.Find(ATSTRINGHASH("TARGETED_LOCK", 3810899439)), &m_BeingTargetedSound, &initParams);
|
|
}
|
|
}
|
|
}
|
|
else if(isMissileApproaching)
|
|
{
|
|
static dev_float IMMINENT_MISSILE_DISTANCE = 35.0f;
|
|
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
sm_TimeTargetLockStarted = 0;
|
|
sm_TimeAllClearStarted = 0;
|
|
|
|
if(sm_TimeMissleFiredStarted == 0)
|
|
sm_TimeMissleFiredStarted = currentTime;
|
|
else if(currentTime - sm_TimeMissleFiredStarted> (g_AircraftWarningSettings ? g_AircraftWarningSettings->MissleFired.MinTimeInStateToTrigger : 1500) )
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_MISSLE_FIRED);
|
|
}
|
|
|
|
StopAndForgetSounds(m_BeingTargetedSound);
|
|
|
|
if(m_MissileApproachingSoundImminent)
|
|
{
|
|
if(m_Vehicle->GetHomingProjectileDistance() >= IMMINENT_MISSILE_DISTANCE)
|
|
{
|
|
StopAndForgetSounds(m_MissileApproachingSoundImminent);
|
|
}
|
|
}
|
|
|
|
if(!m_MissileApproachingSound && !m_AllClearSound && !m_MissileApproachingSoundImminent)
|
|
{
|
|
CreateAndPlaySound_Persistent(sm_MissileLockSoundSet.Find(ATSTRINGHASH("MISSILE_FIRED", 484541956)), &m_MissileApproachingSound, &initParams);
|
|
}
|
|
|
|
if(m_MissileApproachingSound)
|
|
{
|
|
f32 distance = Clamp(m_Vehicle->GetHomingProjectileDistance() / 200.0f, 0.0f, 1.0f);
|
|
|
|
#if __BANK
|
|
if(g_OverrideMissileStatus)
|
|
{
|
|
distance = g_SimulatedMissileDistance;
|
|
}
|
|
#endif
|
|
m_MissileApproachingSound->FindAndSetVariableValue(ATSTRINGHASH("MISSILE_DISTANCE_TO_PLANE", 3642087817), 1.0f - distance);
|
|
|
|
if(m_Vehicle->GetHomingProjectileDistance() < IMMINENT_MISSILE_DISTANCE)
|
|
{
|
|
if(!m_MissileApproachingSoundImminent && !m_AllClearSound)
|
|
{
|
|
CreateAndPlaySound_Persistent(sm_MissileLockSoundSet.Find(ATSTRINGHASH("MISSILE_FIRED_SOLID", 1352055251)), &m_MissileApproachingSoundImminent, &initParams);
|
|
|
|
//Stop the beeping when we have a solid tone
|
|
StopAndForgetSounds(m_MissileApproachingSound);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_WasMissileApproaching || m_WasBeingTargeted)
|
|
{
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
sm_TimeTargetLockStarted = 0;
|
|
sm_TimeMissleFiredStarted = 0;
|
|
|
|
if(sm_TimeAllClearStarted == 0)
|
|
sm_TimeAllClearStarted = currentTime;
|
|
else if(currentTime - sm_TimeAllClearStarted> (g_AircraftWarningSettings ? g_AircraftWarningSettings->AllClear.MinTimeInStateToTrigger : 1500) )
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_ALL_CLEAR);
|
|
}
|
|
|
|
if(!m_AllClearSound && fwTimer::GetTimeInMilliseconds() - m_LastHitByRocketTime > 250)
|
|
{
|
|
CreateAndPlaySound_Persistent(sm_MissileLockSoundSet.Find(ATSTRINGHASH("ALL_CLEAR", 4004323938)), &m_AllClearSound, &initParams);
|
|
m_MissileApproachTimer = 0.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
sm_TimeAllClearStarted = 0;
|
|
}
|
|
}
|
|
|
|
StopAndForgetSounds(m_MissileApproachingSound, m_BeingTargetedSound, m_MissileApproachingSoundImminent);
|
|
}
|
|
|
|
if(isAcquiringTarget && !hasTarget)
|
|
{
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
sm_TimeATargetAcquiredStarted = 0;
|
|
|
|
/*if(sm_TimeAcquiringTargetStarted == 0)
|
|
sm_TimeAcquiringTargetStarted = currentTime;
|
|
else if(currentTime - sm_TimeAcquiringTargetStarted > (g_AircraftWarningSettings ? g_AircraftWarningSettings->AcquiringTarget.MinTimeInStateToTrigger : 1500) )
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_ACQUIRING_TARGET);*/
|
|
}
|
|
|
|
if(!m_WasAcquiringTarget)
|
|
{
|
|
StopAndForgetSounds(m_AcquiringTargetSound);
|
|
}
|
|
|
|
if(!m_AcquiringTargetSound)
|
|
{
|
|
CreateAndPlaySound_Persistent(sm_MissileLockSoundSet.Find(ATSTRINGHASH("ACQUIRING_TARGET", 0xCCF0B21D)), &m_AcquiringTargetSound, &initParams);
|
|
}
|
|
}
|
|
else if(hasTarget)
|
|
{
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
sm_TimeAcquiringTargetStarted = 0;
|
|
|
|
if(sm_TimeATargetAcquiredStarted == 0)
|
|
sm_TimeATargetAcquiredStarted = currentTime;
|
|
else if(currentTime - sm_TimeATargetAcquiredStarted > (g_AircraftWarningSettings ? g_AircraftWarningSettings->TargetAcquired.MinTimeInStateToTrigger : 1500) )
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_TARGET_ACQUIRED);
|
|
}
|
|
|
|
if(!m_HadAcquiredTarget && m_AcquiringTargetSound)
|
|
{
|
|
StopAndForgetSounds(m_AcquiringTargetSound);
|
|
}
|
|
|
|
bool isTimeValid = true;
|
|
|
|
// Stop the locked-on sound after a set period of time
|
|
if(m_IsPlayerVehicle && currentTime - sm_TimeATargetAcquiredStarted > 1000)
|
|
{
|
|
isTimeValid = false;
|
|
}
|
|
|
|
if(isTimeValid)
|
|
{
|
|
if(!m_AcquiringTargetSound)
|
|
{
|
|
CreateAndPlaySound_Persistent(sm_MissileLockSoundSet.Find(ATSTRINGHASH("TARGET_ACQUIRED", 0x96CCCE93)), &m_AcquiringTargetSound, &initParams);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_AcquiringTargetSound);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
sm_TimeAcquiringTargetStarted = 0;
|
|
sm_TimeATargetAcquiredStarted = 0;
|
|
}
|
|
|
|
StopAndForgetSounds(m_AcquiringTargetSound);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_MissileApproachingSound, m_BeingTargetedSound, m_AcquiringTargetSound, m_MissileApproachingSoundImminent);
|
|
}
|
|
|
|
m_WasMissileApproaching = isMissileApproaching;
|
|
m_WasBeingTargeted = isBeingTargeted;
|
|
m_WasAcquiringTarget = isAcquiringTarget;
|
|
m_HadAcquiredTarget = hasTarget;
|
|
}
|
|
else
|
|
{
|
|
m_WasMissileApproaching = false;
|
|
m_WasBeingTargeted = false;
|
|
m_WasAcquiringTarget = false;
|
|
m_HadAcquiredTarget = false;
|
|
}
|
|
}
|
|
|
|
void audVehicleAudioEntity::UpdateCabinTone(audVehicleVariables& params)
|
|
{
|
|
bool cabinToneActive = params.isInFirstPersonCam && m_Vehicle->IsEngineOn();
|
|
|
|
if(cabinToneActive)
|
|
{
|
|
if(!m_VehicleCabinTone)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = GetEnvironmentGroup();
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_INTERIOR_OCCLUSION;
|
|
initParams.UpdateEntity = true;
|
|
CreateAndPlaySound_Persistent(GetCabinToneSound(), &m_VehicleCabinTone, &initParams);
|
|
}
|
|
|
|
if(m_VehicleCabinTone)
|
|
{
|
|
m_VehicleCabinTone->FindAndSetVariableValue(ATSTRINGHASH("openness", 0x2721BC39), GetOpenness(false));
|
|
}
|
|
}
|
|
else if(m_VehicleCabinTone)
|
|
{
|
|
StopAndForgetSounds(m_VehicleCabinTone);
|
|
}
|
|
}
|
|
|
|
void audVehicleAudioEntity::UpdateAircraftWarningSpeech()
|
|
{
|
|
//TODO: AUD_AW_OVERSPEED
|
|
if(!g_AircraftWarningSettings || !m_Vehicle || !AreWarningSoundsValid() ||
|
|
!(m_Vehicle->GetVehicleType() == VEHICLE_TYPE_PLANE || m_Vehicle->GetVehicleType() == VEHICLE_TYPE_HELI) )
|
|
return;
|
|
|
|
u32 currentTime = g_AudioEngine.GetTimeInMilliseconds();
|
|
|
|
if(FindPlayerPed() && FindPlayerPed()->GetPlayerInfo() && FindPlayerPed()->GetPlayerInfo()->HasPlayerLeftTheWorld() &&
|
|
currentTime - m_TimeOfLastAircraftLowFuelWarning > g_AircraftWarningSettings->LowFuel.MinTimeBetweenPlay)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_LOW_FUEL);
|
|
m_TimeOfLastAircraftLowFuelWarning = currentTime;
|
|
}
|
|
|
|
if(currentTime - m_TimeOfLastAircraftOverspeedWarning > g_AircraftWarningSettings->Overspeed.MinTimeBetweenPlay)
|
|
{
|
|
f32 fwdSpeed = DotProduct(m_CachedVehicleVelocity, VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetB()));
|
|
if(fwdSpeed > GetOverspeedValue())
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_OVERSPEED);
|
|
m_TimeOfLastAircraftOverspeedWarning = currentTime;
|
|
}
|
|
}
|
|
|
|
if(fwTimer::GetTimeInMilliseconds() - m_LastTimeOnGround > 15000)
|
|
{
|
|
//Update terrain probe
|
|
u32 frameCount = fwTimer::GetFrameCount();
|
|
|
|
if(frameCount % 30 == 0)
|
|
{
|
|
bool largeVehicle = m_Vehicle->GetSeatManager()->GetMaxSeats() > 8;
|
|
const Vector3& probeForward = VEC3V_TO_VECTOR3(m_Vehicle->GetVehicleForwardDirectionRef()) * g_AircraftWarningSettings->Terrain.ForwardProbeLength;
|
|
|
|
const Vector3& pos = VEC3V_TO_VECTOR3(m_Vehicle->GetVehiclePosition());
|
|
WorldProbe::CShapeTestHitPoint hitPoint;
|
|
WorldProbe::CShapeTestResults probeResults(hitPoint);
|
|
WorldProbe::CShapeTestProbeDesc probeDesc;
|
|
probeDesc.SetResultsStructure(&probeResults);
|
|
probeDesc.SetStartAndEnd(pos, pos + probeForward);
|
|
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_TYPES_MOVER);
|
|
probeDesc.SetExcludeEntity(m_Vehicle, largeVehicle ? WorldProbe::EIEO_DONT_ADD_VEHICLE_OCCUPANTS : EXCLUDE_ENTITY_OPTIONS_NONE);
|
|
bool terrainHit = WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc);
|
|
if(terrainHit )
|
|
{
|
|
if(currentTime - m_LastTimeTerrainProbeHit > g_AircraftWarningSettings->PullUp.MaxTimeSinceTerrainTriggerToPlay )
|
|
{
|
|
if(currentTime - m_LastTimeTerrainProbeNotHit > g_AircraftWarningSettings->Terrain.MinTimeInStateToTrigger)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_TERRAIN);
|
|
}
|
|
m_LastTimeTerrainProbeHit = currentTime;
|
|
}
|
|
else
|
|
if(currentTime - m_LastTimeTerrainProbeNotHit > g_AircraftWarningSettings->PullUp.MinTimeInStateToTrigger)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_PULL_UP);
|
|
}
|
|
}
|
|
else
|
|
m_LastTimeTerrainProbeNotHit = currentTime;
|
|
}
|
|
else if(frameCount % 30 == 15 && m_Vehicle->GetVehicleType() != VEHICLE_TYPE_HELI)
|
|
{
|
|
//Update ground probe
|
|
const Vector3& pos = VEC3V_TO_VECTOR3(m_Vehicle->GetVehiclePosition());
|
|
WorldProbe::CShapeTestHitPoint hitPoint;
|
|
WorldProbe::CShapeTestResults probeResults(hitPoint);
|
|
WorldProbe::CShapeTestProbeDesc probeDesc;
|
|
probeDesc.SetResultsStructure(&probeResults);
|
|
probeDesc.SetStartAndEnd(pos, Vector3(pos.x, pos.y, pos.z - g_AircraftWarningSettings->AltitudeWarningLow.DownProbeLength));
|
|
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_TYPES_MOVER);
|
|
probeDesc.SetExcludeEntity(m_Vehicle);
|
|
bool groundHit = WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc);
|
|
if(groundHit && currentTime - m_LastTimeGroundProbeNotHit > g_AircraftWarningSettings->AltitudeWarningLow.MinTimeInStateToTrigger)
|
|
{
|
|
if(currentTime - m_LastTimeTerrainProbeNotHit > g_AircraftWarningSettings->Terrain.MinTimeInStateToTrigger)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_ALTITUDE_WARNING_LOW);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_LastTimeGroundProbeNotHit = currentTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_Vehicle->GetVehicleDamage() && currentTime - m_LastTimeAircraftDamageReported > g_AircraftWarningSettings->MinTimeBetweenDamageReports)
|
|
{
|
|
f32 overallHealth = m_Vehicle->GetVehicleDamage()->GetOverallHealth();
|
|
if(m_Vehicle->GetVehicleType() == VEHICLE_TYPE_PLANE && ((CPlane*)m_Vehicle)->AnyPlaneEngineOnFire())
|
|
{
|
|
if(!m_HasPlayedEngineOnFire1)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_ENGINE_1_FIRE);
|
|
m_HasPlayedEngineOnFire1 = true;
|
|
}
|
|
else if(!m_HasPlayedEngineOnFire2)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_ENGINE_2_FIRE);
|
|
m_HasPlayedEngineOnFire2 = true;
|
|
}
|
|
else if(!m_HasPlayedEngineOnFire3)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_ENGINE_3_FIRE);
|
|
m_HasPlayedEngineOnFire3 = true;
|
|
}
|
|
else if(!m_HasPlayedEngineOnFire4)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_ENGINE_4_FIRE);
|
|
m_HasPlayedEngineOnFire4 = true;
|
|
}
|
|
|
|
m_LastTimeAircraftDamageReported = currentTime;
|
|
}
|
|
if(overallHealth < GetCriticalDamageThreshold() &&
|
|
currentTime - m_TimeOfLastAircraftLowDamageWarning > g_AircraftWarningSettings->DamagedSerious.MinTimeBetweenPlay)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_DAMAGED_CRITICAL);
|
|
m_TimeOfLastAircraftLowDamageWarning = currentTime;
|
|
m_LastTimeAircraftDamageReported = currentTime;
|
|
}
|
|
else if(overallHealth < GetSeriousDamageThreshold() &&
|
|
currentTime - m_TimeOfLastAircraftHighDamageWarning > g_AircraftWarningSettings->DamagedSerious.MinTimeBetweenPlay)
|
|
{
|
|
g_ScriptAudioEntity.TriggerAircraftWarningSpeech(AUD_AW_DAMAGED_SERIOUS);
|
|
m_TimeOfLastAircraftHighDamageWarning = currentTime;
|
|
m_LastTimeAircraftDamageReported = currentTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity ProcessAnimEvents
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ProcessAnimEvents()
|
|
{
|
|
for(int i=0; i< AUDENTITY_NUM_ANIM_EVENTS; i++)
|
|
{
|
|
if(m_AnimEvents[i])
|
|
{
|
|
if(!IsDisabled())
|
|
{
|
|
for(s32 loop = 0; loop < m_VehicleGadgets.GetCount(); loop++)
|
|
{
|
|
if(m_VehicleGadgets[loop]->HandleAnimationTrigger(m_AnimEvents[i]))
|
|
{
|
|
m_AnimEvents[i] = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_AnimEvents[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
naAudioEntity::ProcessAnimEvents();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Populate any variables we need for the LOD calculations
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::PopulateVehicleLODVariables(audVehicleVariables& vehicleVariables)
|
|
{
|
|
f32 fwdSpeed = DotProduct(m_CachedVehicleVelocity, VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetB()));
|
|
vehicleVariables.fwdSpeed = fwdSpeed;
|
|
vehicleVariables.fwdSpeedAbs = Abs(fwdSpeed);
|
|
f32 invDriveMaxVelocity = m_Vehicle->m_Transmission.GetDriveMaxVelocity() > 0.0f ? 1.0f/m_Vehicle->m_Transmission.GetDriveMaxVelocity() : 0.0f;
|
|
|
|
vehicleVariables.fwdSpeedRatio = Min(1.f, vehicleVariables.fwdSpeedAbs * invDriveMaxVelocity);
|
|
vehicleVariables.invDriveMaxVelocity = invDriveMaxVelocity;
|
|
|
|
const Vec3V listenerPos = g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(audNorthAudioEngine::GetMicrophones().IsTinyRacersMicrophoneActive() ? 1 : 0);
|
|
Vec3V vehPos = m_Vehicle->GetTransform().GetPosition();
|
|
|
|
if (GetVehicleModelNameHash() == ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
vehPos = ComputeClosestPositionOnVehicleYAxis();
|
|
}
|
|
|
|
const Vec3V dirToVeh = vehPos - listenerPos;
|
|
vehicleVariables.distFromListenerSq = static_cast<u32>(MagSquared(dirToVeh).Getf());
|
|
vehicleVariables.visibleBySniper = audNorthAudioEngine::GetMicrophones().IsVisibleBySniper(m_Vehicle);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity::ComputeClosestPositionOnVehicleYAxis
|
|
// ----------------------------------------------------------------
|
|
Vec3V_Out audVehicleAudioEntity::ComputeClosestPositionOnVehicleYAxis()
|
|
{
|
|
const Vec3V listenerPos = g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(audNorthAudioEngine::GetMicrophones().IsTinyRacersMicrophoneActive() ? 1 : 0);
|
|
const Vec3V vehPos = m_Vehicle->GetTransform().GetPosition();
|
|
|
|
Vector3 closestPoint;
|
|
const Vector3 forward = VEC3V_TO_VECTOR3(m_Vehicle->GetMatrix().b());
|
|
fwGeom::fwLine positioningLine = fwGeom::fwLine(VEC3V_TO_VECTOR3(vehPos) + (forward * m_Vehicle->GetBoundingBoxMin().GetY()), VEC3V_TO_VECTOR3(vehPos) + (forward * m_Vehicle->GetBoundingBoxMax().GetY()));
|
|
positioningLine.FindClosestPointOnLine(VEC3V_TO_VECTOR3(listenerPos), closestPoint);
|
|
return VECTOR3_TO_VEC3V(closestPoint);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Populate the rest of the vehicle variables once we've worked out what LOD we are
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::PopulateVehicleVariables(audVehicleVariables& vehicleVariables)
|
|
{
|
|
vehicleVariables.hasMaterialChanged = false;
|
|
vehicleVariables.forcedThrottle = -1.0f;
|
|
vehicleVariables.granularEnginePitchOffset = 0;
|
|
vehicleVariables.wetRoadSkidModifier = 0.f;
|
|
vehicleVariables.movementSpeed = 0.0f;
|
|
vehicleVariables.timeInMs = fwTimer::GetTimeInMilliseconds();
|
|
|
|
if(m_IsFocusVehicle)
|
|
{
|
|
if(audNorthAudioEngine::IsRenderingHoodMountedVehicleCam())
|
|
{
|
|
vehicleVariables.isInHoodMountedCam = true;
|
|
}
|
|
if(audNorthAudioEngine::IsRenderingFirstPersonVehicleCam())
|
|
{
|
|
vehicleVariables.isInFirstPersonCam = true;
|
|
}
|
|
}
|
|
|
|
// LOD is low enough that we're not going to be playing road noise, so just set some sensible defaults
|
|
if(m_VehicleLOD >= AUD_VEHICLE_LOD_SUPER_DUMMY)
|
|
{
|
|
vehicleVariables.wheelSpeed = 0.0f;
|
|
vehicleVariables.wheelSpeedAbs = 0.0f;
|
|
vehicleVariables.wheelSpeedRatio = 0.0f;
|
|
vehicleVariables.roadNoisePitch = 0;
|
|
vehicleVariables.numWheelsTouchingFactor = 1.0f;
|
|
vehicleVariables.numWheelsTouching = m_Vehicle->GetNumWheels();
|
|
vehicleVariables.numDriveWheelsInWaterFactor = 0.0f;
|
|
vehicleVariables.numDriveWheelsInShallowWaterFactor = 0.0f;
|
|
m_LastTimeOnGround = vehicleVariables.timeInMs;
|
|
}
|
|
else
|
|
{
|
|
//Calculate speed variable for all vehicles
|
|
u32 numValidWheels = 0;
|
|
u32 numValidDriveWheels = 0;
|
|
f32 sum = 0.0f;
|
|
u32 numTouching = 0;
|
|
u32 numNonBurstTouching = 0;
|
|
u32 numFrontWheelsTouching = 0;
|
|
u32 numDriveWheelsTouchingWater = 0;
|
|
u32 numDriveWheelsTouchingShallowWater = 0;
|
|
u32 numWheels = m_Vehicle->GetNumWheels();
|
|
|
|
for(s32 i = 0; i < numWheels; i++)
|
|
{
|
|
CWheel* wheel = m_Vehicle->GetWheel(i);
|
|
|
|
if(wheel)
|
|
{
|
|
s32 wheelId = wheel->GetHierarchyId();
|
|
|
|
if(wheelId >= VEH_WHEEL_FIRST_WHEEL && wheelId < VEH_WHEEL_FIRST_WHEEL + 4)
|
|
{
|
|
numValidWheels++;
|
|
f32 groundSpeed = wheel->GetGroundSpeed();
|
|
sum += groundSpeed;
|
|
|
|
if(wheel->GetIsTouching())
|
|
{
|
|
numTouching++;
|
|
|
|
if(wheel->GetTyreHealth() > 0.0f)
|
|
{
|
|
numNonBurstTouching++;
|
|
}
|
|
|
|
if(wheelId == VEH_WHEEL_LF || wheelId == VEH_WHEEL_RF)
|
|
{
|
|
numFrontWheelsTouching++;
|
|
}
|
|
}
|
|
|
|
if(wheel->GetIsDriveWheel())
|
|
{
|
|
numValidDriveWheels++;
|
|
|
|
if(wheel->GetDynamicFlags().IsFlagSet(WF_INSHALLOWWATER))
|
|
{
|
|
numDriveWheelsTouchingShallowWater++;
|
|
|
|
if(wheel->GetDynamicFlags().IsFlagSet(WF_INDEEPWATER))
|
|
{
|
|
numDriveWheelsTouchingWater++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
f32 invValidWheels = numValidWheels > 0? 1.0f/numValidWheels : 0;
|
|
f32 invValidDriveWheels = numValidDriveWheels > 0? 1.0f/numValidDriveWheels : 0;
|
|
vehicleVariables.wheelSpeed = sum * invValidWheels;
|
|
vehicleVariables.wheelSpeedAbs = Abs(vehicleVariables.wheelSpeed);
|
|
vehicleVariables.wheelSpeedRatio = Min(1.f, vehicleVariables.wheelSpeedAbs * vehicleVariables.invDriveMaxVelocity);
|
|
vehicleVariables.roadNoisePitch = (s32)sm_RoadNoisePitchCurve.CalculateValue(vehicleVariables.wheelSpeedAbs);
|
|
vehicleVariables.movementSpeed = m_CachedVehicleVelocity.Mag();
|
|
vehicleVariables.numNonBurstWheelsTouching = numNonBurstTouching;
|
|
|
|
// Prevent underwater skids
|
|
if(!m_Vehicle->m_nVehicleFlags.bIsDrowning)
|
|
{
|
|
vehicleVariables.numWheelsTouchingFactor = numTouching * invValidWheels;
|
|
vehicleVariables.numWheelsTouching = numTouching;
|
|
}
|
|
else
|
|
{
|
|
vehicleVariables.numWheelsTouchingFactor = 0.0f;
|
|
vehicleVariables.numWheelsTouching = 0;
|
|
}
|
|
|
|
vehicleVariables.numDriveWheelsInShallowWaterFactor = numDriveWheelsTouchingShallowWater * invValidDriveWheels;
|
|
vehicleVariables.numDriveWheelsInWaterFactor = numDriveWheelsTouchingWater * invValidDriveWheels;
|
|
|
|
if(vehicleVariables.numWheelsTouching > 0)
|
|
{
|
|
m_LastTimeOnGround = vehicleVariables.timeInMs;
|
|
}
|
|
else
|
|
{
|
|
m_LastTimeInAir = vehicleVariables.timeInMs;
|
|
}
|
|
|
|
if(m_Vehicle->GetNumWheels() == 4 && vehicleVariables.numWheelsTouching == 2 && numFrontWheelsTouching == 1)
|
|
{
|
|
m_LastTimeTwoWheeling = vehicleVariables.timeInMs;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity InitVehicle
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::InitVehicle()
|
|
{
|
|
// This needs to be done before InitVehicleSpecific in case any vehicle types rely on engine/exhaust positions for initializing volume cones
|
|
CalculateEngineExhaustPositions();
|
|
|
|
if(InitVehicleSpecific())
|
|
{
|
|
if(m_Vehicle->GetNumWheels() > 0)
|
|
{
|
|
Vector3 frontPos, backPos;
|
|
GetWheelPosition(0,frontPos);
|
|
GetWheelPosition(m_Vehicle->GetNumWheels()-1,backPos);
|
|
m_DistanceBetweenWheels = frontPos.Dist(backPos);
|
|
m_LastRoadPosFront.x = frontPos.x;
|
|
m_LastRoadPosFront.y = frontPos.y;
|
|
m_LastRoadPosBack.x = backPos.x;
|
|
m_LastRoadPosBack.y = backPos.y;
|
|
}
|
|
|
|
m_ClatterOffsetPos = Vector3(0.0f, -m_Vehicle->GetBoundingBoxMax().GetY() * 0.5f, 0.0f);
|
|
m_LastClatterWorldPos = m_Vehicle->TransformIntoWorldSpace(m_ClatterOffsetPos);
|
|
m_LastFreewayBumpBack = m_LastFreewayBumpFront = fwTimer::GetTimeInMilliseconds();
|
|
|
|
if (IsGoKart())
|
|
{
|
|
m_SkidPitchOffset = 800;
|
|
}
|
|
|
|
if(m_FakeEngineHealth == -1)
|
|
{
|
|
// Default to full health
|
|
m_FakeEngineHealth = 1000;
|
|
m_FakeBodyHealth = 1000;
|
|
|
|
switch(GetRandomDamageClass())
|
|
{
|
|
case RANDOM_DAMAGE_ALWAYS:
|
|
m_FakeEngineHealth = static_cast<s16>(audEngineUtil::GetRandomNumberInRange(200.0f, 400.0f));
|
|
m_FakeBodyHealth = static_cast<s16>(audEngineUtil::GetRandomNumberInRange(200.0f, 400.0f));;
|
|
break;
|
|
case RANDOM_DAMAGE_WORKHORSE:
|
|
if(audEngineUtil::ResolveProbability(0.5f))
|
|
{
|
|
m_FakeEngineHealth = static_cast<s16>(audEngineUtil::GetRandomNumberInRange(400.0f, 1000.0f));
|
|
m_FakeBodyHealth = static_cast<s16>(audEngineUtil::GetRandomNumberInRange(400.0f, 1000.0f));;
|
|
}
|
|
break;
|
|
case RANDOM_DAMAGE_OCCASIONAL:
|
|
{
|
|
if(audEngineUtil::ResolveProbability(0.1f))
|
|
{
|
|
m_FakeEngineHealth = static_cast<s16>(audEngineUtil::GetRandomNumberInRange(700.0f, 1000.0f));
|
|
m_FakeBodyHealth = static_cast<s16>(audEngineUtil::GetRandomNumberInRange(700.0f, 1000.0f));;
|
|
}
|
|
}
|
|
break;
|
|
case RANDOM_DAMAGE_NONE:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity InitSubmersible
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::InitSubmersible(BoatAudioSettings* boatSettings)
|
|
{
|
|
m_SubRevsToSweetenerVolume.Init(boatSettings->TurningToSweetenerVolume);
|
|
m_SubTurningToSweetenerVolume.Init(boatSettings->TurningToSweetenerVolume);
|
|
m_SubTurningToSweetenerPitch.Init(boatSettings->TurningToSweetenerPitch);
|
|
m_SubTurningEnginePitchModifier.Init(boatSettings->SubTurningEnginePitchModifier);
|
|
m_SubRevsToSweetenerVolume.Init(boatSettings->RevsToSweetenerVolume);
|
|
m_SubDiveVelocitySmoother.Init(0.02f, 0.01f, true);
|
|
m_SubAngularVelocityVolumeSmoother.Init(0.1f, 0.05f, true);
|
|
}
|
|
|
|
#if __BANK
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateDebug
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateDebug()
|
|
{
|
|
#if NA_RADIO_ENABLED
|
|
if(g_ShowRadioGenres)
|
|
{
|
|
RadioGenre g1 = RADIO_GENRE_UNSPECIFIED, g2 = RADIO_GENRE_UNSPECIFIED;
|
|
s32 ig1 = 0;
|
|
s32 ig2 = 0;
|
|
|
|
if(m_Vehicle->GetDriver())
|
|
{
|
|
m_Vehicle->GetDriver()->GetPedRadioCategory(ig1, ig2);
|
|
if(ig1 != -1)
|
|
{
|
|
g1 = (RadioGenre)ig1;
|
|
}
|
|
if(ig2 != -1)
|
|
{
|
|
g2 = (RadioGenre)ig2;
|
|
}
|
|
}
|
|
|
|
|
|
char buf[256];
|
|
|
|
const char *stationName = m_RadioStation? m_RadioStation->GetName() : "NULL";
|
|
formatf(buf, "%s\nped1: %s\nped2: %s\nveh: %s\nactual: %s", stationName, RadioGenre_ToString(g1), RadioGenre_ToString(g2), RadioGenre_ToString(m_RadioGenre), m_RadioStation? RadioGenre_ToString(m_RadioStation->GetGenre()) : "NULL");
|
|
grcDebugDraw::Text(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), m_RadioStation? Color32(255,255,255,255) : Color32(255,255,255,96), buf);
|
|
}
|
|
#endif
|
|
|
|
if(g_AudioDebugEntity == m_Vehicle)
|
|
{
|
|
if (m_EnvironmentGroup)
|
|
{
|
|
m_EnvironmentGroup->SetAsDebugEnvironmentGroup(true);
|
|
}
|
|
|
|
#if __DEV
|
|
SetAsDebugEntity(true);
|
|
#endif
|
|
|
|
if(g_BreakOnVehicleUpdate)
|
|
{
|
|
__debugbreak();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_EnvironmentGroup)
|
|
{
|
|
m_EnvironmentGroup->SetAsDebugEnvironmentGroup(false);
|
|
}
|
|
|
|
#if __DEV
|
|
SetAsDebugEntity(false);
|
|
#endif
|
|
}
|
|
|
|
if(g_ShowFocusVehicle)
|
|
{
|
|
if(m_IsFocusVehicle)
|
|
{
|
|
grcDebugDraw::Sphere(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), 3.f, Color32(0,255,0,128));
|
|
}
|
|
}
|
|
|
|
if(g_ShowEngineStates)
|
|
{
|
|
Color32 colour;
|
|
|
|
switch(m_VehicleLOD)
|
|
{
|
|
case AUD_VEHICLE_LOD_DUMMY:
|
|
colour = Color32(0,0,255,128);
|
|
break;
|
|
case AUD_VEHICLE_LOD_DISABLED:
|
|
colour = Color32(255,0,0,128);
|
|
break;
|
|
case AUD_VEHICLE_LOD_SUPER_DUMMY:
|
|
colour = Color32(255,255,255,128);
|
|
break;
|
|
default:
|
|
colour = Color32(0,255,0,128);
|
|
break;
|
|
}
|
|
|
|
Vector3 vehiclePos = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
grcDebugDraw::Sphere(vehiclePos, 3.f, colour);
|
|
|
|
switch(m_PrevDesiredLOD)
|
|
{
|
|
case AUD_VEHICLE_LOD_DUMMY:
|
|
colour = Color32(0,0,255,128);
|
|
break;
|
|
case AUD_VEHICLE_LOD_DISABLED:
|
|
colour = Color32(255,0,0,128);
|
|
break;
|
|
case AUD_VEHICLE_LOD_SUPER_DUMMY:
|
|
colour = Color32(255,255,255,128);
|
|
break;
|
|
default:
|
|
colour = Color32(0,255,0,128);
|
|
break;
|
|
}
|
|
|
|
vehiclePos.SetZ(vehiclePos.GetZ() + 3.5f);
|
|
grcDebugDraw::Sphere(vehiclePos, 0.5f, colour);
|
|
}
|
|
|
|
if(g_DrawLinesToVehiclesWithWaveSlots)
|
|
{
|
|
if(GetWaveSlot())
|
|
{
|
|
grcDebugDraw::Line(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetPosition()), Color32(255,0,0), Color32(255,0,0));
|
|
}
|
|
}
|
|
|
|
if(g_DrawLinesToVehiclesWithSubmixVoices)
|
|
{
|
|
audSound* engineEffectSubmixSound = GetEngineEffectSubmixSound();
|
|
audSound* exhaustEffectSubmixSound = GetExhaustEffectSubmixSound();
|
|
|
|
if(engineEffectSubmixSound && exhaustEffectSubmixSound && engineEffectSubmixSound->GetPlayState() == AUD_SOUND_PLAYING && exhaustEffectSubmixSound->GetPlayState() == AUD_SOUND_PLAYING)
|
|
{
|
|
grcDebugDraw::Line(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetPosition()), Color32(0,0,255), Color32(0,0,255));
|
|
}
|
|
}
|
|
|
|
if(g_DrawLinesToRealCars)
|
|
{
|
|
if(m_VehicleType == AUD_VEHICLE_CAR && m_VehicleLOD == AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
grcDebugDraw::Line(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetPosition()), Color32(0,255,0), Color32(0,255,0));
|
|
}
|
|
}
|
|
|
|
if(g_DrawVehiclesInModShop)
|
|
{
|
|
grcDebugDraw::Sphere(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), 2.f, m_InCarModShop? Color32(0,255,0,128) : Color32(255,0,0,128));
|
|
}
|
|
|
|
if(g_ShowVehiclesWithWaveSlots)
|
|
{
|
|
Color32 colour;
|
|
|
|
if(GetWaveSlot())
|
|
{
|
|
colour = Color32(0,255,0,128);
|
|
}
|
|
else
|
|
{
|
|
colour = Color32(255,0,0,128);
|
|
}
|
|
|
|
grcDebugDraw::Sphere(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), 3.f, colour);
|
|
}
|
|
|
|
if(g_ShowEngineExhaust)
|
|
{
|
|
Vec3V pos;
|
|
pos = m_Vehicle->TransformIntoWorldSpace(m_EngineOffsetPos);
|
|
grcDebugDraw::Sphere(pos, 0.5f, Color32(255,0,0));
|
|
pos = m_Vehicle->TransformIntoWorldSpace(m_ExhaustOffsetPos);
|
|
grcDebugDraw::Sphere(pos, 0.5f, Color32(0,0,255));
|
|
}
|
|
|
|
if(g_ShowNPCRoadNoiseState)
|
|
{
|
|
Color32 colour = Color32(255,0,0,(s32)(255.0f * (1.0f - m_PrevNPCRoadNoiseAttenuation)));
|
|
grcDebugDraw::Sphere(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), 3.f, colour);
|
|
grcDebugDraw::Line(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetPosition()), colour, colour);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateDrowning
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateDrowning(audVehicleVariables& params)
|
|
{
|
|
bool canDrown = true;
|
|
f32 maxDepthFactor = 0.4f;
|
|
bool isSubmersible = IsSubmersible();
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_BOAT || m_Vehicle->InheritsFromAmphibiousAutomobile() || isSubmersible)
|
|
{
|
|
if(isSubmersible)
|
|
{
|
|
maxDepthFactor = 1.25f;
|
|
}
|
|
else
|
|
{
|
|
canDrown = false;
|
|
}
|
|
}
|
|
|
|
if(canDrown || isSubmersible)
|
|
{
|
|
f32 engineDepthFactor = 0.0f;
|
|
|
|
#if __BANK
|
|
if(g_SimulateDrowning)
|
|
{
|
|
engineDepthFactor = 1.0f;
|
|
m_EngineWaterDepth = 0.0f;
|
|
}
|
|
else
|
|
#endif
|
|
if(m_Vehicle->m_nFlags.bPossiblyTouchesWater && !m_Vehicle->m_nFlags.bInMloRoom)
|
|
{
|
|
f32 waterZ = 0.f;
|
|
Vector3 vRiverHitPos, vRiverHitNormal;
|
|
Vector3 buoyancyProbePos = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
bool inRiver = m_Vehicle->m_Buoyancy.GetCachedRiverBoundProbeResult(vRiverHitPos, vRiverHitNormal) && (vRiverHitPos.z+REJECTIONABOVEWATER) > buoyancyProbePos.z;
|
|
Vector3 enginePos;
|
|
|
|
// If we're in a river, then we have to calculate the height at the buoyancy probe position, otherwise we can get inaccurate water height results
|
|
// when sitting on a riverbed at a steep angle
|
|
if(inRiver)
|
|
{
|
|
enginePos.z = buoyancyProbePos.z + m_EngineOffsetPos.GetZf();
|
|
waterZ = vRiverHitPos.z;
|
|
}
|
|
// If we're in standard water then we can query the water level directly
|
|
else
|
|
{
|
|
enginePos = VEC3V_TO_VECTOR3(m_Vehicle->TransformIntoWorldSpace(m_EngineOffsetPos));
|
|
Water::GetWaterLevel(enginePos, &waterZ, false, POOL_DEPTH, REJECTIONABOVEWATER, NULL);
|
|
}
|
|
|
|
m_EngineWaterDepth = enginePos.z - waterZ;
|
|
|
|
if(waterZ > enginePos.z)
|
|
{
|
|
engineDepthFactor = Clamp((waterZ - enginePos.z)/maxDepthFactor, 0.0f, 1.0f);
|
|
|
|
if(engineDepthFactor >= 0.9f)
|
|
{
|
|
if(!m_PlayedDiveSound)
|
|
{
|
|
if (GetVehicleModelNameHash() != ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
TriggerWaterDiveSound();
|
|
}
|
|
|
|
m_PlayedDiveSound = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_EngineWaterDepth = 0.0f;
|
|
}
|
|
|
|
if(isSubmersible && Water::IsCameraUnderwater())
|
|
{
|
|
engineDepthFactor = 1.0f;
|
|
}
|
|
|
|
// Don't allow drowning factor to increase while the screen is faded
|
|
if(!camInterface::IsFadedOut() || engineDepthFactor < m_DrowningFactor)
|
|
{
|
|
m_DrowningFactor = m_DrowningFactorSmoother.CalculateValue(engineDepthFactor, fwTimer::GetTimeInMilliseconds());
|
|
}
|
|
|
|
if(m_PlayedDiveSound)
|
|
{
|
|
if(engineDepthFactor <= 0.4f && !IsWaterDiveSoundPlaying())
|
|
{
|
|
m_PlayedDiveSound = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_VehicleType != AUD_VEHICLE_BOAT && !IsInAmphibiousBoatMode())
|
|
{
|
|
if(m_DrowningFactor > 0.0f && m_EngineWaterDepth > -0.7f)
|
|
{
|
|
if(!m_WaterLappingSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateAndPlaySound_Persistent(sm_ExtrasSoundSet.Find(ATSTRINGHASH("CarWaterLappingLoop", 0xF60AB708)), &m_WaterLappingSound, &initParams);
|
|
}
|
|
|
|
if(m_WaterLappingSound)
|
|
{
|
|
f32 waterLappingVolLin = 1.0f - Min(params.fwdSpeedAbs/5.0f, 1.0f);
|
|
m_WaterLappingSound->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(waterLappingVolLin));
|
|
}
|
|
}
|
|
else if(m_WaterLappingSound)
|
|
{
|
|
m_WaterLappingSound->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdatePedStatus
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdatePedStatus(const u32 distFromListenerSquared)
|
|
{
|
|
const CPed* localPlayerPed = NULL;
|
|
|
|
if(g_PlayerSwitch.IsActive() && camInterface::GetGameplayDirector().GetSwitchHelper())
|
|
{
|
|
localPlayerPed = camInterface::GetGameplayDirector().GetSwitchHelper()->GetNewPed();
|
|
}
|
|
|
|
if(localPlayerPed == NULL)
|
|
{
|
|
localPlayerPed = FindPlayerPed();
|
|
}
|
|
|
|
CVehicle* localPlayerVeh = NULL;
|
|
|
|
if(localPlayerPed && localPlayerPed->GetPedConfigFlag( CPED_CONFIG_FLAG_InVehicle ))
|
|
{
|
|
localPlayerVeh = localPlayerPed->GetMyVehicle();
|
|
}
|
|
|
|
CPed *vehicleDriver = m_Vehicle->GetDriver();
|
|
|
|
if(vehicleDriver)
|
|
{
|
|
m_LastVehicleDriver = vehicleDriver;
|
|
}
|
|
|
|
bool wasPlayerVehicle = m_IsPlayerVehicle;
|
|
bool wasFocusVehicle = m_IsFocusVehicle;
|
|
|
|
m_IsPlayerSeatedInVehicle = false;
|
|
m_IsPlayerVehicle = false;
|
|
m_IsFocusVehicle = false;
|
|
m_IsPlayerDrivingVehicle = false;
|
|
|
|
// The player isn't yet in a vehicle, or they are and its this one, then update the status. Only bother doing this on nearby vehicles
|
|
u32 distance = 900;
|
|
if(m_Vehicle->GetIsAircraft()) // you can get much further away from the players aircrsft, especially large planes
|
|
{
|
|
distance = 50000;
|
|
}
|
|
|
|
if((!localPlayerVeh && distFromListenerSquared < distance) || localPlayerVeh == m_Vehicle)
|
|
{
|
|
for(u32 seatIndex = 0; seatIndex < m_Vehicle->GetSeatManager()->GetMaxSeats(); seatIndex++)
|
|
{
|
|
CPed* pedInSeat = m_Vehicle->GetSeatManager()->GetPedInSeat(seatIndex);
|
|
|
|
if(pedInSeat)
|
|
{
|
|
if(pedInSeat == localPlayerPed)
|
|
{
|
|
bool isPedInCar = true;
|
|
m_IsPlayerVehicle = true;
|
|
m_IsFocusVehicle = true;
|
|
|
|
// want to start fading early if the player is getting in a car, so treat the car as a player car immediately
|
|
if(pedInSeat->GetPedIntelligence()->GetQueriableInterface()->IsTaskCurrentlyRunning(CTaskTypes::TASK_ENTER_VEHICLE))
|
|
{
|
|
CTaskEnterVehicle *task = (CTaskEnterVehicle*)pedInSeat->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_ENTER_VEHICLE);
|
|
if(task && task->GetState() < CTaskEnterVehicle::State_EnterSeat)
|
|
{
|
|
isPedInCar = false;
|
|
}
|
|
}
|
|
else if(pedInSeat->GetPedIntelligence()->GetQueriableInterface()->IsTaskCurrentlyRunning(CTaskTypes::TASK_EXIT_VEHICLE))
|
|
{
|
|
CTaskExitVehicle *task = (CTaskExitVehicle*)pedInSeat->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_EXIT_VEHICLE);
|
|
if(task && task->GetState() >= CTaskExitVehicle::State_ExitSeat)
|
|
{
|
|
isPedInCar = false;
|
|
}
|
|
}
|
|
|
|
if(pedInSeat == m_Vehicle->GetSeatManager()->GetDriver())
|
|
{
|
|
m_IsPlayerDrivingVehicle = true;
|
|
}
|
|
|
|
m_IsPlayerSeatedInVehicle = isPedInCar;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_IsFocusVehicle |= (m_Vehicle == sm_PlayerPedTargetVehicle);
|
|
m_IsFocusVehicle |= (m_Vehicle == localPlayerVeh);
|
|
|
|
#if __BANK
|
|
if(g_ShowEngineStates && m_IsFocusVehicle)
|
|
{
|
|
char buf[256];
|
|
|
|
formatf(buf, " -- Focus Vehicle -- \nTarget Vehicle: %s\nLocal Player Vehicle: %s\nPlayer Vehicle: %s\nSpectated: %s",
|
|
m_Vehicle == sm_PlayerPedTargetVehicle? "true" : "false",
|
|
m_Vehicle == localPlayerVeh? "true" : "false",
|
|
m_IsPlayerVehicle ? "true" : "false",
|
|
sm_IsSpectatorModeActive && m_IsBeingNetworkSpectated? "true" : "false");
|
|
|
|
grcDebugDraw::Text(GetPosition(), Color_white, buf);
|
|
}
|
|
|
|
bool isHighQualitySlotOwner = (m_VehicleType == AUD_VEHICLE_CAR && static_cast<audCarAudioEntity*>(this)->m_EngineWaveSlot == sm_HighQualityWaveSlotManager.GetWaveSlot(0));
|
|
|
|
if(g_ShowEngineStates)
|
|
{
|
|
char buf[256];
|
|
|
|
if (m_IsFocusVehicle)
|
|
{
|
|
f32 xCoord = 0.5f;
|
|
f32 yCoord = 0.05f;
|
|
formatf(buf, "Focus Vehicle: %s (%llu)", m_Vehicle->GetModelName(), this); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Engine State: %d", (u32)static_cast<audCarAudioEntity*>(this)->GetVehicleEngine()->GetState()); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Is Target Vehicle: %s", m_Vehicle == sm_PlayerPedTargetVehicle ? "true" : "false"); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Is Local Player Vehicle: %s", m_Vehicle == localPlayerVeh ? "true" : "false"); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Is Player Vehicle: %s", m_IsPlayerVehicle ? "true" : "false"); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Is Spectated: %s", sm_IsSpectatorModeActive && m_IsBeingNetworkSpectated ? "true" : "false"); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
}
|
|
|
|
if (isHighQualitySlotOwner)
|
|
{
|
|
f32 xCoord = 0.7f;
|
|
f32 yCoord = 0.05f;
|
|
formatf(buf, "High Quality Slot Owner: %s (%llu)", m_Vehicle->GetModelName(), this); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Engine State: %d", (u32)static_cast<audCarAudioEntity*>(this)->GetVehicleEngine()->GetState()); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Is Target Vehicle: %s", m_Vehicle == sm_PlayerPedTargetVehicle ? "true" : "false"); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Is Local Player Vehicle: %s", m_Vehicle == localPlayerVeh ? "true" : "false"); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Is Player Vehicle: %s", m_IsPlayerVehicle ? "true" : "false"); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
formatf(buf, "Is Spectated: %s", sm_IsSpectatorModeActive && m_IsBeingNetworkSpectated ? "true" : "false"); grcDebugDraw::Text(Vector2(xCoord, yCoord), Color_white, buf); yCoord += 0.02f;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(sm_IsSpectatorModeActive)
|
|
{
|
|
if(!m_IsBeingNetworkSpectated)
|
|
{
|
|
m_IsPlayerVehicle = false;
|
|
m_IsFocusVehicle = false;
|
|
m_IsPlayerSeatedInVehicle = false;
|
|
}
|
|
else
|
|
{
|
|
m_IsPlayerVehicle = true;
|
|
m_IsFocusVehicle = true;
|
|
m_IsPlayerSeatedInVehicle = true;
|
|
}
|
|
}
|
|
|
|
// Track remote players getting into and out of vehicles so that we can
|
|
// attach synths to them as necessary
|
|
if(NetworkInterface::IsGameInProgress() && m_Vehicle->ContainsPlayer())
|
|
{
|
|
if(!m_IsNetworkPlayerSeatedInVehicle)
|
|
{
|
|
m_IsNetworkPlayerSeatedInVehicle = true;
|
|
|
|
if(!m_IsFocusVehicle && g_AllowSynthsOnNetworkVehicles)
|
|
{
|
|
m_ResetDSPEffects = true;
|
|
m_ReapplyDSPPresets = true;
|
|
}
|
|
}
|
|
}
|
|
else if(m_IsNetworkPlayerSeatedInVehicle)
|
|
{
|
|
m_IsNetworkPlayerSeatedInVehicle = false;
|
|
|
|
if(!m_IsFocusVehicle && g_AllowSynthsOnNetworkVehicles)
|
|
{
|
|
m_ResetDSPEffects = true;
|
|
m_ReapplyDSPPresets = true;
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_TreatAsPedCar)
|
|
{
|
|
m_IsPlayerSeatedInVehicle = false;
|
|
m_IsPlayerVehicle = false;
|
|
m_IsFocusVehicle = false;
|
|
}
|
|
#endif
|
|
|
|
if(m_IsFocusVehicle != wasFocusVehicle)
|
|
{
|
|
OnFocusVehicleChanged();
|
|
|
|
if(m_IsFocusVehicle && (m_IsPlayerVehicle || m_Vehicle == sm_PlayerPedTargetVehicle))
|
|
{
|
|
audDisplayf("Focus vehicle changed - vehicle engine is currently %s and playing radio station %s"
|
|
, m_Vehicle->m_nVehicleFlags.bEngineOn? "ON" : "OFF"
|
|
, m_RadioStation ? m_RadioStation->GetName() : "NULL"
|
|
);
|
|
}
|
|
|
|
// Minitank has an NPC and player version of the track loop so we need to reset this when swapping
|
|
if (GetVehicleModelNameHash() == ATSTRINGHASH("MINITANK", 0xB53C6C52) && m_CaterpillarTrackLoop)
|
|
{
|
|
m_CaterpillarTrackLoop->StopAndForget(true);
|
|
}
|
|
}
|
|
|
|
// GTA V bug fix - check for vehicles being stuck at the wrong quality setting and reset them if necessary
|
|
audVehicleEngine* vehicleEngine = GetVehicleEngine();
|
|
|
|
if(vehicleEngine)
|
|
{
|
|
if(vehicleEngine->HasBeenInitialised() && (vehicleEngine->GetState() == audVehicleEngine::AUD_ENGINE_ON || vehicleEngine->GetState() == audVehicleEngine::AUD_ENGINE_STARTING))
|
|
{
|
|
const audGranularMix::audGrainPlayerQuality currentEngineQuality = vehicleEngine->GetGranularEngineQuality();
|
|
|
|
if(currentEngineQuality != vehicleEngine->GetDesiredEngineQuality())
|
|
{
|
|
vehicleEngine->QualitySettingChanged();
|
|
}
|
|
}
|
|
}
|
|
// End GTA V bug fix
|
|
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
g_ReflectionsAudioEntity.AttachToVehicle(this);
|
|
}
|
|
else if(m_IsPlayerVehicle != wasPlayerVehicle)
|
|
{
|
|
g_ReflectionsAudioEntity.DetachFromVehicle(this);
|
|
}
|
|
|
|
if(localPlayerVeh && localPlayerVeh == m_Vehicle)
|
|
{
|
|
m_LastPlayerVehicle = true;
|
|
}
|
|
else if(localPlayerVeh)
|
|
{
|
|
m_LastPlayerVehicle = false;
|
|
}
|
|
|
|
if (!localPlayerPed || localPlayerPed->IsDead())
|
|
{
|
|
m_IsSirenOn = false;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity PreUpdateService
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::PreUpdateService(u32 timeInMs)
|
|
{
|
|
if (!g_AudioEngine.IsAudioEnabled() || m_ForcedGameObjectResetRequired)
|
|
{
|
|
return;
|
|
}
|
|
if (!m_Vehicle)
|
|
{
|
|
naErrorf("a vehicle audio entity has to have an owning vehicle");
|
|
return;
|
|
}
|
|
|
|
if(m_IsWaitingToInit)
|
|
{
|
|
if(InitVehicle())
|
|
{
|
|
m_IsWaitingToInit = false;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_CachedNonCameraRelativeOpenness = -1.0f;
|
|
m_CachedCameraRelativeOpenness = -1.0f;
|
|
|
|
m_DistanceFromListener2LastFrame = m_DistanceFromListener2;
|
|
m_DistanceFromListener2 = static_cast<u32>(MagSquared(Subtract(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(), m_Vehicle->GetVehiclePosition())).Getf());
|
|
m_Vehicle->GetPlaceableTracker()->CalculateOrientation();
|
|
UpdatePedStatus(m_DistanceFromListener2);
|
|
|
|
m_DspSettings.ClearDSPParameters();
|
|
m_DspSettings.timeInMs = timeInMs;
|
|
m_QuadrantDirty = true;
|
|
|
|
audVehicleVariables vehicleVariables = {0};
|
|
PopulateVehicleLODVariables(vehicleVariables);
|
|
|
|
// Trains manage their own LOD system, since they don't take up any granular/submix/wave slots like the other vehicles
|
|
if(m_VehicleType != AUD_VEHICLE_TRAIN && m_VehicleType != AUD_VEHICLE_TRAILER)
|
|
{
|
|
UpdateVehicleLOD(vehicleVariables.fwdSpeedRatio, vehicleVariables.distFromListenerSq, vehicleVariables.visibleBySniper);
|
|
}
|
|
|
|
PopulateVehicleVariables(vehicleVariables);
|
|
|
|
if(IsSubmersible() REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive())) //For replay CPacketSubUpdate updates this.
|
|
{
|
|
m_SubAngularVelocityMag = m_Vehicle->IsEngineOn()? m_SubAngularVelocitySmoother.CalculateValue(GetCachedAngularVelocity().Mag()) : 0.0f;
|
|
}
|
|
|
|
UpdateVehicleSpecific(vehicleVariables, m_DspSettings);
|
|
|
|
if(IsReal())
|
|
{
|
|
UpdateDSPEffects(m_DspSettings, vehicleVariables);
|
|
UpdateCabinTone(vehicleVariables);
|
|
}
|
|
|
|
if(IsReal() || IsDummy())
|
|
{
|
|
audVehicleWheelPositionCache wheelPosCache;
|
|
vehicleVariables.wheelPosCache = &wheelPosCache;
|
|
|
|
if(HasEntityVariableBlock())
|
|
{
|
|
if(m_Vehicle->pHandling)
|
|
{
|
|
SetEntityVariable(ATSTRINGHASH("mass", 0x4BC594CB), m_Vehicle->pHandling->m_fMass);
|
|
}
|
|
|
|
SetEntityVariable(ATSTRINGHASH("roofopenness", 0xB146F028), GetConvertibleRoofOpenness());
|
|
SetEntityVariable(ATSTRINGHASH("Vehicle.HealthFactor", 0xD1F00E32), 1.f - ComputeEffectiveBodyDamageFactor());
|
|
}
|
|
|
|
UpdateClatter(vehicleVariables);
|
|
UpdateRoadNoiseSounds(vehicleVariables);
|
|
UpdateMissileLock();
|
|
UpdateDamageWarning();
|
|
UpdateHeadLights();
|
|
UpdateWeaponBlades();
|
|
|
|
if(m_Vehicle->HasParachute() || m_Vehicle->HasJump())
|
|
{
|
|
UpdateParachuteSound();
|
|
}
|
|
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
UpdateAircraftWarningSpeech();
|
|
}
|
|
}
|
|
else if(!IsDisabled())
|
|
{
|
|
if(m_VehicleType == AUD_VEHICLE_TRAILER && GetVehicleModelNameHash() == ATSTRINGHASH("TRAILERSMALL2", 0x8FD54EBB))
|
|
{
|
|
UpdateMissileLock();
|
|
}
|
|
|
|
if(m_Vehicle->m_nVehicleFlags.bIsBeingTowed)
|
|
{
|
|
UpdateClatter(vehicleVariables);
|
|
}
|
|
else if(m_VehicleClatter)
|
|
{
|
|
m_VehicleClatter->StopAndForget();
|
|
}
|
|
}
|
|
#if GTA_REPLAY
|
|
else
|
|
{
|
|
if(CReplayMgr::IsEditModeActive() && !CReplayMgr::IsJustPlaying() && m_Vehicle->HasJump())
|
|
{
|
|
if(m_Vehicle->GetVehicleType() == VEHICLE_TYPE_CAR)
|
|
{
|
|
CAutomobile* automobile = static_cast<CAutomobile*>(m_Vehicle);
|
|
m_Vehicle->SetJumpRechargeTimer(CVehicle::ms_fJumpRechargeTime);
|
|
automobile->GetVehicleAudioEntity()->SetRechargeSoundStartOffset(0);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(CGameWorld::GetMainPlayerInfo()->AreControlsDisabled())
|
|
{
|
|
StopAndForgetSounds(m_MissileApproachingSound, m_BeingTargetedSound, m_AcquiringTargetSound, m_MissileApproachingSoundImminent);
|
|
}
|
|
|
|
if(!IsDisabled())
|
|
{
|
|
for(s32 loop = 0; loop < m_VehicleGadgets.GetCount(); loop++)
|
|
{
|
|
m_VehicleGadgets[loop]->Update();
|
|
}
|
|
|
|
UpdateRadio();
|
|
UpdateRain(vehicleVariables);
|
|
UpdateDoors();
|
|
UpdateSurfaceSettleSounds(vehicleVariables);
|
|
UpdateDrowning(vehicleVariables);
|
|
UpdateDetachedBonnetSound();
|
|
UpdateWarningSounds(vehicleVariables);
|
|
UpdateWaveImpactSounds(vehicleVariables);
|
|
UpdateClothSounds(vehicleVariables);
|
|
m_VehicleFireAudio.Update();
|
|
UpdateWater(vehicleVariables);
|
|
UpdateLandingGear();
|
|
UpdateWeaponCharge();
|
|
|
|
if (m_Vehicle->HasJump())
|
|
{
|
|
UpdateVehicleJump();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ShouldPlayLandingGearSound = false;
|
|
m_ShouldStopLandingGearSound = false;
|
|
m_InWaterTimer = 0.0f;
|
|
m_OutOfWaterTimer = 0.0f;
|
|
m_WasInWaterLastFrame = true;
|
|
}
|
|
|
|
#if __BANK
|
|
UpdateDebug();
|
|
#endif
|
|
|
|
if (m_Vehicle->UsesSiren() && NetworkInterface::IsInCopsAndCrooks() && !m_IsSirenFucked)
|
|
{
|
|
const f32 damageFactor = ComputeEffectiveBodyDamageFactor();
|
|
|
|
if (damageFactor > g_CopsAndCrooksForceSirenSmashDamage && ENTITY_SEED_PROB(m_Vehicle->GetRandomSeed(), g_CopsAndCrooksForceSirenSmashProbability))
|
|
{
|
|
SmashSiren(true);
|
|
}
|
|
}
|
|
|
|
UpdateSpecialFlightModeTransformSounds();
|
|
UpdateCarRecordings();
|
|
ProcessAnimEvents();
|
|
UpdateEnvironment();
|
|
|
|
if(m_HasToTriggerAlarm)
|
|
{
|
|
m_Vehicle->TriggerCarAlarm();
|
|
m_HasToTriggerAlarm = false;
|
|
}
|
|
|
|
// Updating these except on disabled vehicles,
|
|
if(GetVehicleLOD() < AUD_VEHICLE_LOD_DISABLED || m_IsScriptTriggeredHorn)
|
|
{
|
|
UpdateHorn();
|
|
}
|
|
else
|
|
{
|
|
if(m_HornSound)
|
|
{
|
|
m_HornSound->StopAndForget();
|
|
}
|
|
|
|
m_IsScriptTriggeredHorn = false;
|
|
m_IsHornPermanentlyOn = false;
|
|
m_WasHornPermanentlyOn = false;
|
|
}
|
|
|
|
UpdateSiren(vehicleVariables);
|
|
m_TimeSinceLastBulletHit += fwTimer::GetTimeStepInMilliseconds();
|
|
if(m_TimeSinceLastBulletHit >= SUPERCONDUCTOR.GetGunFightConductor().GetFakeScenesConductor().GetTimeToResetBulletCount())
|
|
{
|
|
m_BulletHitCount = 0;
|
|
}
|
|
|
|
// B*3051438 - Erroneous collisions triggering when rotating the vehicle at low framerates - now scaled by timestep when running below 30fps
|
|
const f32 speedDelta = (m_FwdSpeedLastFrame - vehicleVariables.fwdSpeed) * Max(30.0f, fwTimer::GetInvTimeStep());
|
|
|
|
if(speedDelta >= sm_VehDeltaSpeedForCollision && !m_IsVehicleBeingStopped)
|
|
{
|
|
m_CollisionAudio.Fakeimpact(speedDelta, m_CollisionAudio.GetVehicleCollisionSettings()->FakeImpactScale);
|
|
}
|
|
|
|
if(!GetEnvironmentGroup())
|
|
{
|
|
InitOcclusion();
|
|
}
|
|
|
|
if(m_Vehicle->ContainsLocalPlayer() || (sm_IsSpectatorModeActive && m_IsBeingNetworkSpectated))
|
|
{
|
|
// Send message to the superconductor to stop the QUITE_SCENE
|
|
if(audSuperConductor::sm_StopQSOnPlayerInVehicle && m_Vehicle->GetVehicleType() != VEHICLE_TYPE_BICYCLE)
|
|
{
|
|
ConductorMessageData message;
|
|
message.conductorName = SuperConductor;
|
|
message.message = StopQuietScene;
|
|
message.bExtraInfo = false;
|
|
message.vExtraInfo = Vector3((f32)audSuperConductor::sm_PlayerInVehicleQSFadeOutTime
|
|
,(f32)audSuperConductor::sm_PlayerInVehicleQSDelayTime
|
|
,(f32)audSuperConductor::sm_PlayerInVehicleQSFadeInTime);
|
|
SUPERCONDUCTOR.SendConductorMessage(message);
|
|
}
|
|
|
|
if(GetEnvironmentGroup())
|
|
{
|
|
CreateEnvironmentGroup("VehicleMixGroup",PLAYER_MIXGROUP);
|
|
if(naVerifyf(GetEnvironmentGroup(), "Failed to create environment group for local player vehicle"))
|
|
{
|
|
int mixGroupIdx = GetEnvironmentGroup()->GetMixGroupIndex();
|
|
if(m_PlayerVehicleMixGroupIndex < 0)
|
|
{
|
|
if(mixGroupIdx < 0)
|
|
{
|
|
DYNAMICMIXER.AddEntityToMixGroup(m_Vehicle, ATSTRINGHASH("PLAYER_GROUP", 0xC5FA40AC));
|
|
m_PlayerVehicleMixGroupIndex = GetEnvironmentGroup()->GetMixGroupIndex();
|
|
}
|
|
|
|
}
|
|
else if(mixGroupIdx != m_PlayerVehicleMixGroupIndex)
|
|
{
|
|
m_PlayerVehicleMixGroupIndex = -1;
|
|
RemoveEnvironmentGroup(PLAYER_MIXGROUP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(m_PlayerVehicleMixGroupIndex >= 0 && GetEnvironmentGroup())
|
|
{
|
|
int mixGroupIdx = GetEnvironmentGroup()->GetMixGroupIndex();
|
|
if(m_PlayerVehicleMixGroupIndex == mixGroupIdx)
|
|
{
|
|
DYNAMICMIXER.RemoveEntityFromMixGroup(m_Vehicle);
|
|
}
|
|
m_PlayerVehicleMixGroupIndex = -1;
|
|
RemoveEnvironmentGroup(PLAYER_MIXGROUP);
|
|
}
|
|
|
|
if( GetEnvironmentGroup() )
|
|
{
|
|
m_VehicleUnderCover = ((naEnvironmentGroup*)GetEnvironmentGroup())->IsUnderCover();
|
|
}
|
|
else
|
|
{
|
|
m_VehicleUnderCover = false;
|
|
}
|
|
|
|
// Extra safety check - ensure we kill stunt race scenes once we leave stunt race mode (they should be one-shots anyway)
|
|
if(!SUPERCONDUCTOR.GetVehicleConductor().JumpConductorActive() || !NetworkInterface::IsGameInProgress())
|
|
{
|
|
if(sm_StuntRaceSpeedUpScene)
|
|
{
|
|
sm_StuntRaceSpeedUpScene->Stop();
|
|
sm_StuntRaceSpeedUpScene = NULL;
|
|
}
|
|
|
|
if(sm_StuntRaceSlowDownScene)
|
|
{
|
|
sm_StuntRaceSlowDownScene->Stop();
|
|
sm_StuntRaceSlowDownScene = NULL;
|
|
}
|
|
}
|
|
|
|
if(g_ReflectionsAudioEntity.IsFocusVehicleInStuntTunnel() && g_ReflectionsAudioEntity.GetActiveVehicle() == this)
|
|
{
|
|
if(!m_StuntTunnelSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateAndPlaySound_Persistent(ATSTRINGHASH("DLC_Stunt_Tunnel_Interior_Sound", 0x9A98EAAA), &m_StuntTunnelSound, &initParams);
|
|
}
|
|
}
|
|
else if(m_StuntTunnelSound)
|
|
{
|
|
m_StuntTunnelSound->StopAndForget();
|
|
}
|
|
|
|
m_WasEngineOnLastFrame = m_Vehicle->m_nVehicleFlags.bEngineOn;
|
|
m_FwdSpeedLastFrame = vehicleVariables.fwdSpeed;
|
|
m_WasInInteriorViewLastFrame = vehicleVariables.isInFirstPersonCam;
|
|
m_WasOnStairs = m_OnStairs;
|
|
m_OnStairs = false;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity::RequiresWaveSlot
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::RequiresWaveSlot() const
|
|
{
|
|
return m_Vehicle->m_nVehicleFlags.bEngineOn;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the desired lod for the vehicle
|
|
// ----------------------------------------------------------------
|
|
audVehicleLOD audVehicleAudioEntity::GetDesiredLOD(f32 UNUSED_PARAM(fwdSpeedRatio), u32 UNUSED_PARAM(distFromListenerSq), bool UNUSED_PARAM(visibleBySniper))
|
|
{
|
|
if(m_VehicleType != AUD_VEHICLE_NONE)
|
|
{
|
|
if(m_IsFocusVehicle || RequiresWaveSlot())
|
|
{
|
|
return AUD_VEHICLE_LOD_REAL;
|
|
}
|
|
}
|
|
|
|
return AUD_VEHICLE_LOD_DISABLED;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity GetDistance2FromSniperAimVector
|
|
// ----------------------------------------------------------------
|
|
u32 audVehicleAudioEntity::GetDistance2FromSniperAimVector() const
|
|
{
|
|
const Vector3 vehiclePosition = VEC3V_TO_VECTOR3(GetPosition());
|
|
const camFrame& aimFrame = camInterface::GetPlayerControlCamAimFrame();
|
|
|
|
Vector3 vStart, vShot, vEnd;
|
|
vStart = aimFrame.GetPosition();
|
|
vShot = aimFrame.GetFront();
|
|
vEnd = vStart + vShot * 3000.0f;
|
|
|
|
fwGeom::fwLine positioningLine;
|
|
positioningLine.m_start = vStart;
|
|
positioningLine.m_end = vEnd;
|
|
|
|
Vector3 closestPoint;
|
|
positioningLine.FindClosestPointOnLine(vehiclePosition, closestPoint);
|
|
|
|
// Scale the contribution up as the view zooms in
|
|
const f32 currentFOV = camInterface::GetFov();
|
|
const f32 sniperContribution = audCurveRepository::GetLinearInterpolatedValue(2.0f, 0.5f, 7.5f, 45.0f, currentFOV);
|
|
|
|
// Distance divided by constribution (so sniper view vehicles appear to be closer as you zoom in)
|
|
return (u32)(closestPoint.Dist2(vehiclePosition)/sniperContribution);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity GetVehicleHydraulicsSoundSetName
|
|
// ----------------------------------------------------------------
|
|
u32 audVehicleAudioEntity::GetVehicleHydraulicsSoundSetName() const
|
|
{
|
|
if(m_Vehicle && m_Vehicle->GetVehicleModelInfo() && m_Vehicle->GetVehicleModelInfo()->GetVehicleFlag( CVehicleModelInfoFlags::FLAG_HAS_LOWRIDER_DONK_HYDRAULICS))
|
|
{
|
|
return (m_IsFocusVehicle BANK_ONLY(&& !g_ForceNPCHydraulicSounds)) ? ATSTRINGHASH("HYDRAULIC_SUSPENSION_DONK_SS", 0x34143DB1) : ATSTRINGHASH("HYDRAULIC_SUSPENSION_DONK_NPC_SS", 0x370AA4FE);
|
|
}
|
|
else
|
|
{
|
|
return (m_IsFocusVehicle BANK_ONLY(&& !g_ForceNPCHydraulicSounds)) ? ATSTRINGHASH("HYDRAULIC_SUSPENSION_SS", 0x228F3C64) : ATSTRINGHASH("HYDRAULIC_SUSPENSION_NPC_SS", 0x6B83A0FE);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity ShouldForceEngineOff
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::ShouldForceEngineOff() const
|
|
{
|
|
if(IsSubmarineCar())
|
|
{
|
|
CSubmarineCar* submarineCar = (CSubmarineCar*)m_Vehicle;
|
|
|
|
if(submarineCar->IsInSubmarineMode() ||
|
|
submarineCar->GetAnimationState() == CSubmarineCar::State_StartToSubmarine ||
|
|
submarineCar->GetAnimationState() == CSubmarineCar::State_MoveWheelCoversOut ||
|
|
submarineCar->GetAnimationState() == CSubmarineCar::State_FinishToSub)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else if(GetVehicleModelNameHash() == ATSTRINGHASH("DELUXO", 0x586765FB))
|
|
{
|
|
if(m_Vehicle->GetSpecialFlightModeRatio() > 0.f)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity IsHiddenByNetwork
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsHiddenByNetwork() const
|
|
{
|
|
if(m_Vehicle && NetworkInterface::IsGameInProgress())
|
|
{
|
|
if(NetworkInterface::IsEntityConcealed(*m_Vehicle))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if(NetworkInterface::IsInMPCutscene() && m_Vehicle->IsNetworkClone())
|
|
{
|
|
if(m_Vehicle->GetNetworkObject() && !m_Vehicle->GetNetworkObject()->IsLocalFlagSet(CNetObjGame::LOCALFLAG_SHOWINCUTSCENE))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateVehicleLOD
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateVehicleLOD(f32 fwdSpeedRatio, u32 distanceFromListenerSq, bool visibleBySniper)
|
|
{
|
|
|
|
if(visibleBySniper)
|
|
{
|
|
distanceFromListenerSq = Min(distanceFromListenerSq, GetDistance2FromSniperAimVector());
|
|
}
|
|
|
|
// Remember whether we're within the standard dummy radius scale. This is used in several places to determine whether to play one-shot sounds than need to play
|
|
// on nearby vehicles regardless of the actual dummy/active/disabled state of the car
|
|
bool isSuperDummyValid = distanceFromListenerSq < g_SuperDummyRadiusSq;
|
|
|
|
if(IsDummy())
|
|
{
|
|
PF_INCREMENT(NumDummyVehicles);
|
|
sm_NumDummyVehiclesCounter++;
|
|
audAssertf(m_VehicleType == AUD_VEHICLE_CAR, "Only cars should be using dummy LOD");
|
|
}
|
|
else if(IsReal())
|
|
{
|
|
PF_INCREMENT(NumRealVehicles);
|
|
}
|
|
else if(IsDisabled())
|
|
{
|
|
PF_INCREMENT(NumDisabledVehicles);
|
|
}
|
|
else if(IsSuperDummy())
|
|
{
|
|
PF_INCREMENT(NumSuperDummyVehicles);
|
|
}
|
|
|
|
audVehicleLOD desiredLOD;
|
|
|
|
if(IsHiddenByNetwork())
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
isSuperDummyValid = false;
|
|
}
|
|
else if(m_ScriptPriority == AUD_VEHICLE_SCRIPT_PRIORITY_MAX && (fwdSpeedRatio > 0.0f || m_Vehicle->GetDriver()))
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_REAL;
|
|
}
|
|
else if(CScriptHud::bUsingMissionCreator && !m_Vehicle->IsCollisionEnabled())
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
}
|
|
else
|
|
{
|
|
desiredLOD = GetDesiredLOD(fwdSpeedRatio, distanceFromListenerSq, visibleBySniper);
|
|
|
|
if(visibleBySniper && desiredLOD <= AUD_VEHICLE_LOD_DUMMY)
|
|
{
|
|
m_Vehicle->m_nVehicleFlags.bRefreshVisibility = true;
|
|
|
|
if(m_Vehicle->GetNumVisiblePixels() <= 10)
|
|
{
|
|
desiredLOD = GetDesiredLOD(fwdSpeedRatio, distanceFromListenerSq, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(desiredLOD == AUD_VEHICLE_LOD_DISABLED && isSuperDummyValid)
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_SUPER_DUMMY;
|
|
m_ReapplyDSPEffects = false;
|
|
}
|
|
else if(!m_Vehicle->m_nVehicleFlags.bEngineOn)
|
|
{
|
|
// This was added to fix a case where the player can exit a car and re-enter without the car becoming a super dummy(not super dummy long enough) which is what would trigger the engine wave slot to be released.
|
|
// When this happened the DSP wasn't reapplied so no DSP. This flag basically says we tried to transition to super dummy, so lets check if we need to reapply dsp.
|
|
m_ReapplyDSPEffects = true;
|
|
m_ResetDSPEffects = true;
|
|
m_ReapplyDSPPresets = true;
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_ForcePlayerVehicleLOD != AUD_VEHICLE_LOD_UNKNOWN && m_IsPlayerVehicle)
|
|
{
|
|
desiredLOD = (audVehicleLOD) g_ForcePlayerVehicleLOD;
|
|
}
|
|
else if(g_ForceRealLodOnFocusEntity && GetVehicle() == CDebugScene::FocusEntities_Get(0))
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_REAL;
|
|
}
|
|
#endif
|
|
|
|
bool priorityVehicle = m_IsFocusVehicle;
|
|
|
|
if(desiredLOD == AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
if(IsUsingGranularEngine())
|
|
{
|
|
sm_NumVehiclesInGranularActivationRange++;
|
|
}
|
|
|
|
sm_NumVehiclesInActivationRange++;
|
|
|
|
// Mark this vehicle as using up two slots if we need one for an sfx bank. LOD activation range should then automatically shrink to accommodate this.
|
|
if(m_RequiresSFXBank)
|
|
{
|
|
sm_NumVehiclesInActivationRange++;
|
|
}
|
|
}
|
|
|
|
if(m_DummyLODValid)
|
|
{
|
|
audQuadrants vehicleQuadrant = GetVehicleQuadrant();
|
|
sm_NumVehiclesInDummyRange[vehicleQuadrant]++;
|
|
}
|
|
|
|
if(desiredLOD == m_PrevDesiredLOD)
|
|
{
|
|
m_TimeAtDesiredLOD += fwTimer::GetTimeStep();
|
|
}
|
|
else
|
|
{
|
|
m_PrevDesiredLOD = desiredLOD;
|
|
m_TimeAtDesiredLOD = 0.0f;
|
|
}
|
|
|
|
// This occurs when switching from high to low LOD engines - we free the wave slot then must re-grab it
|
|
if(m_VehicleLOD == desiredLOD)
|
|
{
|
|
if(m_VehicleLOD == AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
if(!m_EngineWaveSlot)
|
|
{
|
|
// url:bugstar:6110277 fix - Fix for personal vehicles (which remain at real lod even with the engine off) from re-grabbing a waveslot after the engine waveslot is released
|
|
if (!(m_IsPersonalVehicle && !m_IsFocusVehicle && !m_Vehicle->m_nVehicleFlags.bEngineOn))
|
|
{
|
|
audAssertf(m_VehicleType == AUD_VEHICLE_NONE || (m_EngineSubmixIndex >= 0 && m_ExhaustSubmixIndex >= 0), "Vehicle does not yet have a submix, type %d", (u32)m_VehicleType);
|
|
|
|
if (AcquireWaveSlot())
|
|
{
|
|
ConvertFromDummy();
|
|
}
|
|
else if (priorityVehicle)
|
|
{
|
|
SetPlayerVehicleStarving();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool lodSwitchValid = false;
|
|
|
|
lodSwitchValid = (m_VehicleLOD != desiredLOD) &&
|
|
(m_TimeAtDesiredLOD > g_MinTimeAtDesiredLOD) &&
|
|
(m_TimeAtCurrentLOD >= g_MinTimeAtCurrentLOD || desiredLOD > m_VehicleLOD || priorityVehicle || IsPlayerVehicleStarving());
|
|
|
|
#if GTA_REPLAY
|
|
// Allow for instant switching to a higher LOD on the focus vehicle in replays
|
|
if(CReplayMgr::IsJustPlaying() && priorityVehicle && desiredLOD < m_VehicleLOD)
|
|
{
|
|
lodSwitchValid = true;
|
|
}
|
|
#endif
|
|
|
|
if(lodSwitchValid)
|
|
{
|
|
switch(m_VehicleLOD)
|
|
{
|
|
case AUD_VEHICLE_LOD_REAL:
|
|
{
|
|
if(desiredLOD == AUD_VEHICLE_LOD_DUMMY)
|
|
{
|
|
// Not enough dummy slots - disabled instead
|
|
if(sm_NumDummyVehiclesLastFrame >= g_MaxDummyVehicles)
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AUD_VEHICLE_LOD_DUMMY:
|
|
{
|
|
if(desiredLOD == AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
// Dummy wants to be real, but player is starving so we need to handle that first
|
|
if(IsPlayerVehicleStarving() && !priorityVehicle)
|
|
{
|
|
desiredLOD = m_VehicleLOD;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AUD_VEHICLE_LOD_DISABLED:
|
|
case AUD_VEHICLE_LOD_SUPER_DUMMY:
|
|
{
|
|
if(desiredLOD == AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
// Disabled wants to be real, but player is starving so we need to handle that first
|
|
if(IsPlayerVehicleStarving() && !priorityVehicle)
|
|
{
|
|
desiredLOD = m_VehicleLOD;
|
|
}
|
|
}
|
|
else if(desiredLOD == AUD_VEHICLE_LOD_DUMMY)
|
|
{
|
|
// Disabled wants to be dummy, but not enough slots so remain where we are
|
|
if(sm_NumDummyVehiclesLastFrame >= g_MaxDummyVehicles)
|
|
{
|
|
desiredLOD = m_VehicleLOD;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(desiredLOD == AUD_VEHICLE_LOD_REAL)
|
|
{
|
|
audAssertf(!m_EngineWaveSlot, "Vehicle already has a wave slot, type %d", (u32)m_VehicleType);
|
|
audAssertf(m_EngineSubmixIndex == -1 && m_ExhaustSubmixIndex == -1, "Vehicle already has a submix, type %d", (u32)m_VehicleType);
|
|
|
|
bool success = false;
|
|
|
|
if(!IsUsingGranularEngine() || CalculateNumVehiclesUsingSubmixes(AUD_VEHICLE_ANY, true, true) < g_MaxGranularEngines)
|
|
{
|
|
if(AcquireWaveSlot())
|
|
{
|
|
success = true;
|
|
}
|
|
}
|
|
|
|
if(!success)
|
|
{
|
|
if(priorityVehicle)
|
|
{
|
|
SetPlayerVehicleStarving();
|
|
}
|
|
|
|
// Failed to become real - promote to dummy as second best best
|
|
if(m_DummyLODValid && m_VehicleLOD > AUD_VEHICLE_LOD_DUMMY)
|
|
{
|
|
if(sm_NumDummyVehiclesLastFrame < g_MaxDummyVehicles)
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_DUMMY;
|
|
}
|
|
else
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_DISABLED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
desiredLOD = m_VehicleLOD;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Any disabled vehicles within the super dummy radius get promoted
|
|
if(desiredLOD == AUD_VEHICLE_LOD_DISABLED && isSuperDummyValid)
|
|
{
|
|
desiredLOD = AUD_VEHICLE_LOD_SUPER_DUMMY;
|
|
}
|
|
|
|
SetLOD(desiredLOD);
|
|
}
|
|
|
|
m_TimeAtCurrentLOD += fwTimer::GetTimeStep();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if the hydraulics system is active
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::AreHydraulicsActive() const
|
|
{
|
|
bool hydraulicsActive = m_Vehicle->m_nVehicleFlags.bPlayerModifiedHydraulics ||
|
|
m_Vehicle->m_nVehicleFlags.bAreHydraulicsAllRaised ||
|
|
HydraulicsModifiedRecently();
|
|
|
|
if(!hydraulicsActive)
|
|
{
|
|
if(m_Vehicle->InheritsFromAutomobile())
|
|
{
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
CWheel* wheel = m_Vehicle->GetWheel(i);
|
|
|
|
if(wheel)
|
|
{
|
|
if(wheel->GetSuspensionHydraulicState() == WHS_LOCK_UP_ALL || wheel->GetSuspensionHydraulicState() == WHS_LOCK_UP)
|
|
{
|
|
hydraulicsActive = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hydraulicsActive;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if the hydraulics have been modified recently
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::HydraulicsModifiedRecently() const
|
|
{
|
|
if(m_Vehicle->InheritsFromAutomobile())
|
|
{
|
|
// Allow a bit of leeway after the hydraulics disengage
|
|
if(fwTimer::GetTimeInMilliseconds() - ((CAutomobile*)m_Vehicle)->GetTimeHydraulicsModified() < g_HydraulicsModifiedTimeoutMs ||
|
|
fwTimer::GetTimeInMilliseconds() - m_LastHydraulicSuspensionStateChangeTime < g_HydraulicsModifiedTimeoutMs)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateVehicleJump
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateVehicleJump()
|
|
{
|
|
//if(m_Vehicle->InheritsFromAutomobile())
|
|
{
|
|
if(!m_Vehicle->IsJumpFullyCharged() && m_Vehicle->m_nVehicleFlags.bEngineOn)
|
|
{
|
|
if(!m_JumpRecharge)
|
|
{
|
|
const u32 vehicleModelNameHash = GetVehicleModelNameHash();
|
|
u32 soundsetName = 0u;
|
|
|
|
if (vehicleModelNameHash == ATSTRINGHASH("MINITANK", 0xB53C6C52))
|
|
{
|
|
soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("ch_vehicle_minitank_player_sounds", 0xCF2B0226) : ATSTRINGHASH("ch_vehicle_minitank_remote_sounds", 0x90AF5388);
|
|
}
|
|
else if (vehicleModelNameHash == ATSTRINGHASH("RUINER2", 0x381E10BD) || vehicleModelNameHash == ATSTRINGHASH("SCRAMJET", 0xD9F0503D))
|
|
{
|
|
soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("DLC_ImportExport_Ruiner2_Sounds", 0xB2AD811) : ATSTRINGHASH("DLC_ImportExport_Ruiner2_NPC_Sounds", 0xF09C7816);
|
|
}
|
|
else
|
|
{
|
|
soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("DLC_AW_Mod_Vehicle_Player_Sounds", 0xD5676608) : ATSTRINGHASH("DLC_AWXM2018_Mod_Vehicle_NPC_Sounds", 0x96866E58);
|
|
}
|
|
|
|
audSoundSet soundset;
|
|
const u32 soundName = IsToyCar() ? ATSTRINGHASH("jump_rc_recharge", 0x70468D4A) : ATSTRINGHASH("recharge", 0xFB025813);
|
|
|
|
if (soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
#if GTA_REPLAY
|
|
if (CReplayMgr::IsJustPlaying())
|
|
{
|
|
initParams.StartOffset = m_RechargeStartOffset;
|
|
}
|
|
#endif
|
|
CreateAndPlaySound_Persistent(soundset.Find(soundName), &m_JumpRecharge, &initParams);
|
|
}
|
|
}
|
|
|
|
if(m_JumpRecharge)
|
|
{
|
|
f32 recharge = m_Vehicle->GetJumpRechargeFraction();
|
|
m_JumpRecharge->FindAndSetVariableValue(ATSTRINGHASH("chargeRemaining", 0x44E9F02C), recharge);
|
|
}
|
|
}
|
|
else if(m_JumpRecharge)
|
|
{
|
|
m_JumpRecharge->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateParachuteSound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateParachuteSound()
|
|
{
|
|
if(m_Vehicle->InheritsFromAutomobile())
|
|
{
|
|
REPLAY_ONLY(bool replayRecordStop = false;)
|
|
|
|
if (m_Vehicle->HasParachute())
|
|
{
|
|
if (((CAutomobile*)m_Vehicle)->IsParachuting())
|
|
{
|
|
if (!m_ParachuteLoop)
|
|
{
|
|
const u32 vehicleModelNameHash = GetVehicleModelNameHash();
|
|
|
|
if (vehicleModelNameHash == ATSTRINGHASH("RUINER2", 0x381E10BD))
|
|
{
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("DLC_ImportExport_Ruiner2_Sounds", 0xB2AD811) : ATSTRINGHASH("DLC_ImportExport_Ruiner2_NPC_Sounds", 0xF09C7816);
|
|
const u32 soundName = ATSTRINGHASH("Descend", 0x3A770027);
|
|
|
|
if (soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound_Persistent(soundset.Find(soundName), &m_ParachuteLoop, &initParams);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (m_ParachuteLoop)
|
|
{
|
|
m_ParachuteLoop->StopAndForget(true);
|
|
// record a packet that will clear parachute state
|
|
REPLAY_ONLY(replayRecordStop = true;)
|
|
}
|
|
}
|
|
|
|
#if GTA_REPLAY
|
|
// we're doing this here because we can be parachuting, but not recharging, but we want to use the same packet
|
|
if(CReplayMgr::ShouldRecord() && (m_JumpRecharge || m_ParachuteLoop || replayRecordStop))
|
|
{
|
|
u32 rechargePlayPosition = 0;
|
|
if(m_JumpRecharge)
|
|
{
|
|
rechargePlayPosition = m_JumpRecharge->GetCurrentPlayTime(g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0));
|
|
}
|
|
f32 rechargeTimer = m_JumpRecharge ? (m_Vehicle)->GetJumpRechargeTimer() : CVehicle::ms_fJumpRechargeTime;
|
|
CReplayMgr::RecordFx<CPacketVehicleJumpRechargeTimer>(CPacketVehicleJumpRechargeTimer(rechargeTimer, rechargePlayPosition, ((CAutomobile*)m_Vehicle)->GetParachuteState()), m_Vehicle);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity ToggleHeliWings
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ToggleHeliWings(bool deploy)
|
|
{
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("AKULA", 0x46699F47))
|
|
{
|
|
audSoundInitParams initParams;
|
|
audSoundSet soundSet;
|
|
|
|
if(m_Vehicle && soundSet.Init(ATSTRINGHASH("akula_sounds", 0x6CC7612D)))
|
|
{
|
|
const u32 soundHash = deploy? ATSTRINGHASH("gun_flaps_open", 0xFF8D5D1B) : ATSTRINGHASH("gun_flaps_close", 0xD1A0023);
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(soundSet.Find(soundHash), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundSet.GetNameHash(), soundHash, &initParams, m_Vehicle));
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity TriggerSubmarineDiveSound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSubmarineDiveSound(u32 soundHash)
|
|
{
|
|
//Trigger offline or owner only
|
|
if (!NetworkInterface::IsGameInProgress() || !m_Vehicle->IsNetworkClone())
|
|
{
|
|
audSoundSet soundSet;
|
|
|
|
if (soundSet.Init(ATSTRINGHASH("DLC_Hei4_Kosatka_Sounds", 0xBDDCF962)))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(soundSet.Find(soundHash), &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(ATSTRINGHASH("DLC_Hei4_Kosatka_Sounds", 0xBDDCF962), soundHash, &initParams, m_Vehicle));
|
|
|
|
if (NetworkInterface::IsGameInProgress() && m_Vehicle->GetNetworkObject() && !m_Vehicle->IsNetworkClone())
|
|
{
|
|
CPlaySoundEvent::Trigger(m_Vehicle, ATSTRINGHASH("DLC_Hei4_Kosatka_Sounds", 0xBDDCF962), soundHash, 250);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity SetBombBayDoorsOpen
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetBombBayDoorsOpen(bool open)
|
|
{
|
|
audSoundInitParams initParams;
|
|
audSoundSet bombBaySoundSet;
|
|
|
|
if(m_Vehicle && bombBaySoundSet.Init(ATSTRINGHASH("DLC_SM_Bomb_Bay_Doors_Sounds", 0xC7A83A5C)))
|
|
{
|
|
const u32 soundHash = open? ATSTRINGHASH("open", 0x9C783318) : ATSTRINGHASH("close", 0x47C8D769);
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(bombBaySoundSet.Find(soundHash), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(bombBaySoundSet.GetNameHash(), soundHash, &initParams, m_Vehicle));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateWeaponBlades
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWeaponBlades()
|
|
{
|
|
if (m_Vehicle->GetNumWeaponBlades())
|
|
{
|
|
const u32 timeMs = fwTimer::GetTimeInMilliseconds();
|
|
|
|
for (u32 i = 0; i < CVehicle::MAX_NUM_WEAPON_BLADES; i++)
|
|
{
|
|
const s32 lastCollisionTime = (s32)m_LastWeaponBladeCollisionTime[i];
|
|
|
|
if (m_IsWeaponBladeColliding[i])
|
|
{
|
|
const u32 soundSetName = m_IsPlayerVehicle ? ATSTRINGHASH("DLC_AWXM2018_Mod_Vehicle_Player_Sounds", 0x1D430286) : ATSTRINGHASH("DLC_AWXM2018_Mod_Vehicle_NPC_Sounds", 0x96866E58);
|
|
|
|
audSoundSet soundset;
|
|
|
|
if (soundset.Init(soundSetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.u32ClientVar = (u32)AUD_VEHICLE_SOUND_BLADE_0 + i;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.SetVariableValue(ATSTRINGHASH("bladerpm", 0x643CFF51), m_Vehicle->GetWeaponBlade(i).GetCurrentRPM());
|
|
|
|
if (timeMs - lastCollisionTime > 250)
|
|
{
|
|
u32 soundName = m_LastWeaponBladeCollisionIsPed[i] ? ATSTRINGHASH("blade_impact_ped", 0xCC098265) : ATSTRINGHASH("blade_impact", 0xCC444D1B);
|
|
CreateAndPlaySound(soundset.Find(soundName), &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundSetName, soundName, &initParams, m_Vehicle));
|
|
}
|
|
|
|
if (!m_BladeImpactSound[i])
|
|
{
|
|
const u32 soundName = m_LastWeaponBladeCollisionIsPed[i] ? ATSTRINGHASH("blade_sustained_ped", 0x82DA4A2B) : ATSTRINGHASH("blade_sustained", 0x4E799F0C);
|
|
CreateAndPlaySound_Persistent(soundset.Find(soundName), &m_BladeImpactSound[i], &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSoundPersistant(soundSetName, soundName, &initParams, m_BladeImpactSound[i], m_Vehicle));
|
|
}
|
|
}
|
|
|
|
m_IsWeaponBladeColliding[i] = false;
|
|
m_LastWeaponBladeCollisionIsPed[i] = false;
|
|
m_LastWeaponBladeCollisionTime[i] = timeMs;
|
|
}
|
|
else if (m_BladeImpactSound[i] && timeMs - lastCollisionTime > 250)
|
|
{
|
|
m_BladeImpactSound[i]->StopAndForget(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateHeadLights
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateHeadLights()
|
|
{
|
|
if(m_HeadlightsCoverSwitched)
|
|
{
|
|
u32 headlightSoundSetName = 0u;
|
|
const u32 vehicleModelNameHash = GetVehicleModelNameHash();
|
|
|
|
if(vehicleModelNameHash == ATSTRINGHASH("TROPOS", 0x707E63A4))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("tropos_headlights_ss", 0x475A5417);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("RUINER2", 0x381E10BD))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("ruiner2_headlights_ss", 0xA3340CED);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("INFERNUS2", 0xAC33179C))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("infernus2_headlights_ss", 0x1C00E9AD);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("TURISMO2", 0xC575DF11))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("turismo2_headlights_ss", 0x80EF8AB8);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("CHEETAH2", 0xD4E5F4D))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("cheetah2_headlights_ss", 0xA4A804DA);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("TORERO", 0x59A9E570))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("torero_headlights_ss", 0xE6A80549);
|
|
}
|
|
else if (vehicleModelNameHash == ATSTRINGHASH("TORERO2", 0xF62446BA))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("torero2_headlights_ss", 0x1066C5FE);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("ARDENT", 0x97E5533))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("ardent_headlights_ss", 0x61D0BD14);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("VIGILANTE", 0xB5EF4C33))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("vigilante_headlights_ss", 0x5EF539CC);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("VISERIS", 0xE8A8BA94))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("viseris_headlights_ss", 0x65527488);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("ZR350", 0x91373058))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("zr350_headlights_ss", 0x29A9ED20);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("FUTO2", 0xA6297CC8))
|
|
{
|
|
headlightSoundSetName = ATSTRINGHASH("futo2_headlights_ss", 0x5120B2EE);
|
|
}
|
|
|
|
if(headlightSoundSetName != 0u)
|
|
{
|
|
audSoundSet lightCoverSoundset;
|
|
|
|
if(lightCoverSoundset.Init(headlightSoundSetName))
|
|
{
|
|
u32 lightCoverSoundHash = 0;
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_LIGHTCOVER;
|
|
|
|
switch(m_Vehicle->GetHeadlightCoverState())
|
|
{
|
|
case CVehicle::LIGHTCOVER_OPENING:
|
|
lightCoverSoundHash = ATSTRINGHASH("LightCover_PopUp", 0x6B9F809D);
|
|
break;
|
|
|
|
case CVehicle::LIGHTCOVER_CLOSING:
|
|
lightCoverSoundHash = ATSTRINGHASH("LightCover_PopDown", 0x4DA77B7B);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(lightCoverSoundHash != 0)
|
|
{
|
|
audMetadataRef lightCoverSoundRef = lightCoverSoundset.Find(lightCoverSoundHash);
|
|
|
|
if(lightCoverSoundRef != g_NullSoundRef)
|
|
{
|
|
CreateAndPlaySound(lightCoverSoundRef, &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(lightCoverSoundset.GetNameHash(), lightCoverSoundHash, &initParams, m_Vehicle));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_HeadlightsCoverSwitched = false;
|
|
}
|
|
|
|
if(m_HeadlightsSwitched)
|
|
{
|
|
audMetadataRef soundRef = g_NullSoundRef;
|
|
u32 soundHash = 0;
|
|
bool switchedOn = m_Vehicle->m_nVehicleFlags.bHeadlightsFullBeamOn;
|
|
|
|
switch(m_VehicleType)
|
|
{
|
|
case AUD_VEHICLE_CAR:
|
|
if(IsSubmersible())
|
|
{
|
|
soundHash = switchedOn? ATSTRINGHASH("Headlamp_SwitchOn_Submersible", 0x8895D4EA) : ATSTRINGHASH("Headlamp_SwitchOff_Submersible", 0x2051CFDD);
|
|
}
|
|
else
|
|
{
|
|
soundHash = switchedOn? ATSTRINGHASH("Headlamp_SwitchOn", 0xA1D32831) : ATSTRINGHASH("Headlamp_SwitchOff", 0xB9F6F7F);
|
|
}
|
|
break;
|
|
case AUD_VEHICLE_PLANE:
|
|
soundHash = switchedOn? ATSTRINGHASH("Headlamp_SwitchOn_Plane", 0x2FB63D2A) : ATSTRINGHASH("Headlamp_SwitchOff_Plane", 0x8978EF66);
|
|
break;
|
|
case AUD_VEHICLE_BOAT:
|
|
if(m_Vehicle && m_Vehicle->InheritsFromSubmarine())
|
|
{
|
|
soundHash = switchedOn? ATSTRINGHASH("Headlamp_SwitchOn_Submersible", 0x8895D4EA) : ATSTRINGHASH("Headlamp_SwitchOff_Submersible", 0x2051CFDD);
|
|
}
|
|
else
|
|
{
|
|
soundHash = switchedOn? ATSTRINGHASH("Headlamp_SwitchOn_Boat", 0xDFB28208) : ATSTRINGHASH("Headlamp_SwitchOff_Boat", 0x2CD0CA60);
|
|
}
|
|
break;
|
|
case AUD_VEHICLE_BICYCLE:
|
|
soundHash = switchedOn? ATSTRINGHASH("Headlamp_SwitchOn_Bicycle", 0xAB457F9E) : ATSTRINGHASH("Headlamp_SwitchOff_Bicycle", 0x4A6FFF8B);
|
|
break;
|
|
case AUD_VEHICLE_HELI:
|
|
soundHash = switchedOn? ATSTRINGHASH("Headlamp_SwitchOn_Heli", 0x5B2256A6) : ATSTRINGHASH("Headlamp_SwitchOff_Heli", 0x55529031);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(soundHash != 0)
|
|
{
|
|
soundRef = sm_LightsSoundSet.Find(soundHash);
|
|
|
|
if(soundRef != g_NullSoundRef)
|
|
{
|
|
CreateAndPlaySound(soundRef);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(sm_LightsSoundSet.GetNameHash(), soundHash, NULL, m_Vehicle));
|
|
}
|
|
}
|
|
|
|
m_HeadlightsSwitched = false;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity SetHydraulicSuspensionInputAxis
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetHydraulicSuspensionInputAxis(f32 hydraulicSuspensionInputAxisX, f32 hydraulicSuspensionInputAxisY)
|
|
{
|
|
m_PrevHydraulicsInputAxis = m_HydraulicsInputAxis;
|
|
m_HydraulicsInputAxis = Vector2(hydraulicSuspensionInputAxisX, hydraulicSuspensionInputAxisY);
|
|
|
|
if(m_Vehicle && !m_ShouldTriggerHydraulicBounce)
|
|
{
|
|
if(Sign(m_PrevHydraulicsInputAxis.x) != Sign(hydraulicSuspensionInputAxisX) || Sign(m_PrevHydraulicsInputAxis.y) != Sign(hydraulicSuspensionInputAxisY))
|
|
{
|
|
bool allWheelsInFreeMode = true;
|
|
|
|
for( int i = 0; i < m_Vehicle->GetNumWheels(); i++ )
|
|
{
|
|
CWheel *pWheel = m_Vehicle->GetWheel(i);
|
|
|
|
if(!pWheel || pWheel->GetSuspensionHydraulicState() != eWheelHydraulicState::WHS_FREE)
|
|
{
|
|
allWheelsInFreeMode = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(allWheelsInFreeMode)
|
|
{
|
|
TriggerHydraulicBounce(m_IsPlayerVehicle);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_HydraulicSuspensionInputSmoother.CalculateValue((m_HydraulicsInputAxis - m_PrevHydraulicsInputAxis).Mag() * fwTimer::GetInvTimeStep() * 0.1f);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity OnJumpingVehicleJumpActivate
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::OnJumpingVehicleJumpActivate()
|
|
{
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
u32 soundsetName = 0u;
|
|
|
|
if (modelNameHash == ATSTRINGHASH("MINITANK", 0xB53C6C52))
|
|
{
|
|
soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("ch_vehicle_minitank_player_sounds", 0xCF2B0226) : ATSTRINGHASH("ch_vehicle_minitank_remote_sounds", 0x90AF5388);
|
|
}
|
|
else if (modelNameHash == ATSTRINGHASH("RUINER2", 0x381E10BD) || modelNameHash == ATSTRINGHASH("SCRAMJET", 0xD9F0503D))
|
|
{
|
|
soundsetName = m_IsFocusVehicle? ATSTRINGHASH("DLC_ImportExport_Ruiner2_Sounds", 0xB2AD811) : ATSTRINGHASH("DLC_ImportExport_Ruiner2_NPC_Sounds", 0xF09C7816);
|
|
}
|
|
else
|
|
{
|
|
soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("DLC_AW_Mod_Vehicle_Player_Sounds", 0xD5676608) : ATSTRINGHASH("DLC_AW_Mod_Vehicle_NPC_Sounds", 0x29A11603);
|
|
}
|
|
|
|
audSoundSet soundset;
|
|
const u32 soundName = IsToyCar() ? ATSTRINGHASH("jump_rc_activate", 0xCB05A19) : ATSTRINGHASH("jump_activate", 0xF1AFC397);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(soundset.Find(soundName), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundsetName, soundName, &initParams, m_Vehicle));
|
|
}
|
|
|
|
m_IsWaitingOnActivatedJumpLand = true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity OnJumpingVehicleJumpPrimed
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::OnJumpingVehicleJumpPrimed()
|
|
{
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
u32 soundsetName = 0u;
|
|
|
|
if (modelNameHash == ATSTRINGHASH("MINITANK", 0xB53C6C52))
|
|
{
|
|
soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("ch_vehicle_minitank_player_sounds", 0xCF2B0226) : ATSTRINGHASH("ch_vehicle_minitank_remote_sounds", 0x90AF5388);
|
|
}
|
|
else if (modelNameHash == ATSTRINGHASH("RUINER2", 0x381E10BD) || modelNameHash == ATSTRINGHASH("SCRAMJET", 0xD9F0503D))
|
|
{
|
|
soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("DLC_ImportExport_Ruiner2_Sounds", 0xB2AD811) : ATSTRINGHASH("DLC_ImportExport_Ruiner2_NPC_Sounds", 0xF09C7816);
|
|
}
|
|
else
|
|
{
|
|
soundsetName = m_IsFocusVehicle ? ATSTRINGHASH("DLC_AW_Mod_Vehicle_Player_Sounds", 0xD5676608) : ATSTRINGHASH("DLC_AW_Mod_Vehicle_NPC_Sounds", 0x29A11603);
|
|
}
|
|
|
|
audSoundSet soundset;
|
|
const u32 soundName = IsToyCar() ? ATSTRINGHASH("jump_rc_armed", 0xFA26825D) : ATSTRINGHASH("jump_armed", 0xA9B32005);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(soundset.Find(soundName), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundsetName, soundName, &initParams, m_Vehicle));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity OnVehicleParachutePrepare
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::OnVehicleParachuteStabilize()
|
|
{
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
|
|
if(modelNameHash == ATSTRINGHASH("RUINER2", 0x381E10BD))
|
|
{
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = m_IsFocusVehicle? ATSTRINGHASH("DLC_ImportExport_Ruiner2_Sounds", 0xB2AD811) : ATSTRINGHASH("DLC_ImportExport_Ruiner2_NPC_Sounds", 0xF09C7816);
|
|
const u32 soundName = ATSTRINGHASH("Stabilize", 0x13306A9B);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(soundset.Find(soundName), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundsetName, soundName, &initParams, m_Vehicle));
|
|
|
|
if (NetworkInterface::IsGameInProgress() && m_Vehicle->GetNetworkObject() && !m_Vehicle->IsNetworkClone())
|
|
{
|
|
CPlaySoundEvent::Trigger(m_Vehicle, soundsetName, soundName, 100);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity TriggerEMPShutdownSound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerEMPShutdownSound()
|
|
{
|
|
if (m_IsFocusVehicle)
|
|
{
|
|
TriggerSimpleSoundFromSoundset(ATSTRINGHASH("DLC_AW_EMP_Sounds", 0xBBB256C9), ATSTRINGHASH("EMP_vehicle_affected", 0x3F586A15) REPLAY_ONLY(, true));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity TriggerBoostActivateFail
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerBoostActivateFail()
|
|
{
|
|
TriggerSimpleSoundFromSoundset(m_IsPlayerVehicle ? ATSTRINGHASH("DLC_AWXM2018_Mod_Vehicle_Player_Sounds", 0x1D430286) : ATSTRINGHASH("DLC_AWXM2018_Mod_Vehicle_NPC_Sounds", 0x96866E58), ATSTRINGHASH("boost_fail", 0x22A21643) REPLAY_ONLY(, true));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity TriggerSideShunt
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSideShunt()
|
|
{
|
|
TriggerSimpleSoundFromSoundset(m_IsPlayerVehicle ? ATSTRINGHASH("DLC_AW_Mod_Vehicle_Player_Sounds", 0xD5676608) : ATSTRINGHASH("DLC_AW_Mod_Vehicle_NPC_Sounds", 0x29A11603), ATSTRINGHASH("sideswipe", 0x59CD6870) REPLAY_ONLY(, true));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity IsLockedToRadioStation
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsLockedToRadioStation()
|
|
{
|
|
#if HEIST3_HIDDEN_RADIO_ENABLED
|
|
if (GetVehicleModelNameHash() == HEIST3_HIDDEN_RADIO_VEHICLE && m_RadioStation && m_RadioStation->GetNameHash() == HEIST3_HIDDEN_RADIO_STATION_NAME)
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity TriggerStationarySuspensionDrop
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerStationarySuspensionDrop()
|
|
{
|
|
if(!m_WasSuspensionDropped)
|
|
{
|
|
if (GetVehicleModelNameHash() != ATSTRINGHASH("DYNASTY", 0x127E90D5))
|
|
{
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = ATSTRINGHASH("DLC_XM_Air_Suspension_Sounds", 0x6638FEF);
|
|
const u32 soundName = ATSTRINGHASH("air_suspension_down", 0xF7F05AB7);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.u32ClientVar = (u32)AUD_VEHICLE_SOUND_UNKNOWN;
|
|
initParams.UpdateEntity = true;
|
|
CreateDeferredSound(soundset.Find(soundName), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundsetName, soundName, &initParams, m_Vehicle));
|
|
}
|
|
}
|
|
|
|
m_WasSuspensionDropped = true;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity CancelStationarySuspensionDrop
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::CancelStationarySuspensionDrop()
|
|
{
|
|
m_WasSuspensionDropped = false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity TriggerSpecialFlightModeTransform
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSpecialFlightModeTransform(bool flightModeEnabled)
|
|
{
|
|
m_SpecialFlightModeTransformSoundToTrigger = flightModeEnabled? ATSTRINGHASH("transform_to_flight", 0x906FAB11) : ATSTRINGHASH("transform_to_car", 0xD8B90941);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateSpecialFlightModeTransformSounds
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateSpecialFlightModeTransformSounds()
|
|
{
|
|
if(m_SpecialFlightModeTransformSoundToTrigger != 0u)
|
|
{
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("DELUXO", 0x586765FB))
|
|
{
|
|
if(m_SpecialFlightModeTransformSound)
|
|
{
|
|
m_SpecialFlightModeTransformSound->StopAndForget(true);
|
|
}
|
|
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = ATSTRINGHASH("deluxo_transform_ss", 0x33CF0FA6);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.u32ClientVar = (u32)AUD_VEHICLE_SOUND_UNKNOWN;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound_Persistent(soundset.Find(m_SpecialFlightModeTransformSoundToTrigger), &m_SpecialFlightModeTransformSound, &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSoundPersistant(soundsetName, m_SpecialFlightModeTransformSoundToTrigger, &initParams, m_SpecialFlightModeTransformSound, m_Vehicle));
|
|
}
|
|
}
|
|
|
|
m_SpecialFlightModeTransformSoundToTrigger = 0u;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity CancelSpecialFlightModeTransform
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::CancelSpecialFlightModeTransform()
|
|
{
|
|
if(m_SpecialFlightModeTransformSound)
|
|
{
|
|
m_SpecialFlightModeTransformSound->StopAndForget(true);
|
|
}
|
|
|
|
m_SpecialFlightModeTransformSoundToTrigger = 0u;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity TriggerSpecialFlightModeWingDeploy
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSpecialFlightModeWingDeploy(bool deployWings)
|
|
{
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("DELUXO", 0x586765FB))
|
|
{
|
|
if(deployWings != m_SpecialFlightModeWingsDeployed)
|
|
{
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = ATSTRINGHASH("deluxo_transform_ss", 0x33CF0FA6);
|
|
const u32 soundName = deployWings? ATSTRINGHASH("wings_out", 0xA92ED867) : ATSTRINGHASH("wings_in", 0x862E16BE);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.u32ClientVar = (u32)AUD_VEHICLE_SOUND_UNKNOWN;
|
|
initParams.UpdateEntity = true;
|
|
CreateDeferredSound(soundset.Find(soundName), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundsetName, soundName, &initParams, m_Vehicle));
|
|
}
|
|
|
|
m_SpecialFlightModeWingsDeployed = deployWings;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity OnVehicleParachuteDeploy
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::OnVehicleParachuteDeploy()
|
|
{
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
|
|
if(modelNameHash == ATSTRINGHASH("RUINER2", 0x381E10BD))
|
|
{
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = m_IsFocusVehicle? ATSTRINGHASH("DLC_ImportExport_Ruiner2_Sounds", 0xB2AD811) : ATSTRINGHASH("DLC_ImportExport_Ruiner2_NPC_Sounds", 0xF09C7816);
|
|
const u32 soundName = ATSTRINGHASH("Deploy", 0xC9200261);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(soundset.Find(soundName), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundsetName, soundName, &initParams, m_Vehicle));
|
|
|
|
if (NetworkInterface::IsGameInProgress() && m_Vehicle->GetNetworkObject() && !m_Vehicle->GetNetworkObject()->IsClone())
|
|
{
|
|
CPlaySoundEvent::Trigger(m_Vehicle, soundsetName, soundName, 100);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity OnReducedSuspensionForceSet
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::OnReducedSuspensionForceSet(bool isReduced)
|
|
{
|
|
if(isReduced == m_WasReducedSuspensionForceSet)
|
|
{
|
|
return;
|
|
}
|
|
|
|
audSoundSet suspensionForceSoundSet;
|
|
u32 soundSetName = GetVehicleHydraulicsSoundSetName();
|
|
u32 soundName = isReduced ? ATSTRINGHASH("Stance_Lowered", 0x90AA859B) : ATSTRINGHASH("Stance_Raised", 0xC5B6339F);
|
|
|
|
if(suspensionForceSoundSet.Init(soundSetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(suspensionForceSoundSet.Find(soundName), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundSetName, soundName, &initParams, m_Vehicle));
|
|
|
|
/*
|
|
if (NetworkInterface::IsGameInProgress() && m_Vehicle->GetNetworkObject() && !m_Vehicle->GetNetworkObject()->IsClone())
|
|
{
|
|
CPlaySoundEvent::Trigger(m_Vehicle, soundsetName, soundName, 100);
|
|
}
|
|
*/
|
|
}
|
|
|
|
m_WasReducedSuspensionForceSet = isReduced;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity OnVehicleParachuteDetach
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::OnVehicleParachuteDetach()
|
|
{
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
|
|
if(modelNameHash == ATSTRINGHASH("RUINER2", 0x381E10BD))
|
|
{
|
|
audSoundSet soundset;
|
|
const u32 soundsetName = m_IsFocusVehicle? ATSTRINGHASH("DLC_ImportExport_Ruiner2_Sounds", 0xB2AD811) : ATSTRINGHASH("DLC_ImportExport_Ruiner2_NPC_Sounds", 0xF09C7816);
|
|
const u32 soundName = ATSTRINGHASH("Detach", 0xFFC528E4);
|
|
|
|
if(soundset.Init(soundsetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(soundset.Find(soundName), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundsetName, soundName, &initParams, m_Vehicle));
|
|
|
|
if (NetworkInterface::IsGameInProgress() && m_Vehicle->GetNetworkObject() && !m_Vehicle->GetNetworkObject()->IsClone())
|
|
{
|
|
CPlaySoundEvent::Trigger(m_Vehicle, soundsetName, soundName, 100);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity CalculateHydraulicSuspensionAngle
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::CalculateHydraulicSuspensionAngle()
|
|
{
|
|
if(m_Vehicle && m_Vehicle->InheritsFromAutomobile())
|
|
{
|
|
CAutomobile* automobile = static_cast<CAutomobile*>(m_Vehicle);
|
|
f32 suspensionAngleUnitCircleX = 0.f;
|
|
f32 suspensionAngleUnitCircleY = 0.f;
|
|
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
f32 xAxis = 0.0;
|
|
f32 yAxis = 0.0;
|
|
|
|
CWheel *pWheel = m_Vehicle->GetWheel(i);
|
|
|
|
if(pWheel)
|
|
{
|
|
switch(pWheel->GetHierarchyId())
|
|
{
|
|
case VEH_WHEEL_LF:
|
|
xAxis = -0.707f;
|
|
yAxis = 0.707f;
|
|
break;
|
|
case VEH_WHEEL_LR:
|
|
xAxis = -0.707f;
|
|
yAxis = -0.707f;
|
|
break;
|
|
case VEH_WHEEL_RR:
|
|
xAxis = 0.707f;
|
|
yAxis = -0.707f;
|
|
break;
|
|
case VEH_WHEEL_RF:
|
|
xAxis = 0.707f;
|
|
yAxis = 0.707f;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
suspensionAngleUnitCircleX += (xAxis * pWheel->GetSuspensionRaiseAmount() / automobile->m_fHydraulicsUpperBound);
|
|
suspensionAngleUnitCircleY += (yAxis * pWheel->GetSuspensionRaiseAmount() / automobile->m_fHydraulicsUpperBound);
|
|
}
|
|
}
|
|
|
|
m_PrevHydraulicsSuspensionAngle = m_HydraulicsSuspensionAngle;
|
|
m_HydraulicsSuspensionAngle = Vector2(suspensionAngleUnitCircleX, suspensionAngleUnitCircleY);
|
|
m_HydraulicSuspensionAngleSmoother.CalculateValue((m_HydraulicsSuspensionAngle - m_PrevHydraulicsSuspensionAngle).Mag() * fwTimer::GetInvTimeStep() * 0.1f);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateRadio
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateRadio()
|
|
{
|
|
#if NA_RADIO_ENABLED
|
|
if(m_RadioStation && GetAudioVehicleType() != AUD_VEHICLE_BOAT && !IsInAmphibiousBoatMode() && !GetVehicle()->InheritsFromSubmarineCar() && m_DrowningFactor > 0.f)
|
|
{
|
|
if(!m_DrowningRadioSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
CreateAndPlaySound_Persistent(g_RadioAudioEntity.GetRadioSounds().Find(ATSTRINGHASH("RadioDrown", 0x37CE14E5)), &m_DrowningRadioSound, &initParams);
|
|
}
|
|
if(m_DrowningRadioSound)
|
|
{
|
|
m_DrowningRadioSound->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(m_DrowningFactor));
|
|
}
|
|
}
|
|
if(m_DrowningFactor == 0.f && m_DrowningRadioSound)
|
|
{
|
|
if(!m_Vehicle->m_nVehicleFlags.bIsDrowning)
|
|
{
|
|
// ensure the sound is muted so that the final spark sound is inaudible
|
|
m_DrowningRadioSound->SetRequestedVolume(-100.f);
|
|
}
|
|
m_DrowningRadioSound->StopAndForget();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateEnvironment
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateEnvironment()
|
|
{
|
|
if(m_EnvironmentGroup)
|
|
{
|
|
if(m_Vehicle)
|
|
{
|
|
m_EnvironmentGroup->SetSource(m_Vehicle->GetTransform().GetPosition());
|
|
}
|
|
|
|
if(IsReal())
|
|
{
|
|
m_EnvironmentGroup->SetSourceEnvironmentUpdates(200);
|
|
}
|
|
else if(!IsDisabled())
|
|
{
|
|
m_EnvironmentGroup->SetSourceEnvironmentUpdates(1000);
|
|
}
|
|
else
|
|
{
|
|
m_EnvironmentGroup->SetSourceEnvironmentUpdates(1); // enough to do updates, but only in interiors
|
|
}
|
|
|
|
// don't occlude the player (TODO case this for camera modes)
|
|
CPed* localPlayer = CGameWorld::FindLocalPlayer();
|
|
if(localPlayer && localPlayer->GetVehiclePedInside() == m_Vehicle )
|
|
{
|
|
m_EnvironmentGroup->SetNotOccluded(true);
|
|
}
|
|
else
|
|
{
|
|
m_EnvironmentGroup->SetNotOccluded(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity SmoothSirenVolume
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SmoothSirenVolume(f32 rate,f32 desireLinVol,bool stopSiren)
|
|
{
|
|
// Flag the entity to stop the siren after muting it if we want to.
|
|
m_ShouldStopSiren = stopSiren;
|
|
// Set rates and desire volume
|
|
m_SirensDesireLinVol = desireLinVol;
|
|
m_SirensVolumeSmoother.SetRate(rate);
|
|
// If the smoother hasn't been used yet, initialize it with the current volume (1 - desire)
|
|
if(!m_SirensVolumeSmoother.IsInitialized())
|
|
{
|
|
m_SirensVolumeSmoother.CalculateValue(1.f-desireLinVol,fwTimer::GetTimeInMilliseconds());
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateCarRecordings
|
|
// Check if the veh is playing a car recording and tells the audio entity to play the audio for it.
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::CheckForRecordingChange()
|
|
{
|
|
s32 index = CVehicleRecordingMgr::GetPlaybackIdForCar(m_Vehicle);
|
|
#if __BANK
|
|
if(CVehicleRecordingMgr::GetRecordingHash(index) == sm_DebugCarRecording.nameHash)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
CarRecordingAudioSettings * newSettings = audNorthAudioEngine::GetObject<CarRecordingAudioSettings>(CVehicleRecordingMgr::GetRecordingHash(index));
|
|
if( newSettings && newSettings != m_CRSettings)
|
|
{
|
|
u8* numPersistentMixerScenes = (u8*)(&m_CRSettings->Event[m_CRSettings->numEvents]);
|
|
for(u8 i=0; i < *numPersistentMixerScenes; i++)
|
|
{
|
|
if (m_CarRecordingPersistentScenes[i])
|
|
{
|
|
m_CarRecordingPersistentScenes[i]->Stop();
|
|
}
|
|
}
|
|
if(m_CRSettings && m_CRSettings->Mixgroup)
|
|
{
|
|
DYNAMICMIXER.RemoveEntityFromMixGroup(m_Vehicle);
|
|
}
|
|
m_CRSettings = newSettings;
|
|
m_LastCREventProcessed = 0;
|
|
}
|
|
if(m_CRSettings && m_CRSettings->Mixgroup)
|
|
{
|
|
DYNAMICMIXER.AddEntityToMixGroup(m_Vehicle, m_CRSettings->Mixgroup);
|
|
}
|
|
}
|
|
|
|
void audVehicleAudioEntity::UpdateCarRecordings()
|
|
{
|
|
#if __BANK
|
|
if( sm_PauseGame)
|
|
{
|
|
fwTimer::SetTimeWarp(0.f);
|
|
}
|
|
#endif
|
|
//Check if there is a car recording going on.
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(m_Vehicle))
|
|
{
|
|
if(!m_CRSettings)
|
|
{
|
|
s32 index = CVehicleRecordingMgr::GetPlaybackIdForCar(m_Vehicle);
|
|
#if __BANK
|
|
if(CVehicleRecordingMgr::GetRecordingHash(index) == sm_DebugCarRecording.nameHash)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
m_CRSettings = audNorthAudioEngine::GetObject<CarRecordingAudioSettings>(CVehicleRecordingMgr::GetRecordingHash(index));
|
|
}
|
|
if (m_CRSettings)
|
|
{
|
|
if(m_CRSettings->Mixgroup)
|
|
{
|
|
DYNAMICMIXER.AddEntityToMixGroup(m_Vehicle, m_CRSettings->Mixgroup);
|
|
}
|
|
AllocateVehicleVariableBlock();
|
|
if(m_LastCREventProcessed >= m_CRSettings->numEvents)
|
|
{
|
|
CheckForRecordingChange();
|
|
}
|
|
s32 playBackSlot = CVehicleRecordingMgr::GetPlaybackSlot(m_Vehicle);
|
|
f32 curretPlaybackTime = CVehicleRecordingMgr::GetPlaybackRunningTime(playBackSlot);
|
|
for(u8 i=m_LastCREventProcessed; i < m_CRSettings->numEvents; i++)
|
|
{
|
|
if(curretPlaybackTime >= m_CRSettings->Event[i].Time)
|
|
{
|
|
// Play the sound.
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_CAR_RECORDING;
|
|
initParams.UpdateEntity = true;
|
|
CreateAndPlaySound(m_CRSettings->Event[i].Sound, &initParams);
|
|
// Trigger the scene.
|
|
if(m_CRSettings->Event[i].OneShotScene != 0)
|
|
{
|
|
DYNAMICMIXER.StartScene(m_CRSettings->Event[i].OneShotScene);
|
|
}
|
|
m_LastCREventProcessed = i + 1u;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Need to do a bit of funky pointer manipulation here due to having two variable length lists one after another
|
|
u8* numPersistentMixerScenes = (u8*)(&m_CRSettings->Event[m_CRSettings->numEvents]);
|
|
CarRecordingAudioSettings::tPersistentMixerScenes* persistentMixerScenes = (CarRecordingAudioSettings::tPersistentMixerScenes*)(numPersistentMixerScenes + sizeof(u32));
|
|
|
|
for(u8 i=0; i < *numPersistentMixerScenes; i++)
|
|
{
|
|
if(curretPlaybackTime >= persistentMixerScenes[i].StartTime
|
|
&& curretPlaybackTime < persistentMixerScenes[i].EndTime
|
|
&& !m_CarRecordingPersistentScenes[i])
|
|
{
|
|
DYNAMICMIXER.StartScene(persistentMixerScenes[i].Scene,&m_CarRecordingPersistentScenes[i]);
|
|
}
|
|
else if (m_CarRecordingPersistentScenes[i] && curretPlaybackTime > persistentMixerScenes[i].EndTime)
|
|
{
|
|
m_CarRecordingPersistentScenes[i]->Stop();
|
|
}
|
|
}
|
|
#if __BANK
|
|
if(sm_DrawCREvents)
|
|
{
|
|
if(g_CRFilter[0] != 0 && !audAmbientAudioEntity::MatchName(audNorthAudioEngine::GetMetadataManager().GetObjectName(m_CRSettings->NameTableOffset,0),g_CRFilter))
|
|
{
|
|
return;
|
|
}
|
|
for(int i=0; i < m_CRSettings->numEvents; i++)
|
|
{
|
|
Vector3 pos;
|
|
if (CVehicleRecordingMgr::HasRecordingFileBeenLoaded(playBackSlot))
|
|
{
|
|
CVehicleRecordingMgr::GetPositionOfCarRecordingAtTime(playBackSlot,m_CRSettings->Event[i].Time,pos);
|
|
}
|
|
else
|
|
{
|
|
Matrix34 mat;
|
|
s32 IndexInRecording = 0;
|
|
CVehicleStateEachFrame *pVehState = reinterpret_cast<CVehicleStateEachFrame *>(&((CVehicleRecordingMgr::GetPlaybackBuffer(playBackSlot))[0]));
|
|
CVehicleRecordingMgr::RestoreInfoForMatrix(mat, pVehState);
|
|
|
|
while ( (IndexInRecording < CVehicleRecordingMgr::GetPlaybackBufferSize(playBackSlot)) && ((CVehicleStateEachFrame *) &((CVehicleRecordingMgr::GetPlaybackBuffer(playBackSlot))[IndexInRecording]))->TimeInRecording < m_CRSettings->Event[i].Time)
|
|
{
|
|
CVehicleRecordingMgr::RestoreInfoForMatrix( mat, reinterpret_cast<CVehicleStateEachFrame *>(&((CVehicleRecordingMgr::GetPlaybackBuffer(playBackSlot))[IndexInRecording])));
|
|
IndexInRecording += sizeof(CVehicleStateEachFrame);
|
|
}
|
|
pos = mat.d;
|
|
}
|
|
Color32 color = Color_red;
|
|
if(curretPlaybackTime > m_CRSettings->Event[i].Time)
|
|
{
|
|
color = Color_green;
|
|
}
|
|
grcDebugDraw::Sphere(pos,0.3f,color);
|
|
char txt [128];
|
|
formatf(txt,"%f",m_CRSettings->Event[i].Time);
|
|
grcDebugDraw::Text(pos + Vector3(0.f,0.f,1.f),color,txt);
|
|
formatf(txt,"%s",g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectName(m_CRSettings->Event[i].Sound));
|
|
grcDebugDraw::Text(pos + Vector3(0.f,0.f,0.75f),color,txt);
|
|
formatf(txt,"%s",g_AudioEngine.GetDynamicMixManager().GetMetadataManager().GetObjectName(m_CRSettings->Event[i].OneShotScene));
|
|
grcDebugDraw::Text(pos + Vector3(0.f,0.f,0.5f),color,txt);
|
|
if(sm_DrawCRName)
|
|
{
|
|
formatf(txt,"%s",audNorthAudioEngine::GetMetadataManager().GetObjectName(m_CRSettings->NameTableOffset,0));
|
|
grcDebugDraw::Text(pos + Vector3(0.f,0.f,1.25f),color,txt);
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_CRSettings)
|
|
{
|
|
u8* numPersistentMixerScenes = (u8*)(&m_CRSettings->Event[m_CRSettings->numEvents]);
|
|
for(u8 i=0; i < *numPersistentMixerScenes; i++)
|
|
{
|
|
if (m_CarRecordingPersistentScenes[i])
|
|
{
|
|
m_CarRecordingPersistentScenes[i]->Stop();
|
|
}
|
|
}
|
|
if(m_CRSettings->Mixgroup)
|
|
{
|
|
DYNAMICMIXER.RemoveEntityFromMixGroup(m_Vehicle);
|
|
}
|
|
m_CRSettings = NULL;
|
|
}
|
|
m_LastCREventProcessed = 0;
|
|
m_CRSettings = NULL;
|
|
}
|
|
}
|
|
#if __BANK
|
|
void audVehicleAudioEntity::UpdateCarRecordingTool()
|
|
{
|
|
if( sm_PauseGame)
|
|
{
|
|
fwTimer::SetTimeWarp(0.f);
|
|
}
|
|
if(sm_EnableCREditor)
|
|
{
|
|
if ((g_pFocusEntity && g_pFocusEntity->GetIsTypeVehicle()) || sm_LoadExistingCR)
|
|
{
|
|
CVehicle* pVeh = NULL;
|
|
if(sm_LoadExistingCR && sm_DebugCarRecording.settings)
|
|
{
|
|
if ( !sm_VehCreated)
|
|
{
|
|
if(naVerifyf(sm_DebugCarRecording.settings->VehicleModelId != fwModelId::MI_INVALID, "No veh id. stored for this CR, either do it from the mission or contact audio team."))
|
|
{
|
|
sm_DebugCarRecording.modelId = sm_DebugCarRecording.settings->VehicleModelId;
|
|
}
|
|
}
|
|
pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if (pVeh)
|
|
{
|
|
sm_VehCreated = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pVeh = static_cast<CVehicle*>(g_pFocusEntity);
|
|
}
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh) || sm_LoadExistingCR)
|
|
{
|
|
s32 index = CVehicleRecordingMgr::GetPlaybackIdForCar(pVeh);
|
|
if(index >= 0 || sm_LoadExistingCR)
|
|
{
|
|
if(sm_DebugCarRecording.nameHash.IsNull())
|
|
{
|
|
// Get the car recording and add the audio prefix
|
|
char recording[128];
|
|
if( !sm_LoadExistingCR)
|
|
{
|
|
formatf(sm_CRAudioSettingsCreator,sizeof(sm_CRAudioSettingsCreator),"%s", CVehicleRecordingMgr::GetRecordingName(index));
|
|
formatf(recording,sizeof(recording),"%s", CVehicleRecordingMgr::GetRecordingName(index));
|
|
sm_DebugCarRecording.modelId = pVeh->GetModelIndex();
|
|
}
|
|
else
|
|
{
|
|
u32 nameIdx = 3;// TO AVOID CR_
|
|
u32 strLength = ustrlen(sm_CRAudioSettingsCreator);
|
|
for(s32 i = nameIdx; i < strLength + 1; i++)
|
|
{
|
|
recording[i - nameIdx] = sm_CRAudioSettingsCreator[i];
|
|
}
|
|
}
|
|
//Store it in our debug object.
|
|
sm_DebugCarRecording.nameHash.SetFromString(sm_CRAudioSettingsCreator);
|
|
//Get the recording name and index for the manager
|
|
char recordingName[128];
|
|
char recordNum[64];
|
|
u32 length = ustrlen(recording);
|
|
u32 nameLength = length - 3;
|
|
formatf(recordingName,nameLength + 1,"%s", recording);
|
|
u32 numIdx = 0;
|
|
for(s32 i = nameLength; i < length; i++)
|
|
{
|
|
recordNum[numIdx++] = recording[i];
|
|
}
|
|
CVehicleRecordingMgr::SetCurrentRecording(recordingName,(u32)atoi(recordNum));
|
|
sm_LoadExistingCR = false;
|
|
}
|
|
else
|
|
{
|
|
char newRecording[128];
|
|
formatf(newRecording,sizeof(newRecording),"%s", CVehicleRecordingMgr::GetRecordingName(index));
|
|
if( atStringHash(sm_CRAudioSettingsCreator) != sm_DebugCarRecording.nameHash.GetHash())
|
|
{
|
|
char errorMsg[128];
|
|
formatf(errorMsg,sizeof(errorMsg),"%s", CVehicleRecordingMgr::GetRecordingName(index));
|
|
naAssertf(false,"Currently working on %s, in order to work with a new recording, please finish your work.",errorMsg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(sm_DebugCarRecording.nameHash.IsNotNull())
|
|
{
|
|
sm_DebugCarRecording.settings = NULL;
|
|
sm_DebugCarRecording.settings = audNorthAudioEngine::GetObject<CarRecordingAudioSettings>(sm_DebugCarRecording.nameHash);
|
|
|
|
}
|
|
if(sm_DebugCarRecording.settings)
|
|
{
|
|
//sm_DebugCarRecording.eventList.Reset();
|
|
for(int j=0; j < sm_DebugCarRecording.settings->numEvents; j++)
|
|
{
|
|
if(j < sm_DebugCarRecording.eventList.GetCount())
|
|
{
|
|
sm_DebugCarRecording.eventList[j].time = sm_DebugCarRecording.settings->Event[j].Time;
|
|
sm_DebugCarRecording.eventList[j].hashEvent = sm_DebugCarRecording.settings->Event[j].Sound;
|
|
}
|
|
else
|
|
{
|
|
audioRecordingEvent event;
|
|
event.time = sm_DebugCarRecording.settings->Event[j].Time;
|
|
event.hashEvent = sm_DebugCarRecording.settings->Event[j].Sound;
|
|
sm_DebugCarRecording.eventList.PushAndGrow(event);
|
|
}
|
|
}
|
|
}
|
|
if(sm_UpdateCRTime && !sm_ManualTimeSet)
|
|
{
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh))
|
|
{
|
|
s32 playBackSlot = CVehicleRecordingMgr::GetPlaybackSlot(pVeh);
|
|
sm_CRCurrentTime = CVehicleRecordingMgr::GetPlaybackRunningTime(playBackSlot);
|
|
sm_CRProgress = (f32)(sm_CRCurrentTime / (f32) CVehicleRecordingMgr::GetEndTimeOfRecording(playBackSlot)) * 100.f;
|
|
if(sm_DebugCarRecording.settings)
|
|
{
|
|
for(int i=0; i < sm_DebugCarRecording.settings->numEvents; i++)
|
|
{
|
|
if(!sm_DebugCarRecording.eventList[i].processed && sm_CRCurrentTime >= sm_DebugCarRecording.settings->Event[i].Time)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = pVeh->GetAudioEnvironmentGroup();
|
|
initParams.TrackEntityPosition = true;
|
|
sm_DebugCarRecording.eventList[i].processed = true;
|
|
pVeh->GetVehicleAudioEntity()->CreateAndPlaySound(sm_DebugCarRecording.settings->Event[i].Sound, &initParams);
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if(sm_DrawCREvents)
|
|
{
|
|
if(g_CRFilter[0] != 0 && sm_DebugCarRecording.nameHash != atStringHash(g_CRFilter))//!audAmbientAudioEntity::MatchName(GetName(), g_CRFilter))
|
|
{
|
|
return;
|
|
}
|
|
for(int i=0; i < sm_DebugCarRecording.settings->numEvents; i++)
|
|
{
|
|
Vector3 pos;
|
|
if (CVehicleRecordingMgr::HasRecordingFileBeenLoaded(playBackSlot))
|
|
{
|
|
CVehicleRecordingMgr::GetPositionOfCarRecordingAtTime(playBackSlot,sm_DebugCarRecording.settings->Event[i].Time,pos);
|
|
}
|
|
else
|
|
{
|
|
Matrix34 mat;
|
|
s32 IndexInRecording = 0;
|
|
CVehicleStateEachFrame *pVehState = reinterpret_cast<CVehicleStateEachFrame *>(&((CVehicleRecordingMgr::GetPlaybackBuffer(playBackSlot))[0]));
|
|
CVehicleRecordingMgr::RestoreInfoForMatrix(mat, pVehState);
|
|
|
|
while ( (IndexInRecording < CVehicleRecordingMgr::GetPlaybackBufferSize(playBackSlot)) && ((CVehicleStateEachFrame *) &((CVehicleRecordingMgr::GetPlaybackBuffer(playBackSlot))[IndexInRecording]))->TimeInRecording < sm_DebugCarRecording.settings->Event[i].Time)
|
|
{
|
|
CVehicleRecordingMgr::RestoreInfoForMatrix( mat, reinterpret_cast<CVehicleStateEachFrame *>(&((CVehicleRecordingMgr::GetPlaybackBuffer(playBackSlot))[IndexInRecording])));
|
|
IndexInRecording += sizeof(CVehicleStateEachFrame);
|
|
}
|
|
pos = mat.d;
|
|
}
|
|
Color32 color = Color_red;
|
|
if(sm_CRCurrentTime > sm_DebugCarRecording.settings->Event[i].Time)
|
|
{
|
|
color = Color_green;
|
|
}
|
|
grcDebugDraw::Sphere(pos,0.3f,color);
|
|
char txt [128];
|
|
formatf(txt,"%f",sm_DebugCarRecording.settings->Event[i].Time);
|
|
grcDebugDraw::Text(pos + Vector3(0.f,0.f,1.f),color,txt);
|
|
formatf(txt,"%s",g_AudioEngine.GetSoundManager().GetFactory().GetMetadataManager().GetObjectName(sm_DebugCarRecording.settings->Event[i].Sound));
|
|
grcDebugDraw::Text(pos + Vector3(0.f,0.f,0.75f),color,txt);
|
|
formatf(txt,"%s",g_AudioEngine.GetDynamicMixManager().GetMetadataManager().GetObjectName(sm_DebugCarRecording.settings->Event[i].OneShotScene));
|
|
grcDebugDraw::Text(pos + Vector3(0.f,0.f,0.5f),color,txt);
|
|
if(sm_DrawCRName && sm_DebugCarRecording.settings)
|
|
{
|
|
formatf(txt,"%s",audNorthAudioEngine::GetMetadataManager().GetObjectName(sm_DebugCarRecording.settings->NameTableOffset,0));
|
|
grcDebugDraw::Text(pos + Vector3(0.f,0.f,1.25f),color,txt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// Find the priority of a given skid sound
|
|
// ----------------------------------------------------------------
|
|
u8 audVehicleAudioEntity::FindSkidSurfacePriority(const u8 priorityType)
|
|
{
|
|
// Priorities from low->high
|
|
static const u8 surfacePriorityOrder[NUM_SURFACEPRIORITY] =
|
|
{
|
|
PRIORITY_OTHER,
|
|
GRASS,
|
|
TARMAC,
|
|
SAND,
|
|
GRAVEL,
|
|
};
|
|
|
|
|
|
for(u8 k = 0; k < NUM_SURFACEPRIORITY; k ++)
|
|
{
|
|
if(priorityType == surfacePriorityOrder[k])
|
|
{
|
|
return k;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// IsPedOnMovingTrain
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsPedOnMovingTrain(const CPed* pPed)
|
|
{
|
|
if(!pPed)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(!audVerifyf(sysThreadType::IsUpdateThread(), "Not safe to query IsPedOnMovingTrain on audio thread"))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Vec3V vVelocity;
|
|
CEntity* pTargetAttachedEntity = static_cast<CEntity*>(pPed->GetAttachParent());
|
|
CPhysical* pTargetGroundPhysical = pPed->GetGroundPhysical();
|
|
|
|
if( pTargetGroundPhysical && pTargetGroundPhysical->GetIsTypeVehicle() &&
|
|
static_cast<CVehicle*>(pTargetGroundPhysical)->InheritsFromTrain() )
|
|
{
|
|
vVelocity = VECTOR3_TO_VEC3V(pTargetGroundPhysical->GetVelocity());
|
|
}
|
|
else if( pTargetAttachedEntity && pTargetAttachedEntity->GetIsTypeVehicle() &&
|
|
static_cast<CVehicle*>(pTargetAttachedEntity)->InheritsFromTrain() )
|
|
{
|
|
CTrain* pTrain = static_cast<CTrain*>(pTargetAttachedEntity);
|
|
vVelocity = VECTOR3_TO_VEC3V(pTrain->GetVelocity());
|
|
}
|
|
else if(pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_RidingTrain))
|
|
{
|
|
vVelocity = VECTOR3_TO_VEC3V(pPed->GetVelocity());
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ScalarV scMinTrainSpeedSq = LoadScalar32IntoScalarV(V_ONE);
|
|
scMinTrainSpeedSq = (scMinTrainSpeedSq * scMinTrainSpeedSq);
|
|
return IsGreaterThanAll(MagSquared(vVelocity), scMinTrainSpeedSq) != 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Load any banks as requested by script
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ProcessScriptVehicleBankLoad()
|
|
{
|
|
if(sm_ScriptVehicleRequest != 0u)
|
|
{
|
|
if(sm_ScriptVehicleWaveSlot && IsPlayerVehicleStarving())
|
|
{
|
|
audWaveSlotManager::FreeWaveSlot(sm_ScriptVehicleWaveSlot);
|
|
}
|
|
else if(!sm_ScriptVehicleWaveSlot && !IsPlayerVehicleStarving())
|
|
{
|
|
u32 bankLoadSound = 0;
|
|
audMetadataObjectInfo objectInfo;
|
|
bool useHighQualitySlot = false;
|
|
|
|
if(audNorthAudioEngine::GetMetadataManager().GetObjectInfo(sm_ScriptVehicleRequest, objectInfo))
|
|
{
|
|
switch(objectInfo.GetType())
|
|
{
|
|
case CarAudioSettings::TYPE_ID:
|
|
{
|
|
const CarAudioSettings* carSettings = objectInfo.GetObject<CarAudioSettings>();
|
|
|
|
if(carSettings->EngineType == ELECTRIC)
|
|
{
|
|
const ElectricEngineAudioSettings* engineSettings = audNorthAudioEngine::GetMetadataManager().GetObject<ElectricEngineAudioSettings>(carSettings->ElectricEngine);
|
|
bankLoadSound = engineSettings ? engineSettings->BankLoadSound : 0u;
|
|
}
|
|
else
|
|
{
|
|
const GranularEngineAudioSettings* engineSettings = audNorthAudioEngine::GetMetadataManager().GetObject<GranularEngineAudioSettings>(carSettings->GranularEngine);
|
|
bankLoadSound = engineSettings ? engineSettings->EngineAccel : 0u;
|
|
useHighQualitySlot = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PlaneAudioSettings::TYPE_ID:
|
|
{
|
|
const PlaneAudioSettings* planeSettings = objectInfo.GetObject<PlaneAudioSettings>();
|
|
|
|
if(planeSettings)
|
|
{
|
|
if(planeSettings->SimpleSoundForLoading != g_NullSoundHash)
|
|
{
|
|
bankLoadSound = planeSettings->SimpleSoundForLoading;
|
|
}
|
|
else
|
|
{
|
|
bankLoadSound = planeSettings->BankingLoop;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HeliAudioSettings::TYPE_ID:
|
|
{
|
|
const HeliAudioSettings* heliSettings = objectInfo.GetObject<HeliAudioSettings>();
|
|
|
|
if(heliSettings)
|
|
{
|
|
if(heliSettings->SimpleSoundForLoading != g_NullSoundHash)
|
|
{
|
|
bankLoadSound = heliSettings->SimpleSoundForLoading;
|
|
}
|
|
else
|
|
{
|
|
bankLoadSound = heliSettings->StartUpOneShot;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BoatAudioSettings::TYPE_ID:
|
|
{
|
|
const GranularEngineAudioSettings* engineSettings = audNorthAudioEngine::GetMetadataManager().GetObject<GranularEngineAudioSettings>(objectInfo.GetObject<BoatAudioSettings>()->GranularEngine);
|
|
bankLoadSound = engineSettings ? engineSettings->EngineAccel : 0u;
|
|
useHighQualitySlot = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(bankLoadSound != 0u)
|
|
{
|
|
if(useHighQualitySlot)
|
|
{
|
|
sm_ScriptVehicleWaveSlot = sm_HighQualityWaveSlotManager.LoadBankForSound(bankLoadSound, AUD_WAVE_SLOT_ANY, false, NULL, naWaveLoadPriority::General);
|
|
}
|
|
else
|
|
{
|
|
sm_ScriptVehicleWaveSlot = sm_StandardWaveSlotManager.LoadBankForSound(bankLoadSound, AUD_WAVE_SLOT_ANY, false, NULL, naWaveLoadPriority::General);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sm_ScriptVehicleRequest = 0u;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// ClassFinishUpdate
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ClassFinishUpdate()
|
|
{
|
|
ProcessScriptVehicleBankLoad();
|
|
|
|
CPed* followPlayer = FindFollowPed();
|
|
if(IsPedOnMovingTrain(followPlayer))
|
|
{
|
|
if(!sm_OnMovingTrainScene)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("ON_MOVING_TRAIN_SCENE", 0x6A8E30DA), &sm_OnMovingTrainScene);
|
|
}
|
|
}
|
|
else if(sm_OnMovingTrainScene)
|
|
{
|
|
sm_OnMovingTrainScene->Stop();
|
|
sm_OnMovingTrainScene = NULL;
|
|
}
|
|
|
|
if(g_ReflectionsAudioEntity.IsFocusVehicleInStuntTunnel())
|
|
{
|
|
if(!sm_StuntTunnelScene)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("STUNT_TUNNEL_SCENE", 0x58F4A9AB), &sm_StuntTunnelScene);
|
|
}
|
|
}
|
|
else if(sm_StuntTunnelScene)
|
|
{
|
|
sm_StuntTunnelScene->Stop();
|
|
sm_StuntTunnelScene = NULL;
|
|
}
|
|
|
|
sm_IsSpectatorModeActive = NetworkInterface::IsInSpectatorMode();
|
|
|
|
if(!sm_ExhaustProximityScene)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("EXHAUST_PROXIMITY_SCENE", 0xB1A84119), &sm_ExhaustProximityScene);
|
|
}
|
|
|
|
if(sm_ExhaustProximityScene)
|
|
{
|
|
sm_ExhaustProximityScene->SetVariableValue(ATSTRINGHASH("apply", 0xE865CDE8), sm_PlayerVehicleProximityRatio);
|
|
}
|
|
|
|
sm_PlayerVehicleOpenness = 1.0f;
|
|
f32 playerVehicleEngineOpenness = 1.0f;
|
|
|
|
CVehicle* followPlayerVehicle = CGameWorld::FindFollowPlayerVehicle();
|
|
if(!followPlayerVehicle)
|
|
{
|
|
followPlayerVehicle = audPedAudioEntity::GetBJVehicle();
|
|
}
|
|
|
|
if(followPlayerVehicle)
|
|
{
|
|
VehicleType vehicleType = followPlayerVehicle->GetVehicleType();
|
|
u32 vehicleNameHash = followPlayerVehicle->GetVehicleAudioEntity()->GetVehicleModelNameHash();
|
|
bool isBike = vehicleType == VEHICLE_TYPE_BIKE || vehicleType == VEHICLE_TYPE_QUADBIKE || vehicleType == VEHICLE_TYPE_AMPHIBIOUS_QUADBIKE;
|
|
bool isBicycle = vehicleType == VEHICLE_TYPE_BICYCLE;
|
|
bool isAircraft = vehicleType == VEHICLE_TYPE_PLANE || vehicleType == VEHICLE_TYPE_HELI;
|
|
|
|
if (vehicleNameHash == ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
if (!sm_VehicleGeneralScene)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("dlc_hei4_kosatka_driving_scene", 0x19ACDDEF), &sm_VehicleGeneralScene);
|
|
}
|
|
}
|
|
else if(followPlayerVehicle->GetVehicleAudioEntity()->IsGoKart())
|
|
{
|
|
if (!sm_VehicleGeneralScene)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("Karts_Driving_Scene", 0xDF1D0DF0), &sm_VehicleGeneralScene);
|
|
}
|
|
}
|
|
else if (sm_VehicleGeneralScene)
|
|
{
|
|
sm_VehicleGeneralScene->Stop();
|
|
sm_VehicleGeneralScene = NULL;
|
|
}
|
|
|
|
if(audNorthAudioEngine::IsRenderingFirstPersonTurretCam())
|
|
{
|
|
if(!sm_VehicleFirstPersonTurretScene)
|
|
{
|
|
const camBaseCamera* dominantRenderedCamera = camInterface::GetDominantRenderedCamera();
|
|
u32 turretSceneName = ATSTRINGHASH("VEHICLE_FIRSTPERSON_TURRET_SCENE", 0xDB9C390B);
|
|
|
|
if(dominantRenderedCamera)
|
|
{
|
|
if(dominantRenderedCamera->GetNameHash() == ATSTRINGHASH("POV_TURRET_CAMERA_DUNE3", 0x8501FD84) ||
|
|
dominantRenderedCamera->GetNameHash() == ATSTRINGHASH("POV_TURRET_CAMERA_APC_CANNON", 0xD3FE954B) ||
|
|
dominantRenderedCamera->GetNameHash() == ATSTRINGHASH("POV_TURRET_CAMERA_APC_MISSILE", 0xD4FCAB99))
|
|
{
|
|
turretSceneName = ATSTRINGHASH("VEHICLE_FIRSTPERSON_TURRET_INTERIOR_SCENE", 0x67F22C56);
|
|
}
|
|
}
|
|
|
|
const MixerScene* mixerScene = DYNAMICMIXMGR.GetObject<MixerScene>(turretSceneName);
|
|
|
|
if(mixerScene != NULL)
|
|
{
|
|
DYNAMICMIXER.StartScene(mixerScene, &sm_VehicleFirstPersonTurretScene);
|
|
}
|
|
}
|
|
}
|
|
else if(sm_VehicleFirstPersonTurretScene)
|
|
{
|
|
sm_VehicleFirstPersonTurretScene->Stop();
|
|
sm_VehicleFirstPersonTurretScene = NULL;
|
|
}
|
|
|
|
if(audNorthAudioEngine::IsRenderingHoodMountedVehicleCam() || followPlayerVehicle->GetVehicleAudioEntity()->IsToyCar())
|
|
{
|
|
if(sm_VehicleInteriorScene)
|
|
{
|
|
sm_VehicleInteriorScene->Stop();
|
|
sm_VehicleInteriorScene = NULL;
|
|
}
|
|
|
|
if(!sm_VehicleBonnetCamScene)
|
|
{
|
|
u32 bonnetCamSceneName = 0u;
|
|
|
|
if (followPlayerVehicle->GetVehicleAudioEntity()->IsToyCar())
|
|
{
|
|
bonnetCamSceneName = ATSTRINGHASH("rcbandito_general_scene", 0x563AF803);
|
|
}
|
|
else if (followPlayerVehicle->GetVehicleAudioEntity()->GetVehicleModelNameHash() == ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
bonnetCamSceneName = ATSTRINGHASH("KOSATKA_BONNET_CAM_SCENE", 0x81E0D389);
|
|
}
|
|
else if(isAircraft)
|
|
{
|
|
bonnetCamSceneName = ATSTRINGHASH("BONNET_CAM_AIRCRAFT_SCENE", 0x664CF87B);
|
|
}
|
|
else if(isBike)
|
|
{
|
|
bonnetCamSceneName = ATSTRINGHASH("BONNET_CAM_BIKE_SCENE", 0x3236F4E7);
|
|
}
|
|
else if(isBicycle)
|
|
{
|
|
bonnetCamSceneName = ATSTRINGHASH("BONNET_CAM_BICYCLE_SCENE", 0xA212AE03);
|
|
}
|
|
else
|
|
{
|
|
bonnetCamSceneName = ATSTRINGHASH("BONNET_CAM_SCENE", 0x420AE17A);
|
|
}
|
|
|
|
if(DYNAMICMIXMGR.GetObject<MixerScene>(bonnetCamSceneName) != NULL)
|
|
{
|
|
DYNAMICMIXER.StartScene(bonnetCamSceneName, &sm_VehicleBonnetCamScene);
|
|
}
|
|
}
|
|
}
|
|
else if(audNorthAudioEngine::IsRenderingFirstPersonVehicleCam() || (isAircraft && naMicrophones::IsSniping()))
|
|
{
|
|
if(sm_VehicleBonnetCamScene)
|
|
{
|
|
sm_VehicleBonnetCamScene->Stop();
|
|
sm_VehicleBonnetCamScene = NULL;
|
|
}
|
|
|
|
if(!sm_VehicleInteriorScene)
|
|
{
|
|
if(isAircraft)
|
|
{
|
|
bool isPassengerSeat = true;
|
|
s32 seatIndex = followPlayerVehicle->GetSeatManager()->GetPedsSeatIndex(followPlayer);
|
|
u32 numCabinSeats = 2;
|
|
|
|
switch(vehicleNameHash)
|
|
{
|
|
case 0x3E2E4F8A: // TULA
|
|
numCabinSeats = 1;
|
|
break;
|
|
|
|
case 0xD35698EF: // MOGUL
|
|
numCabinSeats = 1;
|
|
break;
|
|
}
|
|
|
|
if(seatIndex != -1)
|
|
{
|
|
if(seatIndex < numCabinSeats)
|
|
{
|
|
isPassengerSeat = false;
|
|
}
|
|
}
|
|
|
|
switch(vehicleNameHash)
|
|
{
|
|
case 0xA52F6866: // ALPHAZ1
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("ALPHAZ1_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0xAD7B5E21) : ATSTRINGHASH("ALPHAZ1_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x875D1F93), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xFE0A508C: // BOMBUSHKA
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("BOMBUSHKA_INTERIOR_VIEW_AIRCRAFT_PASSENGER_Scene", 0x95007263) : ATSTRINGHASH("BOMBUSHKA_INTERIOR_VIEW_AIRCRAFT_Scene", 0x2EB257A6), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x89BA59F5: // HAVOK
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("HAVOK_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0x134AB13D) : ATSTRINGHASH("HAVOK_INTERIOR_VIEW_AIRCRAFT_SCENE", 0xE75BFD1A), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xC3F25753: // HOWARD
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("HOWARD_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0x73CA819F) : ATSTRINGHASH("HOWARD_INTERIOR_VIEW_AIRCRAFT_SCENE", 0xC035FEC5), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x11962E49: // Annihilator2
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("ANNIHILATOR2_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x432D4669), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x96E24857: // MICROLIGHT
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("MICROLIGHT_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x1BE19149), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x5D56F01B: // MOLOTOK
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("MOLOTOK_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0x7593FD98) : ATSTRINGHASH("MOLOTOK_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x15D962DC), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xD35698EF: // MOGUL
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("MOGUL_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0xD0EB500) : ATSTRINGHASH("MOGUL_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x77ED8E0C), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x3DC92356: // NOKOTA
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("NOKOTA_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0xAA580D13) : ATSTRINGHASH("NOKOTA_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x36B2F355), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xAD6065C0: // PYRO
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("PYRO_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0xE184AC63) : ATSTRINGHASH("PYRO_INTERIOR_VIEW_AIRCRAFT_SCENE", 0xA1C58A3A), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x9A9EB7DE: // STARLING
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("STARLING_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0xF1AA0734) : ATSTRINGHASH("STARLING_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x45A2D655), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xE8983F9F: // SEABREEZE
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("SEABREEZE_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0x793AC0EB) : ATSTRINGHASH("SEABREEZE_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x6CC6F902), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x3E2E4F8A: // TULA
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("TULA_INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0x4EE16B4E) : ATSTRINGHASH("TULA_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x9EECE232), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xFCFCB68B: // CARGOBOB
|
|
case 0x60A7EA10: // CARGOBOB2
|
|
case 0x53174EEF: // CARGOBOB3
|
|
case 0x78BC1A3C: // CARGOBOB4
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("CARGOBOB_INTERIOR_SCENE", 0x9535FB29), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xB79C1BF5: // SHAMAL
|
|
case 0xA4B7B1D4: // SHAMAL3
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("SHAMAL_INTERIOR_SCENE", 0xCB8FA3F5), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xFD707EDE: // HUNTER
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("HUNTER_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x65A71D9E), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xC5DD6967: // ROGUE
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("ROGUE_INTERIOR_VIEW_AIRCRAFT_SCENE", 0x2EC6F888), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x250B0C5E: // LUXOR
|
|
case 0xB79F589E: // LUXOR2
|
|
case 0x2A54C47D: // SUPERVOLITO
|
|
case 0x9C5E5644: // SUPERVOLITO2
|
|
case 0xEBC24DF2: // SWIFT
|
|
case 0x4019CB4C: // SWIFT2
|
|
DYNAMICMIXER.StartScene(isPassengerSeat? ATSTRINGHASH("INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0x7EBA8171) : ATSTRINGHASH("INTERIOR_VIEW_AIRCRAFT_SCENE", 0x96E81BB6), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(!sm_VehicleInteriorScene)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_AIRCRAFT_SCENE", 0x96E81BB6), &sm_VehicleInteriorScene);
|
|
}
|
|
}
|
|
else if(isBike)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_BIKE_SCENE", 0xF9DFBAF5), &sm_VehicleInteriorScene);
|
|
}
|
|
else if(isBicycle)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_BICYCLE_SCENE", 0xE2000C3E), &sm_VehicleInteriorScene);
|
|
}
|
|
else
|
|
{
|
|
switch (vehicleNameHash)
|
|
{
|
|
case 0x360A438E: // COG55
|
|
case 0x29FCD3E4: // COG552
|
|
case 0x86FE0B60: // COGNOSCENTI
|
|
case 0xDBF2D57A: // COGNOSCENTI2
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_COG55", 0xF27417DD), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xEDC6F847: // BRICKADE
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_BRICKADE", 0x7622EBE), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xB472D2B5: // ELLIE
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("ELLIE_INTERIOR_VIEW_SCENE", 0xE0698E9A), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xB4F32118: // FLASHGT
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("FLASHGT_INTERIOR_VIEW_SCENE", 0xA1C16D4C), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x71CBEA98: // GB200
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("GB200_INTERIOR_VIEW_SCENE", 0x7408304C), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x42836BE5: // HOTRING
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("HOTRING_INTERIOR_VIEW_SCENE", 0x39DCD571), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x3E5BD8D9: // MICHELLI
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("MICHELLI_INTERIOR_VIEW_SCENE", 0x20532D68), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xE78CC3D9: // REVOLTOR
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_REVOLTER", 0x87EA6740), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xF9E67C05: // SQUADDIE
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("SQUADDIE_INTERIOR_VIEW_SCENE", 0x91814DD8), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x5E4327C8: // WINDSOR
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_WINDSOR", 0xCBD47406), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x3201DD49: // Z190
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("Z190_INTERIOR_VIEW_SCENE", 0xA8BCDEAB), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x8CF5CAE1: // WINDSOR2
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_WINDSOR2", 0xC424529B), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x866BCE26: // FACTION3
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_FACTION3", 0xF38CD46E), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x7E8F677F: // PROTOTIPO
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_PROTOTIPO", 0xDA144B16), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x61E3E6C4: // 770
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_770", 0x7D8C1136), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0xBEDC8A50: // 811
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_811", 0xE31B09DF), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x1324E960: // STAFFORD
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_STAFFORD", 0x1425CE20), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x82CAC433: // TUG
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_TUG", 0xBA1842BD), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
case 0x19DD9ED1: // NIGHTSHARK
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE_NIGHTSHARK", 0xCB8B65C7), &sm_VehicleInteriorScene);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(!sm_VehicleInteriorScene)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("INTERIOR_VIEW_SCENE", 0xA3467F8D), &sm_VehicleInteriorScene);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(sm_VehicleInteriorScene)
|
|
{
|
|
bool safeToShutdownInteriorScene = true;
|
|
|
|
if(followPlayer->GetPedIntelligence()->GetQueriableInterface()->IsTaskCurrentlyRunning(CTaskTypes::TASK_EXIT_VEHICLE))
|
|
{
|
|
// Delay switching off the interior scene until the ped starts opening the appropriate door
|
|
const s32 pedSeatIndex = followPlayerVehicle->GetSeatManager()->GetPedsSeatIndex(followPlayer);
|
|
|
|
if(followPlayerVehicle->IsSeatIndexValid(pedSeatIndex))
|
|
{
|
|
const s32 entryPointIndex = followPlayerVehicle->GetDirectEntryPointIndexForSeat(pedSeatIndex);
|
|
|
|
if(followPlayerVehicle->IsEntryIndexValid(entryPointIndex))
|
|
{
|
|
const CCarDoor* exitDoor = CTaskVehicleFSM::GetDoorForEntryPointIndex(followPlayerVehicle, entryPointIndex);
|
|
|
|
if(exitDoor && exitDoor->GetIsClosed(0.1f))
|
|
{
|
|
safeToShutdownInteriorScene = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(safeToShutdownInteriorScene)
|
|
{
|
|
sm_VehicleInteriorScene->Stop();
|
|
sm_VehicleInteriorScene = NULL;
|
|
}
|
|
}
|
|
|
|
if(sm_VehicleBonnetCamScene)
|
|
{
|
|
sm_VehicleBonnetCamScene->Stop();
|
|
sm_VehicleBonnetCamScene = NULL;
|
|
}
|
|
}
|
|
|
|
if(audNorthAudioEngine::IsRenderingHoodMountedVehicleCam())
|
|
{
|
|
sm_PlayerVehicleOpenness = 1.0f;
|
|
}
|
|
else if(isBike || isBicycle)
|
|
{
|
|
CPed* pPed = CGameWorld::FindLocalPlayer();
|
|
if(pPed && pPed->GetHelmetComponent() && pPed->GetHelmetComponent()->IsHelmetEnabled())
|
|
{
|
|
sm_PlayerVehicleOpenness = 0.7f;
|
|
}
|
|
else
|
|
{
|
|
sm_PlayerVehicleOpenness = 1.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sm_PlayerVehicleOpenness = sm_OpennessSmoother.CalculateValue(followPlayerVehicle->GetVehicleAudioEntity()->GetOpenness(false), fwTimer::GetTimeStep());
|
|
}
|
|
|
|
// Vehicles may have engines inside the cabin (eg. rear engine sports cars) - these should stay unoccluded when in first person mode
|
|
playerVehicleEngineOpenness = Max(sm_PlayerVehicleOpenness, followPlayerVehicle->GetVehicleAudioEntity()->GetInteriorViewEngineOpenness());
|
|
|
|
if(!isBike && !isBicycle && !sm_InCarViewWind)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.Tracker = followPlayerVehicle->GetPlaceableTracker();
|
|
initParams.EnvironmentGroup = followPlayerVehicle->GetVehicleAudioEntity()->GetEnvironmentGroup();
|
|
initParams.SetVariableValue(ATSTRINGHASH("openness", 0x2721BC39), sm_PlayerVehicleOpenness);
|
|
|
|
if(vehicleNameHash == ATSTRINGHASH("Thruster", 0x58CDAF30))
|
|
{
|
|
audSoundSet thrusterSounds;
|
|
|
|
if(thrusterSounds.Init(ATSTRINGHASH("thruster_turbine_sounds", 0x9C4F5C78)))
|
|
{
|
|
g_FrontendAudioEntity.CreateAndPlaySound_Persistent(thrusterSounds.Find(ATSTRINGHASH("wind", 0x35369828)),&sm_InCarViewWind,&initParams);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_FrontendAudioEntity.CreateAndPlaySound_Persistent(ATSTRINGHASH("INTERIOR_VIEW_WIND_OPENNESS", 0x5DEBE1D0),&sm_InCarViewWind,&initParams);
|
|
}
|
|
}
|
|
if( sm_InCarViewWind )
|
|
{
|
|
// Duster is fully open but has wind shields in front of the cockpit seat. Full interior wind sounds a bit full-on.
|
|
f32 interiorViewWindOpennessScalar = (followPlayerVehicle->GetVehicleAudioEntity()->GetVehicleModelNameHash() == ATSTRINGHASH("DUSTER", 0x39D6779E) ? 0.5f : 1.0f);
|
|
sm_InCarViewWind->FindAndSetVariableValue(ATSTRINGHASH("openness", 0x2721BC39), sm_PlayerVehicleOpenness * interiorViewWindOpennessScalar);
|
|
REPLAY_ONLY(sm_InCarViewWind->SetRequestedVolume(audNorthAudioEngine::IsRenderingReplayFreeCamera()? g_SilenceVolume : 0.f);)
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sm_PlayerVehicleOpenness = sm_OpennessSmoother.CalculateValue(1.f, fwTimer::GetTimeStep());
|
|
|
|
if(sm_VehicleInteriorScene)
|
|
{
|
|
sm_VehicleInteriorScene->Stop();
|
|
sm_VehicleInteriorScene = NULL;
|
|
}
|
|
if(sm_InCarViewWind)
|
|
{
|
|
sm_InCarViewWind->StopAndForget();
|
|
sm_InCarViewWind = NULL;
|
|
}
|
|
if(sm_VehicleFirstPersonTurretScene)
|
|
{
|
|
sm_VehicleFirstPersonTurretScene->Stop();
|
|
sm_VehicleFirstPersonTurretScene = NULL;
|
|
}
|
|
if (sm_VehicleBonnetCamScene)
|
|
{
|
|
sm_VehicleBonnetCamScene->Stop();
|
|
sm_VehicleBonnetCamScene = NULL;
|
|
}
|
|
if (sm_VehicleGeneralScene)
|
|
{
|
|
sm_VehicleGeneralScene->Stop();
|
|
sm_VehicleGeneralScene = NULL;
|
|
}
|
|
}
|
|
|
|
if(sm_VehicleInteriorScene)
|
|
{
|
|
sm_VehicleInteriorScene->SetVariableValue(ATSTRINGHASH("apply", 0xE865CDE8), 1.0f - sm_PlayerVehicleOpenness);
|
|
sm_VehicleInteriorScene->SetVariableValue(ATSTRINGHASH("engineapply", 0xB378F6DF), 1.0f - playerVehicleEngineOpenness);
|
|
}
|
|
|
|
f32 highSpeedApplyFactor = 0.0f;
|
|
f32 highSpeedApplyFactorSmoothed = 0.0f;
|
|
f32 fwdSpeed = 0.0f;
|
|
f32 fwdSpeedRatio = 0.0f;
|
|
|
|
if(followPlayerVehicle)
|
|
{
|
|
if(!sm_HighSpeedScene)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("HIGH_SPEED_SCENE", 0xE371E209), &sm_HighSpeedScene);
|
|
}
|
|
|
|
if(followPlayerVehicle->GetVehicleAudioEntity()->GetAudioVehicleType() == AUD_VEHICLE_CAR)
|
|
{
|
|
fwdSpeed = DotProduct(followPlayerVehicle->GetVehicleAudioEntity()->GetCachedVelocity(), VEC3V_TO_VECTOR3(followPlayerVehicle->GetTransform().GetB()));
|
|
|
|
if(followPlayerVehicle->m_Transmission.GetDriveMaxVelocity() > 0.0f)
|
|
{
|
|
fwdSpeedRatio = Abs(fwdSpeed)/followPlayerVehicle->m_Transmission.GetDriveMaxVelocity();
|
|
}
|
|
|
|
if(followPlayerVehicle->m_Transmission.GetDriveMaxVelocity() >= sm_HighSpeedReqVehicleVelocity &&
|
|
followPlayerVehicle->m_Transmission.GetGear() >= followPlayerVehicle->m_Transmission.GetNumGears() - sm_HighSpeedMaxGearOffset)
|
|
{
|
|
// Apply factor ranges from 90%-98% of top speed
|
|
highSpeedApplyFactor = Clamp((fwdSpeedRatio - sm_HighSpeedApplyStart)/(sm_HighSpeedApplyEnd - sm_HighSpeedApplyStart), 0.0f, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
else if(sm_HighSpeedScene)
|
|
{
|
|
sm_HighSpeedScene->Stop();
|
|
sm_HighSpeedScene = NULL;
|
|
}
|
|
|
|
if(sm_HighSpeedScene)
|
|
{
|
|
highSpeedApplyFactorSmoothed = sm_HighSpeedSceneApplySmoother.CalculateValue(highSpeedApplyFactor, g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0));
|
|
sm_HighSpeedScene->SetVariableValue(ATSTRINGHASH("apply", 0xE865CDE8), highSpeedApplyFactorSmoothed);
|
|
}
|
|
|
|
if(sm_TriggerStuntRaceSpeedBoostScene)
|
|
{
|
|
if(!sm_StuntRaceSpeedUpScene)
|
|
{
|
|
if(sm_StuntRaceVehicleType == AUD_VEHICLE_HELI || sm_StuntRaceVehicleType == AUD_VEHICLE_PLANE)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("DLC_AIRRACE_Powerup_Speed_Up_Scene", 0x68133539), &sm_StuntRaceSpeedUpScene);
|
|
}
|
|
else
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("DLC_STUNT_Powerup_Speed_Up_Scene", 0x7835F632), &sm_StuntRaceSpeedUpScene);
|
|
}
|
|
}
|
|
|
|
sm_TriggerStuntRaceSpeedBoostScene = false;
|
|
}
|
|
|
|
if(sm_TriggerStuntRaceSlowDownScene)
|
|
{
|
|
if(!sm_StuntRaceSlowDownScene)
|
|
{
|
|
if(sm_StuntRaceVehicleType == AUD_VEHICLE_HELI || sm_StuntRaceVehicleType == AUD_VEHICLE_PLANE)
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("DLC_AIRRACE_Powerup_Speed_Down_Scene", 0x6D62B92), &sm_StuntRaceSlowDownScene);
|
|
}
|
|
else
|
|
{
|
|
DYNAMICMIXER.StartScene(ATSTRINGHASH("DLC_STUNT_Powerup_Speed_Down_Scene", 0xCE7A2CB), &sm_StuntRaceSlowDownScene);
|
|
}
|
|
}
|
|
|
|
sm_TriggerStuntRaceSlowDownScene = false;
|
|
}
|
|
|
|
#if __BANK
|
|
sm_HighSpeedSceneApplySmoother.SetRates(1.0f/sm_InvHighSpeedSmootherIncreaseRate, 1.0f/sm_InvHighSpeedSmootherDecreaseRate);
|
|
|
|
if(g_DebugHighSpeedEffect && followPlayerVehicle)
|
|
{
|
|
char tempString[128];
|
|
f32 xCoord = 0.1f;
|
|
f32 yCoord = 0.1f;
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), "High Speed Effect");
|
|
yCoord += 0.02f;
|
|
xCoord += 0.05f;
|
|
|
|
sprintf(tempString, "Apply Factor: %.02f", highSpeedApplyFactor);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += 0.02f;
|
|
|
|
sprintf(tempString, "Apply Factor Smoothed: %.02f", highSpeedApplyFactorSmoothed);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += 0.02f;
|
|
|
|
sprintf(tempString, "Fwd Speed: %.02f", fwdSpeed);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += 0.02f;
|
|
|
|
sprintf(tempString, "Fwd Speed Ratio: %.02f", fwdSpeedRatio);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += 0.02f;
|
|
|
|
sprintf(tempString, "Gear: %d/%d", followPlayerVehicle->m_Transmission.GetGear(), followPlayerVehicle->m_Transmission.GetNumGears());
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
yCoord += 0.02f;
|
|
}
|
|
#endif
|
|
|
|
sm_PlayerVehicleProximityRatio = 0.0f;
|
|
sm_LowLatencyWaveSlotManager.Update();
|
|
sm_HighQualityWaveSlotManager.Update();
|
|
sm_StandardWaveSlotManager.Update();
|
|
|
|
// Stop any DSP voices that we're not using any more
|
|
for(u32 loop = 0; loop < EFFECT_ROUTE_VEHICLE_ENGINE_MAX - EFFECT_ROUTE_VEHICLE_ENGINE_MIN + 1; loop++)
|
|
{
|
|
if(g_AudioEngine.GetEnvironment().IsEngineSubmixFree(loop))
|
|
{
|
|
if(sm_VehicleEngineSubmixes[loop].submixSound || sm_VehicleEngineSubmixes[loop].vehicleType != AUD_VEHICLE_NONE)
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(loop)->SetEffectParam(0, synthCorePcmSource::Params::CompiledSynthNameHash, g_NullSoundHash);
|
|
g_FrontendAudioEntity.StopAndForgetSounds(sm_VehicleEngineSubmixes[loop].submixSound);
|
|
sm_VehicleEngineSubmixes[loop].submixSound = NULL;
|
|
sm_VehicleEngineSubmixes[loop].vehicleType = AUD_VEHICLE_NONE;
|
|
sm_VehicleEngineSubmixes[loop].isGranular = false;
|
|
}
|
|
}
|
|
|
|
if(g_AudioEngine.GetEnvironment().IsExhaustSubmixFree(loop))
|
|
{
|
|
if(sm_VehicleExhaustSubmixes[loop].submixSound || sm_VehicleExhaustSubmixes[loop].vehicleType != AUD_VEHICLE_NONE)
|
|
{
|
|
g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(loop)->SetEffectParam(0, synthCorePcmSource::Params::CompiledSynthNameHash, g_NullSoundHash);
|
|
g_FrontendAudioEntity.StopAndForgetSounds(sm_VehicleExhaustSubmixes[loop].submixSound);
|
|
sm_VehicleExhaustSubmixes[loop].submixSound = NULL;
|
|
sm_VehicleExhaustSubmixes[loop].vehicleType = AUD_VEHICLE_NONE;
|
|
sm_VehicleEngineSubmixes[loop].isGranular = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Safety mechanism incase the player car is starving but then cancels the load request before it finishes
|
|
sm_FramesSincePlayerVehicleStarvation = Max(0, sm_FramesSincePlayerVehicleStarvation - 1);
|
|
|
|
// As soon as the player starts entering a vehicle, we want to start streaming in bank data
|
|
sm_PlayerPedTargetVehicle = NULL;
|
|
const CPed* localPlayer = g_PlayerSwitch.IsActive() && camInterface::GetGameplayDirector().GetSwitchHelper()? camInterface::GetGameplayDirector().GetSwitchHelper()->GetNewPed() : CGameWorld::FindLocalPlayer();
|
|
|
|
if(localPlayer)
|
|
{
|
|
if(localPlayer->GetPedIntelligence()->GetQueriableInterface()->IsTaskCurrentlyRunning(CTaskTypes::TASK_ENTER_VEHICLE))
|
|
{
|
|
CTaskEnterVehicle *task = (CTaskEnterVehicle*)localPlayer->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_ENTER_VEHICLE);
|
|
|
|
if(task)
|
|
{
|
|
sm_PlayerPedTargetVehicle = task->GetVehicle();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_DebugDSPParams)
|
|
{
|
|
char tempString[128];
|
|
f32 xCoord = 0.4f;
|
|
f32 yCoord = 0.1f;
|
|
|
|
for(u32 loop = 0; loop < EFFECT_ROUTE_VEHICLE_ENGINE_MAX - EFFECT_ROUTE_VEHICLE_ENGINE_MIN + 1; loop++)
|
|
{
|
|
u32 numVoices = audDriver::GetMixer()->GetActiveVoiceCount(audDriver::GetMixer()->GetSubmixIndex(g_AudioEngine.GetEnvironment().GetVehicleEngineSubmix(loop)));
|
|
sprintf(tempString, "Engine %d:%s - %d (%s)", loop, sm_VehicleEngineSubmixes[loop].submixSound && sm_VehicleEngineSubmixes[loop].submixSound->GetPlayState() == AUD_SOUND_PLAYING? "ON":"OFF", numVoices, GetVehicleTypeName(sm_VehicleEngineSubmixes[loop].vehicleType));
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255,255,255), tempString);
|
|
|
|
numVoices = audDriver::GetMixer()->GetActiveVoiceCount(audDriver::GetMixer()->GetSubmixIndex(g_AudioEngine.GetEnvironment().GetVehicleExhaustSubmix(loop)));
|
|
sprintf(tempString, "Exhaust %d:%s - %d (%s)", loop, sm_VehicleExhaustSubmixes[loop].submixSound && sm_VehicleExhaustSubmixes[loop].submixSound->GetPlayState() == AUD_SOUND_PLAYING? "ON":"OFF", numVoices, GetVehicleTypeName(sm_VehicleExhaustSubmixes[loop].vehicleType));
|
|
grcDebugDraw::Text(Vector2(xCoord + 0.22f, yCoord), Color32(255,255,255), tempString);
|
|
|
|
yCoord += 0.02f;
|
|
}
|
|
}
|
|
|
|
if(g_RenderSlotManager)
|
|
{
|
|
sm_StandardWaveSlotManager.DebugDraw(0.1f, 0.1f);
|
|
sm_HighQualityWaveSlotManager.DebugDraw(0.1f, 0.5f);
|
|
sm_LowLatencyWaveSlotManager.DebugDraw(0.1f, 0.7f);
|
|
}
|
|
|
|
if(g_DrawSuperDummyRadius)
|
|
{
|
|
Vector3 listenerPosition = VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetPanningListenerPosition());
|
|
grcDebugDraw::Sphere(listenerPosition, sqrtf((f32)g_SuperDummyRadiusSq), Color32(255,255,255), false, 1, 128, true);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// UpdateClass
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateClass()
|
|
{
|
|
#if RSG_BANK
|
|
if (g_CopyOverridenLeakageFromCurrentSettings)
|
|
{
|
|
g_OverridenLeakageVolMin = g_RadioOpennessVols[g_OverriddenVehicleRadioLeakage][0];
|
|
g_OverridenLeakageVolMax = g_RadioOpennessVols[g_OverriddenVehicleRadioLeakage][1];
|
|
|
|
g_OverridenLeakageLpfLinearMin = g_RadioLPFLinear[g_OverriddenVehicleRadioLeakage][0];
|
|
g_OverridenLeakageLpfLinearMax = g_RadioLPFLinear[g_OverriddenVehicleRadioLeakage][1];
|
|
|
|
g_OverridenLeakageRolloffMin = g_RadioRolloffs[g_OverriddenVehicleRadioLeakage][0];
|
|
g_OverridenLeakageRolloffMax = g_RadioRolloffs[g_OverriddenVehicleRadioLeakage][1];
|
|
|
|
g_OverridenLeakageHPFCutoff = g_RadioHPFCutoffs[g_OverriddenVehicleRadioLeakage];
|
|
g_OverridenLeakageMaxRadius = Sqrtf(g_MaxRadiusForAmbientRadio2[g_OverriddenVehicleRadioLeakage]);
|
|
|
|
g_CopyOverridenLeakageFromCurrentSettings = false;
|
|
}
|
|
|
|
if (CPed* playerPed = FindPlayerPed())
|
|
{
|
|
if (CVehicle* playerVehicle = playerPed->GetMyVehicle())
|
|
{
|
|
if (g_SmashPlayerSiren)
|
|
{
|
|
playerVehicle->GetVehicleAudioEntity()->SmashSiren(true);
|
|
}
|
|
|
|
if (g_FixPlayerSiren)
|
|
{
|
|
playerVehicle->GetVehicleAudioEntity()->FixSiren();
|
|
}
|
|
}
|
|
}
|
|
|
|
g_SmashPlayerSiren = false;
|
|
g_FixPlayerSiren = false;
|
|
#endif
|
|
|
|
CInteriorInst* pIntInst = CPortalVisTracker::GetPrimaryInteriorInst();
|
|
sm_IsInCarMeet = pIntInst && pIntInst->GetModelNameHash() == ATSTRINGHASH("tr_tuner_car_meet", 0xD813540);
|
|
}
|
|
|
|
const char* audVehicleAudioEntity::GetVehicleTypeName(audVehicleType type)
|
|
{
|
|
switch(type)
|
|
{
|
|
case AUD_VEHICLE_TRAIN:
|
|
return "Train";
|
|
case AUD_VEHICLE_PLANE:
|
|
return "Plane";
|
|
case AUD_VEHICLE_HELI:
|
|
return "Heli";
|
|
case AUD_VEHICLE_CAR:
|
|
return "Car";
|
|
case AUD_VEHICLE_BOAT:
|
|
return "Boat";
|
|
case AUD_VEHICLE_BICYCLE:
|
|
return "Bicycle";
|
|
case AUD_VEHICLE_TRAILER:
|
|
return "Trailer";
|
|
case AUD_VEHICLE_ANY:
|
|
return "Any";
|
|
case AUD_VEHICLE_NONE:
|
|
return "None";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
bool audVehicleAudioEntity::IsPlayerOnFootOrOnBicycle()
|
|
{
|
|
bool isOnFootOrOnBicycle = true;
|
|
const CPed* playerPed = FindPlayerPed();
|
|
|
|
if(playerPed && playerPed->GetPedConfigFlag( CPED_CONFIG_FLAG_InVehicle ))
|
|
{
|
|
const CVehicle* playerVehicle = playerPed->GetMyVehicle();
|
|
|
|
if(playerVehicle && !playerVehicle->InheritsFromBicycle())
|
|
{
|
|
isOnFootOrOnBicycle = false;
|
|
}
|
|
}
|
|
|
|
return isOnFootOrOnBicycle;
|
|
}
|
|
|
|
void audVehicleAudioEntity::UpdateActivationRanges()
|
|
{
|
|
#if __DEV
|
|
PF_SET(NumVehiclesInActivationRange, sm_NumVehiclesInActivationRange);
|
|
PF_SET(NumVehiclesInGranularRange, sm_NumVehiclesInGranularActivationRange);
|
|
#endif
|
|
|
|
sm_NumVehiclesInGranularActivationRangeLastFrame = sm_NumVehiclesInGranularActivationRange;
|
|
sm_NumVehiclesInActivationRangeLastFrame = sm_NumVehiclesInActivationRange;
|
|
|
|
if(sm_NumVehiclesInGranularActivationRange > g_MaxGranularEngines)
|
|
{
|
|
sm_GranularActivationRangeScale -= (fwTimer::GetTimeStep() * g_GranularActivationScaleDecreaseRate);
|
|
}
|
|
else if(sm_NumVehiclesInGranularActivationRange < g_MaxGranularEngines)
|
|
{
|
|
sm_GranularActivationRangeScale += (fwTimer::GetTimeStep() * g_GranularActivationScaleIncreaseRate);
|
|
}
|
|
|
|
sm_NumVehiclesInGranularActivationRange = 0;
|
|
sm_GranularActivationRangeScale = Clamp(sm_GranularActivationRangeScale, 0.02f, g_MaxGranularRangeScale);
|
|
//audAssert(CalculateNumVehiclesUsingSubmixes(AUD_VEHICLE_ANY, true, true) <= g_MaxGranularEngines);
|
|
|
|
if(sm_NumVehiclesInActivationRange > g_MaxVehicleSubmixes)
|
|
{
|
|
sm_ActivationRangeScale -= (fwTimer::GetTimeStep() * g_ActivationScaleDecreaseRate);
|
|
}
|
|
else if(sm_NumVehiclesInActivationRange < g_MaxVehicleSubmixes)
|
|
{
|
|
sm_ActivationRangeScale += (fwTimer::GetTimeStep() * g_ActivationScaleIncreaseRate);
|
|
}
|
|
|
|
sm_NumVehiclesInActivationRange = 0;
|
|
sm_ActivationRangeScale = Clamp(sm_ActivationRangeScale, 0.1f, g_MaxRealRangeScale);
|
|
|
|
for(u32 quadrant = 0; quadrant < NumQuadrants; quadrant++)
|
|
{
|
|
if(sm_NumVehiclesInDummyRange[quadrant] > g_MaxDumyVehiclesPerQuadrant)
|
|
{
|
|
sm_DummyRangeScale[quadrant] -= fwTimer::GetTimeStep() * g_DummyActivationScaleDecreaseRate;
|
|
}
|
|
else if(sm_NumVehiclesInDummyRange[quadrant] < g_MaxDumyVehiclesPerQuadrant)
|
|
{
|
|
sm_DummyRangeScale[quadrant] += fwTimer::GetTimeStep() * g_DummyActivationScaleIncreaseRate;
|
|
}
|
|
|
|
sm_DummyRangeScale[quadrant] = Clamp(sm_DummyRangeScale[quadrant], 0.1f, g_MaxDummyRangeScale);
|
|
}
|
|
|
|
sysMemSet(sm_NumVehiclesInDummyRange, 0, sizeof(u32) * NumQuadrants);
|
|
sm_NumDummyVehiclesLastFrame = sm_NumDummyVehiclesCounter;
|
|
sm_NumDummyVehiclesCounter = 0;
|
|
|
|
for(u32 quadrant = 0; quadrant < NumQuadrants; quadrant++)
|
|
{
|
|
if(sm_NumVehiclesInWaterSlapRadius[quadrant] > g_MaxWaterSlapVehiclesPerQuadrant)
|
|
{
|
|
sm_WaterSlapRadiusScalar[quadrant] -= fwTimer::GetTimeStep();
|
|
}
|
|
else if(sm_NumVehiclesInWaterSlapRadius[quadrant] < g_MaxWaterSlapVehiclesPerQuadrant)
|
|
{
|
|
sm_WaterSlapRadiusScalar[quadrant] += fwTimer::GetTimeStep();
|
|
}
|
|
|
|
sm_WaterSlapRadiusScalar[quadrant] = Clamp(sm_WaterSlapRadiusScalar[quadrant], 0.0f, 1.0f);
|
|
}
|
|
|
|
sysMemSet(sm_NumVehiclesInWaterSlapRadius, 0, sizeof(u32) * NumQuadrants);
|
|
|
|
for(u32 quadrant = 0; quadrant < NumQuadrants; quadrant++)
|
|
{
|
|
if(sm_NumVehiclesInRainRadius[quadrant] > g_MaxRainVehiclesPerQuadrant)
|
|
{
|
|
sm_RainRadiusScalar[quadrant] -= fwTimer::GetTimeStep();
|
|
}
|
|
else if(sm_NumVehiclesInRainRadius[quadrant] < g_MaxRainVehiclesPerQuadrant)
|
|
{
|
|
sm_RainRadiusScalar[quadrant] += fwTimer::GetTimeStep();
|
|
}
|
|
|
|
sm_RainRadiusScalar[quadrant] = Clamp(sm_RainRadiusScalar[quadrant], 0.0f, 1.0f);
|
|
}
|
|
|
|
sysMemSet(sm_NumVehiclesInRainRadius, 0, sizeof(u32) * NumQuadrants);
|
|
|
|
#if __DEV
|
|
PF_SET(GranularRadiusScalar, sm_GranularActivationRangeScale);
|
|
PF_SET(RealRadiusScalar, sm_ActivationRangeScale);
|
|
PF_SET(DummyRadiusScalarQ1, sm_DummyRangeScale[0]);
|
|
PF_SET(DummyRadiusScalarQ2, sm_DummyRangeScale[1]);
|
|
PF_SET(DummyRadiusScalarQ3, sm_DummyRangeScale[2]);
|
|
PF_SET(DummyRadiusScalarQ4, sm_DummyRangeScale[3]);
|
|
PF_SET(RainRadiusScalarQ1, sm_RainRadiusScalar[0]);
|
|
PF_SET(RainRadiusScalarQ2, sm_RainRadiusScalar[1]);
|
|
PF_SET(RainRadiusScalarQ3, sm_RainRadiusScalar[2]);
|
|
PF_SET(RainRadiusScalarQ4, sm_RainRadiusScalar[3]);
|
|
PF_SET(WaterSlapRadiusScalarQ1, sm_WaterSlapRadiusScalar[0]);
|
|
PF_SET(WaterSlapRadiusScalarQ2, sm_WaterSlapRadiusScalar[1]);
|
|
PF_SET(WaterSlapRadiusScalarQ3, sm_WaterSlapRadiusScalar[2]);
|
|
PF_SET(WaterSlapRadiusScalarQ4, sm_WaterSlapRadiusScalar[3]);
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Stop road noise sounds
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::StopRoadNoiseSounds()
|
|
{
|
|
StopAndForgetSounds(m_RoadNoiseFast, m_RoadNoiseHeavy, m_RoadNoiseWet, m_RoadNoiseRidged, m_RoadNoiseNPC, m_WheelDetailLoop);
|
|
StopAndForgetSounds(m_RoadNoiseRidgedPulse, m_DirtyWheelLoop, m_GlassyWheelLoop, m_CaterpillarTrackLoop);
|
|
StopAndForgetSounds(m_MainSkidLoop, m_SideSkidLoop, m_UndersteerSkidLoop, m_WheelSpinLoop, m_WetWheelSpinLoop, m_DriveWheelSlipLoop, m_WetSkidLoop);
|
|
|
|
for(s32 i = 0; i < NUM_VEH_CWHEELS_MAX; i++)
|
|
{
|
|
if(m_ShallowWaterSounds[i])
|
|
{
|
|
m_ShallowWaterSounds[i]->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update any road noise sounds
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateRoadNoiseSounds(audVehicleVariables& vehicleVariables)
|
|
{
|
|
PF_FUNC(UpdateRoadNoise);
|
|
|
|
if(HasEntityVariableBlock())
|
|
{
|
|
SetEntityVariable(ATSTRINGHASH("speed", 0xf997622b), Abs(vehicleVariables.fwdSpeed));
|
|
}
|
|
|
|
// Helicopters apparently have wheels...
|
|
if(m_Vehicle->GetNumWheels() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_HELI)
|
|
{
|
|
CalculateWheelMaterials(vehicleVariables);
|
|
return;
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_DisableRoadNoise)
|
|
{
|
|
StopRoadNoiseSounds();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if(m_Vehicle->InheritsFromAmphibiousQuadBike() && ((CAmphibiousQuadBike*)m_Vehicle)->IsWheelsFullyRaised())
|
|
{
|
|
StopRoadNoiseSounds();
|
|
return;
|
|
}
|
|
|
|
if(m_Vehicle->InheritsFromSubmarineCar() && !((CSubmarineCar*)m_Vehicle)->AreWheelsActive())
|
|
{
|
|
StopRoadNoiseSounds();
|
|
return;
|
|
}
|
|
|
|
if(IsSeaPlane() && CalculateIsInWater())
|
|
{
|
|
StopRoadNoiseSounds();
|
|
return;
|
|
}
|
|
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("DELUXO", 0x586765FB) && m_Vehicle->GetSpecialFlightModeRatio() > 0.f)
|
|
{
|
|
StopRoadNoiseSounds();
|
|
return;
|
|
}
|
|
|
|
if(IsReal())
|
|
{
|
|
// no smoothing in slow mo
|
|
if(audNorthAudioEngine::IsInSlowMo())
|
|
{
|
|
m_MainSkidSmoother.SetRates(1.f, 1.f);
|
|
m_LateralSkidSmoother.SetRates(1.f, 1.f);
|
|
}
|
|
else
|
|
{
|
|
m_MainSkidSmoother.SetRates(g_MainSkidSmootherIncrease * 0.001f, g_MainSkidSmootherDecrease * 0.001f);
|
|
m_LateralSkidSmoother.SetRates(g_LateralSkidSmootherIncrease * 0.001f, g_LateralSkidSmootherDecrease * 0.001f);
|
|
}
|
|
|
|
CalculateWheelMaterials(vehicleVariables);
|
|
UpdateWheelDetail(vehicleVariables);
|
|
UpdateWheelDirtyness(vehicleVariables);
|
|
UpdateCaterpillarTracks(vehicleVariables);
|
|
|
|
if(!(m_Vehicle->pHandling->mFlags & MF_HAS_TRACKS))
|
|
{
|
|
UpdateSkids(vehicleVariables);
|
|
|
|
if (!IsToyCar())
|
|
{
|
|
UpdateWheelWater(vehicleVariables);
|
|
}
|
|
|
|
UpdateRidgedSurfaces(vehicleVariables);
|
|
UpdateWheelSpin(vehicleVariables);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//invalidate the stored material settings, we'll always play concrete for dummy cars
|
|
m_CachedMaterialSettings = NULL;
|
|
}
|
|
|
|
// Special pass-by loops for Franklin's special ability
|
|
if(!m_IsPlayerVehicle && g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeFranklin)
|
|
{
|
|
const u32 relativeSpeedVar = ATSTRINGHASH("relativeSpeed", 0x842B383);
|
|
const u32 fwdSpeedRatioVar = ATSTRINGHASH("fwdSpeedRatio", 0xB10DFAB9);
|
|
|
|
if(!m_FranklinSpecialPassby)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.SetVariableValue(relativeSpeedVar, 0.f);
|
|
initParams.SetVariableValue(fwdSpeedRatioVar, 0.f);
|
|
CreateAndPlaySound_Persistent(g_FrontendAudioEntity.GetSpecialAbilitySounds().Find("Franklin_Passby"), &m_FranklinSpecialPassby, &initParams);
|
|
}
|
|
else
|
|
{
|
|
const f32 relativeSpeed = (m_CachedVehicleVelocity - VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetListenerVelocity())).Mag();
|
|
m_FranklinSpecialPassby->FindAndSetVariableValue(relativeSpeedVar, relativeSpeed);
|
|
m_FranklinSpecialPassby->FindAndSetVariableValue(fwdSpeedRatioVar, vehicleVariables.fwdSpeedRatio);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_FranklinSpecialPassby);
|
|
}
|
|
|
|
UpdateFreewayBumps(vehicleVariables);
|
|
UpdateFastRoadNoise(vehicleVariables);
|
|
UpdateNPCRoadNoise(vehicleVariables);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Calculate wheel materials
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::CalculateWheelMaterials(audVehicleVariables& params)
|
|
{
|
|
phMaterialMgr::Id mainWheelMaterial = 0;
|
|
const f32 fwdSpeedVolDb = audDriverUtil::ComputeDbVolumeFromLinear(Min(0.5f, params.fwdSpeedRatio));
|
|
const f32 massVolDb = Clamp(audDriverUtil::ComputeDbVolumeFromLinear(m_Vehicle->pHandling->m_fMass / 1500.f), -5.f, 12.f);
|
|
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
phMaterialMgr::Id matId = PGTAMATERIALMGR->UnpackMtlId(m_Vehicle->GetWheel(i)->GetMaterialId());
|
|
|
|
// Did this wheel hit another vehicle? If so, check if the vehicle wants to overwrite the specified material
|
|
CPhysical* contactEntity = m_Vehicle->GetWheel(i)->GetHitPhysical();
|
|
|
|
if(contactEntity)
|
|
{
|
|
CollisionMaterialSettings* collisionSettings = g_audCollisionMaterials[static_cast<s32>(matId)];
|
|
|
|
if(collisionSettings)
|
|
{
|
|
collisionSettings = audCollisionAudioEntity::GetMaterialOverride(contactEntity, collisionSettings, m_Vehicle->GetWheel(i)->GetHitComponent());
|
|
|
|
if(collisionSettings)
|
|
{
|
|
if(collisionSettings->MaterialID >= 0 && collisionSettings->MaterialID < (phMaterialMgr::Id)g_audCollisionMaterials.GetCount())
|
|
{
|
|
matId = collisionSettings->MaterialID;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(ShouldForceSnow())
|
|
{
|
|
CollisionMaterialSettings* collisionSettings = audNorthAudioEngine::GetObject<CollisionMaterialSettings>(ATSTRINGHASH("AM_BASE_SNOW_COMPACT", 0x10AFB64F));
|
|
|
|
if(collisionSettings && collisionSettings->MaterialID >= 0 && collisionSettings->MaterialID < (phMaterialMgr::Id)g_audCollisionMaterials.GetCount())
|
|
{
|
|
matId = collisionSettings->MaterialID;
|
|
}
|
|
}
|
|
|
|
// preserve the actual material so that we can do component specific audio (head/torso etc) but
|
|
// for history purposes treat any ped material as one
|
|
phMaterialMgr::Id historyMatId = matId;
|
|
|
|
if(PGTAMATERIALMGR->GetIsPed(matId))
|
|
{
|
|
historyMatId = g_PedMaterialId;
|
|
|
|
// ensure we play a ped tyre bump
|
|
naAssertf(matId<(phMaterialMgr::Id)g_audCollisionMaterials.GetCount(), "Out of bounds matid");
|
|
const s32 matId32=static_cast<s32>(matId);
|
|
g_audCollisionMaterials[matId32]->TyreBump = ATSTRINGHASH("TYRE_BUMP_PED", 0x3421B9D8);
|
|
}
|
|
|
|
// only for four wheels
|
|
if((i == 0 || i == 1 || i == m_Vehicle->GetNumWheels() - 2 || i == m_Vehicle->GetNumWheels() -1)
|
|
&& m_Vehicle->GetWheel(i)->GetIsTouching())
|
|
{
|
|
// only play tyrebumps for cars the right way up and moving a little
|
|
if(m_VehicleType != AUD_VEHICLE_HELI && m_VehicleType != AUD_VEHICLE_BICYCLE && !m_Vehicle->IsUpsideDown() && Abs(params.fwdSpeed) > 0.1f)
|
|
{
|
|
if(m_LastMaterialIds[i] != ~0U && m_LastTyreBumpTimes[i/2] + 250 < fwTimer::GetTimeInMilliseconds())
|
|
{
|
|
naAssertf(m_LastMaterialIds[i]<(phMaterialMgr::Id)g_audCollisionMaterials.GetCount(), "out of bounds");
|
|
|
|
if(m_LastMaterialIds[i] != historyMatId && matId < (u32)g_audCollisionMaterials.GetCount() && m_LastMaterialIds[i] < (u32)g_audCollisionMaterials.GetCount() && g_audCollisionMaterials[static_cast<u32>(matId)] && g_audCollisionMaterials[static_cast<u32>(m_LastMaterialIds[i])])
|
|
{
|
|
if(g_audCollisionMaterials[static_cast<u32>(matId)]->TyreBump == ATSTRINGHASH("TYRE_BUMP_PED", 0x3421B9D8) || (g_audCollisionMaterials[static_cast<u32>(matId)]->TyreBump != g_NullSoundHash && g_audCollisionMaterials[static_cast<u32>(m_LastMaterialIds[i])]->TyreBump != g_NullSoundHash))
|
|
{
|
|
// material has changed - play a tyre bump
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
u32 soundHash = g_audCollisionMaterials[static_cast<u32>(matId)]->TyreBump;
|
|
if(IsToyCar())
|
|
{
|
|
soundHash = ATSTRINGHASH("RC_BANDITTO_TYRE_BUMPS_MULTI", 0xAA32FAE1);
|
|
}
|
|
// only boost volume based on mass for interesting tyre bumps
|
|
else if(soundHash == ATSTRINGHASH("TYRE_BUMPS_CONCRETE", 0xE6F65DED))
|
|
{
|
|
initParams.Volume = fwdSpeedVolDb;
|
|
if(m_Vehicle->GetWheel(i)->GetTyreHealth()<=0.f)
|
|
{
|
|
soundHash = ATSTRINGHASH("STREET_PROPS_CAR_WHEEL", 0x2940F3DC);
|
|
}
|
|
}
|
|
else if(g_audCollisionMaterials[static_cast<u32>(matId)]->TyreBump == ATSTRINGHASH("TYRE_BUMP_PED", 0x3421B9D8))
|
|
{
|
|
// ped crunches only affected by vehicle mass
|
|
initParams.Volume = Clamp(massVolDb, -3.f, 6.f);
|
|
if(m_Vehicle->GetWheel(i)->GetHitPhysical() && m_Vehicle->GetWheel(i)->GetHitPhysical()->GetType() == ENTITY_TYPE_PED)
|
|
{
|
|
// break a bone?
|
|
if(audEngineUtil::ResolveProbability(0.4f))
|
|
{
|
|
((CPed*)m_Vehicle->GetWheel(i)->GetHitPhysical())->GetPedAudioEntity()->TriggerBoneBreak((RagdollComponent)m_Vehicle->GetWheel(i)->GetHitComponent());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
initParams.Volume = fwdSpeedVolDb + massVolDb;
|
|
}
|
|
|
|
Vector3 pos;
|
|
GetCachedWheelPosition(i, pos, params);
|
|
initParams.Position = pos;
|
|
CreateAndPlaySound(soundHash, &initParams);
|
|
m_LastTyreBumpTimes[i/2] = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_LastMaterialIds[i] = historyMatId;
|
|
}
|
|
|
|
u32 maxWheelsUsingMaterial = 0;
|
|
atFixedArray<WheelMaterialUsage, NUM_VEH_CWHEELS_MAX> wheelMaterialUsage;
|
|
|
|
// We're only playing one material per car, so we want to select the one that is being used by the majority of wheels. In the event
|
|
// that we have multiple materials being used by the same number of wheels, we fall back to the priority system. First of all, count up
|
|
// what materials are being used, and by how many wheels.
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
bool alreadyExists = false;
|
|
CollisionMaterialSettings* materialSettings = g_audCollisionMaterials[static_cast<u32>(m_LastMaterialIds[i])];
|
|
|
|
if(materialSettings)
|
|
{
|
|
for(u32 loop = 0; loop < wheelMaterialUsage.GetCount(); loop++)
|
|
{
|
|
if(wheelMaterialUsage[loop].materialSettings == materialSettings)
|
|
{
|
|
alreadyExists = true;
|
|
wheelMaterialUsage[loop].numWheels++;
|
|
maxWheelsUsingMaterial = Max(wheelMaterialUsage[loop].numWheels, maxWheelsUsingMaterial);
|
|
}
|
|
}
|
|
|
|
if(!alreadyExists)
|
|
{
|
|
WheelMaterialUsage materialUsageEntry;
|
|
materialUsageEntry.materialSettings = materialSettings;
|
|
materialUsageEntry.numWheels = 1;
|
|
materialUsageEntry.wheelIndex = i;
|
|
wheelMaterialUsage.Push(materialUsageEntry);
|
|
maxWheelsUsingMaterial = Max(materialUsageEntry.numWheels, maxWheelsUsingMaterial);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now get rid of any materials that aren't being used by the max number of wheels
|
|
for(s32 i = 0; i < wheelMaterialUsage.GetCount(); )
|
|
{
|
|
if(wheelMaterialUsage[i].numWheels < maxWheelsUsingMaterial)
|
|
{
|
|
wheelMaterialUsage.Delete(i);
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
|
|
s32 loudestSurface = -1;
|
|
s32 wheelIndexToUse = -1;
|
|
|
|
// Check for burnout materials, as they take priority
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
if(m_Vehicle->GetWheel(i)->GetDynamicFlags().IsFlagSet(WF_BURNOUT))
|
|
{
|
|
CollisionMaterialSettings* materialSettings = g_audCollisionMaterials[static_cast<u32>(m_LastMaterialIds[i])];
|
|
|
|
if(materialSettings)
|
|
{
|
|
u8 prio = FindSkidSurfacePriority(materialSettings->SurfacePriority);
|
|
|
|
if(prio > loudestSurface)
|
|
{
|
|
loudestSurface = prio;
|
|
wheelIndexToUse = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// No burnout materials, so select the highest priority material from the ones being used
|
|
if(wheelIndexToUse == -1)
|
|
{
|
|
for(s32 i = 0; i < wheelMaterialUsage.GetCount(); i++)
|
|
{
|
|
u8 prio = FindSkidSurfacePriority(wheelMaterialUsage[i].materialSettings->SurfacePriority);
|
|
|
|
if(prio > loudestSurface)
|
|
{
|
|
loudestSurface = prio;
|
|
wheelIndexToUse = wheelMaterialUsage[i].wheelIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
if(g_DisplayGroundMaterial && GetVehicle()->ContainsLocalPlayer())
|
|
{
|
|
formatf(g_DrivingMaterialName, "%s", PGTAMATERIALMGR->GetMaterial(m_LastMaterialIds[wheelIndexToUse]).GetName());
|
|
}
|
|
#endif
|
|
|
|
mainWheelMaterial = m_LastMaterialIds[wheelIndexToUse];
|
|
params.hasMaterialChanged = (mainWheelMaterial != m_MainWheelMaterial);
|
|
|
|
if(params.hasMaterialChanged || !m_CachedMaterialSettings)
|
|
{
|
|
CollisionMaterialSettings* oldMaterialSettings = m_CachedMaterialSettings;
|
|
|
|
// material has changed, need to regrab cached settings
|
|
naAssertf(mainWheelMaterial<(phMaterialMgr::Id)g_audCollisionMaterials.GetCount(), "Out of bounds");
|
|
m_CachedMaterialSettings = g_audCollisionMaterials[static_cast<s32>(mainWheelMaterial)];
|
|
m_MainWheelMaterial = mainWheelMaterial;
|
|
|
|
if(m_CachedMaterialSettings && oldMaterialSettings)
|
|
{
|
|
// Play a bit of clatter if we transition to/from a dirty material
|
|
if((m_CachedMaterialSettings->Dirtiness >= 0.75f && oldMaterialSettings->Dirtiness <= 0.3f) ||
|
|
(m_CachedMaterialSettings->Dirtiness <= 0.3f && oldMaterialSettings->Dirtiness >= 0.75f))
|
|
{
|
|
audMetadataRef clatterSound = g_NullSoundRef;
|
|
|
|
if(!m_Vehicle->m_nVehicleFlags.bIsBeingTowed && m_VehicleType != AUD_VEHICLE_TRAILER)
|
|
{
|
|
clatterSound = GetClatterSound();
|
|
|
|
const f32 rescaledSpeedRatio = Min(1.f, params.movementSpeed * params.invDriveMaxVelocity * 0.8f);
|
|
|
|
if(clatterSound != g_NullSoundRef &&
|
|
params.numWheelsTouching > 0 &&
|
|
rescaledSpeedRatio > 0.0f
|
|
BANK_ONLY(&& !g_DisableClatter))
|
|
{
|
|
if(params.timeInMs - m_LastSurfaceChangeClatterTime > 1000)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_HEAVY_CLATTER;
|
|
initParams.UpdateEntity = true;
|
|
|
|
// Heavy vehicle clatter is a bit much here, so scale the volume down
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(rescaledSpeedRatio * (HasHeavyRoadNoise()? 0.5f : 1.0f)) + GetClatterVolumeBoost();
|
|
CreateAndPlaySound(clatterSound, &initParams);
|
|
}
|
|
|
|
// Set this even if we haven't played a sound - means the player needs to be travelling on a clean/dirty surface for a minimum period of time
|
|
m_LastSurfaceChangeClatterTime = params.timeInMs;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update surface settle sounds
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateSurfaceSettleSounds(audVehicleVariables& params)
|
|
{
|
|
if(m_VehicleType == AUD_VEHICLE_CAR || m_VehicleType == AUD_VEHICLE_BICYCLE)
|
|
{
|
|
// Force settling to happen when we go back onto tarmac
|
|
const float levelToUseForSettling = m_CachedMaterialSettings && m_CachedMaterialSettings->SurfaceSettle == g_NullSoundHash ? 0.f : params.skidLevel;
|
|
|
|
m_SurfaceSettleSmoother.CalculateValue(levelToUseForSettling);
|
|
|
|
// If we've stopped skidding abruptly, play a surface settle sound
|
|
if(!m_SurfaceSettleSound)
|
|
{
|
|
static float s_SettleRateThreshold = 4.f;
|
|
const float changeRate = (m_SurfaceSettleSmoother.GetLastValue() - levelToUseForSettling) * fwTimer::GetInvTimeStep();
|
|
if(IsReal() && changeRate > s_SettleRateThreshold)
|
|
{
|
|
if(m_CachedMaterialSettings && m_CachedMaterialSettings->SurfaceSettle != g_NullSoundHash)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Position = VEC3V_TO_VECTOR3(m_Vehicle->GetVehiclePosition());
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(sm_RecentSpeedToSettleVolume.CalculateValue(m_SurfaceSettleSmoother.GetLastValue()));
|
|
CreateAndPlaySound_Persistent(m_CachedMaterialSettings->SurfaceSettle, &m_SurfaceSettleSound, &initParams);
|
|
|
|
if(m_SurfaceSettleSound)
|
|
{
|
|
if(AUD_GET_TRISTATE_VALUE(m_CachedMaterialSettings->Flags, FLAG_ID_COLLISIONMATERIALSETTINGS_SURFACESETTLEISLOOP) == AUD_TRISTATE_TRUE)
|
|
{
|
|
m_SurfaceSettleSound->SetReleaseTime((s32)(1000.0f * sm_RecentSpeedToSettleReleaseTime.CalculateValue(m_SurfaceSettleSmoother.GetLastValue())));
|
|
}
|
|
}
|
|
}
|
|
|
|
m_SurfaceSettleSmoother.Reset();
|
|
m_SurfaceSettleSmoother.CalculateValue(0.0f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// For surface settle sounds that are loops - we want to turn it on, set the release time, then turn it off again
|
|
if(!m_CachedMaterialSettings || AUD_GET_TRISTATE_VALUE(m_CachedMaterialSettings->Flags, FLAG_ID_COLLISIONMATERIALSETTINGS_SURFACESETTLEISLOOP) == AUD_TRISTATE_TRUE)
|
|
{
|
|
StopAndForgetSounds(m_SurfaceSettleSound);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update wheel detail loop
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWheelDetail(audVehicleVariables& params)
|
|
{
|
|
f32 detailVolFactor;
|
|
f32 vehicleSteerAngle = m_Vehicle->GetSteerAngle();
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_BICYCLE)
|
|
{
|
|
detailVolFactor = sm_RoadNoiseBicycleVolCurve.CalculateValue(params.fwdSpeedAbs);
|
|
}
|
|
else if(m_IsFastRoadNoiseDisabled || m_VehicleType == AUD_VEHICLE_PLANE)
|
|
{
|
|
detailVolFactor = sm_RoadNoiseSingleVolCurve.CalculateValue(params.fwdSpeedAbs);
|
|
}
|
|
else
|
|
{
|
|
detailVolFactor = sm_RoadNoiseDetailVolCurve.CalculateValue(params.fwdSpeedAbs);
|
|
}
|
|
|
|
f32 stationaryVolumeDB = g_SilenceVolume;
|
|
|
|
// If we're stationary, also play the detail sound if we start adjusting the wheels (volume scaled by angle change rate). Only doing
|
|
// this on the player vehicle as any jerky NPC wheel movements have the potential to sound rubbish
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
u32 numSteeringWheels = 0;
|
|
u32 numSteeringWheelsTouching = 0;
|
|
|
|
for(u32 wheelIndex = 0; wheelIndex < m_Vehicle->GetNumWheels(); wheelIndex++)
|
|
{
|
|
CWheel* wheel = m_Vehicle->GetWheel(wheelIndex);
|
|
|
|
if(wheel && wheel->GetConfigFlags().IsFlagSet(WCF_STEER))
|
|
{
|
|
numSteeringWheels++;
|
|
|
|
if(wheel->GetIsTouching())
|
|
{
|
|
numSteeringWheelsTouching++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(numSteeringWheels > 0 && numSteeringWheelsTouching > 0 && GetVehicleModelNameHash() != ATSTRINGHASH("ZHABA", 0x4C8DBA51))
|
|
{
|
|
bool hasDonkSuspension = (m_Vehicle->GetVehicleModelInfo() && m_Vehicle->GetVehicleModelInfo()->GetVehicleFlag(CVehicleModelInfoFlags::FLAG_HAS_LOWRIDER_DONK_HYDRAULICS));
|
|
f32 steeringAngleCR = Abs(vehicleSteerAngle - m_SteeringAngleLastFrame) * fwTimer::GetInvTimeStep();
|
|
|
|
if(hasDonkSuspension)
|
|
{
|
|
steeringAngleCR = Max(steeringAngleCR, m_HydraulicSuspensionAngleSmoother.GetLastValue() * 25.0f);
|
|
}
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_BICYCLE)
|
|
{
|
|
steeringAngleCR *= 2.0f;
|
|
}
|
|
|
|
const f32 stationaryVolumeScale = numSteeringWheelsTouching/(f32)numSteeringWheels;
|
|
f32 stationaryVolumeLin = sm_RoadNoiseSteeringAngleCRToVolume.CalculateValue(steeringAngleCR * stationaryVolumeScale * GetRoadNoiseVolumeScale());
|
|
|
|
if(IsMonsterTruck())
|
|
{
|
|
// Monster truck has super big tyres, so exaggerate this effect
|
|
stationaryVolumeLin *= 2.0f;
|
|
}
|
|
else if(hasDonkSuspension)
|
|
{
|
|
stationaryVolumeLin *= 1.5f;
|
|
}
|
|
|
|
stationaryVolumeLin *= (1.0f - Min(params.fwdSpeedRatio/0.05f, 1.0f));
|
|
stationaryVolumeDB = audDriverUtil::ComputeDbVolumeFromLinear(stationaryVolumeLin);
|
|
|
|
static const float steeringAngleSqueakLimit = 20.0f * DtoR;
|
|
|
|
if((vehicleSteerAngle < -steeringAngleSqueakLimit && m_SteeringAngleLastFrame > -steeringAngleSqueakLimit) ||
|
|
(vehicleSteerAngle > steeringAngleSqueakLimit && m_SteeringAngleLastFrame < steeringAngleSqueakLimit))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.UpdateEntity = true;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.Volume = stationaryVolumeDB;
|
|
CreateAndPlaySound(ATSTRINGHASH("STEERING_ANGLE_SQUEAL", 0x797A3325), &initParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
f32 volumeLin = detailVolFactor * GetRoadNoiseVolumeScale() * audDriverUtil::ComputeLinearVolumeFromDb(m_IsPlayerVehicle?0.f:5.f);
|
|
|
|
// On a bike, lets treat having only one wheel as putting additional pressure on it (stoppie/endo) and therefore scale up the
|
|
// road noise volume rather than decreasing it
|
|
if(m_VehicleType == AUD_VEHICLE_BICYCLE && params.numWheelsTouchingFactor > 0.0f)
|
|
{
|
|
f32 endoStoppieVolumeScalar = (1.0f - params.numWheelsTouchingFactor);
|
|
CWheel* rearWheel = m_Vehicle->GetWheelFromId(BIKE_WHEEL_R);
|
|
|
|
// Reduce volume for wheelies vs. stoppies, as we can sustain them for longer so having a super loud increase sounds weird
|
|
if(rearWheel && rearWheel->GetIsTouching())
|
|
{
|
|
endoStoppieVolumeScalar *= 0.5f;
|
|
}
|
|
|
|
volumeLin *= (0.66f + (0.5f * endoStoppieVolumeScalar));
|
|
}
|
|
else
|
|
{
|
|
volumeLin *= params.numWheelsTouchingFactor;
|
|
}
|
|
|
|
f32 volumeDB = audDriverUtil::ComputeDbVolumeFromLinear(volumeLin);
|
|
|
|
// Steering angle on aircraft is controlled by adjusting the ailerons rather than actually rotating the wheels
|
|
// so doesn't make sense to play a wheel sound in this situation
|
|
if(!m_Vehicle->InheritsFromPlane() && !m_Vehicle->InheritsFromHeli())
|
|
{
|
|
volumeDB += sm_RoadNoiseSteeringAngleToAttenuation.CalculateValue(Abs(vehicleSteerAngle) * RtoD);
|
|
}
|
|
|
|
volumeDB = Max(volumeDB, stationaryVolumeDB);
|
|
|
|
if(volumeDB > g_SilenceVolume)
|
|
{
|
|
// detail tyre noise
|
|
if(!m_WheelDetailLoop || params.hasMaterialChanged || (m_VehicleType == AUD_VEHICLE_BICYCLE && Abs(m_FwdSpeedLastFrame) < 0.05f))
|
|
{
|
|
if(m_CachedMaterialSettings)
|
|
{
|
|
u32 detailRollHash = g_NullSoundHash;
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_BICYCLE && Abs(params.fwdSpeed) >= 0.05f)
|
|
{
|
|
detailRollHash = m_CachedMaterialSettings->BicycleTyreRoll;
|
|
m_IsFastRoadNoiseDisabled = true;
|
|
}
|
|
else if(m_CachedMaterialSettings->DetailTyreRoll != g_NullSoundHash)
|
|
{
|
|
detailRollHash = m_CachedMaterialSettings->DetailTyreRoll;
|
|
m_IsFastRoadNoiseDisabled = false;
|
|
}
|
|
else
|
|
{
|
|
detailRollHash = m_CachedMaterialSettings->FastTyreRoll;
|
|
m_IsFastRoadNoiseDisabled = true;
|
|
}
|
|
|
|
if(m_WheelDetailLoop)
|
|
{
|
|
if(detailRollHash != m_PrevDetailRoadNoiseHash)
|
|
{
|
|
m_WheelDetailLoop->SetReleaseTime(300);
|
|
m_WheelDetailLoop->StopAndForget();
|
|
}
|
|
}
|
|
|
|
if(!m_WheelDetailLoop)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.UpdateEntity = true;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateAndPlaySound_Persistent(detailRollHash, &m_WheelDetailLoop, &initParams);
|
|
m_PrevDetailRoadNoiseHash = detailRollHash;
|
|
}
|
|
}
|
|
else if(m_WheelDetailLoop)
|
|
{
|
|
m_WheelDetailLoop->SetReleaseTime(300);
|
|
m_WheelDetailLoop->StopAndForget();
|
|
}
|
|
}
|
|
|
|
if(m_WheelDetailLoop)
|
|
{
|
|
m_WheelDetailLoop->SetRequestedVolume(volumeDB);
|
|
m_WheelDetailLoop->SetRequestedPitch(params.roadNoisePitch);
|
|
}
|
|
}
|
|
else if(m_WheelDetailLoop)
|
|
{
|
|
m_WheelDetailLoop->SetReleaseTime(300);
|
|
m_WheelDetailLoop->StopAndForget();
|
|
}
|
|
|
|
if(m_IsPlayerVehicle && m_VehicleType == AUD_VEHICLE_CAR && g_FrontendAudioEntity.GetSpecialAbilityMode() == audFrontendAudioEntity::kSpecialAbilityModeFranklin)
|
|
{
|
|
const u32 wheelSpeedVar = ATSTRINGHASH("wheelSpeed", 0xAF5C7495);
|
|
const u32 steeringAngleVar = ATSTRINGHASH("steeringAngle", 0x926D6EC9);
|
|
|
|
if(!m_FranklinSpecialTraction)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.SetVariableValue(wheelSpeedVar, 0.f);
|
|
initParams.SetVariableValue(steeringAngleVar, 0.f);
|
|
CreateAndPlaySound_Persistent(g_FrontendAudioEntity.GetSpecialAbilitySounds().Find("Franklin_Traction"), &m_FranklinSpecialTraction, &initParams);
|
|
}
|
|
else
|
|
{
|
|
m_FranklinSpecialTraction->FindAndSetVariableValue(wheelSpeedVar, params.wheelSpeedRatio);
|
|
m_FranklinSpecialTraction->FindAndSetVariableValue(steeringAngleVar, vehicleSteerAngle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_FranklinSpecialTraction);
|
|
}
|
|
|
|
m_SteeringAngleLastFrame = vehicleSteerAngle;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if this is a monster truck
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsMonsterTruck() const
|
|
{
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
|
|
if(modelNameHash == ATSTRINGHASH("MONSTER", 0xCD93A7DB) ||
|
|
modelNameHash == ATSTRINGHASH("MARSHALL", 0x49863E9C))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update NPC road noise
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateNPCRoadNoise(audVehicleVariables& UNUSED_PARAM(params))
|
|
{
|
|
#if __BANK
|
|
if(g_DisableNPCRoadNoise)
|
|
{
|
|
if(m_RoadNoiseNPC)
|
|
{
|
|
m_RoadNoiseNPC->StopAndForget();
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if(!m_IsPlayerVehicle && GetAudioVehicleType() == AUD_VEHICLE_CAR)
|
|
{
|
|
if(!m_RoadNoiseNPC)
|
|
{
|
|
if(GetEntityVariableValue(ATSTRINGHASH("mass", 0x4BC594CB)) > 0.0f)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.AttackTime = g_NPCRoadNoiseAttackTime;
|
|
CreateSound_PersistentReference(GetNPCRoadNoiseSound(), &m_RoadNoiseNPC, &initParams);
|
|
|
|
if(m_RoadNoiseNPC)
|
|
{
|
|
m_RoadNoiseNPC->SetReleaseTime(g_NPCRoadNoiseReleaseTime);
|
|
m_RoadNoiseNPC->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_RoadNoiseNPC)
|
|
{
|
|
PF_INCREMENT(NumNPCRoadNoise);
|
|
|
|
Mat34V m = m_Vehicle->GetMatrix();
|
|
f32 leftAttenuation = m_RoadNoiseLeftCone.ComputeAttenuation(m);
|
|
f32 rightAttenuation = m_RoadNoiseRightCone.ComputeAttenuation(m);
|
|
f32 minAttenuation = Min(leftAttenuation, rightAttenuation);
|
|
BANK_ONLY(m_PrevNPCRoadNoiseAttenuation = minAttenuation * 2.0f);
|
|
|
|
Vec3V vehicleToListener = Subtract(g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(), m_Vehicle->GetVehiclePosition());
|
|
Vec3V vehicleToListenerDirection = NormalizeFastSafe(vehicleToListener, Vec3V(V_ZERO));
|
|
|
|
f32 relativeVelocity = (m_CachedVehicleVelocity - VEC3V_TO_VECTOR3(g_AudioEngine.GetEnvironment().GetListenerVelocity())).Mag();
|
|
f32 volLin = sm_NPCRoadNoiseRelativeSpeedToVol.CalculateValue(relativeVelocity);
|
|
|
|
Vec3V vehicleVelocity = RCC_VEC3V(m_CachedVehicleVelocity);
|
|
Vec3V vehicleForward = m_Vehicle->GetTransform().GetForward();
|
|
Vec3V vehicleDirection = NormalizeFastSafe(vehicleVelocity, vehicleForward);
|
|
f32 forwardDot = Dot(vehicleDirection, vehicleToListenerDirection).Getf();
|
|
|
|
// Adjust the smoothing based on z height above us (so overhead roads are smooth, but passbys are still nice and quick)
|
|
static f32 maxSmoothing = 0.0001f;
|
|
f32 zOffsetFactor = Clamp(abs(vehicleToListener.GetZf())/5.0f, 0.0f, 1.0f);
|
|
f32 smoothingRequired = 1.0f;
|
|
|
|
// Choppy remote vehicle updates in network games means that need heavier smoothing
|
|
if(NetworkInterface::IsGameInProgress())
|
|
{
|
|
smoothingRequired = maxSmoothing;
|
|
}
|
|
// In single player, blend between 1.0 and maxSmoothing depending on the zOffset
|
|
else
|
|
{
|
|
smoothingRequired = maxSmoothing + ((1.0f - maxSmoothing) * (1.0f - zOffsetFactor));
|
|
}
|
|
|
|
m_NPCRoadNoiseSmoother.SetRate(smoothingRequired);
|
|
|
|
// Sweep the synth param forwards or backwards from the centre as the car moves toward/away from us
|
|
f32 finalParam = m_NPCRoadNoiseSmoother.CalculateValue(0.5f + ((forwardDot > 0.0f)? -minAttenuation : minAttenuation), fwTimer::GetTimeInMilliseconds());
|
|
m_RoadNoiseNPC->FindAndSetVariableValue(ATSTRINGHASH("CTRL", 0xAF169697), finalParam);
|
|
m_RoadNoiseNPC->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(volLin));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_RoadNoiseNPC)
|
|
{
|
|
m_RoadNoiseNPC->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if any water VFX are playing
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsAnyWaterVFXActive() const
|
|
{
|
|
for(u32 i = 0; i < BOAT_WATER_SAMPLES; i++)
|
|
{
|
|
if(m_WaterSamples.IsSet(i))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Request a weapon charge sfx
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::RequestWeaponChargeSfx(s32 boneIndex, f32 chargeLevel)
|
|
{
|
|
m_WeaponChargeBone = boneIndex;
|
|
m_WeaponChargeLevel = chargeLevel;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the transformation soundset associated with a submarine car vehicle
|
|
// ----------------------------------------------------------------
|
|
u32 audVehicleAudioEntity::GetSubmarineCarTransformSoundSet() const
|
|
{
|
|
if (GetVehicleModelNameHash() == ATSTRINGHASH("STROMBERG", 0x34DBA661))
|
|
{
|
|
return m_IsFocusVehicle ? ATSTRINGHASH("stromberg_transform_ss", 0xDE029774) : ATSTRINGHASH("stromberg_transform_npc_ss", 0x48112622);
|
|
}
|
|
else if (GetVehicleModelNameHash() == ATSTRINGHASH("TOREADOR", 0x56C8A5EF))
|
|
{
|
|
return m_IsFocusVehicle ? ATSTRINGHASH("toreador_transform_ss", 0xA29C53CF) : ATSTRINGHASH("toreador_transform_npc_ss", 0xEFE26236);
|
|
}
|
|
|
|
return 0u;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the soundset associated with a submarine car vehicle
|
|
// ----------------------------------------------------------------
|
|
u32 audVehicleAudioEntity::GetSubmarineCarSoundset() const
|
|
{
|
|
if (GetVehicleModelNameHash() == ATSTRINGHASH("STROMBERG", 0x34DBA661))
|
|
{
|
|
return ATSTRINGHASH("stromberg_submersible_sounds", 0x1DF32727);
|
|
}
|
|
else if (GetVehicleModelNameHash() == ATSTRINGHASH("TOREADOR", 0x56C8A5EF))
|
|
{
|
|
return ATSTRINGHASH("toreador_submersible_sounds", 0x9919A4F4);
|
|
}
|
|
|
|
return 0u;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Query if this is a submarine car type vehicle
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsSubmarineCar() const
|
|
{
|
|
return GetVehicleModelNameHash() == ATSTRINGHASH("STROMBERG", 0x34DBA661) || GetVehicleModelNameHash() == ATSTRINGHASH("TOREADOR", 0x56C8A5EF);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Called when submarine car wings tilt fully up/down
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSubmarineCarWingFlapSound()
|
|
{
|
|
TriggerSimpleSoundFromSoundset(GetSubmarineCarSoundset(), ATSTRINGHASH("wing_flap", 0x531673B5) REPLAY_ONLY(, true));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Called when submarine car rudders start turning
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSubmarineCarRudderTurnStart()
|
|
{
|
|
if(fwTimer::GetTimeInMilliseconds() - m_LastSubCarRudderTurnSoundTime > g_MinSubRudderRepeatTime)
|
|
{
|
|
TriggerSimpleSoundFromSoundset(GetSubmarineCarSoundset(), ATSTRINGHASH("rotor_turn", 0xC24998A7) REPLAY_ONLY(, true));
|
|
m_LastSubCarRudderTurnSoundTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Called when a submarine car starts transforming
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::OnSubmarineCarAnimationStateChanged(u32 newState, f32 UNUSED_PARAM(phase))
|
|
{
|
|
if(!IsDisabled())
|
|
{
|
|
switch((CSubmarineCar::AnimationState)newState)
|
|
{
|
|
case CSubmarineCar::State_StartToSubmarine: // State_MoveWheelsUp
|
|
m_SubmarineTransformSoundHash = ATSTRINGHASH("transform_to_sub", 0xF585770F);
|
|
break;
|
|
|
|
case CSubmarineCar::State_MoveWheelCoversOut:
|
|
m_SubmarineTransformSoundHash = ATSTRINGHASH("move_wheel_covers_out", 0xC56A6456);
|
|
break;
|
|
|
|
case CSubmarineCar::State_FinishToSub:
|
|
m_SubmarineTransformSoundHash = ATSTRINGHASH("finish_to_sub", 0xE9EC6B7);
|
|
break;
|
|
|
|
case CSubmarineCar::State_StartToCar: // Same as State_MoveWheelCoversIn
|
|
m_SubmarineTransformSoundHash = m_TriggerFastSubCarTransformSound? ATSTRINGHASH("transform_to_car_short", 0x99F3DA7) : ATSTRINGHASH("transform_to_car", 0xD8B90941);
|
|
|
|
if(m_ShouldStopSubTransformSound && m_TriggerFastSubCarTransformSound)
|
|
{
|
|
m_ShouldStopSubTransformSound = false;
|
|
}
|
|
|
|
m_TriggerFastSubCarTransformSound = false;
|
|
break;
|
|
|
|
case CSubmarineCar::State_MoveWheelsDown:
|
|
m_SubmarineTransformSoundHash = ATSTRINGHASH("move_wheel_covers_down", 0x23DE340B);
|
|
m_TriggerFastSubCarTransformSound = false;
|
|
break;
|
|
|
|
case CSubmarineCar::State_FinishToCar:
|
|
m_SubmarineTransformSoundHash = ATSTRINGHASH("finish_to_car", 0xF3722B5A);
|
|
m_TriggerFastSubCarTransformSound = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateWeaponCharge
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWeaponCharge()
|
|
{
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("KHANJALI", 0xAA6F980A))
|
|
{
|
|
if(m_WeaponChargeLevel > 0.f)
|
|
{
|
|
if(!m_WeaponChargeSound)
|
|
{
|
|
const u32 soundNameHash = m_IsFocusVehicle? ATSTRINGHASH("xm_vehicle_khanjali_railgun_charge_player_master", 0x842C8EC3) : ATSTRINGHASH("xm_vehicle_khanjali_railgun_charge_npc_master", 0xD294CA0D);
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
|
|
if(m_WeaponChargeBone != -1)
|
|
{
|
|
initParams.UpdateEntity = true;
|
|
initParams.u32ClientVar = (u32(AUD_VEHICLE_SOUND_CUSTOM_BONE)&0xffff) | ((u32)m_WeaponChargeBone << 16);
|
|
}
|
|
else
|
|
{
|
|
initParams.TrackEntityPosition = true;
|
|
}
|
|
|
|
CreateAndPlaySound_Persistent(soundNameHash, &m_WeaponChargeSound, &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSoundPersistant(soundNameHash, &initParams, m_WeaponChargeSound, GetOwningEntity()));
|
|
}
|
|
|
|
if(m_WeaponChargeSound)
|
|
{
|
|
m_WeaponChargeSound->FindAndSetVariableValue(ATSTRINGHASH("chargeLevel", 0x6C265400), m_WeaponChargeLevel);
|
|
}
|
|
}
|
|
else if(m_WeaponChargeSound)
|
|
{
|
|
m_WeaponChargeSound->StopAndForget(true);
|
|
}
|
|
|
|
m_WeaponChargeLevel = 0.f;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateWaterState
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateLandingGear()
|
|
{
|
|
if(m_ShouldStopLandingGearSound && GetVehicleModelNameHash() == ATSTRINGHASH("Thruster", 0x58CDAF30))
|
|
{
|
|
if(m_LandingGearSound)
|
|
{
|
|
m_LandingGearSound->StopAndForget(true);
|
|
}
|
|
|
|
m_ShouldStopLandingGearSound = false;
|
|
}
|
|
else if(m_ShouldPlayLandingGearSound)
|
|
{
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("BLAZER5", 0xA1355F67))
|
|
{
|
|
audSoundSet soundSet;
|
|
|
|
if(soundSet.Init(ATSTRINGHASH("DLC_ImportExport_Blazer5_Wheel_Sounds", 0x50782A26)))
|
|
{
|
|
TriggerLandingGearSound(soundSet, m_IsLandingGearRetracting? ATSTRINGHASH("retract", 0x8E1F66E6) : ATSTRINGHASH("deploy", 0xC9200261));
|
|
}
|
|
}
|
|
|
|
m_ShouldPlayLandingGearSound = false;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity StopLandingGearSound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::StopLandingGearSound()
|
|
{
|
|
m_ShouldPlayLandingGearSound = false;
|
|
m_ShouldStopLandingGearSound = true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateWaterState
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWaterState(const VfxWaterSampleData_s* pFxSampleData)
|
|
{
|
|
for(u32 i = 0; i < BOAT_WATER_SAMPLES; i++)
|
|
{
|
|
m_WaterSamples.Set(i, pFxSampleData[i].isInWater);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update fast road noise
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateFastRoadNoise(audVehicleVariables& params)
|
|
{
|
|
if(!m_IsFastRoadNoiseDisabled)
|
|
{
|
|
// dummy vehicles don't seem to have a valid ground speed
|
|
const f32 fastRoadNoiseVolLin = (m_IsPlayerVehicle?g_PlayerRoadNoiseFastVolCurve.CalculateValue(Abs(params.fwdSpeed)):sm_RoadNoiseFastVolCurve.CalculateValue(Abs(params.fwdSpeed))) * params.numWheelsTouchingFactor * GetRoadNoiseVolumeScale() * audDriverUtil::ComputeLinearVolumeFromDb(m_IsPlayerVehicle?0.f:5.f);
|
|
|
|
if(fastRoadNoiseVolLin > g_SilenceVolumeLin)
|
|
{
|
|
if(!m_RoadNoiseFast || params.hasMaterialChanged)
|
|
{
|
|
u32 soundHash = (m_CachedMaterialSettings?m_CachedMaterialSettings->FastTyreRoll:g_FastConcreteTyreRollHash);
|
|
|
|
if(m_RoadNoiseFast)
|
|
{
|
|
// Only stop the sound if we've actually changed over
|
|
if(m_PrevFastRoadNoiseHash != soundHash)
|
|
{
|
|
m_RoadNoiseFast->SetReleaseTime(300);
|
|
StopAndForgetSounds(m_RoadNoiseFast);
|
|
}
|
|
}
|
|
|
|
if(!m_RoadNoiseFast)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
initParams.AttackTime = 300;
|
|
CreateSound_PersistentReference(soundHash, &m_RoadNoiseFast, &initParams);
|
|
if(m_RoadNoiseFast)
|
|
{
|
|
m_RoadNoiseFast->PrepareAndPlay();
|
|
m_PrevFastRoadNoiseHash = soundHash;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_RoadNoiseFast)
|
|
{
|
|
// 10dB louder for AI cars
|
|
m_RoadNoiseFast->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(fastRoadNoiseVolLin));
|
|
m_RoadNoiseFast->SetRequestedPitch(params.roadNoisePitch);
|
|
}
|
|
}
|
|
else if(m_RoadNoiseFast)
|
|
{
|
|
m_RoadNoiseFast->SetReleaseTime(300);
|
|
StopAndForgetSounds(m_RoadNoiseFast);
|
|
}
|
|
|
|
f32 wetRollVolumeLin = 0.0f;
|
|
|
|
if(!m_Vehicle->m_nFlags.bInMloRoom &&
|
|
m_EnvironmentGroup &&
|
|
!m_EnvironmentGroup->IsUnderCover())
|
|
{
|
|
wetRollVolumeLin = g_weather.GetWetness() * params.numWheelsTouchingFactor * GetRoadNoiseVolumeScale() * (g_RoadNoiseWetRoadVolCurve.CalculateValue(params.fwdSpeedAbs) + params.wetRoadSkidModifier);
|
|
}
|
|
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_RoadNoiseWet, sm_TarmacSkidSounds.Find(ATSTRINGHASH("WetRoll", 0x7B8E2BAA)), wetRollVolumeLin, Max(params.roadNoisePitch, (s32)sm_RoadNoisePitchCurve.CalculateValue(params.fwdSpeedAbs)), m_EnvironmentGroup, g_RoadNoiseCategory, true, false);
|
|
|
|
if(HasHeavyRoadNoise())
|
|
{
|
|
// heavy vehicle rumble
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_RoadNoiseHeavy, ATSTRINGHASH("TRUCK_LOW_ROAD_NOISE", 0x314B4DBE), fastRoadNoiseVolLin * g_VehicleMassToRumbleVol.CalculateValue(m_Vehicle->pHandling->m_fMass), 0, m_EnvironmentGroup, NULL, true, false, 0.f);
|
|
}
|
|
|
|
u32 tireSweetenerWheelVar = AUD_VEHICLE_SOUND_UNKNOWN;
|
|
|
|
if(m_IsPlayerVehicle && m_Vehicle->GetOwnedBy()!=ENTITY_OWNEDBY_CUTSCENE)
|
|
{
|
|
const camCinematicDirector& cinematicDirector = camInterface::GetCinematicDirector();
|
|
|
|
if(cinematicDirector.IsRenderingAnyInVehicleCinematicCamera())
|
|
{
|
|
const camBaseCamera* renderedCinematicCamera = cinematicDirector.GetRenderedCamera();
|
|
|
|
if(renderedCinematicCamera)
|
|
{
|
|
CWheel* tireSweetenerWheel = NULL;
|
|
|
|
if(renderedCinematicCamera->GetNameHash() == ATSTRINGHASH("WHEEL_FRONT_LEFT_CAMERA", 0x4472093A))
|
|
{
|
|
tireSweetenerWheel = m_Vehicle->GetWheelFromId(VEH_WHEEL_LF);
|
|
}
|
|
else if(renderedCinematicCamera->GetNameHash() == ATSTRINGHASH("WHEEL_FRONT_RIGHT_CAMERA", 0x9843718D))
|
|
{
|
|
tireSweetenerWheel = m_Vehicle->GetWheelFromId(VEH_WHEEL_RF);
|
|
}
|
|
else if(renderedCinematicCamera->GetNameHash() == ATSTRINGHASH("WHEEL_REAR_LEFT_CAMERA", 0xA4EAD485))
|
|
{
|
|
tireSweetenerWheel = m_Vehicle->GetWheelFromId(VEH_WHEEL_LR);
|
|
}
|
|
else if(renderedCinematicCamera->GetNameHash() == ATSTRINGHASH("WHEEL_REAR_RIGHT_CAMERA", 0x560D1CF6))
|
|
{
|
|
tireSweetenerWheel = m_Vehicle->GetWheelFromId(VEH_WHEEL_RR);
|
|
}
|
|
|
|
if(!tireSweetenerWheel || !tireSweetenerWheel->GetIsTouching())
|
|
{
|
|
tireSweetenerWheelVar = AUD_VEHICLE_SOUND_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
// Left front isn't always wheel 0 as things like trailers only have two rear wheels, so go through and grab the appropriate
|
|
// index for the chosen wheelID
|
|
for(u32 loop = 0; loop < m_Vehicle->GetNumWheels(); loop++)
|
|
{
|
|
if(m_Vehicle->GetWheel(loop) == tireSweetenerWheel)
|
|
{
|
|
tireSweetenerWheelVar = GetWheelSoundUpdateClientVar(loop);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(tireSweetenerWheelVar != AUD_VEHICLE_SOUND_UNKNOWN)
|
|
{
|
|
if(!m_CinematicTireSweetener)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.u32ClientVar = tireSweetenerWheelVar;
|
|
initParams.UpdateEntity = true;
|
|
CreateAndPlaySound_Persistent(sm_TarmacSkidSounds.Find(ATSTRINGHASH("CinematicTireSweetener", 0x383949C7)), &m_CinematicTireSweetener, &initParams);
|
|
}
|
|
|
|
if(m_CinematicTireSweetener)
|
|
{
|
|
m_CinematicTireSweetener->SetRequestedDopplerFactor(0.0f);
|
|
m_CinematicTireSweetener->SetClientVariable(tireSweetenerWheelVar);
|
|
m_CinematicTireSweetener->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(fastRoadNoiseVolLin));
|
|
m_CinematicTireSweetener->SetRequestedPitch(params.roadNoisePitch);
|
|
}
|
|
}
|
|
else if(m_CinematicTireSweetener)
|
|
{
|
|
m_CinematicTireSweetener->StopAndForget();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_RoadNoiseFast)
|
|
{
|
|
m_RoadNoiseFast->StopAndForget();
|
|
}
|
|
|
|
if(m_RoadNoiseWet)
|
|
{
|
|
m_RoadNoiseWet->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update ridged surfaces
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateRidgedSurfaces(audVehicleVariables& params)
|
|
{
|
|
u32 ridgedSoundHash = g_NullSoundHash;
|
|
|
|
if(params.numWheelsTouchingFactor > 0.0f)
|
|
{
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
if(m_Vehicle->GetWheel(i)->GetIsTouching() && Abs(m_Vehicle->GetWheel(i)->GetGroundSpeed()) > 0.2f)
|
|
{
|
|
CollisionMaterialSettings* materialSettings = g_audCollisionMaterials[static_cast<s32>(m_LastMaterialIds[i])];
|
|
|
|
if(materialSettings && materialSettings->RidgedSurfaceLoop != g_NullSoundHash)
|
|
{
|
|
ridgedSoundHash = materialSettings->RidgedSurfaceLoop;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ridgedSoundHash != g_NullSoundHash)
|
|
{
|
|
if(ridgedSoundHash != m_LastRidgedRoadNoise)
|
|
{
|
|
StopAndForgetSounds(m_RoadNoiseRidged);
|
|
}
|
|
|
|
m_LastRidgedRoadNoise = ridgedSoundHash;
|
|
|
|
if(!m_RoadNoiseRidged)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateSound_PersistentReference(ridgedSoundHash, &m_RoadNoiseRidged, &initParams);
|
|
if(m_RoadNoiseRidged)
|
|
{
|
|
m_RoadNoiseRidged->PrepareAndPlay();
|
|
}
|
|
}
|
|
|
|
if(m_RoadNoiseRidged)
|
|
{
|
|
f32 vehicleSpeed = Abs(Dot(m_Vehicle->GetTransform().GetB(), VECTOR3_TO_VEC3V(m_CachedVehicleVelocity)).Getf()) * m_RidgedSurfaceDirectionMatch;
|
|
m_RoadNoiseRidged->FindAndSetVariableValue(ATSTRINGHASH("SPEED", 0xf997622b), vehicleSpeed);
|
|
|
|
f32 ridgedHPFCutoff = 0;
|
|
|
|
if(!m_IsPlayerVehicle)
|
|
{
|
|
ridgedHPFCutoff = 500.0f;
|
|
if(m_RoadNoiseRidgedPulse)
|
|
{
|
|
m_RoadNoiseRidgedPulse->StopAndForget();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
if(audNorthAudioEngine::ShouldTriggerPulseHeadset())
|
|
{
|
|
if(!m_RoadNoiseRidgedPulse)
|
|
{
|
|
CreateAndPlaySound_Persistent(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("RumbleStrip", 0xE1802336)), &m_RoadNoiseRidgedPulse);
|
|
}
|
|
|
|
if(m_RoadNoiseRidgedPulse)
|
|
{
|
|
m_RoadNoiseRidgedPulse->FindAndSetVariableValue(ATSTRINGHASH("SPEED", 0xf997622b), vehicleSpeed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_RoadNoiseRidgedPulse);
|
|
}
|
|
|
|
static const f32 minDistanceSq = 15.0f * 15.0f;
|
|
static const f32 maxDistanceSq = 50.0f * 50.0f;
|
|
ridgedHPFCutoff = 500.0f * Clamp((m_DistanceFromListener2LastFrame - minDistanceSq)/(maxDistanceSq - minDistanceSq), 0.0f, 1.0f);
|
|
}
|
|
|
|
m_RoadNoiseRidged->SetRequestedHPFCutoff((u32)ridgedHPFCutoff);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_RoadNoiseRidged);
|
|
StopAndForgetSounds(m_RoadNoiseRidgedPulse);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update skids
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateFreewayBumps(audVehicleVariables& params)
|
|
{
|
|
const bool isOnFreeway = (m_IsPlayerVehicle?FindPlayerPed()->GetPlayerInfo()->GetPlayerDataPlayerOnHighway()!=0
|
|
:m_Vehicle->GetIntelligence()->IsOnHighway());
|
|
|
|
if(m_Vehicle && m_Vehicle->GetDriver() && m_Vehicle->GetDriver() == FindPlayerPed())
|
|
{
|
|
u32 currentTime = g_AudioEngine.GetTimeInMilliseconds();
|
|
if(!m_WasOnFreeWayLastFrame && isOnFreeway)
|
|
{
|
|
m_TimeEnteredFreeway = currentTime;
|
|
m_TriggeredDispatchEnteredFreeway = false;
|
|
}
|
|
else if(!m_WasOnFreeWayLastFrame && isOnFreeway)
|
|
{
|
|
m_TimeExitedFreeway = currentTime;
|
|
m_TriggeredDispatchExitedFreeway = false;
|
|
}
|
|
|
|
if(isOnFreeway && !m_TriggeredDispatchEnteredFreeway && currentTime - m_TimeEnteredFreeway > 4000)
|
|
{
|
|
g_AudioScannerManager.TriggerCopDispatchInteraction(SCANNER_CDIT_REPORT_SUSPECT_ENTERED_FREEWAY);
|
|
m_TriggeredDispatchEnteredFreeway = true;
|
|
}
|
|
if(!isOnFreeway && !m_TriggeredDispatchExitedFreeway && currentTime - m_TimeExitedFreeway > 4000)
|
|
{
|
|
g_AudioScannerManager.TriggerCopDispatchInteraction(SCANNER_CDIT_REPORT_SUSPECT_LEFT_FREEWAY);
|
|
m_TriggeredDispatchExitedFreeway = true;
|
|
}
|
|
}
|
|
m_WasOnFreeWayLastFrame = isOnFreeway;
|
|
|
|
if((m_VehicleType == AUD_VEHICLE_CAR || m_VehicleType == AUD_VEHICLE_TRAILER) && isOnFreeway)
|
|
{
|
|
// fake freeway bumps every 12m axis aligned
|
|
Vector3 vehiclePosition = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
Vector3 positionToWheel = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetForward()) * (m_DistanceBetweenWheels * 0.5f);
|
|
Vector3 frontPos = vehiclePosition + positionToWheel;
|
|
Vector3 backPos = vehiclePosition - positionToWheel;
|
|
|
|
u32 lastFront, curFront;
|
|
u32 lastBack, curBack;
|
|
bank_float fDistScalar = (1.f/30.f);
|
|
if(Abs(m_CachedVehicleVelocity.x) > Abs(m_CachedVehicleVelocity.y))
|
|
{
|
|
// use x axis
|
|
lastFront = (u32)Abs(m_LastRoadPosFront.x * fDistScalar);
|
|
curFront = (u32)Abs(frontPos.x * fDistScalar);
|
|
lastBack = (u32)Abs(m_LastRoadPosBack.x * fDistScalar);
|
|
curBack = (u32)Abs(backPos.x * fDistScalar);
|
|
}
|
|
else
|
|
{
|
|
// use y axis
|
|
lastFront = (u32)Abs(m_LastRoadPosFront.y * fDistScalar);
|
|
curFront = (u32)Abs(frontPos.y * fDistScalar);
|
|
lastBack = (u32)Abs(m_LastRoadPosBack.y * fDistScalar);
|
|
curBack = (u32)Abs(backPos.y * fDistScalar);
|
|
}
|
|
|
|
const f32 bumpVolOffset = (m_IsPlayerVehicle?0.f:2.f);
|
|
|
|
if(lastFront != curFront)
|
|
{
|
|
if(m_LastFreewayBumpFront + 300 < fwTimer::GetTimeInMilliseconds() && m_Vehicle->GetWheel(0)->GetIsTouching())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Position = frontPos;
|
|
initParams.Volume = bumpVolOffset + audDriverUtil::ComputeDbVolumeFromLinear(g_FreewayBumpSpeedToVol.CalculateValue(params.wheelSpeedAbs));
|
|
initParams.Pitch = (s16) (m_FreewayBumpPitch + (s32)g_FreewayBumpSpeedToPitch.CalculateValue(params.wheelSpeedAbs));
|
|
CreateAndPlaySound(ATSTRINGHASH("TYRE_BUMPS_FREEWAY", 0x48022590), &initParams);
|
|
}
|
|
m_LastFreewayBumpFront = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
|
|
if(lastBack != curBack)
|
|
{
|
|
if(m_LastFreewayBumpBack + 300 < fwTimer::GetTimeInMilliseconds() && m_Vehicle->GetWheel(m_Vehicle->GetNumWheels()-1)->GetIsTouching())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Position = backPos;
|
|
initParams.Volume = bumpVolOffset + audDriverUtil::ComputeDbVolumeFromLinear(g_FreewayBumpSpeedToVol.CalculateValue(params.wheelSpeedAbs));
|
|
initParams.Pitch = (s16) (m_FreewayBumpPitch + (s32)g_FreewayBumpSpeedToPitch.CalculateValue(params.wheelSpeedAbs));
|
|
CreateAndPlaySound(ATSTRINGHASH("TYRE_BUMPS_FREEWAY", 0x48022590), &initParams);
|
|
}
|
|
m_LastFreewayBumpBack = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
|
|
m_LastRoadPosFront.x = frontPos.x;
|
|
m_LastRoadPosFront.y = frontPos.y;
|
|
m_LastRoadPosBack.x = backPos.x;
|
|
m_LastRoadPosBack.y = backPos.y;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update wheel spin
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWheelSpin(audVehicleVariables& params)
|
|
{
|
|
if(params.hasMaterialChanged || !m_CachedMaterialSettings)
|
|
{
|
|
StopAndForgetSounds(m_WheelSpinLoop);
|
|
}
|
|
|
|
if(!m_CachedMaterialSettings)
|
|
{
|
|
StopAndForgetSounds(m_WetWheelSpinLoop);
|
|
}
|
|
|
|
if(m_CachedMaterialSettings)
|
|
{
|
|
f32 vehicleSpeed2 = m_CachedVehicleVelocity.Mag2();
|
|
f32 maxWheelSpin = 0.0f;
|
|
|
|
for(u32 loop = 0; loop < m_Vehicle->GetNumWheels(); loop++)
|
|
{
|
|
CWheel* wheel = m_Vehicle->GetWheel(loop);
|
|
|
|
if (wheel && wheel->GetConfigFlags().IsFlagSet(WCF_REARWHEEL))
|
|
{
|
|
if (vehicleSpeed2 < 4.0f)
|
|
{
|
|
f32 wheelGroundSpeed = Abs(wheel->GetGroundSpeed());
|
|
|
|
if (wheelGroundSpeed > 4.0f)
|
|
{
|
|
maxWheelSpin = Max(maxWheelSpin, CVfxHelper::GetInterpValue(wheelGroundSpeed, 4.0f, 12.0f));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
f32 wheelSpinRatio = m_WheelSpinSmoother.CalculateValue(maxWheelSpin, fwTimer::GetTimeInMilliseconds());
|
|
|
|
if(wheelSpinRatio > 0.0f)
|
|
{
|
|
if(!m_WheelSpinLoop)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateAndPlaySound_Persistent(m_CachedMaterialSettings->WheelSpinLoop, &m_WheelSpinLoop, &initParams);
|
|
}
|
|
|
|
f32 wetnessFactor = 0.0f;
|
|
|
|
if(!m_Vehicle->m_nFlags.bInMloRoom &&
|
|
m_EnvironmentGroup &&
|
|
!m_EnvironmentGroup->IsUnderCover())
|
|
{
|
|
wetnessFactor = Max(g_weather.GetWetness(), params.numDriveWheelsInShallowWaterFactor);
|
|
}
|
|
|
|
if(!m_WetWheelSpinLoop && wetnessFactor > 0.0f)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateAndPlaySound_Persistent(sm_TarmacSkidSounds.Find(ATSTRINGHASH("WetWheelSpin", 0x9A716CA8)), &m_WetWheelSpinLoop, &initParams);
|
|
}
|
|
|
|
if(m_WheelSpinLoop)
|
|
{
|
|
m_WheelSpinLoop->FindAndSetVariableValue(ATSTRINGHASH("wheelSpinRatio", 0x73422810), wheelSpinRatio);
|
|
}
|
|
|
|
if(m_WetWheelSpinLoop)
|
|
{
|
|
m_WetWheelSpinLoop->FindAndSetVariableValue(ATSTRINGHASH("wheelSpinRatio", 0x73422810), wheelSpinRatio);
|
|
m_WetWheelSpinLoop->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(wetnessFactor * wheelSpinRatio));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_WheelSpinLoop, m_WetWheelSpinLoop);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// GetShallowWaterWheelSound
|
|
// ----------------------------------------------------------------
|
|
audMetadataRef audVehicleAudioEntity::GetShallowWaterWheelSound() const
|
|
{
|
|
return sm_ExtrasSoundSet.Find(ATSTRINGHASH("VehicleWheelWaterLoop", 0x1182FD91));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// GetShallowWaterEnterSound
|
|
// ----------------------------------------------------------------
|
|
audMetadataRef audVehicleAudioEntity::GetShallowWaterEnterSound() const
|
|
{
|
|
return sm_ExtrasSoundSet.Find(ATSTRINGHASH("VehicleWheelWaterEntry", 0x86ABA8E5));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update wheel water sounds
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWheelWater(audVehicleVariables& params)
|
|
{
|
|
audMetadataRef shallowWaterSound = GetShallowWaterWheelSound();
|
|
|
|
if(shallowWaterSound != g_NullSoundRef)
|
|
{
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
CWheel *wheel = m_Vehicle->GetWheel(i);
|
|
|
|
if(wheel->GetHierarchyId() >= VEH_WHEEL_LF && wheel->GetHierarchyId() <= VEH_WHEEL_RR)
|
|
{
|
|
f32 speedRatio = (wheel->GetIsTouching()?Clamp(Abs(wheel->GetGroundSpeed()) / m_Vehicle->m_Transmission.GetDriveMaxVelocity(), 0.0f,1.0f):0.0f);
|
|
bool inWater = wheel->GetDynamicFlags().IsFlagSet(WF_INSHALLOWWATER) || (wheel->GetDynamicFlags().IsFlagSet(WF_INDEEPWATER) && m_DrowningFactor <= 0.0f) BANK_ONLY(|| g_ForceShallowWater);
|
|
const f32 shallowWaterVol = inWater? Clamp(speedRatio/0.3f, 0.0f, 1.0f) : 0.0f;
|
|
bool wasShallowWaterPlaying = (m_ShallowWaterSounds[i] != NULL);
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_ShallowWaterSounds[i], shallowWaterSound, shallowWaterVol, 0, m_EnvironmentGroup, NULL, true, false, 0.f, true, true);
|
|
|
|
if(!wasShallowWaterPlaying && m_ShallowWaterSounds[i] && !m_ShallowWaterEnterSound)
|
|
{
|
|
if(m_Vehicle->InheritsFromAutomobile())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(Min(params.fwdSpeedAbs/20.0f, 1.0f));
|
|
CreateAndPlaySound_Persistent(GetShallowWaterEnterSound(), &m_ShallowWaterEnterSound, &initParams);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Calculate water speed factor
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::CalculateWaterSpeedFactor() const
|
|
{
|
|
return Min(1.f, DotProduct(m_CachedVehicleVelocity, VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetB()) ) / 20.f);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update water sounds - common across all vehicles as we can have water
|
|
// based helis/planes in addition to boats
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWater(audVehicleVariables& vehicleVariables)
|
|
{
|
|
bool isInWater = CalculateIsInWater();
|
|
u32 idleSlapSound = GetIdleHullSlapSound();
|
|
const u32 timeInMs = fwTimer::GetTimeInMilliseconds();
|
|
f32 minWaveHitDelay = (GetAudioVehicleType() == AUD_VEHICLE_HELI && IsSeaPlane()) ? 1000.f : 250.f;
|
|
|
|
if(idleSlapSound != g_NullSoundHash)
|
|
{
|
|
f32 idleSlapLinVolume = GetIdleHullSlapVolumeLinear(vehicleVariables.fwdSpeedAbs);
|
|
|
|
if(CScriptHud::bUsingMissionCreator && !m_Vehicle->IsCollisionEnabled())
|
|
{
|
|
idleSlapLinVolume = 0.0f;
|
|
}
|
|
|
|
if((isInWater || (IsSubmersible() && isInWater && m_EngineWaterDepth > -1.5f)) && idleSlapLinVolume > g_SilenceVolumeLin)
|
|
{
|
|
u32 vehicleQuadrant = GetVehicleQuadrant();
|
|
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
const f32 hullSlapDistanceScalar = modelNameHash == ATSTRINGHASH("Kosatka", 0x4FAF0D70) ? 3.f : 1.f;
|
|
|
|
if((m_IsFocusVehicle && modelNameHash == ATSTRINGHASH("Kosatka", 0x4FAF0D70)) || // Kosatka is so big that we don't want to cull hull slaps when panning around the camera on the focus vehicle
|
|
(vehicleVariables.distFromListenerSq < (g_SuperDummyRadiusSq * hullSlapDistanceScalar * sm_WaterSlapRadiusScalar[vehicleQuadrant]) * 0.5f))
|
|
{
|
|
// Kosatka requires data from the sfx bank for the hull slaps, which isn't loaded unless real
|
|
if (modelNameHash != ATSTRINGHASH("Kosatka", 0x4FAF0D70) || IsReal())
|
|
{
|
|
sm_NumVehiclesInWaterSlapRadius[vehicleQuadrant]++;
|
|
|
|
if (!m_IdleHullSlapSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.StartOffset = audEngineUtil::GetRandomNumberInRange(0, 99);
|
|
initParams.IsStartOffsetPercentage = true;
|
|
|
|
if (modelNameHash != ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
}
|
|
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
CreateAndPlaySound_Persistent(idleSlapSound, &m_IdleHullSlapSound, &initParams);
|
|
}
|
|
|
|
if (m_IdleHullSlapSound && modelNameHash == ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
m_IdleHullSlapSound->SetRequestedPosition(ComputeClosestPositionOnVehicleYAxis());
|
|
}
|
|
}
|
|
}
|
|
else if(m_IdleHullSlapSound && m_IdleHullSlapSound->GetCurrentPlayTime(g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0)) > 500)
|
|
{
|
|
m_IdleHullSlapSound->StopAndForget();
|
|
}
|
|
|
|
if(m_IdleHullSlapSound)
|
|
{
|
|
m_IdleHullSlapSound->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(idleSlapLinVolume));
|
|
}
|
|
}
|
|
else if(m_IdleHullSlapSound)
|
|
{
|
|
m_IdleHullSlapSound->StopAndForget();
|
|
}
|
|
}
|
|
|
|
// wave hit
|
|
if(isInWater && !m_WasInWaterLastFrame && m_LastWaveHitTime + minWaveHitDelay < timeInMs)
|
|
{
|
|
u32 soundHash = GetWaveHitSound();
|
|
|
|
if(soundHash != g_NullSoundHash)
|
|
{
|
|
m_LastWaveHitTime = timeInMs;
|
|
audSoundInitParams initParams;
|
|
const f32 timerVol = Min(1.f, m_OutOfWaterTimer);
|
|
const f32 minVelocityRatio = (GetAudioVehicleType() == AUD_VEHICLE_HELI && IsSeaPlane()) ? 0.4f : 0.0f;
|
|
const f32 velocityRatio = Clamp(m_CachedVehicleVelocity.Mag2()/50.0f, minVelocityRatio, 1.0f);
|
|
u32 bigSoundHash = GetWaveHitBigSound();
|
|
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(velocityRatio);
|
|
|
|
if(bigSoundHash != g_NullSoundHash)
|
|
{
|
|
if((m_IsPlayerVehicle || m_DistanceFromListener2LastFrame < g_FakeWaveHitDistanceSq) && timeInMs - m_LastBigWaveHitTime > 500 && m_OutOfWaterTimer >= GetWaveHitBigAirTime() && velocityRatio >= 0.75f)
|
|
{
|
|
soundHash = GetWaveHitBigSound();
|
|
m_LastBigWaveHitTime = timeInMs;
|
|
}
|
|
}
|
|
|
|
audSound* waveHitSound = NULL;
|
|
if(g_FrontendAudioEntity.GetSpecialAbilityMode() != audFrontendAudioEntity::kSpecialAbilityModeTrevor)
|
|
{
|
|
CreateSound_LocalReference(soundHash, &waveHitSound, &initParams);
|
|
}
|
|
|
|
f32 speedFactor = CalculateWaterSpeedFactor();
|
|
f32 impactForce = timerVol * (0.5f + (speedFactor * 0.5f));
|
|
|
|
if(waveHitSound)
|
|
{
|
|
waveHitSound->FindAndSetVariableValue(ATSTRINGHASH("impactForce", 0x165EF795), impactForce);
|
|
waveHitSound->PrepareAndPlay();
|
|
|
|
#if __BANK
|
|
if(m_IsPlayerVehicle && g_DebugDrawVehicleWater)
|
|
{
|
|
char tempString[128];
|
|
formatf(tempString, soundHash == bigSoundHash? "BIG Splash!" : "Splash!");
|
|
grcDebugDraw::Text(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), Color32(0,0,255), tempString, true, 5);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else if(m_WasInWaterLastFrame && !isInWater && m_LastWaterLeaveTime + minWaveHitDelay < timeInMs)
|
|
{
|
|
u32 leftWaterSound = GetLeftWaterSound();
|
|
|
|
if(leftWaterSound != g_NullSoundHash)
|
|
{
|
|
m_LastWaterLeaveTime = timeInMs;
|
|
audSoundInitParams initParams;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(Clamp(m_CachedVehicleVelocity.Mag2()/50.0f, 0.0f, 1.0f));
|
|
CreateAndPlaySound(leftWaterSound, &initParams);
|
|
|
|
#if __BANK
|
|
if(m_IsPlayerVehicle && g_DebugDrawVehicleWater)
|
|
{
|
|
char tempString[128];
|
|
formatf(tempString, "Left!");
|
|
grcDebugDraw::Text(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), Color32(0,0,255), tempString, true, 5);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if(isInWater)
|
|
{
|
|
m_InWaterTimer += fwTimer::GetTimeStep();
|
|
m_OutOfWaterTimer = 0.f;
|
|
}
|
|
else
|
|
{
|
|
m_OutOfWaterTimer += fwTimer::GetTimeStep();
|
|
m_InWaterTimer = 0.f;
|
|
}
|
|
|
|
m_WasInWaterLastFrame = isInWater;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if warning sounds are valid
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::AreWarningSoundsValid()
|
|
{
|
|
// Avoid playing warning sounds on the player vehicle in multiplayer when the player can't actually control the vehicle (eg. on leaderboards)
|
|
if(m_IsPlayerVehicle && NetworkInterface::IsGameInProgress() && CGameWorld::GetMainPlayerInfo() && CGameWorld::GetMainPlayerInfo()->AreControlsDisabled())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// AddCommonDSPParameters
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::AddCommonDSPParameters(audVehicleDSPSettings& dspSettings)
|
|
{
|
|
const f32 engineBayUpgradeLevel0 = GetEngineBayUpgradeLevel(0);
|
|
const f32 engineBayUpgradeLevel1 = GetEngineBayUpgradeLevel(1);
|
|
const f32 engineBayUpgradeLevel2 = GetEngineBayUpgradeLevel(2);
|
|
const f32 turboUpgradeLevel = GetTurboUpgradeLevel();
|
|
const f32 firstPerson = *g_AudioEngine.GetSoundManager().GetVariableAddress(ATSTRINGHASH("Game.Microphone.FirstPerson", 0x378A1D92));
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Upgrade_Level", 0x893FF500), GetEngineUpgradeLevel(), audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_ENGINE);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Upgrade_Level", 0x893FF500), GetExhaustUpgradeLevel(), audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_EXHAUST);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Turbo_Upgrade_Level", 0x282B095B), turboUpgradeLevel, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_ENGINE);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Turbo_Upgrade_Level", 0x282B095B), turboUpgradeLevel, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_EXHAUST);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Slot_0_Upgrade_Level", 0x2E672FAF), engineBayUpgradeLevel0, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_ENGINE);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Slot_0_Upgrade_Level", 0x2E672FAF), engineBayUpgradeLevel0, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_EXHAUST);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Slot_1_Upgrade_Level", 0x4951A638), engineBayUpgradeLevel1, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_ENGINE);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Slot_1_Upgrade_Level", 0x4951A638), engineBayUpgradeLevel1, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_EXHAUST);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Slot_2_Upgrade_Level", 0xE26554E6), engineBayUpgradeLevel2, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_ENGINE);
|
|
dspSettings.AddDSPParameter(atHashString("Mod_Slot_2_Upgrade_Level", 0xE26554E6), engineBayUpgradeLevel2, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_EXHAUST);
|
|
dspSettings.AddDSPParameter(atHashString("FirstPerson", 0xEE38E8E0), firstPerson, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_ENGINE);
|
|
dspSettings.AddDSPParameter(atHashString("FirstPerson", 0xEE38E8E0), firstPerson, audVehicleDSPSettings::AUD_VEHICLE_DSP_PARAM_EXHAUST);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Check how much the engine is upgraded
|
|
// -------------------------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetEngineUpgradeLevel() const
|
|
{
|
|
#if __BANK
|
|
if(g_ForceUpgradeEngine || (g_EngineVolumeCaptureActive && audCarAudioEntity::sm_VolumeCaptureState == audCarAudioEntity::State_CapturingAccelModded))
|
|
{
|
|
return g_ForcedEngineUpgradeLevel;
|
|
}
|
|
#endif
|
|
|
|
if(m_Vehicle->GetVariationInstance().GetModIndex(VMT_ENGINE) != INVALID_MOD)
|
|
{
|
|
if(VMT_ENGINE >= VMT_TOGGLE_MODS)
|
|
{
|
|
return 1.0f;
|
|
}
|
|
else
|
|
{
|
|
return m_Vehicle->GetVariationInstance().GetAudioApply(VMT_ENGINE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Check how much the engine bay is upgraded
|
|
// -------------------------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetEngineBayUpgradeLevel(u32 slot) const
|
|
{
|
|
audAssert(slot < 3);
|
|
const u32 modIndex = VMT_ENGINEBAY1 + slot;
|
|
|
|
#if __BANK
|
|
if(g_ForceUpgradeEngineBay[slot])
|
|
{
|
|
return g_ForcedEngineBayUpgradeLevel[slot];
|
|
}
|
|
#endif
|
|
|
|
if(m_Vehicle->GetVariationInstance().GetModIndex((eVehicleModType)modIndex) != INVALID_MOD)
|
|
{
|
|
if(modIndex >= VMT_TOGGLE_MODS)
|
|
{
|
|
return 1.0f;
|
|
}
|
|
else
|
|
{
|
|
return m_Vehicle->GetVariationInstance().GetAudioApply((eVehicleModType)modIndex);
|
|
}
|
|
}
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Check how much the radio is upgraded
|
|
// -------------------------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetRadioUpgradeLevel() const
|
|
{
|
|
#if __BANK
|
|
if(g_ForceUpgradeRadio)
|
|
{
|
|
return g_ForcedRadioUpgradeLevel;
|
|
}
|
|
#endif
|
|
|
|
f32 upgradeLevel = 0.f;
|
|
|
|
// Take the biggest upgrade provided by either the ICE or the Trunk speaker mods
|
|
if(m_Vehicle->GetVariationInstance().GetModIndex(VMT_ICE) != INVALID_MOD && !m_Vehicle->HasExpandedMods())
|
|
{
|
|
if(VMT_ICE >= VMT_TOGGLE_MODS)
|
|
{
|
|
upgradeLevel = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
upgradeLevel = m_Vehicle->GetVariationInstance().GetAudioApply(VMT_ICE);
|
|
}
|
|
}
|
|
|
|
if(m_Vehicle->GetVariationInstance().GetModIndex(VMT_TRUNK) != INVALID_MOD)
|
|
{
|
|
if(VMT_TRUNK >= VMT_TOGGLE_MODS)
|
|
{
|
|
upgradeLevel = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
upgradeLevel = Max(upgradeLevel, m_Vehicle->GetVariationInstance().GetAudioApply(VMT_TRUNK));
|
|
}
|
|
}
|
|
|
|
return upgradeLevel;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Check how much the transmission is upgraded
|
|
// -------------------------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetTransmissionUpgradeLevel() const
|
|
{
|
|
#if __BANK
|
|
if(g_ForceUpgradeTransmission)
|
|
{
|
|
return g_ForcedTransmissionUpgradeLevel;
|
|
}
|
|
#endif
|
|
|
|
if(m_Vehicle->GetVariationInstance().GetModIndex(VMT_GEARBOX) != INVALID_MOD)
|
|
{
|
|
if(VMT_GEARBOX >= VMT_TOGGLE_MODS)
|
|
{
|
|
return 1.0f;
|
|
}
|
|
else
|
|
{
|
|
return m_Vehicle->GetVariationInstance().GetAudioApply(VMT_GEARBOX);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Check how much the exhaust is upgraded
|
|
// -------------------------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetExhaustUpgradeLevel() const
|
|
{
|
|
#if __BANK
|
|
if(g_ForceUpgradeExhaust || (g_EngineVolumeCaptureActive && audCarAudioEntity::sm_VolumeCaptureState == audCarAudioEntity::State_CapturingAccelModded))
|
|
{
|
|
return g_ForcedExhaustUpgradeLevel;
|
|
}
|
|
#endif
|
|
|
|
if(m_Vehicle->GetVariationInstance().GetModIndex(VMT_EXHAUST) != INVALID_MOD)
|
|
{
|
|
if(VMT_EXHAUST >= VMT_TOGGLE_MODS)
|
|
{
|
|
return 1.0f;
|
|
}
|
|
else
|
|
{
|
|
return m_Vehicle->GetVariationInstance().GetAudioApply(VMT_EXHAUST);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Check how much the turbo is upgraded
|
|
// -------------------------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetTurboUpgradeLevel() const
|
|
{
|
|
#if __BANK
|
|
if(g_ForceUpgradeTurbo)
|
|
{
|
|
return g_ForcedTurboUpgradeLevel;
|
|
}
|
|
#endif
|
|
|
|
if(m_Vehicle->GetVariationInstance().GetModIndex(VMT_TURBO) != INVALID_MOD)
|
|
{
|
|
if(VMT_TURBO >= VMT_TOGGLE_MODS)
|
|
{
|
|
return 1.0f;
|
|
}
|
|
else
|
|
{
|
|
return m_Vehicle->GetVariationInstance().GetAudioApply(VMT_TURBO);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if we're forcing snow sounds (eg. Xmas DLC)
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::ShouldForceSnow()
|
|
{
|
|
if(g_vfxWheel.GetUseSnowWheelVfxWhenUnsheltered())
|
|
{
|
|
if (m_EnvironmentGroup)
|
|
{
|
|
// If we're inside or under cover, don't use the snow settings
|
|
if(m_EnvironmentGroup->IsUnderCover() || m_EnvironmentGroup->GetInteriorInst() != NULL)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if it is safe to apply DSP changes
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsSafeToApplyDSPChanges()
|
|
{
|
|
// In network games, it's common for the focus vehicle to swap to another vehicle whilst the vehicle is actively revving
|
|
// (eg. the player gets into a remote player's car as a passenger). This triggers a swap to the high quality/DSP'd version
|
|
// of the asset, which can sound quite jarring mid-revs, especially on vehicles with more aggressive DSP settings. For this
|
|
// reason, we wait until the car has returned to idle before switching on the DSP. In single player it is rarely an issue
|
|
// as you're generally pulling an NPC out of the car in order to get into it, so the car is idle anyway when it becomes the
|
|
// focus vehicle. In future, we ideally want to build an 'apply' value into all of the synth effects so that we can smoothly
|
|
// fade them in rather than just having a binary on/off.
|
|
#if __BANK
|
|
if(g_AutoReapplyDSPPresets)
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
if(NetworkInterface::IsGameInProgress() && m_IsFocusVehicle)
|
|
{
|
|
if(IsUsingGranularEngine())
|
|
{
|
|
audVehicleEngine* vehicleEngine = GetVehicleEngine();
|
|
|
|
if(vehicleEngine)
|
|
{
|
|
const audGranularEngineComponent* granularEngine = vehicleEngine->GetGranularEngine();
|
|
|
|
if(granularEngine)
|
|
{
|
|
if(!m_Vehicle->m_nVehicleFlags.bEngineOn || m_ReapplyDSPEffects ||
|
|
granularEngine->GetIdleVolumeScale() >= 1.0f ||
|
|
vehicleEngine->GetTransmission()->GetLastGearChangeTimeMs() == fwTimer::GetTimeInMilliseconds())
|
|
{
|
|
m_ReapplyDSPEffects = false;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update vehicle caterpillar tracks
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateCaterpillarTracks(audVehicleVariables& params)
|
|
{
|
|
const u32 vehicleModelNameHash = GetVehicleModelNameHash();
|
|
if (vehicleModelNameHash == ATSTRINGHASH("ZHABA", 0x4C8DBA51))
|
|
{
|
|
m_VehicleCaterpillarTrackSpeed = params.wheelSpeedAbs;
|
|
}
|
|
|
|
bool shouldPlayTrackSound = m_VehicleCaterpillarTrackSpeed > 0.01f;
|
|
|
|
if (vehicleModelNameHash == ATSTRINGHASH("MINITANK", 0xB53C6C52))
|
|
{
|
|
shouldPlayTrackSound = m_Vehicle->IsEngineOn();
|
|
}
|
|
|
|
if(shouldPlayTrackSound)
|
|
{
|
|
if(!m_CaterpillarTrackLoop)
|
|
{
|
|
u32 trackSoundSetName = 0u;
|
|
u32 trackSoundName = ATSTRINGHASH("track_move_loop", 0xDC74446F);
|
|
|
|
if(vehicleModelNameHash == ATSTRINGHASH("HALFTRACK", 0xFE141DA6))
|
|
{
|
|
trackSoundSetName = ATSTRINGHASH("halftrack_wheels_ss", 0x91D832CB);
|
|
}
|
|
else if (vehicleModelNameHash == ATSTRINGHASH("MINITANK", 0xB53C6C52))
|
|
{
|
|
if (m_IsFocusVehicle)
|
|
{
|
|
trackSoundSetName = ATSTRINGHASH("ch_vehicle_minitank_player_sounds", 0xCF2B0226);
|
|
}
|
|
else
|
|
{
|
|
trackSoundSetName = ATSTRINGHASH("ch_vehicle_minitank_remote_sounds", 0x90AF5388);
|
|
}
|
|
|
|
trackSoundName = ATSTRINGHASH("move_loop", 0xADFCA51D);
|
|
}
|
|
else if (vehicleModelNameHash == ATSTRINGHASH("ZHABA", 0x4C8DBA51))
|
|
{
|
|
trackSoundSetName = ATSTRINGHASH("zhaba_wheels_ss", 0x554AD4A9);
|
|
trackSoundName = ATSTRINGHASH("move_loop", 0xADFCA51D);
|
|
}
|
|
else if(vehicleModelNameHash == ATSTRINGHASH("KHANJALI", 0xAA6F980A))
|
|
{
|
|
trackSoundSetName = ATSTRINGHASH("khanjali_wheels_ss", 0xFEB271E4);
|
|
}
|
|
else if (vehicleModelNameHash == ATSTRINGHASH("SCARAB", 0xBBA2A2F7) ||
|
|
vehicleModelNameHash == ATSTRINGHASH("SCARAB2", 0x5BEB3CE0) ||
|
|
vehicleModelNameHash == ATSTRINGHASH("SCARAB3", 0xDD71BFEB))
|
|
{
|
|
trackSoundSetName = ATSTRINGHASH("scarab_wheels_ss", 0x50C9A4F3);
|
|
}
|
|
|
|
if(trackSoundSetName != 0)
|
|
{
|
|
audSoundSet soundSet;
|
|
|
|
if(soundSet.Init(trackSoundSetName))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
CreateAndPlaySound_Persistent(soundSet.Find(trackSoundName), &m_CaterpillarTrackLoop, &initParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_CaterpillarTrackLoop)
|
|
{
|
|
m_CaterpillarTrackLoop->FindAndSetVariableValue(ATSTRINGHASH("trackspeed", 0xBDAAE8C), m_VehicleCaterpillarTrackSpeed);
|
|
m_CaterpillarTrackLoop->FindAndSetVariableValue(ATSTRINGHASH("wheelTouchingFactor", 0x870DDA90), params.numWheelsTouchingFactor);
|
|
m_CaterpillarTrackLoop->FindAndSetVariableValue(ATSTRINGHASH("throttleInput", 0x918028C4), params.throttleInput);
|
|
}
|
|
|
|
m_LastCaterpillarTrackValidTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
else if(m_CaterpillarTrackLoop)
|
|
{
|
|
if(fwTimer::GetTimeInMilliseconds() - m_LastCaterpillarTrackValidTime > 500)
|
|
{
|
|
m_CaterpillarTrackLoop->StopAndForget(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Calculate the wheel dirtiness
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWheelDirtyness(audVehicleVariables& variables)
|
|
{
|
|
f32 dirtiness = 0.0f;
|
|
f32 desiredDirtiness = m_CachedMaterialSettings? m_CachedMaterialSettings->Dirtiness : 0.0f;
|
|
|
|
#if __BANK
|
|
if(g_ForceDirtySurface)
|
|
{
|
|
desiredDirtiness = 1.0f;
|
|
}
|
|
#endif
|
|
|
|
f32 dirtinessVolume = 0.0f;
|
|
|
|
if(variables.numWheelsTouchingFactor > 0.0f)
|
|
{
|
|
dirtinessVolume = Max(0.0f, m_PrevDirtinessVolume - fwTimer::GetTimeStep() * 2.0f);
|
|
|
|
// We want to interpolate to the material dirtiness - pick up/shed more dirt the faster we are traveling
|
|
f32 speedRatio = Clamp(variables.fwdSpeedAbs/20.0f, 0.0f, 1.0f);
|
|
f32 smoothRateIncrease = g_WheelDirtinessIncreaseSmoothRate * speedRatio;
|
|
f32 smoothRateDecrease = g_WheelDirtinessDecreaseSmoothRate * speedRatio;
|
|
m_WheelDirtinessSmoother.SetRates(smoothRateIncrease, smoothRateDecrease);
|
|
|
|
f32 oldDirtiness = m_WheelDirtinessSmoother.GetLastValue();
|
|
dirtiness = m_WheelDirtinessSmoother.CalculateValue(desiredDirtiness, variables.timeInMs);
|
|
|
|
// If we're losing dirtyness by transitioning to a clean(ish) surface, play the sound
|
|
if(oldDirtiness > dirtiness && desiredDirtiness <= 0.3f)
|
|
{
|
|
dirtinessVolume = Clamp(variables.fwdSpeedAbs/5.0f, 0.0f, 1.0f);
|
|
|
|
if(dirtiness < desiredDirtiness + 0.3f)
|
|
{
|
|
dirtinessVolume *= (dirtiness/(desiredDirtiness + 0.3f));
|
|
}
|
|
}
|
|
}
|
|
|
|
const u32 dirtyWheelSound = m_VehicleType == AUD_VEHICLE_BICYCLE? ATSTRINGHASH("BicycleDirtyWheelLoop", 0x123EA33) : ATSTRINGHASH("CarDirtyWheelLoop", 0xC2701795);
|
|
UpdateSoundsetLoopWithLinearVolumeAndPitch(&m_DirtyWheelLoop, dirtyWheelSound, &sm_ExtrasSoundSet, dirtinessVolume, variables.roadNoisePitch, m_EnvironmentGroup, NULL, true, true);
|
|
m_PrevDirtinessVolume = dirtinessVolume;
|
|
|
|
f32 glassiness = 0.0f;
|
|
f32 desiredGlassiness = g_GlassAudioEntity.GetGlassiness(GetPosition(), true, fwTimer::GetTimeStep() * g_GlassAreaDepletionRate * variables.fwdSpeedRatio);
|
|
|
|
#if __BANK
|
|
if(g_ForceGlassySurface)
|
|
{
|
|
desiredGlassiness = 1.0f;
|
|
}
|
|
#endif
|
|
|
|
f32 glassinessVolume = 0.0f;
|
|
|
|
if(variables.numWheelsTouchingFactor > 0.0f)
|
|
{
|
|
glassinessVolume = Max(0.0f, m_PrevGlassinessVolume - fwTimer::GetTimeStep() * 2.0f);
|
|
f32 smoothRateIncrease = g_WheelGlassinessIncreaseSmoothRate * Min(variables.fwdSpeedAbs, 1.0f);
|
|
f32 smoothRateDecrease = g_WheelGlassinessDecreaseSmoothRate * Min(variables.fwdSpeedAbs/10.0f, 1.0f);
|
|
m_WheelGlassinessSmoother.SetRates(smoothRateIncrease, smoothRateDecrease);
|
|
glassiness = m_WheelGlassinessSmoother.CalculateValue(desiredGlassiness, variables.timeInMs);
|
|
|
|
if(glassiness < 0.3f)
|
|
{
|
|
glassinessVolume *= glassiness/0.3f;
|
|
}
|
|
|
|
glassinessVolume = glassiness;
|
|
}
|
|
|
|
const u32 glassyWheelSound = m_VehicleType == AUD_VEHICLE_BICYCLE? ATSTRINGHASH("BicycleGlassyWheelLoop", 0x776F9315) : ATSTRINGHASH("CarGlassyWheelLoop", 0xF392D925);
|
|
UpdateSoundsetLoopWithLinearVolumeAndPitch(&m_GlassyWheelLoop, glassyWheelSound, &sm_ExtrasSoundSet, glassinessVolume, variables.roadNoisePitch, m_EnvironmentGroup, NULL, true, true);
|
|
m_PrevGlassinessVolume = glassinessVolume;
|
|
|
|
#if __BANK
|
|
if(g_DisplayDirtGlassInfo && m_IsPlayerVehicle)
|
|
{
|
|
char tempString[128];
|
|
sprintf(tempString, "Material Dirtiness: %.02f", desiredDirtiness);
|
|
grcDebugDraw::Text(Vector2(0.08f, 0.1f), Color32(255,255,255), tempString);
|
|
|
|
sprintf(tempString, "Wheel Dirtiness: %.02f", m_WheelDirtinessSmoother.GetLastValue());
|
|
grcDebugDraw::Text(Vector2(0.08f, 0.12f), Color32(255,255,255), tempString);
|
|
|
|
sprintf(tempString, "Ground Glassiness: %.02f", desiredGlassiness);
|
|
grcDebugDraw::Text(Vector2(0.08f, 0.14f), Color32(255,255,255), tempString);
|
|
|
|
sprintf(tempString, "Wheel Glassiness: %.02f", m_WheelGlassinessSmoother.GetLastValue());
|
|
grcDebugDraw::Text(Vector2(0.08f, 0.16f), Color32(255,255,255), tempString);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update skids
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateSkids(audVehicleVariables& params)
|
|
{
|
|
#if __BANK
|
|
if (g_OverridenSkidPitchOffset != 0)
|
|
{
|
|
m_SkidPitchOffset = g_OverridenSkidPitchOffset;
|
|
}
|
|
#endif
|
|
|
|
// skids
|
|
f32 sideVol;
|
|
|
|
// take the largest fwd/lateral slip angle from all wheels
|
|
f32 fwdSlipAngle = 0.f;
|
|
|
|
const f32 numTyresScalar = 1.f / (f32)m_Vehicle->GetNumWheels();
|
|
bool burnOut = false;
|
|
|
|
float numDriveWheelsTouching = 0.f;
|
|
u32 numDriveWheels = 0;
|
|
f32 averageDriveWheelSpeed = 0.0f;
|
|
|
|
s32 numWheelsTouching = 0;
|
|
const f32 moveMag = params.movementSpeed;
|
|
Vector3 normVel = m_CachedVehicleVelocity;
|
|
normVel.NormalizeSafe();
|
|
Vec3V normForward = m_Vehicle->GetTransform().GetB();
|
|
normForward = NormalizeSafe(normForward,Vec3V(V_X_AXIS_WZERO));
|
|
|
|
float slipAngleDeltas[NUM_VEH_CWHEELS_MAX] = {0.f};
|
|
|
|
float meanDriveWheelSlip = 0.f;
|
|
|
|
naCErrorf(m_Vehicle->GetNumWheels()<=NUM_VEH_CWHEELS_MAX, "Vehicle has too many wheels");
|
|
for(s32 i = 0 ; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
CWheel* thisWheel = m_Vehicle->GetWheel(i);
|
|
|
|
if(thisWheel->GetIsDriveWheel())
|
|
{
|
|
numDriveWheels++;
|
|
}
|
|
|
|
if(thisWheel->GetIsTouching() && !m_Vehicle->m_nVehicleFlags.bIsDrowning && !thisWheel->GetDynamicFlags().IsFlagSet(WF_INSHALLOWWATER) && !thisWheel->GetDynamicFlags().IsFlagSet(WF_INDEEPWATER))
|
|
{
|
|
numWheelsTouching++;
|
|
|
|
const float effectiveSlipAngle = thisWheel->GetEffectiveSlipAngle();
|
|
const f32 healthScalar = m_Vehicle->GetWheel(i)->GetTyreHealth() * TYRE_HEALTH_DEFAULT_INV;
|
|
fwdSlipAngle += effectiveSlipAngle * healthScalar * numTyresScalar;
|
|
if(thisWheel->GetDynamicFlags().IsFlagSet(WF_BURNOUT))
|
|
{
|
|
burnOut = true;
|
|
}
|
|
|
|
if(thisWheel->GetIsDriveWheel())
|
|
{
|
|
averageDriveWheelSpeed += thisWheel->GetGroundSpeed();
|
|
meanDriveWheelSlip += thisWheel->GetFwdSlipAngle() * healthScalar;
|
|
numDriveWheelsTouching += 1.f;
|
|
}
|
|
|
|
const float slipAngle = thisWheel->GetSideSlipAngle();
|
|
slipAngleDeltas[i] = (slipAngle - m_LastSlipAngle[i]) * fwTimer::GetInvTimeStep();
|
|
m_LastSlipAngle[i] = slipAngle;
|
|
}
|
|
else
|
|
{
|
|
m_LastSlipAngle[i] = 0.f;
|
|
}
|
|
}
|
|
|
|
f32 driftAngle = 0.f;
|
|
|
|
f32 burnOutPitch = 0.f;
|
|
|
|
const bool hasRearWheelSteering = m_Vehicle->InheritsFromAutomobile() && (((CAutomobile*)m_Vehicle)->pHandling->hFlags & HF_STEER_REARWHEELS);
|
|
if(burnOut)
|
|
{
|
|
driftAngle = 1.f;
|
|
burnOutPitch = Min(200.f, m_BurnoutPitch + fwTimer::GetTimeStep() * 150.f);
|
|
|
|
// Don't play a squeal at the start of a burnout
|
|
m_LastDriftAngle = driftAngle;
|
|
}
|
|
else
|
|
{
|
|
driftAngle = (moveMag>0.5f?(1.f - Abs(DotProduct(VEC3V_TO_VECTOR3(normForward), normVel))):0.f);
|
|
burnOutPitch = Max(-200.f, m_BurnoutPitch - fwTimer::GetTimeStep() * 150.f);
|
|
}
|
|
|
|
if(hasRearWheelSteering)
|
|
{
|
|
driftAngle *= 0.3f;
|
|
}
|
|
|
|
u32 mainSkidHash = (m_CachedMaterialSettings?m_CachedMaterialSettings->MainSkid:g_MainTarmacSkid);
|
|
|
|
const bool tarmacSkids = mainSkidHash == g_MainTarmacSkid;
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_BICYCLE && tarmacSkids)
|
|
{
|
|
mainSkidHash = g_MainTarmacSkidBicycle;
|
|
}
|
|
|
|
const float driftAngleDeltaS = (driftAngle - m_LastDriftAngle) * fwTimer::GetInvTimeStep();
|
|
m_LastDriftAngle = driftAngle;
|
|
|
|
if(numDriveWheelsTouching > 0)
|
|
{
|
|
meanDriveWheelSlip /= numDriveWheelsTouching;
|
|
}
|
|
|
|
// AI time-slicing is leading to jittery NPC skids under braking. Ignore +ve slip if both throttle and brake are applied, and scale
|
|
// down by brake
|
|
if(!m_IsPlayerVehicle && meanDriveWheelSlip > 0.f)
|
|
{
|
|
meanDriveWheelSlip *= (1.f - Min(1.f, 3.f * params.throttleInput)) * (params.brakePedal * params.brakePedal);
|
|
}
|
|
meanDriveWheelSlip *= Min(1.f, 2.f * Max(params.wheelSpeedRatio, params.throttle));
|
|
|
|
m_LastDriftAngleDelta = driftAngleDeltaS;
|
|
|
|
f32 entityVariableLongSlipAngle = 0.0f;
|
|
f32 entityVariableLatSlipAngle = 0.0f;
|
|
|
|
if(HasEntityVariableBlock())
|
|
{
|
|
entityVariableLongSlipAngle = GetEntityVariableValue(ATSTRINGHASH("fakelongslip", 0x6E7FF3FC));
|
|
entityVariableLatSlipAngle = GetEntityVariableValue(ATSTRINGHASH("fakelatslip", 0x34DA17A0));
|
|
}
|
|
|
|
m_BurnoutPitch = burnOutPitch;
|
|
|
|
f32 driftScalar = 1.f;
|
|
if(m_VehicleType != AUD_VEHICLE_BICYCLE)
|
|
{
|
|
driftScalar = m_LateralSkidSmoother.CalculateValue(sm_SkidDriftAngleToVolume.CalculateValue(driftAngle), fwTimer::GetTimeInMilliseconds());
|
|
}
|
|
|
|
fwdSlipAngle = m_MainSkidSmoother.CalculateValue(fwdSlipAngle, fwTimer::GetTimeInMilliseconds());
|
|
|
|
s32 burnoutPitchCents = (s32)burnOutPitch;
|
|
|
|
if(params.hasMaterialChanged)
|
|
{
|
|
if(m_MainSkidLoop)
|
|
{
|
|
m_MainSkidLoop->SetReleaseTime(300);
|
|
m_MainSkidLoop->StopAndForget(true);
|
|
}
|
|
if(m_UndersteerSkidLoop)
|
|
{
|
|
m_UndersteerSkidLoop->SetReleaseTime(100);
|
|
m_UndersteerSkidLoop->StopAndForget(true);
|
|
}
|
|
if(m_SideSkidLoop)
|
|
{
|
|
m_SideSkidLoop->SetReleaseTime(300);
|
|
m_SideSkidLoop->StopAndForget(true);
|
|
}
|
|
}
|
|
|
|
#if __DEV
|
|
if(g_BreakOnVehicleUpdate && g_AudioDebugEntity == m_Vehicle)
|
|
{
|
|
__debugbreak();
|
|
}
|
|
#endif
|
|
|
|
const s32 skidPitch = Max(burnoutPitchCents, (s32)(sm_SkidSpeedRatioToPitch.CalculateValue(params.fwdSpeedRatio)) + m_EnginePitchOffset);
|
|
|
|
// compute amount of skidding 'on the water'
|
|
params.wetRoadSkidModifier = Min(0.5f, sm_SkidFwdSlipToMainVol.CalculateValue(fwdSlipAngle) * 0.5f) * params.numWheelsTouchingFactor;
|
|
|
|
// increase threshold and decrease volume with road wetness, only on tarmac
|
|
float mainVol = UpdateSkidsVolume(params, tarmacSkids, numWheelsTouching, fwdSlipAngle, slipAngleDeltas);
|
|
|
|
const float burnoutOverride = m_BurnoutSmoother.CalculateValue(burnOut ? 1.f : 0.f, params.timeInMs);
|
|
|
|
float angVelMag = m_CachedAngularVelocity.Mag() / (2.f * PI);
|
|
const float mainSpeedFactor = Max(burnoutOverride, Min(1.f, params.fwdSpeedRatio * 2.f));
|
|
|
|
float finalMainVol = mainSpeedFactor * mainVol * Min(1.f,(2.f*driftScalar)) * params.numWheelsTouchingFactor * (1.0f - params.numDriveWheelsInWaterFactor);
|
|
|
|
// Allow entity variable to drive volume directly
|
|
finalMainVol = Max(finalMainVol, entityVariableLongSlipAngle);
|
|
|
|
static float s_DriveWheelSlipScalar = 2.f * PI;
|
|
float burnoutScalar = Lerp(params.throttle, params.fwdSpeedRatio, 1.f);
|
|
|
|
bool isQuietVehicle = false;
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_CAR && ((audCarAudioEntity*)this)->IsElectricOrHybrid())
|
|
{
|
|
isQuietVehicle = true;
|
|
}
|
|
|
|
if(tarmacSkids && g_DisableBurnoutSkidsInReverse && !isQuietVehicle)
|
|
{
|
|
// lots of wheel spin sounds wrong on tarmac, but necessary for off-road materials
|
|
burnoutScalar *= (m_Vehicle->m_Transmission.GetGear() <= 0 ? 0.f : 1.f);
|
|
}
|
|
|
|
if(hasRearWheelSteering)
|
|
{
|
|
driftScalar *= 0.5f;
|
|
fwdSlipAngle *= 0.5f;
|
|
angVelMag *= 0.5f;
|
|
}
|
|
|
|
float driveWheelSlipVol = Min(1.f, Abs(meanDriveWheelSlip * burnoutScalar) / s_DriveWheelSlipScalar);
|
|
|
|
driveWheelSlipVol *= driveWheelSlipVol;
|
|
driveWheelSlipVol *= GetSkidVolumeScale();
|
|
|
|
// Special case speculative bug fix for NPC vehicles getting wheel slip loop stuck on. Don't allow it to
|
|
// play if the vehicle isn't moving and no throttle is being applied
|
|
if(!m_IsPlayerVehicle && params.fwdSpeedAbs < 0.1f && params.throttle == 0.0f && !burnOut)
|
|
{
|
|
driveWheelSlipVol = 0.0f;
|
|
}
|
|
|
|
// side skid volume
|
|
const float sideSpeedFactor = Max(burnoutOverride, Min(1.f, Max(params.wheelSpeedRatio * 2.f, 2.f*angVelMag)));
|
|
sideVol = sideSpeedFactor * Min(1.f, 1.2f*mainVol) * driftScalar * params.numWheelsTouchingFactor * (1.0f - params.numDriveWheelsInWaterFactor) * GetSkidVolumeScale();
|
|
sideVol *= GetSkidVolumeScale();
|
|
|
|
float driftChangeVol = 0.f;
|
|
|
|
// High rate of drift angle change triggers also side skid
|
|
static float s_DriftAngleDeltaScalar = 3.f;
|
|
float driftChangeFactor = Min(1.f, Abs(driftAngleDeltaS) * s_DriftAngleDeltaScalar);
|
|
|
|
// Recorded vehicles don't have correct slip angles (the wheels are asleep so don't get physics updates) so increase the drift contribution
|
|
// to ensure that we still get squeals when cornering
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(m_Vehicle) && params.numWheelsTouchingFactor == 1.0f)
|
|
{
|
|
driftChangeFactor *= 5.0f;
|
|
driftChangeFactor = m_DriftFactorSmoother.CalculateValue(driftChangeFactor);
|
|
}
|
|
|
|
driftChangeVol = params.numWheelsTouchingFactor * (1.0f - params.numDriveWheelsInWaterFactor) * Min(1.f, 2.f*params.wheelSpeedRatio) * driftChangeFactor * 1.2f;
|
|
driftChangeVol *= GetSkidVolumeScale();
|
|
|
|
// Muting bicycle drifts during car recordings - bike velocity vs wheel angle is generally incorrect, giving us skids when we don't want them
|
|
if(m_VehicleType == AUD_VEHICLE_BICYCLE && CVehicleRecordingMgr::IsPlaybackGoingOnForCar(m_Vehicle))
|
|
{
|
|
sideVol = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
sideVol = Max(sideVol, Min(0.7f, driftChangeVol * driftChangeVol));
|
|
sideVol = Max(sideVol, entityVariableLatSlipAngle);
|
|
}
|
|
|
|
const u32 sideSkidHash = (m_CachedMaterialSettings?m_CachedMaterialSettings->SideSkid:g_SideTarmacSkid);
|
|
|
|
float mainSkidVolume = 0.f;
|
|
if(m_VehicleType == AUD_VEHICLE_BICYCLE)
|
|
{
|
|
mainSkidVolume = Max(finalMainVol, sideVol);
|
|
}
|
|
else if((m_Vehicle->InheritsFromBike() || hasRearWheelSteering) && tarmacSkids)
|
|
{
|
|
// main skid is too much for bikes and the forklift
|
|
sideVol = Max(finalMainVol, sideVol);
|
|
mainVol = 0.f;
|
|
}
|
|
else
|
|
{
|
|
mainSkidVolume = tarmacSkids ? finalMainVol : Max(finalMainVol, driveWheelSlipVol);
|
|
}
|
|
|
|
float understeerVolume = 0.f;
|
|
float understeerThrottleScalar = Lerp(params.throttle, 0.85f, 1.f);
|
|
|
|
TUNE_FLOAT(bikeSlipScalar, 1.7f, 0.f, 10.f, 0.1f)
|
|
float fwdSlipAngleForUndersteer = fwdSlipAngle;
|
|
if (m_Vehicle->InheritsFromBike())
|
|
fwdSlipAngleForUndersteer *= bikeSlipScalar;
|
|
understeerVolume = Min(1.f, GetSkidVolumeScale() * Lerp(mainVol, 1.f, 0.5f) * understeerThrottleScalar * Min(1.5f, params.fwdSpeedRatio * 2.4f) * sm_SlipToUndersteerVol.CalculateValue(fwdSlipAngleForUndersteer));
|
|
|
|
// Non-tarmac skids don't have a bespoke understeer loop, so allow understeer to contribute to main skid volume
|
|
if(GetAudioVehicleType() == AUD_VEHICLE_CAR && !tarmacSkids BANK_ONLY(&& g_UndersteerAffectsMainSkidVol))
|
|
{
|
|
mainSkidVolume = Max(mainSkidVolume, understeerVolume);
|
|
}
|
|
|
|
// Drop out all tarmac skids if all the wheels have totally burst (as these are very obviously rubber-on-tarmac sounds)
|
|
if(tarmacSkids && GetAudioVehicleType() == AUD_VEHICLE_CAR)
|
|
{
|
|
if(params.numNonBurstWheelsTouching == 0)
|
|
{
|
|
mainSkidVolume = 0.0f;
|
|
sideVol = 0.0f;
|
|
driveWheelSlipVol = 0.0f;
|
|
understeerVolume = 0.0f;
|
|
}
|
|
}
|
|
|
|
if (IsToyCar())
|
|
{
|
|
f32 maxVolume = Max(Max(mainSkidVolume, sideVol), understeerVolume);
|
|
|
|
if (!m_MainSkidLoop && m_IsFocusVehicle && maxVolume > 0)
|
|
{
|
|
audSoundSet soundSet;
|
|
|
|
if (soundSet.Init(ATSTRINGHASH("rcbandito_sounds", 0x7B9D9FE0)))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
initParams.u32ClientVar = (u32)AUD_VEHICLE_SOUND_UNKNOWN;
|
|
CreateAndPlaySound_Persistent(soundSet.Find(ATSTRINGHASH("skid_loop", 0x63D72B3C)), &m_MainSkidLoop, &initParams);
|
|
}
|
|
}
|
|
|
|
if (m_MainSkidLoop)
|
|
{
|
|
if (!m_IsFocusVehicle || maxVolume <= 0)
|
|
{
|
|
m_MainSkidLoop->StopAndForget(true);
|
|
}
|
|
else
|
|
{
|
|
f32 throttleInput = Abs(params.throttle);
|
|
|
|
if (!CReplayMgr::IsEditModeActive())
|
|
{
|
|
throttleInput = Max(throttleInput, Abs(params.throttleInput));
|
|
}
|
|
|
|
const f32 rollAngle = m_Vehicle->GetTransform().GetRoll() * RtoD;
|
|
|
|
m_MainSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("maxSkidVolume", 0x2628A402), maxVolume);
|
|
m_MainSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("mainSkidVolume", 0x6A01D3CB), mainSkidVolume);
|
|
m_MainSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("understeerVolume", 0x3EF3A4EA), understeerVolume);
|
|
m_MainSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("sideSkidVolume", 0x8C3D7FDC), sideVol);
|
|
m_MainSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("surfaceHardness", 0x55D4D89C), m_CachedMaterialSettings ? m_CachedMaterialSettings->FootstepMaterialHardness : 0.f);
|
|
m_MainSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("throttle", 0xEA0151DC), throttleInput);
|
|
m_MainSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("rollAngle", 0x94FC4D71), rollAngle);
|
|
m_MainSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("steerAngle", 0x6D2AC1CE), Abs(m_Vehicle->GetSteerAngle()) * RtoD);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_MainSkidLoop, mainSkidHash, mainSkidVolume, skidPitch + m_SkidPitchOffset, m_EnvironmentGroup, g_SkidCategory, true, false);
|
|
|
|
if(sideSkidHash != g_NullSoundHash && m_VehicleType != AUD_VEHICLE_BICYCLE)
|
|
{
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_SideSkidLoop, sideSkidHash, sideVol, skidPitch + m_SkidPitchOffset, m_EnvironmentGroup, g_SkidCategory, true, false);
|
|
}
|
|
|
|
if(tarmacSkids)
|
|
{
|
|
const f32 wetSkidVol = 0.55f * g_weather.GetWetness() * GetSkidVolumeScale() * sm_SkidFwdSlipToMainVol.CalculateValue(fwdSlipAngle) * sideSpeedFactor * params.numWheelsTouchingFactor;
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_WetSkidLoop, sm_TarmacSkidSounds.Find(ATSTRINGHASH("WetSkid", 0xCFD760FC)), wetSkidVol, skidPitch + m_SkidPitchOffset, m_EnvironmentGroup, g_SkidCategory, true, false);
|
|
|
|
// Only play drivewheelslip and understeer for cars
|
|
if(GetAudioVehicleType() == AUD_VEHICLE_CAR)
|
|
{
|
|
/*if(driveWheelSlipVol > 0.1f)
|
|
{
|
|
char message[128];
|
|
formatf(message, "DWS: %f, meanDWS: %f, speed: %f throttle: %f brake: %f", driveWheelSlipVol, meanDriveWheelSlip, params.fwdSpeed, params.throttleInput, params.brakePedal);
|
|
grcDebugDraw::Text(m_Vehicle->GetTransform().GetPosition() + Vec3V(0.f,0.f,2.f), Color32(255,0,0), 0,0, message, true, 1000);
|
|
}*/
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_DriveWheelSlipLoop, sm_TarmacSkidSounds.Find(ATSTRINGHASH("DriveWheelSlip", 0x95EDB1AB)), driveWheelSlipVol, m_SkidPitchOffset, m_EnvironmentGroup, g_SkidCategory, true, false);
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_UndersteerSkidLoop, sm_TarmacSkidSounds.Find(ATSTRINGHASH("Understeer", 0x6605017D)), understeerVolume, m_SkidPitchOffset + (m_Vehicle->InheritsFromBike() ? 200 : 0), m_EnvironmentGroup, g_SkidCategory, true, false);
|
|
|
|
if(m_UndersteerSkidLoop)
|
|
{
|
|
const float scrapeSkidRatio = Min(1.f, Max(params.fwdSpeedRatio, angVelMag));
|
|
m_UndersteerSkidLoop->FindAndSetVariableValue(ATSTRINGHASH("scrapeSkidRatio", 0xB3882CB), scrapeSkidRatio);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_UndersteerSkidLoop)
|
|
{
|
|
m_UndersteerSkidLoop->StopAndForget(true);
|
|
}
|
|
if(m_DriveWheelSlipLoop)
|
|
{
|
|
m_DriveWheelSlipLoop->StopAndForget(true);
|
|
}
|
|
if(m_WetSkidLoop)
|
|
{
|
|
m_WetSkidLoop->StopAndForget(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
params.skidLevel = Max(Max(mainSkidVolume, sideVol), driveWheelSlipVol);
|
|
|
|
if (!IsToyCar())
|
|
{
|
|
const float envLoudness = Lerp(params.skidLevel*params.skidLevel, 0.5f, 1.f);
|
|
const float skidRolloff = Lerp(params.skidLevel, 1.f, 2.5f);
|
|
const u8 envLoudnessU8 = (u8)(255.f * envLoudness);
|
|
if (m_MainSkidLoop)
|
|
{
|
|
m_MainSkidLoop->SetRequestedEnvironmentalLoudness(envLoudnessU8);
|
|
m_MainSkidLoop->SetRequestedVolumeCurveScale(skidRolloff);
|
|
}
|
|
if (m_SideSkidLoop)
|
|
{
|
|
m_SideSkidLoop->SetRequestedEnvironmentalLoudness(envLoudnessU8);
|
|
m_SideSkidLoop->SetRequestedVolumeCurveScale(skidRolloff);
|
|
}
|
|
if (m_DriveWheelSlipLoop)
|
|
{
|
|
m_DriveWheelSlipLoop->SetRequestedEnvironmentalLoudness(envLoudnessU8);
|
|
m_DriveWheelSlipLoop->SetRequestedVolumeCurveScale(skidRolloff);
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
if(m_IsPlayerVehicle && g_DebugVehicleSkids)
|
|
{
|
|
static const char * wheelMeterNames[] = {"Fwd", "Effective", "Side"};
|
|
static audMeterList wheelMeterList[4];
|
|
static u32 numWheelMeters = 3;
|
|
static f32 wheelMeterValues[12];
|
|
|
|
for (s32 wheelIndex = 0; wheelIndex < m_Vehicle->GetNumWheels() && wheelIndex < 4; wheelIndex++)
|
|
{
|
|
CWheel* thisWheel = m_Vehicle->GetWheel(wheelIndex);
|
|
|
|
if(thisWheel)
|
|
{
|
|
s32 i = wheelIndex * 3;
|
|
wheelMeterValues[i++] = thisWheel->GetFwdSlipAngle();
|
|
wheelMeterValues[i++] = thisWheel->GetEffectiveSlipAngle();
|
|
wheelMeterValues[i++] = thisWheel->GetSideSlipAngle();
|
|
|
|
audMeterList& meterList = wheelMeterList[wheelIndex];
|
|
meterList.left = 100.f;
|
|
meterList.bottom = 250.f + (220 * wheelIndex);
|
|
meterList.width = 220.f;
|
|
meterList.height = 180.f;
|
|
meterList.rangeMax = 15.f;
|
|
meterList.values = &wheelMeterValues[wheelIndex * 3];
|
|
meterList.names = wheelMeterNames;
|
|
meterList.numValues = numWheelMeters;
|
|
meterList.drawValues = true;
|
|
|
|
audNorthAudioEngine::DrawLevelMeters(&meterList);
|
|
}
|
|
}
|
|
|
|
static const char *meterNames[] = {"Skid Level", "Main Vol", "Side Vol", "Understeer Vol", "Drift Ang", "Angular Vel", "Fwd Speed Ratio", "Drift Angle Delta"};
|
|
const u32 numMeters = sizeof(meterNames)/sizeof(meterNames[0]);
|
|
static audMeterList meterList;
|
|
static f32 meterValues[numMeters];
|
|
|
|
s32 i = 0;
|
|
meterValues[i++] = params.skidLevel;
|
|
meterValues[i++] = finalMainVol;
|
|
meterValues[i++] = sideVol;
|
|
meterValues[i++] = understeerVolume;
|
|
meterValues[i++] = driftAngle;
|
|
meterValues[i++] = angVelMag;
|
|
meterValues[i++] = params.fwdSpeedRatio;
|
|
|
|
meterValues[i++] = Abs(driftAngleDeltaS);
|
|
meterList.left = 430.f;
|
|
meterList.bottom = 320.f;
|
|
meterList.width = 1100.f;
|
|
meterList.height = 300.f;
|
|
meterList.values = &meterValues[0];
|
|
meterList.names = meterNames;
|
|
meterList.numValues = numMeters;
|
|
audNorthAudioEngine::DrawLevelMeters(&meterList);
|
|
}
|
|
#endif // __BANK
|
|
}
|
|
|
|
float audVehicleAudioEntity::UpdateSkidsVolume(audVehicleVariables& params, bool tarmacSkids, s32 numWheelsTouching, float fwdSlipAngle, const float* slipAngleDeltas)
|
|
{
|
|
const f32 wetModifier = Max(0.25f, 1.f - g_weather.GetWetness());
|
|
|
|
float mainVol;
|
|
if(tarmacSkids)
|
|
{
|
|
mainVol = sm_SkidFwdSlipToMainVol.CalculateValue(fwdSlipAngle * wetModifier) * (1.f - g_weather.GetWetness()*0.5f);
|
|
|
|
// Disable chirps for bikes until the ABS bug is fixed
|
|
if(AreTyreChirpsEnabled() && m_IsPlayerVehicle && GetAudioVehicleType() == AUD_VEHICLE_CAR && !IsToyCar())
|
|
{
|
|
if(params.fwdSpeedRatio > 0.1f && m_Vehicle->GetBrake() >= 1.0f && numWheelsTouching == m_Vehicle->GetNumWheels())
|
|
{
|
|
if(!m_TyreChirpBrakePlayed)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.Pitch = (s16)m_SkidPitchOffset;
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(Min(1.f, 2.5f * params.fwdSpeedRatio * m_Vehicle->GetBrake()));
|
|
CreateAndPlaySound(sm_TarmacSkidSounds.Find(ATSTRINGHASH("HeavyBrakingChirp", 0xE79FD624)), &initParams);
|
|
m_TyreChirpBrakePlayed = true;
|
|
}
|
|
}
|
|
|
|
{
|
|
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
static float s_ChirpDeltaThreshold = 32.f;
|
|
|
|
if(Abs(slipAngleDeltas[i]) > s_ChirpDeltaThreshold)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.u32ClientVar = GetWheelSoundUpdateClientVar(i);
|
|
initParams.UpdateEntity = true;
|
|
initParams.Pitch = (s16)m_SkidPitchOffset;
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(Min(1.f, GetSkidVolumeScale() * params.fwdSpeedRatio*2.f));
|
|
GetCachedWheelPosition(i, initParams.Position, params);
|
|
|
|
CreateAndPlaySound(sm_TarmacSkidSounds.Find(ATSTRINGHASH("TyreChirps", 0xEF29A2D8)), &initParams);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mainVol = sm_SkidFwdSlipToMainVol.CalculateValue(fwdSlipAngle);
|
|
}
|
|
mainVol *= GetSkidVolumeScale();
|
|
|
|
if(m_TyreChirpBrakePlayed && fwdSlipAngle * wetModifier < 0.25f && m_Vehicle->GetBrake() <= 0.25f)
|
|
{
|
|
m_TyreChirpBrakePlayed = false;
|
|
}
|
|
|
|
return mainVol;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
audMetadataRef audVehicleAudioEntity::GetHornLoopRef(const u32 hornPattern)
|
|
{
|
|
audMetadataRef hornLoop = g_NullSoundRef;
|
|
hornLoop = SOUNDFACTORY.GetMetadataManager().GetObjectMetadataRefFromHash(hornPattern);
|
|
bool useSirenForHorn = false;
|
|
const bool alarmActive = m_Vehicle->IsAlarmActivated();
|
|
if(!alarmActive)
|
|
{
|
|
if(m_Vehicle->UsesSiren() && m_UseSirenForHorn)
|
|
{
|
|
useSirenForHorn = audEngineUtil::ResolveProbability(0.2f);
|
|
}
|
|
if(useSirenForHorn && m_VehSirenSounds.IsInitialised())
|
|
{
|
|
hornLoop = m_VehSirenSounds.Find(audEngineUtil::ResolveProbability(0.5f) ? ATSTRINGHASH("HORN_SLOW", 0xD91C6C0F): ATSTRINGHASH("HORN_FAST", 0xCB4A8157));
|
|
}
|
|
if(m_SirenLoop && m_VehSirenSounds.IsInitialised())
|
|
{
|
|
hornLoop = m_VehSirenSounds.Find(ATSTRINGHASH("BLIP", 0x26D96F23));
|
|
}
|
|
}
|
|
if(m_OverrideHorn)
|
|
{
|
|
hornLoop = SOUNDFACTORY.GetMetadataManager().GetObjectMetadataRefFromHash(m_OverridenHornHash);
|
|
}
|
|
return hornLoop;
|
|
}
|
|
// ----------------------------------------------------------------
|
|
// Update the horn and siren
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::HornOffHandler(u32 /*hash*/, void *context)
|
|
{
|
|
CPed *ped = (CPed*)context;
|
|
if(ped)
|
|
{
|
|
CVehicle* vehicle = ped->GetVehiclePedInside();
|
|
if(vehicle && vehicle->GetVehicleAudioEntity())
|
|
{
|
|
vehicle->GetVehicleAudioEntity()->SetHornPermanentlyOn(false);
|
|
vehicle->GetVehicleAudioEntity()->StopHorn();
|
|
}
|
|
}
|
|
}
|
|
|
|
void audVehicleAudioEntity::TriggerAlarm()
|
|
{
|
|
if(HasAlarm() && !m_Vehicle->IsAlarmActivated())
|
|
{
|
|
m_HasToTriggerAlarm = true;
|
|
}
|
|
}
|
|
void audVehicleAudioEntity::PlayVehicleAlarm()
|
|
{
|
|
if (m_AlarmType == AUD_CAR_ALARM_TYPE_HORN)
|
|
{
|
|
naAssertf(m_Vehicle->IsAlarmActivated(),"Trying to play the alarm but it is not active");
|
|
m_LastTimeAlarmPlayed = fwTimer::GetTimeInMilliseconds();
|
|
m_RandomAlarmInterval = audEngineUtil::GetRandomNumberInRange(0,150);
|
|
if(m_LastTimeAlarmPlayed > (2u * (sm_AlarmIntervalInMs + m_RandomAlarmInterval)))
|
|
m_LastTimeAlarmPlayed -= (2u * (sm_AlarmIntervalInMs + m_RandomAlarmInterval));
|
|
m_LastTimeAlarmPlayed += audEngineUtil::GetRandomNumberInRange(0,1000);
|
|
//PlayHeldDownHorn(sm_AlarmIntervalInMs/1000.f);
|
|
}
|
|
}
|
|
void audVehicleAudioEntity::UpdateHorn()
|
|
{
|
|
#if __BANK
|
|
if(g_DisableHorns)
|
|
{
|
|
StopAndForgetSounds(m_HornSound);
|
|
return;
|
|
}
|
|
#endif
|
|
if(!m_IsHornEnabled)
|
|
{
|
|
StopHorn();
|
|
return;
|
|
}
|
|
if(!m_WasInCarModShop && m_InCarModShop)
|
|
{
|
|
StopHorn();
|
|
}
|
|
m_WasInCarModShop = m_InCarModShop;
|
|
naAssertf(m_Vehicle, "m_Vehicle must be valid, about to access a null ptr...");
|
|
if(m_Vehicle->GetStatus() != STATUS_WRECKED)
|
|
{
|
|
if(m_IsHornPermanentlyOn)
|
|
{
|
|
m_WasHornPermanentlyOn = m_IsHornPermanentlyOn;
|
|
m_IsHornPermanentlyOn = false;
|
|
if(!m_HornSound)
|
|
{
|
|
PlayHeldDownHorn(-1.f);
|
|
}
|
|
}
|
|
else if (m_WasHornPermanentlyOn)
|
|
{
|
|
m_WasHornPermanentlyOn = false;
|
|
if(m_HornSound)
|
|
{
|
|
m_HornSound->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_HornSound)
|
|
{
|
|
m_HornSound->StopAndForget();
|
|
}
|
|
}
|
|
|
|
if(m_HornSound)
|
|
{
|
|
// Disable doppler on the player's horn if we're just in a regular vehicle camera (prevents pitching when spinning the camera around)
|
|
if(m_IsPlayerVehicle && !camInterface::GetCinematicDirector().IsAnyCinematicContextActive())
|
|
{
|
|
m_HornSound->SetRequestedDopplerFactor(0.0f);
|
|
}
|
|
else
|
|
{
|
|
m_HornSound->SetRequestedDopplerFactor(1.0f);
|
|
}
|
|
}
|
|
|
|
if(m_AlarmType > AUD_CAR_ALARM_TYPE_HORN && m_AlarmType <= AUD_CAR_ALARM_TYPE_4)
|
|
{
|
|
const bool alarmActive = m_Vehicle->IsAlarmActivated();
|
|
if(m_AlarmSound && !alarmActive)
|
|
{
|
|
m_AlarmSound->StopAndForget();
|
|
}
|
|
else
|
|
{
|
|
if(alarmActive && !m_AlarmSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.Predelay = audEngineUtil::GetRandomNumberInRange(0,1100);
|
|
initParams.StartOffset = audEngineUtil::GetRandomNumberInRange(0,99);
|
|
initParams.IsStartOffsetPercentage = true;
|
|
char soundName[32];
|
|
formatf(soundName, sizeof(soundName), "VEHICLES_EXTRAS_CAR_ALARM_%u", m_AlarmType);
|
|
CreateAndPlaySound_Persistent(soundName, &m_AlarmSound, &initParams);
|
|
}
|
|
}
|
|
}
|
|
else if (m_AlarmType == AUD_CAR_ALARM_TYPE_HORN)
|
|
{
|
|
const bool alarmActive = m_Vehicle->IsAlarmActivated();
|
|
if(alarmActive)
|
|
{
|
|
if(!m_HornSound)
|
|
{
|
|
if (m_LastTimeAlarmPlayed + (2u * (sm_AlarmIntervalInMs + m_RandomAlarmInterval)) < fwTimer::GetTimeInMilliseconds())
|
|
{
|
|
// already had sm_AlarmIntervalInMs milliseconds gap, play again
|
|
PlayHeldDownHorn((sm_AlarmIntervalInMs + m_RandomAlarmInterval)/1000.f);
|
|
m_LastTimeAlarmPlayed = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
m_WasAlarmActive = true;
|
|
}
|
|
else if(m_HornSound && m_WasAlarmActive)
|
|
{
|
|
m_HornSound->StopAndForget();
|
|
m_WasAlarmActive = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void audVehicleAudioEntity::OnScriptSetHydraulicWheelState()
|
|
{
|
|
CAutomobile* automobile = static_cast<CAutomobile*>(m_Vehicle);
|
|
f32 suspensionAngleUnitCircleX = 0.f;
|
|
f32 suspensionAngleUnitCircleY = 0.f;
|
|
|
|
for(s32 i = 0; i < m_Vehicle->GetNumWheels(); i++)
|
|
{
|
|
f32 xAxis = 0.0;
|
|
f32 yAxis = 0.0;
|
|
|
|
CWheel *pWheel = m_Vehicle->GetWheel(i);
|
|
|
|
if(pWheel)
|
|
{
|
|
switch(pWheel->GetHierarchyId())
|
|
{
|
|
case VEH_WHEEL_LF:
|
|
xAxis = -0.707f;
|
|
yAxis = 0.707f;
|
|
break;
|
|
case VEH_WHEEL_LR:
|
|
xAxis = -0.707f;
|
|
yAxis = -0.707f;
|
|
break;
|
|
case VEH_WHEEL_RR:
|
|
xAxis = 0.707f;
|
|
yAxis = -0.707f;
|
|
break;
|
|
case VEH_WHEEL_RF:
|
|
xAxis = 0.707f;
|
|
yAxis = 0.707f;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
suspensionAngleUnitCircleX += (xAxis * pWheel->GetSuspensionTargetRaiseAmount() / automobile->m_fHydraulicsUpperBound);
|
|
suspensionAngleUnitCircleY += (yAxis * pWheel->GetSuspensionTargetRaiseAmount() / automobile->m_fHydraulicsUpperBound);
|
|
}
|
|
}
|
|
|
|
SetHydraulicSuspensionInputAxis(suspensionAngleUnitCircleX, suspensionAngleUnitCircleY);
|
|
}
|
|
|
|
void audVehicleAudioEntity::RequestHydraulicActivation()
|
|
{
|
|
m_ShouldTriggerHydraulicActivate = true;
|
|
m_HydraulicActivationDelayFrames = g_NumHydraulicActivationDelayFrames;
|
|
}
|
|
|
|
void audVehicleAudioEntity::UpdateSiren(audVehicleVariables& vehicleVariables)
|
|
{
|
|
naAssertf(m_Vehicle, "m_Vehicle must be valid, about to access a null ptr...");
|
|
if(!m_Vehicle->UsesSiren())
|
|
{
|
|
return;
|
|
}
|
|
if(m_WantsToPlaySiren)
|
|
{
|
|
m_TimeToPlaySiren += fwTimer::GetTimeStepInMilliseconds();
|
|
if(m_TimeToPlaySiren >= g_TimeToPlaySiren)
|
|
{
|
|
m_ShouldPlayPlayerVehSiren = true;
|
|
}
|
|
}
|
|
bool enteringExitingVehicle = false;
|
|
if(m_Vehicle->GetDriver())
|
|
{
|
|
enteringExitingVehicle = m_Vehicle->GetDriver()->GetPedResetFlag(CPED_RESET_FLAG_IsEnteringOrExitingVehicle);
|
|
}
|
|
|
|
bool hasDriver = m_IsSirenForcedOn || !enteringExitingVehicle;
|
|
|
|
const bool isEngineOn = m_IsSirenForcedOn || m_Vehicle->m_nVehicleFlags.bEngineOn;
|
|
|
|
bool isPlayer = false;
|
|
if(m_Vehicle->GetDriver() && m_Vehicle->GetDriver()->IsPlayer())
|
|
{
|
|
isPlayer = true;
|
|
}
|
|
u32 sirenSlow = ((m_IsSirenFucked && isPlayer) ? ATSTRINGHASH("FUCKED", 0x4DD32855) : ATSTRINGHASH("SLOW", 0xC4EE147F));
|
|
|
|
bool isIceVan = false;
|
|
// Please implement icecream truck through modelinfo or vehicle flags ... MI currently not in metadata
|
|
//else if(m_Vehicle->GetModelIndex() == MI_CAR_ICEVAN)
|
|
//{
|
|
// isIceVan = true;
|
|
// sirenSlow = iceVanSiren;
|
|
//}
|
|
|
|
if(m_Vehicle->GetStatus() == STATUS_WRECKED && !m_WasWrecked)
|
|
{
|
|
m_WasWrecked = true;
|
|
|
|
if(isIceVan)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(ATSTRINGHASH("ICECREAM_MELTING", 0xAC534109), &initParams);
|
|
}
|
|
}
|
|
|
|
bool mustPlaySiren = m_IsSirenForcedOn || m_MustPlaySiren;
|
|
CVehicle* playerVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
mustPlaySiren = mustPlaySiren || (playerVeh == m_Vehicle);
|
|
bool isSirenOn = m_Vehicle->m_nVehicleFlags.GetIsSirenAudioOn();
|
|
if( !m_SirenLoop && (!mustPlaySiren || !isSirenOn))
|
|
{
|
|
return;
|
|
}
|
|
if(m_Vehicle->GetDriver())
|
|
{
|
|
m_IsSirenOn = isSirenOn && !(m_Vehicle->GetDriver()->GetSpeechAudioEntity() && m_Vehicle->GetDriver()->GetSpeechAudioEntity()->IsMegaphoneSpeechPlaying()) && !m_Vehicle->GetDriver()->IsDead();
|
|
}
|
|
else
|
|
{
|
|
if(NetworkInterface::IsGameInProgress())
|
|
{
|
|
CPed* player = CGameWorld::FindLocalPlayer();
|
|
if (player)
|
|
{
|
|
m_IsSirenOn = m_IsSirenOn && isSirenOn && (m_SirenBypassMPDriverCheck || m_PlaySirenWithNoNetworkPlayerDriver || SUPERCONDUCTOR.GetVehicleConductor().PlaySirenWithNoNetworkPlayerDriver());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_IsSirenOn = isSirenOn && SUPERCONDUCTOR.GetVehicleConductor().PlaySirenWithNoDriver();
|
|
}
|
|
}
|
|
isSirenOn = mustPlaySiren && m_IsSirenOn && m_ShouldPlayPlayerVehSiren && !m_WasWrecked;
|
|
|
|
switch(m_SirenState)
|
|
{
|
|
case AUD_SIREN_OFF:
|
|
if(m_SirenLoop && !IsHornOn())
|
|
{
|
|
m_SirenLoop->StopAndForget(true);
|
|
}
|
|
|
|
if((!m_IsSirenFucked || isPlayer) && isSirenOn)
|
|
{
|
|
if(IsHornOn() && !m_IsSirenFucked && !isIceVan)
|
|
{
|
|
// fast siren when horn is pressed
|
|
m_SirenState = AUD_SIREN_FAST;
|
|
}
|
|
else
|
|
{
|
|
m_SirenState = AUD_SIREN_SLOW;
|
|
}
|
|
}
|
|
break;
|
|
case AUD_SIREN_SLOW:
|
|
if(!isSirenOn)
|
|
{
|
|
if(m_SirenLoop)
|
|
{
|
|
if(m_Vehicle->GetStatus() == STATUS_WRECKED)
|
|
{
|
|
m_SirenLoop->FindAndSetVariableValue(ATSTRINGHASH("isFucked", 0x82DA7FEC), 1.f);
|
|
}
|
|
m_SirenLoop->StopAndForget(true);
|
|
}
|
|
m_PlaySirenWithNoNetworkPlayerDriver = false;
|
|
m_SirenState = AUD_SIREN_OFF;
|
|
}
|
|
else if(IsHornOn() && !isIceVan && !m_IsSirenFucked )
|
|
{
|
|
// switch to fast siren
|
|
if(m_SirenLoop)
|
|
{
|
|
m_SirenLoop->StopAndForget(true);
|
|
}
|
|
if(m_Vehicle->GetDriver() && !m_Vehicle->GetDriver()->IsDead())
|
|
{
|
|
m_SirenState = AUD_SIREN_FAST;
|
|
m_LastSirenChangeTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
else if(!isIceVan && !isPlayer && m_Vehicle->m_nVehicleFlags.bApproachingJunctionWithSiren && m_Vehicle->GetDriver() && vehicleVariables.fwdSpeed > 5.f)
|
|
{
|
|
if(fwTimer::GetTimeInMilliseconds() > m_LastSirenChangeTime + 4000)
|
|
{
|
|
if(m_SirenLoop)
|
|
{
|
|
m_SirenLoop->StopAndForget(true);
|
|
}
|
|
|
|
m_SirenState = AUD_SIREN_WARNING;
|
|
m_LastSirenChangeTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
else if(!m_SirenLoop && !m_SirenBlip)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.UpdateEntity = true;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.RemoveHierarchy = false;
|
|
if((m_Vehicle->GetDriver() && !m_Vehicle->GetDriver()->IsLocalPlayer()))
|
|
{
|
|
// random predelay so that lots of sirens starting on the same frame don't sound ridiculous
|
|
initParams.Predelay = audEngineUtil::GetRandomNumberInRange(0, 350);
|
|
}
|
|
if(m_VehSirenSounds.IsInitialised())
|
|
{
|
|
CreateSound_PersistentReference(m_VehSirenSounds.Find(sirenSlow), &m_SirenLoop, &initParams);
|
|
}
|
|
if(m_SirenLoop)
|
|
{
|
|
if(isIceVan)
|
|
{
|
|
// hack hack hack :) use the smoothing to stop the pitch bend at the end of the note, when the retriggered overlap
|
|
// kicks off the mathop sound to choose the next random pitch.
|
|
m_SirenLoop->SetRequestedFrequencySmoothingRate(0.0f);
|
|
|
|
// step through all ice van tunes since playing the same one more than once at a time causes bad things to happen
|
|
f32 var;
|
|
bool hasVar = m_SirenLoop->FindVariableValue(g_VariationVariableHash, var);
|
|
const u32 numTunes = (u32)(hasVar?var+1:1);
|
|
m_SirenLoop->FindAndSetVariableValue(g_VariationVariableHash, static_cast<f32>(g_IceVanTune));
|
|
// lookup this variation tempo scaling
|
|
m_SirenLoop->FindAndSetVariableValue(ATSTRINGHASH("tempoScaling", 0xB4873DA8), g_IceVanTempoScalingCurve.CalculateValue(static_cast<f32>(g_IceVanTune)));
|
|
g_IceVanTuneTextId = 400 + g_IceVanTune;
|
|
g_IceVanTune = (g_IceVanTune + 1) % numTunes;
|
|
|
|
// turn off the player radio so that they can enjoy the icevan tunes that I've worked so hard on :)
|
|
if(m_Vehicle->GetDriver() && m_Vehicle->GetDriver()->IsLocalPlayer())
|
|
{
|
|
NA_RADIO_ENABLED_ONLY(g_RadioAudioEntity.RetuneToStation(ATSTRINGHASH("OFF", 0x77E9145)));
|
|
}
|
|
}
|
|
m_SirenLoop->PrepareAndPlay();
|
|
}
|
|
|
|
}
|
|
break;
|
|
case AUD_SIREN_FAST:
|
|
|
|
if(!IsHornOn() || isIceVan)
|
|
{
|
|
//switch to slow siren
|
|
if(m_SirenLoop)
|
|
{
|
|
m_SirenLoop->StopAndForget(true);
|
|
}
|
|
m_SirenState = AUD_SIREN_SLOW;
|
|
m_LastSirenChangeTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
else if(!m_SirenLoop && !m_SirenBlip)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
u32 soundHash = ATSTRINGHASH("WARNING", 0xE91F183C);
|
|
// sometimes trigger the warning for player vehicles
|
|
if((m_Vehicle->GetDriver() && isPlayer) && m_Vehicle->GetNumSequentialSirenPresses() == 1)
|
|
{
|
|
soundHash = ATSTRINGHASH("FAST", 0x64B8047E);
|
|
}
|
|
m_Vehicle->ResetNumSequentialSirenPresses();
|
|
|
|
if(m_VehSirenSounds.IsInitialised())
|
|
{
|
|
CreateAndPlaySound_Persistent(m_VehSirenSounds.Find(soundHash), &m_SirenLoop, &initParams);
|
|
}
|
|
}
|
|
break;
|
|
case AUD_SIREN_WARNING:
|
|
if(!m_IsSirenOn || !isEngineOn || !hasDriver || isIceVan)
|
|
{
|
|
if(m_SirenLoop)
|
|
{
|
|
m_SirenLoop->StopAndForget(true);
|
|
}
|
|
m_PlaySirenWithNoNetworkPlayerDriver = false;
|
|
m_SirenState = AUD_SIREN_OFF;
|
|
}
|
|
else if(fwTimer::GetTimeInMilliseconds() > m_LastSirenChangeTime + 1000 && (!m_Vehicle->m_nVehicleFlags.bApproachingJunctionWithSiren || vehicleVariables.fwdSpeed <= 5.f || fwTimer::GetTimeInMilliseconds() > m_LastSirenChangeTime + 3000))
|
|
{
|
|
if(m_SirenLoop)
|
|
{
|
|
m_SirenLoop->StopAndForget(true);
|
|
}
|
|
if(IsHornOn())
|
|
{
|
|
m_SirenState = AUD_SIREN_FAST;
|
|
}
|
|
else
|
|
{
|
|
m_SirenState = AUD_SIREN_SLOW;
|
|
}
|
|
|
|
m_LastSirenChangeTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
else if(!m_SirenLoop && !m_SirenBlip)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.UpdateEntity = true;
|
|
initParams.TrackEntityPosition = true;
|
|
if(m_VehSirenSounds.IsInitialised())
|
|
{
|
|
CreateAndPlaySound_Persistent(m_VehSirenSounds.Find(ATSTRINGHASH("WARNING", 0xE91F183C)), &m_SirenLoop, &initParams);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(m_SirenLoop)
|
|
{
|
|
if(isIceVan)
|
|
{
|
|
const f32 damageFactor = 1.f - (m_Vehicle->GetHealth() * 0.001f);
|
|
const f32 pitchRange = 0.17f + (damageFactor*0.8f);
|
|
const f32 delay = (0.250f * (1.f - vehicleVariables.fwdSpeedRatio));
|
|
|
|
m_SirenLoop->FindAndSetVariableValue(ATSTRINGHASH("minPitch", 0x60D1797E), -pitchRange);
|
|
m_SirenLoop->FindAndSetVariableValue(ATSTRINGHASH("maxPitch", 0x3FA79219), pitchRange);
|
|
m_SirenLoop->FindAndSetVariableValue(ATSTRINGHASH("delayTime", 0xDA06E848), delay);
|
|
m_SirenLoop->FindAndSetVariableValue(ATSTRINGHASH("playDirection", 0x4A65EC8F), (vehicleVariables.fwdSpeed < -0.5f ? -1.f : 1.f));
|
|
}
|
|
else
|
|
{
|
|
// dont cone the ice cream van.
|
|
m_SirenLoop->SetRequestedOrientation(m_Vehicle->GetMatrix());
|
|
}
|
|
// Conductors siren volume.
|
|
f32 newVolume = m_SirensVolumeSmoother.CalculateValue(m_SirensDesireLinVol, vehicleVariables.timeInMs);
|
|
m_SirenLoop->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(newVolume));
|
|
// if the siren is muted and we want to stop it
|
|
if(newVolume == 0.f && m_ShouldStopSiren)
|
|
{
|
|
// set Must play siren (it will stop the siren )
|
|
m_MustPlaySiren = false;
|
|
}
|
|
}
|
|
|
|
const bool enableStereoSirens = g_EnableStereoSirens && m_IsFocusVehicle && NetworkInterface::IsInCopsAndCrooks();
|
|
|
|
if (m_SirenLoop)
|
|
{
|
|
m_SirenLoop->SetRequestedPan(enableStereoSirens ? 0 : -1);
|
|
}
|
|
|
|
if (m_SirenBlip)
|
|
{
|
|
m_SirenBlip->SetRequestedPan(enableStereoSirens ? 0 : -1);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity UpdateWarningSounds
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateWarningSounds(audVehicleVariables& vehicleVariables)
|
|
{
|
|
if(vehicleVariables.distFromListenerSq < 900)
|
|
{
|
|
// default to true for door open warning
|
|
CCarDoor* pDoor = m_Vehicle->GetDoorFromId(VEH_DOOR_DSIDE_F);
|
|
if(pDoor && HasDoorOpenWarning())
|
|
{
|
|
const bool shouldPlayDoorWarning = m_Vehicle->m_nVehicleFlags.bLightsOn && !pDoor->GetIsClosed() && m_Vehicle->IsEngineOn() && !m_InCarModShop;
|
|
|
|
if(m_DoorOpenWarning)
|
|
{
|
|
if(!shouldPlayDoorWarning)
|
|
{
|
|
m_DoorOpenWarning->StopAndForget();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(shouldPlayDoorWarning)
|
|
{
|
|
audSoundInitParams initParams;
|
|
f32 atten;
|
|
u32 cutoff;
|
|
GetInteriorSoundOcclusion(atten,cutoff);
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.LPFCutoff = cutoff;
|
|
initParams.Volume = atten;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
CreateSound_PersistentReference(sm_ExtrasSoundSet.Find(ATSTRINGHASH("Warning_DoorOpen", 0xB8D9B657)), &m_DoorOpenWarning, &initParams);
|
|
if(m_DoorOpenWarning)
|
|
{
|
|
m_DoorOpenWarning->SetClientVariable((u32)AUD_VEHICLE_SOUND_INTERIOR_OCCLUSION);
|
|
m_DoorOpenWarning->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(HasReverseWarning())
|
|
{
|
|
bool inReverseGear = m_Vehicle->m_Transmission.GetGear() <= 0;
|
|
|
|
// We can't trust car recordings to be in the correct gear - but if they're going backwards then it should be
|
|
// safe to asssume that they're reversing intentionally
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(m_Vehicle))
|
|
{
|
|
inReverseGear = true;
|
|
}
|
|
|
|
inReverseGear |= m_ForceReverseWarning;
|
|
|
|
if(m_ReverseWarning)
|
|
{
|
|
if(!inReverseGear || vehicleVariables.fwdSpeed >= 0.f || !m_Vehicle->m_nVehicleFlags.bEngineOn)
|
|
{
|
|
m_ReverseWarning->StopAndForget();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(inReverseGear && vehicleVariables.fwdSpeed < -0.5f && m_Vehicle->m_nVehicleFlags.bEngineOn)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
|
|
u32 customReverseWarningSoundHash = GetReverseWarningSound();
|
|
|
|
if(customReverseWarningSoundHash != g_NullSoundHash)
|
|
{
|
|
CreateAndPlaySound_Persistent(customReverseWarningSoundHash, &m_ReverseWarning, &initParams);
|
|
}
|
|
else
|
|
{
|
|
CreateAndPlaySound_Persistent(sm_ExtrasSoundSet.Find(ATSTRINGHASH("Warning_Reversing", 0x1AE37740)), &m_ReverseWarning, &initParams);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StopAndForgetSounds(m_DoorOpenWarning, m_ReverseWarning);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the default vehicle collision settings
|
|
// ----------------------------------------------------------------
|
|
VehicleCollisionSettings* audVehicleAudioEntity::GetVehicleCollisionSettings() const
|
|
{
|
|
static u32 propTrailerHash = ATSTRINGHASH("proptrailer", 0x153e1b0a);
|
|
if(propTrailerHash == m_Vehicle->GetBaseModelInfo()->GetModelNameHash())
|
|
{
|
|
return audNorthAudioEngine::GetObject<VehicleCollisionSettings>(ATSTRINGHASH("VEHICLE_COLLISION_PROP_TRAILER", 0x49b15570));
|
|
}
|
|
return audNorthAudioEngine::GetObject<VehicleCollisionSettings>(ATSTRINGHASH("VEHICLE_COLLISION_CAR", 0xC2FB47));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Compute the engine health
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::ComputeEffectiveEngineHealth() const
|
|
{
|
|
const f32 maxHealth = CTransmission::GetEngineHealthMax();
|
|
const f32 knackeredCarHealth = Min((f32)m_FakeEngineHealth, maxHealth);
|
|
const f32 drowningEngineHealth = GetAudioVehicleType() == AUD_VEHICLE_BOAT? maxHealth : Lerp(m_DrowningFactor, maxHealth, 0.f);
|
|
f32 engineHealth = Min((1.0f - m_ScriptEngineDamageFactor) * maxHealth, Min(knackeredCarHealth, m_Vehicle->GetVehicleDamage()->GetEngineHealth(), drowningEngineHealth));
|
|
|
|
#if __BANK
|
|
if(g_ForceDamage && m_IsPlayerVehicle)
|
|
{
|
|
engineHealth = maxHealth * (1.0f - g_ForcedDamageFactor);
|
|
}
|
|
#endif
|
|
|
|
return engineHealth;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Fix the vehicle
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::Fix()
|
|
{
|
|
FixSiren();
|
|
m_ScriptEngineDamageFactor = 0.0f;
|
|
m_ScriptBodyDamageFactor = 0.0f;
|
|
m_FakeBodyHealth = static_cast<s16>(CVehicleDamage::GetBodyHealthMax());
|
|
m_FakeEngineHealth = static_cast<s16>(CTransmission::GetEngineHealthMax());
|
|
};
|
|
|
|
// ----------------------------------------------------------------
|
|
// Compute the vehicle's body damage factor
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::ComputeEffectiveBodyDamageFactor() const
|
|
{
|
|
const f32 maxHealth = CVehicleDamage::GetBodyHealthMax();
|
|
f32 bodyDamageFactor = Max(m_ScriptBodyDamageFactor, 1.0f - (m_Vehicle->GetVehicleDamage()->GetBodyHealth() / maxHealth));
|
|
bodyDamageFactor = Max(bodyDamageFactor, 1.0f - (m_FakeBodyHealth/1000.0f));
|
|
|
|
#if __BANK
|
|
if(g_ForceDamage)
|
|
{
|
|
bodyDamageFactor = g_ForcedDamageFactor;
|
|
}
|
|
#endif
|
|
|
|
return bodyDamageFactor;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Compute the vehicle suspension health
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::ComputeEffectiveSuspensionHealth() const
|
|
{
|
|
f32 averageSuspensionHealth = 0.f;
|
|
|
|
for(u32 loop = 0; loop < m_Vehicle->GetNumWheels(); loop++)
|
|
{
|
|
CWheel* wheel = m_Vehicle->GetWheel(loop);
|
|
|
|
if(wheel && wheel->GetTyreHealth() > 0.0f)
|
|
{
|
|
averageSuspensionHealth += wheel->GetSuspensionHealth();
|
|
}
|
|
}
|
|
|
|
// Suspension health as 0-1 range
|
|
averageSuspensionHealth /= m_Vehicle->GetNumWheels();
|
|
averageSuspensionHealth = Clamp(averageSuspensionHealth * 0.001f, 0.0f, 1.0f);
|
|
|
|
#if __BANK
|
|
if(g_OverrideHydraulicSuspensionDamage)
|
|
{
|
|
averageSuspensionHealth = g_OverridenHydraulicSuspensionDamage;
|
|
}
|
|
#endif
|
|
|
|
return averageSuspensionHealth;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update chassis stress sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateClatter(audVehicleVariables& state)
|
|
{
|
|
const Vector3 clatterWorldPos = m_Vehicle->TransformIntoWorldSpace(m_ClatterOffsetPos) - VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
Vector3 delta = (clatterWorldPos - m_LastClatterWorldPos) * fwTimer::GetInvTimeStep();
|
|
const f32 spinVelocity = Abs(DotProduct(delta, VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetA())));
|
|
const f32 forwardVelocity = Abs(DotProduct(delta, VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetB())));
|
|
const f32 velocityRatio = spinVelocity/forwardVelocity;
|
|
f32 bodyDamageFactor = ComputeEffectiveBodyDamageFactor();
|
|
|
|
const f32 clatterUpVelocity = DotProduct(delta, VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetC()));
|
|
const f32 clatterAcceleration = clatterUpVelocity - m_LastClatterUpVel;
|
|
|
|
if(state.timeInMs - m_TimeCreated > 500 && (!m_Vehicle->GetVehicleAiLod().IsLodFlagSet(CVehicleAILod::AL_LodTimeslicing) || m_VisibilitySmoother.GetLastValue() >= 0.5f))
|
|
{
|
|
// acceleration changed direction
|
|
// NOTE: minimum of 0.4f contribution from speed, all the way up to 1.4 (so small bumps at high speeds are pretty loud)
|
|
// NOTE: 0.4 now scaled by wheel speed to prevent sounds triggering when stationary (eg. when physics pop slightly when transitioning between LODs)
|
|
const f32 rescaledSpeedRatio = (0.4f * Min(1.0f, state.wheelSpeed)) + Min(1.f,state.wheelSpeedRatio);
|
|
f32 clatterAccelerationCR = Abs(clatterAcceleration - m_LastClatterAcceleration) * fwTimer::GetInvTimeStep();
|
|
f32 heavyVehicleScaler = HasHeavyRoadNoise()? 2.5f : 1.0f;
|
|
f32 trailerScaler = 1.0f;
|
|
|
|
// Scale up sensitivity on big trailers Small trailers have mass ~1000, massive ones are ~3500
|
|
if(m_Vehicle->InheritsFromTrailer())
|
|
{
|
|
trailerScaler = 8.0f * ClampRange(m_Vehicle->pHandling->m_fMass - 1000.0f, 0.0f, 2500.0f);
|
|
}
|
|
|
|
// Ignore chassis stress if hydraulics are fully raised (prevents squeaks when initially raising)
|
|
if(m_Vehicle->m_nVehicleFlags.bAreHydraulicsAllRaised)
|
|
{
|
|
clatterAccelerationCR = 0.f;
|
|
}
|
|
|
|
// Bump up chassis stress when stationary at low speed
|
|
f32 hydraulicsChassisStressScalar = AreHydraulicsActive()? Lerp(1.0f - Min(state.fwdSpeedRatio/0.5f, 1.0f), 1.0f, g_HydraulicsChassisStressSensitivityMultiplier) : 1.0f;
|
|
f32 clatterRatio = rescaledSpeedRatio * trailerScaler * heavyVehicleScaler * Min(1.f, (clatterAccelerationCR * GetClatterSensitivityScalar()) / g_ClatterMaxAcceleration);
|
|
f32 chassisStressRatio = m_ChassisStressSmoother.CalculateValue((AreHydraulicsActive() ? 1.0f : rescaledSpeedRatio) * Min(1.f, (clatterAccelerationCR * GetChassisStressSensitivityScalar() * hydraulicsChassisStressScalar) / g_ChassisStressMaxAcceleration), state.timeInMs);
|
|
|
|
if(m_Vehicle->m_nVehicleFlags.bIsDrowning || g_ReflectionsAudioEntity.IsStuntTunnelMaterial(GetMainWheelMaterial()))
|
|
{
|
|
clatterRatio = 0.f;
|
|
chassisStressRatio = 0.f;
|
|
}
|
|
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("DELUXO", 0x586765FB) && m_Vehicle->GetSpecialFlightModeRatio() > 0.f)
|
|
{
|
|
chassisStressRatio = 0.f;
|
|
}
|
|
|
|
audMetadataRef clatterSoundRef = g_NullSoundRef;
|
|
|
|
if(m_Vehicle->m_nVehicleFlags.bIsBeingTowed)
|
|
{
|
|
audSoundSet soundSet;
|
|
soundSet.Init(GetTowTruckSoundSet());
|
|
clatterSoundRef = soundSet.Find(ATSTRINGHASH("TowedVehicleClatter", 0xA1510B56));
|
|
}
|
|
else
|
|
{
|
|
clatterSoundRef = GetClatterSound();
|
|
}
|
|
|
|
if(m_CachedMaterialSettings)
|
|
{
|
|
// add some random clatter when driving on cobbles
|
|
clatterRatio = Min(1.f, clatterRatio + (state.wheelSpeedRatio * audEngineUtil::GetRandomNumberInRange(m_CachedMaterialSettings->Roughness/2.0f,m_CachedMaterialSettings->Roughness)));
|
|
chassisStressRatio = Min(1.f, chassisStressRatio + (state.wheelSpeedRatio * audEngineUtil::GetRandomNumberInRange(m_CachedMaterialSettings->Roughness/2.0f,m_CachedMaterialSettings->Roughness)));
|
|
}
|
|
|
|
f32 clatterVolumeLin = clatterRatio;
|
|
clatterVolumeLin *= audDriverUtil::ComputeLinearVolumeFromDb(3.0f * state.engineDamageFactor);
|
|
|
|
f32 chassisStressVolumeLin = chassisStressRatio;
|
|
chassisStressVolumeLin *= audDriverUtil::ComputeLinearVolumeFromDb(3.0f * state.engineDamageFactor);
|
|
|
|
// Chassis stress comes in with damage on non-truck vehicles
|
|
if(!HasHeavyRoadNoise() && !AreHydraulicsActive())
|
|
{
|
|
chassisStressVolumeLin *= 0.3f + (0.7f * Min(bodyDamageFactor/0.6f, 1.0f));
|
|
}
|
|
|
|
if(!m_VehicleClatter)
|
|
{
|
|
if(state.numWheelsTouching > 0 &&
|
|
clatterRatio > 0.3f &&
|
|
!HydraulicsModifiedRecently())
|
|
{
|
|
TriggerClatter(clatterSoundRef, clatterVolumeLin);
|
|
|
|
if(forwardVelocity > 0.f && state.wheelSpeedAbs > g_SpeedForSpinDebris && state.movementSpeed > g_SpeedForSpinDebris
|
|
&& velocityRatio > g_SpinRatioForDebris && bodyDamageFactor > g_BodyDamageFactorForDebris)
|
|
{
|
|
GetCollisionAudio().TriggerDebrisSounds(velocityRatio);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
f32 currentVolumeLin = audDriverUtil::ComputeLinearVolumeFromDb(m_VehicleClatter->GetRequestedVolume());
|
|
|
|
if(clatterVolumeLin > currentVolumeLin)
|
|
{
|
|
// Smooth out the volume increase if we get a sudden spike
|
|
clatterVolumeLin = Min(currentVolumeLin + (10.0f * fwTimer::GetTimeStep()), clatterVolumeLin);
|
|
m_VehicleClatter->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(clatterVolumeLin) + GetClatterVolumeBoost());
|
|
}
|
|
}
|
|
|
|
if(chassisStressVolumeLin > g_SilenceVolumeLin)
|
|
{
|
|
if(!m_ChassisStressLoop)
|
|
{
|
|
const audMetadataRef chassisStressSoundRef = GetChassisStressSound();
|
|
if(chassisStressSoundRef != g_NullSoundRef)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_HEAVY_CLATTER;
|
|
initParams.UpdateEntity = true;
|
|
CreateAndPlaySound_Persistent(chassisStressSoundRef, &m_ChassisStressLoop, &initParams);
|
|
}
|
|
}
|
|
}
|
|
else if(m_ChassisStressLoop)
|
|
{
|
|
m_ChassisStressLoop->StopAndForget();
|
|
}
|
|
|
|
if(m_ChassisStressLoop)
|
|
{
|
|
m_ChassisStressLoop->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(chassisStressVolumeLin) + GetChassisStressVolumeBoost());
|
|
}
|
|
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
PF_SET(ClatterAcceleration, clatterAccelerationCR);
|
|
PF_SET(ClatterRatioValue, clatterRatio);
|
|
}
|
|
}
|
|
else if(m_ChassisStressLoop)
|
|
{
|
|
m_ChassisStressLoop->StopAndForget();
|
|
}
|
|
|
|
m_LastClatterAcceleration = clatterAcceleration;
|
|
m_LastClatterUpVel = clatterUpVelocity;
|
|
m_LastClatterWorldPos = clatterWorldPos;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger some clatter
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerClatter(audMetadataRef clatterSoundRef, f32 volumeLin)
|
|
{
|
|
if(!m_VehicleClatter)
|
|
{
|
|
if(clatterSoundRef != g_NullSoundRef &&
|
|
fwTimer::GetTimeInMilliseconds() > m_NextClatterTime &&
|
|
volumeLin > g_SilenceVolumeLin
|
|
BANK_ONLY(&& !g_DisableClatter))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_HEAVY_CLATTER;
|
|
initParams.UpdateEntity = true;
|
|
CreateAndPlaySound_Persistent(clatterSoundRef, &m_VehicleClatter, &initParams);
|
|
m_NextClatterTime = fwTimer::GetTimeInMilliseconds() + (u32)audEngineUtil::GetRandomNumberInRange(300,500);
|
|
|
|
if(m_VehicleClatter)
|
|
{
|
|
m_VehicleClatter->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(volumeLin) + GetClatterVolumeBoost());
|
|
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
if(audNorthAudioEngine::ShouldTriggerPulseHeadset())
|
|
{
|
|
audSound* clatterPulseSound = NULL;
|
|
|
|
CreateSound_LocalReference(g_FrontendAudioEntity.GetPulseHeadsetSounds().Find(ATSTRINGHASH("VehicleClatter", 0x75805775)), &clatterPulseSound);
|
|
|
|
if(clatterPulseSound)
|
|
{
|
|
clatterPulseSound->FindAndSetVariableValue(ATSTRINGHASH("CLATTERVOL", 0x9E3FAEBB), volumeLin);
|
|
clatterPulseSound->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the clatter sound for the given type
|
|
// ----------------------------------------------------------------
|
|
audMetadataRef audVehicleAudioEntity::GetClatterSoundFromType(ClatterType clatterType)
|
|
{
|
|
audMetadataRef clatterRef = g_NullSoundRef;
|
|
|
|
switch(clatterType)
|
|
{
|
|
case AUD_CLATTER_TRUCK_CAB:
|
|
clatterRef = sm_ClatterSoundSet.Find(ATSTRINGHASH("TruckCab", 0x755FCFFE));
|
|
break;
|
|
case AUD_CLATTER_TRUCK_CAGES:
|
|
clatterRef = sm_ClatterSoundSet.Find(ATSTRINGHASH("TruckCages", 0x736A7A81));
|
|
break;
|
|
case AUD_CLATTER_DETAIL:
|
|
clatterRef = sm_ClatterSoundSet.Find(ATSTRINGHASH("Detailed", 0xDCE667E1));
|
|
break;
|
|
case AUD_CLATTER_TAXI:
|
|
clatterRef = sm_ClatterSoundSet.Find(ATSTRINGHASH("Taxi", 0xC703DB5F));
|
|
break;
|
|
case AUD_CLATTER_BUS:
|
|
clatterRef = sm_ClatterSoundSet.Find(ATSTRINGHASH("Bus", 0xD577C962));
|
|
break;
|
|
case AUD_CLATTER_TRANSIT:
|
|
clatterRef = sm_ClatterSoundSet.Find(ATSTRINGHASH("TransitVan", 0x72B297F4));
|
|
break;
|
|
case AUD_CLATTER_TRANSIT_CLOWN:
|
|
clatterRef = sm_ClatterSoundSet.Find(ATSTRINGHASH("TransitVanClown", 0x7E67381B));
|
|
break;
|
|
case AUD_CLATTER_TRUCK_TRAILER_CHAINS:
|
|
clatterRef = sm_ClatterSoundSet.Find(ATSTRINGHASH("TruckTrailerChains", 0xCCD2EB7C));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return clatterRef;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if a stunt race is active
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsStuntRaceActive()
|
|
{
|
|
return SUPERCONDUCTOR.GetVehicleConductor().JumpConductorActive() && NetworkInterface::IsGameInProgress();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Preload the vehicle audio for a particular vehicle
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::PreloadScriptVehicleAudio(const u32 vehicleModelNameHash, s32 scriptID)
|
|
{
|
|
if(sm_ScriptVehicleRequestScriptID == -1 || scriptID == sm_ScriptVehicleRequestScriptID)
|
|
{
|
|
if(sm_ScriptVehicleRequest != vehicleModelNameHash)
|
|
{
|
|
if(sm_ScriptVehicleWaveSlot)
|
|
{
|
|
audWaveSlotManager::FreeWaveSlot(sm_ScriptVehicleWaveSlot);
|
|
}
|
|
|
|
audDisplayf("PRELOAD_VEHICLE_AUDIO_BANK - script requesting preload for vehicle %u", vehicleModelNameHash);
|
|
sm_ScriptVehicleRequest = vehicleModelNameHash;
|
|
|
|
if(vehicleModelNameHash != 0u)
|
|
{
|
|
sm_ScriptVehicleRequestScriptID = scriptID;
|
|
}
|
|
else
|
|
{
|
|
sm_ScriptVehicleRequestScriptID = -1;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the chassis stress sound for the given type
|
|
// ----------------------------------------------------------------
|
|
audMetadataRef audVehicleAudioEntity::GetChassisStressSoundFromType(ClatterType clatterType)
|
|
{
|
|
audMetadataRef chassisStressRef = g_NullSoundRef;
|
|
|
|
switch(clatterType)
|
|
{
|
|
case AUD_CLATTER_TRUCK_CAB:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("TruckCab", 0x755FCFFE));
|
|
break;
|
|
case AUD_CLATTER_TRUCK_CAGES:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("TruckCages", 0x736A7A81));
|
|
break;
|
|
case AUD_CLATTER_DETAIL:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("Detailed", 0xDCE667E1));
|
|
break;
|
|
case AUD_CLATTER_TAXI:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("Taxi", 0xC703DB5F));
|
|
break;
|
|
case AUD_CLATTER_BUS:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("Bus", 0xD577C962));
|
|
break;
|
|
case AUD_CLATTER_TRANSIT:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("TransitVan", 0x72B297F4));
|
|
break;
|
|
case AUD_CLATTER_TRANSIT_CLOWN:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("TransitVanClown", 0x7E67381B));
|
|
break;
|
|
case AUD_CLATTER_TRUCK_TRAILER_CHAINS:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("TruckTrailerChains", 0xCCD2EB7C));
|
|
break;
|
|
default:
|
|
chassisStressRef = sm_ChassisStressSoundSet.Find(ATSTRINGHASH("Detail", 0x677DF1B8));
|
|
break;
|
|
}
|
|
|
|
return chassisStressRef;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update entity sounds
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateSound(audSound *sound, audRequestedSettings *reqSets, u32 timeInMs)
|
|
{
|
|
Vector3 pos;
|
|
|
|
u32 clientVariable;
|
|
reqSets->GetClientVariable(clientVariable);
|
|
audVehicleSounds soundId = (audVehicleSounds)clientVariable;
|
|
u32 cutoff = kVoiceFilterLPFMaxCutoff;
|
|
|
|
if((soundId & 0xffff) == AUD_VEHICLE_SOUND_CUSTOM_BONE)
|
|
{
|
|
u32 boneIndex = soundId >> 16;
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(boneIndex).d));
|
|
}
|
|
else
|
|
{
|
|
switch(soundId)
|
|
{
|
|
case AUD_VEHICLE_SOUND_WHEEL0:
|
|
case AUD_VEHICLE_SOUND_WHEEL1:
|
|
case AUD_VEHICLE_SOUND_WHEEL2:
|
|
case AUD_VEHICLE_SOUND_WHEEL3:
|
|
case AUD_VEHICLE_SOUND_WHEEL4:
|
|
case AUD_VEHICLE_SOUND_WHEEL5:
|
|
GetWheelPosition(clientVariable - (u32)AUD_VEHICLE_SOUND_WHEEL0, pos);
|
|
reqSets->SetPosition(pos);
|
|
break;
|
|
case AUD_VEHICLE_SOUND_WHEEL6:
|
|
case AUD_VEHICLE_SOUND_WHEEL7:
|
|
GetWheelPosition((clientVariable-(u32)AUD_VEHICLE_SOUND_WHEEL6) + 6, pos);
|
|
reqSets->SetPosition(pos);
|
|
break;
|
|
case AUD_VEHICLE_SOUND_INTERIOR_OCCLUSION:
|
|
f32 atten;
|
|
GetInteriorSoundOcclusion(atten,cutoff);
|
|
reqSets->SetVolume(atten);
|
|
break;
|
|
case AUD_VEHICLE_SOUND_ENGINE:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_EngineOffsetPos));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_HORN:
|
|
pos.Zero();
|
|
GetHornOffsetPos(pos);
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(pos));
|
|
if(m_Vehicle->ContainsLocalPlayer() && !m_Vehicle->IsAlarmActivated())
|
|
{
|
|
reqSets->SetVolume(g_PlayerHornOffset);
|
|
}
|
|
else
|
|
{
|
|
reqSets->SetVolume(0.f);
|
|
}
|
|
reqSets->SetOrientation(m_Vehicle->GetPlaceableTracker()->GetOrientation());
|
|
break;
|
|
case AUD_VEHICLE_SOUND_SCRAPE:
|
|
case AUD_VEHICLE_SOUND_FOLIAGE:
|
|
GetCollisionAudio().UpdateSound(sound, reqSets, timeInMs);
|
|
break;
|
|
case AUD_VEHICLE_SOUND_LIGHTCOVER:
|
|
{
|
|
const s32 lightCoverBone = m_Vehicle->GetBoneIndex(VEH_LIGHTCOVER);
|
|
|
|
if(lightCoverBone > -1)
|
|
{
|
|
Matrix34 boneMatrix = RCC_MATRIX34(m_Vehicle->GetSkeletonData().GetDefaultTransform(lightCoverBone));
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(boneMatrix.d));
|
|
}
|
|
}
|
|
break;
|
|
case AUD_VEHICLE_SOUND_SPOILER_STRUTS:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(m_Vehicle->GetBoneIndex(VEH_STRUTS)).d));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_SPOILER:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(m_Vehicle->GetBoneIndex(VEH_SPOILER)).d));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_AIRBRAKE_L:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(m_Vehicle->GetBoneIndex(HELI_AIRBRAKE_L)).d));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_AIRBRAKE_R:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(m_Vehicle->GetBoneIndex(HELI_AIRBRAKE_R)).d));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_SUBMARINECAR_PROPELLOR:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace((m_Vehicle->GetObjectMtx(m_Vehicle->GetBoneIndex(SUBMARINECAR_PROPELLER_1)).d + m_Vehicle->GetObjectMtx(m_Vehicle->GetBoneIndex(SUBMARINECAR_PROPELLER_2)).d) * 0.5f));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_SUBMARINE_PROPELLOR:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace((m_Vehicle->GetObjectMtx(m_Vehicle->GetBoneIndex(SUB_PROPELLER_1)).d + m_Vehicle->GetObjectMtx(m_Vehicle->GetBoneIndex(SUB_PROPELLER_2)).d) * 0.5f));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_EXHAUST:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_ExhaustOffsetPos));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_HEAVY_CLATTER:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_ClatterOffsetPos));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_BLADE_0:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(m_Vehicle->GetWeaponBlade(0).GetFastBone() != -1 ? m_Vehicle->GetWeaponBlade(0).GetFastBone() : m_Vehicle->GetWeaponBlade(0).GetModBone()).d));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_BLADE_1:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(m_Vehicle->GetWeaponBlade(1).GetFastBone() != -1 ? m_Vehicle->GetWeaponBlade(1).GetFastBone() : m_Vehicle->GetWeaponBlade(1).GetModBone()).d));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_BLADE_2:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(m_Vehicle->GetWeaponBlade(2).GetFastBone() != -1 ? m_Vehicle->GetWeaponBlade(2).GetFastBone() : m_Vehicle->GetWeaponBlade(2).GetModBone()).d));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_BLADE_3:
|
|
reqSets->SetPosition(m_Vehicle->TransformIntoWorldSpace(m_Vehicle->GetObjectMtx(m_Vehicle->GetWeaponBlade(3).GetFastBone() != -1 ? m_Vehicle->GetWeaponBlade(3).GetFastBone() : m_Vehicle->GetWeaponBlade(3).GetModBone()).d));
|
|
break;
|
|
case AUD_VEHICLE_SOUND_CAR_RECORDING:
|
|
if(!CVehicleRecordingMgr::IsPlaybackGoingOnForCar(m_Vehicle))
|
|
{
|
|
sound->StopAndForget();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
cutoff = Min(cutoff, CalculateVehicleSoundLPFCutoff());
|
|
reqSets->SetLowPassFilterCutoff(cutoff);
|
|
}
|
|
|
|
u32 audVehicleAudioEntity::GetWheelSoundUpdateClientVar(u32 wheelIndex)
|
|
{
|
|
// These are no longer consecutive in the enum so we can't simply do (AUD_VEHICLE_SOUND_WHEEL0 + i)
|
|
switch (wheelIndex)
|
|
{
|
|
case 0:
|
|
return AUD_VEHICLE_SOUND_WHEEL0;
|
|
case 1:
|
|
return AUD_VEHICLE_SOUND_WHEEL1;
|
|
case 2:
|
|
return AUD_VEHICLE_SOUND_WHEEL2;
|
|
case 3:
|
|
return AUD_VEHICLE_SOUND_WHEEL3;
|
|
case 4:
|
|
return AUD_VEHICLE_SOUND_WHEEL4;
|
|
case 5:
|
|
return AUD_VEHICLE_SOUND_WHEEL5;
|
|
case 6:
|
|
return AUD_VEHICLE_SOUND_WHEEL6;
|
|
case 7:
|
|
return AUD_VEHICLE_SOUND_WHEEL7;
|
|
case 8:
|
|
return AUD_VEHICLE_SOUND_WHEEL8;
|
|
case 9:
|
|
return AUD_VEHICLE_SOUND_WHEEL9;
|
|
case 10:
|
|
return AUD_VEHICLE_SOUND_WHEEL10;
|
|
default:
|
|
audAssertf(false, "Wheel index %d has no matching sound update enum", wheelIndex);
|
|
break;
|
|
}
|
|
|
|
return AUD_VEHICLE_SOUND_UNKNOWN;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// CalculateVehicleSoundCutoff
|
|
// ----------------------------------------------------------------
|
|
u32 audVehicleAudioEntity::CalculateVehicleSoundLPFCutoff()
|
|
{
|
|
f32 cutoff = kVoiceFilterLPFMaxCutoff;
|
|
|
|
// If the player is in bonnet cam, low pass filter sounds from all other vehicles
|
|
if(audNorthAudioEngine::IsRenderingFirstPersonVehicleCam())
|
|
{
|
|
if(!m_IsFocusVehicle)
|
|
{
|
|
static const float minInteriorViewCutoff = 1000.0f;
|
|
const f32 interiorViewCutoff = minInteriorViewCutoff + ((kVoiceFilterLPFMaxCutoff - minInteriorViewCutoff) * sm_PlayerVehicleOpenness);
|
|
cutoff = Min(cutoff, interiorViewCutoff);
|
|
}
|
|
}
|
|
|
|
f32 minUnderwaterCutoff = 1000.0f;
|
|
|
|
// all sounds get lowpassed when underwater
|
|
if(IsSubmersible())
|
|
{
|
|
minUnderwaterCutoff = g_SubmersibleUnderwaterCutoff;
|
|
}
|
|
|
|
const f32 underwaterCutoff = minUnderwaterCutoff + ((kVoiceFilterLPFMaxCutoff - minUnderwaterCutoff) * (1.0f - m_DrowningFactor));
|
|
return (u32)Min(cutoff, underwaterCutoff);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity::DeployOutriggers
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::DeployOutriggers(bool deploy)
|
|
{
|
|
if(!IsDisabled() && GetVehicleModelNameHash() == ATSTRINGHASH("CHERNOBOG", 0xD6BC7523) REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive()))
|
|
{
|
|
TriggerSimpleSoundFromSoundset(ATSTRINGHASH("chernobog_barrage_sounds", 0x9EB5B64D), deploy? ATSTRINGHASH("activate", 0xE64E0807) : ATSTRINGHASH("deactivate", 0x51AFCCE6));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity::StartGliding
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::StartGliding()
|
|
{
|
|
if(!IsDisabled() && GetVehicleModelNameHash() == ATSTRINGHASH("OPPRESSOR", 0x34B82784) REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive()))
|
|
{
|
|
TriggerSimpleSoundFromSoundset(m_IsFocusVehicle? ATSTRINGHASH("DLC_Gunrunning_Oppressor_Sounds", 0xC98DA953) : ATSTRINGHASH("DLC_Gunrunning_Oppressor_NPC_Sounds", 0x23FDA269), ATSTRINGHASH("wings_out", 0xA92ED867));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity::StopGliding
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::StopGliding()
|
|
{
|
|
if(!IsDisabled() && GetVehicleModelNameHash() == ATSTRINGHASH("OPPRESSOR", 0x34B82784) REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive()))
|
|
{
|
|
TriggerSimpleSoundFromSoundset(m_IsFocusVehicle? ATSTRINGHASH("DLC_Gunrunning_Oppressor_Sounds", 0xC98DA953) : ATSTRINGHASH("DLC_Gunrunning_Oppressor_NPC_Sounds", 0x23FDA269), ATSTRINGHASH("wings_in", 0x862E16BE));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity::TriggerSimpleSoundFromSoundset
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSimpleSoundFromSoundset(u32 soundSetHash, u32 soundFieldHash REPLAY_ONLY(, bool recordSound))
|
|
{
|
|
if(soundSetHash != 0u)
|
|
{
|
|
audSoundSet soundSet;
|
|
|
|
if(soundSet.Init(soundSetHash))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
CreateDeferredSound(soundSet.Find(soundFieldHash), m_Vehicle, &initParams, true);
|
|
|
|
#if GTA_REPLAY
|
|
if(recordSound)
|
|
{
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundSetHash, soundFieldHash, &initParams, m_Vehicle));
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Notify vehicle that it is in a mod shop
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetIsInCarModShop(bool inCarMod)
|
|
{
|
|
if(inCarMod != m_InCarModShop)
|
|
{
|
|
audDisplayf("SET_VEHICLE_IN_CAR_MOD_SHOP - Vehicle %s in mod shop = %s", GetVehicleModelName(), inCarMod? "TRUE" : "FALSE");
|
|
m_InCarModShop = inCarMod;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// isHornOn
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsHornOn()
|
|
{
|
|
return (m_HornSound != NULL || m_PlayerHornOn);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Play veh horn
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::PlayVehicleHorn(f32 holdTimeInSeconds,bool updateTime,bool isScriptTriggered)
|
|
{
|
|
// If wrecked or siren or alarm activated, then horn disabled
|
|
// also stop the horn when the car is frozen by an interior, since its super annoying.
|
|
// Please implement icecream truck through modelinfo or vehicle flags ... MI currently not in metadata
|
|
if(m_Vehicle->m_nVehicleFlags.bIsDrowning || !m_IsHornEnabled || IsDisabled() || m_Vehicle->m_nDEflags.bFrozenByInterior || IsHiddenByNetwork())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// url:bugstar:6756505 - DLC Vehicle Audio - Toreador - Is it possible to disable the horn under water?
|
|
if (IsSubmarineCar() && m_Vehicle->IsInSubmarineMode())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(m_Vehicle->m_nVehicleFlags.GetIsSirenAudioOn())
|
|
{
|
|
if(m_Vehicle->GetDriver() && m_Vehicle->GetDriver()->IsPlayer())
|
|
{
|
|
m_PlayerHornOn = true;
|
|
}
|
|
if(m_SirenLoop || (!m_SirenLoop && m_SirenState == AUD_SIREN_FAST))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
if (m_Vehicle->IsAlarmActivated())
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
bool bWasHornOn = IsHornOn();
|
|
|
|
CVehicleVariationInstance& variation = m_Vehicle->GetVariationInstance();
|
|
if(!m_Vehicle->GetDriver() || (m_Vehicle->GetDriver() && !m_Vehicle->GetDriver()->IsPlayer()) || (m_InCarModShop && !m_Vehicle->UsesSiren()))
|
|
{
|
|
switch(m_HornType)
|
|
{
|
|
case 0x839504CB: //HeldDown
|
|
PlayHeldDownHorn(holdTimeInSeconds,updateTime);
|
|
break;
|
|
case 0xC91D8B07: //Aggressive
|
|
PlayAggressiveHorn();
|
|
break;
|
|
case 0x4F485502: //Normal
|
|
default:
|
|
// Avoid rest if not need to be computed
|
|
if(g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::AggressiveHorns))
|
|
{
|
|
PlayAggressiveHorn();
|
|
}
|
|
else
|
|
{
|
|
PlayNormalHorn();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
naAssertf(m_Vehicle->GetDriver()->IsPlayer(),"playing the player horn on a NPC vehicle");
|
|
if(m_HornSound && m_Vehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE)
|
|
{
|
|
m_HornSound->StopAndForget();
|
|
}
|
|
|
|
audSound** hornSoundPtr = &m_HornSound;
|
|
|
|
if (m_Vehicle->UsesSiren() && m_Vehicle->IsLawEnforcementVehicle() /*&& !m_IsSirenFucked*/)
|
|
{
|
|
hornSoundPtr = &m_SirenLoop;
|
|
}
|
|
|
|
if(!(*hornSoundPtr))
|
|
{
|
|
audMetadataRef hornLoop = g_NullSoundRef;
|
|
hornLoop = SOUNDFACTORY.GetMetadataManager().GetObjectMetadataRefFromHash(GetVehicleHornSoundHash());
|
|
if(m_Vehicle->UsesSiren() && m_Vehicle->IsLawEnforcementVehicle() /*&& !m_IsSirenFucked*/)
|
|
{
|
|
if(m_VehSirenSounds.IsInitialised())
|
|
{
|
|
hornLoop = m_VehSirenSounds.Find(ATSTRINGHASH("HORN", 0x3E34681F));
|
|
}
|
|
}
|
|
if(hornLoop != g_NullSoundRef)
|
|
{
|
|
if(variation.GetMods()[VMT_HORN] != 255)
|
|
{
|
|
if(variation.GetKit()->GetStatMods()[variation.GetMods()[VMT_HORN]].GetModifier() != 0)
|
|
{
|
|
hornLoop = SOUNDFACTORY.GetMetadataManager().GetObjectMetadataRefFromHash(variation.GetKit()->GetStatMods()[variation.GetMods()[VMT_HORN]].GetModifier());
|
|
}
|
|
}
|
|
if(m_OverrideHorn)
|
|
{
|
|
hornLoop = SOUNDFACTORY.GetMetadataManager().GetObjectMetadataRefFromHash(m_OverridenHornHash);
|
|
}
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_HORN;
|
|
if(m_Vehicle->ContainsLocalPlayer() && !m_Vehicle->IsAlarmActivated())
|
|
{
|
|
initParams.Volume = g_PlayerHornOffset;
|
|
}
|
|
|
|
Vector3 pos;
|
|
pos.Zero();
|
|
GetHornOffsetPos(pos);
|
|
initParams.Position = m_Vehicle->TransformIntoWorldSpace(pos);
|
|
CreateSound_PersistentReference(hornLoop, hornSoundPtr, &initParams);
|
|
if(*hornSoundPtr)
|
|
{
|
|
if(!DoesHornHaveTail())
|
|
{
|
|
(*hornSoundPtr)->SetReleaseTime(60);
|
|
}
|
|
|
|
(*hornSoundPtr)->PrepareAndPlay();
|
|
m_PlayerHornOn = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// tell other cars that we're honking
|
|
if (IsHornOn() && !bWasHornOn)
|
|
{
|
|
m_IsScriptTriggeredHorn = isScriptTriggered;
|
|
m_Vehicle->GetIntelligence()->TellOthersAboutHonk();
|
|
}
|
|
|
|
#if __BANK
|
|
if (IsHornOn())
|
|
{
|
|
audDisplayf("Frame : %i, Horn is on for vehicle %s : 0x%p, m_HornSound 0x%p, m_PlayerHornOn = %s, m_HornType = %u, m_IsHornPermanentlyOn = %s, holdTimeInSeconds = %.2f",
|
|
fwTimer::GetFrameCount(), m_Vehicle->GetDebugName(), m_Vehicle, m_HornSound, m_PlayerHornOn ? "TRUE" : "FALSE", m_HornType, m_IsHornPermanentlyOn ? "TRUE" : "FALSE", holdTimeInSeconds);
|
|
}
|
|
#endif // __BANK
|
|
|
|
#if GTA_REPLAY
|
|
if(CReplayMgr::ShouldRecord())
|
|
{
|
|
CReplayMgr::RecordFx<CPacketVehicleHorn>(
|
|
CPacketVehicleHorn(m_HornType,m_HornSoundIndex, holdTimeInSeconds),
|
|
m_Vehicle);
|
|
}
|
|
#endif // GTA_REPLAY
|
|
}
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::PlayNormalHorn()
|
|
{
|
|
if(naVerifyf(m_Vehicle, "Trying to play the horn on a NULL vehicle"))
|
|
{
|
|
if(!m_HornSound)
|
|
{
|
|
audMetadataRef hornLoop = GetHornLoopRef(GetNormalPattern());
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_HORN;
|
|
|
|
Vector3 pos;
|
|
pos.Zero();
|
|
GetHornOffsetPos(pos);
|
|
initParams.Position = m_Vehicle->TransformIntoWorldSpace(pos);
|
|
CreateSound_PersistentReference(hornLoop, &m_HornSound, &initParams);
|
|
if(m_HornSound)
|
|
{
|
|
if(!DoesHornHaveTail())
|
|
{
|
|
m_HornSound->SetReleaseTime(60);
|
|
}
|
|
|
|
m_HornSound->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::PlayAggressiveHorn()
|
|
{
|
|
if(naVerifyf(m_Vehicle, "Trying to play the horn on a NULL vehicle"))
|
|
{
|
|
if(!m_HornSound)
|
|
{
|
|
audMetadataRef hornLoop = GetHornLoopRef(GetAggressivePattern());
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_HORN;
|
|
|
|
Vector3 pos;
|
|
pos.Zero();
|
|
GetHornOffsetPos(pos);
|
|
initParams.Position = m_Vehicle->TransformIntoWorldSpace(pos);
|
|
CreateSound_PersistentReference(hornLoop, &m_HornSound, &initParams);
|
|
if(m_HornSound)
|
|
{
|
|
if(!DoesHornHaveTail())
|
|
{
|
|
m_HornSound->SetReleaseTime(60);
|
|
}
|
|
|
|
m_HornSound->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::PlayHeldDownHorn(f32 holdTimeInSeconds,bool updateTime)
|
|
{
|
|
//naAssertf(holdTimeInSeconds > 0.f, "Wrong time to play the horn. ");
|
|
if(naVerifyf(m_Vehicle, "Trying to play the horn on a NULL vehicle"))
|
|
{
|
|
if(!m_HornSound)
|
|
{
|
|
audMetadataRef hornLoop = GetHornLoopRef(GetHeldDownPattern());
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.u32ClientVar = AUD_VEHICLE_SOUND_HORN;
|
|
|
|
Vector3 pos;
|
|
pos.Zero();
|
|
GetHornOffsetPos(pos);
|
|
initParams.Position = m_Vehicle->TransformIntoWorldSpace(pos);
|
|
initParams.SetVariableValue(ATSTRINGHASH("HoldTime", 0x96499EA2),holdTimeInSeconds);
|
|
CreateSound_PersistentReference(hornLoop, &m_HornSound, &initParams);
|
|
if(m_HornSound)
|
|
{
|
|
if(!DoesHornHaveTail())
|
|
{
|
|
m_HornSound->SetReleaseTime(60);
|
|
}
|
|
|
|
m_HornSound->PrepareAndPlay();
|
|
}
|
|
}
|
|
else if(updateTime)
|
|
{
|
|
naAssertf(holdTimeInSeconds != -1.f, "Trying to play the horn sound forever with the wrong command");
|
|
m_IsHornPermanentlyOn = false;
|
|
m_WasHornPermanentlyOn = false;
|
|
m_HornSound->FindAndSetVariableValue(ATSTRINGHASH("HoldTime", 0x96499EA2),holdTimeInSeconds);
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity PostUpdate
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::PostUpdate()
|
|
{
|
|
m_InAirRotationalForceXLastFrame = m_InAirRotationalForceX;
|
|
m_InAirRotationalForceYLastFrame = m_InAirRotationalForceY;
|
|
|
|
m_CachedVehicleVelocityLastFrame = m_CachedVehicleVelocity;
|
|
m_CachedVehicleVelocity = m_Vehicle->GetVelocity();
|
|
m_CachedAngularVelocity = m_Vehicle->GetAngVelocity();
|
|
m_CollisionAudio.PostUpdate();
|
|
m_IsBeingNetworkSpectated = false;
|
|
m_IsVehicleBeingStopped = false;
|
|
m_IsPersonalVehicle = m_Vehicle->IsPersonalVehicle();
|
|
|
|
if(NetworkInterface::IsInSpectatorMode())
|
|
{
|
|
m_IsBeingNetworkSpectated = (m_Vehicle == CGameWorld::FindFollowPlayerVehicle());
|
|
}
|
|
|
|
if (m_TriggerDeferredSubmarineDiveHorn BANK_ONLY(|| (m_Vehicle->InheritsFromSubmarine() && g_ForceTriggerSubmarineDiveHorn)))
|
|
{
|
|
TriggerSubmarineDiveSound(ATSTRINGHASH("dive_horn", 0xD4CA7D22));
|
|
TriggerSubmarineDiveSound(ATSTRINGHASH("dive", 0xE7E43AD4));
|
|
m_TriggerDeferredSubmarineDiveHorn = false;
|
|
BANK_ONLY(g_ForceTriggerSubmarineDiveHorn = false;)
|
|
}
|
|
|
|
if (m_TriggerDeferredSubmarineSurface)
|
|
{
|
|
TriggerSubmarineDiveSound(ATSTRINGHASH("surface_horn", 0xF949F920));
|
|
TriggerSubmarineDiveSound(ATSTRINGHASH("surface", 0xF3C674C0));
|
|
m_TriggerDeferredSubmarineSurface = false;
|
|
}
|
|
|
|
m_IsPlayerPedInFullyOpenSeat = IsPedSatInExternalSeat(FindFollowPed()) || GetVehicleModelNameHash() == ATSTRINGHASH("DUSTER", 0x39D6779E);
|
|
|
|
#if NA_RADIO_ENABLED
|
|
|
|
naAssertf(GetControllerId() != AUD_INVALID_CONTROLLER_ENTITY_ID, "Invalid controller entity id");
|
|
bool wasRadioValid = m_RadioStation != NULL;
|
|
|
|
AmbientRadioLeakage leakage = GetAmbientRadioLeakage();
|
|
|
|
if(m_RadioStation && (m_RadioStation->IsLocked() || m_RadioStation->IsHidden()) && !m_IsPlayerVehicle)
|
|
{
|
|
// if we are playing an invalid station (ie a station that has since been locked) then dump it
|
|
// Don't do this for the player, since we handle that case explicitly in radio audio entity
|
|
audDisplayf("Stopping locked/hidden station (%s) on non-player vehicle %s", m_RadioStation->GetStationSettings()->Name, GetVehicleModelName());
|
|
g_RadioAudioEntity.StopVehicleRadio(m_Vehicle);
|
|
m_RadioStation = NULL;
|
|
m_LastRadioStation = NULL;
|
|
}
|
|
else if(m_RadioStation && (!IsRadioEnabled() || IsRadioSwitchedOff()))
|
|
{
|
|
g_RadioAudioEntity.StopVehicleRadio(m_Vehicle);
|
|
m_RadioStation = NULL;
|
|
}
|
|
else if(IsRadioEnabled() && GetHasNormalRadio() && !IsRadioSwitchedOff())
|
|
{
|
|
bool shouldStopRadio = false;
|
|
if(ShouldRequestRadio(leakage, shouldStopRadio))
|
|
{
|
|
// Only automatically turn on the radio if there is a driver (prevents radio magically coming on when getting
|
|
// in a car as a passenger)
|
|
if((m_RadioStation == NULL && m_Vehicle->GetDriver()) || m_IsPersonalVehicle || (m_Vehicle->IsEngineOn() && (GetVehicleModelNameHash() == ATSTRINGHASH("PBUS2", 0x149BD32A) || GetVehicleModelNameHash() == ATSTRINGHASH("BLIMP3", 0xEDA4ED97))))
|
|
{
|
|
m_RadioStation = g_RadioAudioEntity.RequestVehicleRadio(m_Vehicle);
|
|
if(!HasLoudRadio() && !m_RadioStation)
|
|
{
|
|
// Don't keep requesting
|
|
//SetRadioOffState(true);
|
|
}
|
|
}
|
|
}
|
|
else if(shouldStopRadio)
|
|
{
|
|
if(m_RadioStation)
|
|
{
|
|
g_RadioAudioEntity.StopVehicleRadio(m_Vehicle, false);
|
|
//m_RadioStation = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Reset flag automatically; script can call every frame they want to force it on
|
|
m_ScriptForcedRadio = false;
|
|
if(m_RadioStation)
|
|
{
|
|
f32 openness = GetOpenness();
|
|
bool isAircraftPassengerSceneEnabled = DYNAMICMIXER.GetActiveSceneFromHash(ATSTRINGHASH("INTERIOR_VIEW_AIRCRAFT_PASSENGER_SCENE", 0x7EBA8171)) != NULL;
|
|
|
|
if(m_IsPlayerVehicle && (g_PositionedPlayerVehicleRadioEnabled || isAircraftPassengerSceneEnabled))
|
|
{
|
|
leakage = GetPositionalPlayerRadioLeakage();
|
|
|
|
// If aircraft passenger scene is enabled then we're inside and want this as loud as possible
|
|
if(isAircraftPassengerSceneEnabled)
|
|
{
|
|
openness = 1.0f;
|
|
}
|
|
}
|
|
|
|
// If the trunk is upgraded with a speaker mod, then base the radio openness on the openness of the trunk
|
|
if(m_Vehicle->GetVariationInstance().GetModIndex(VMT_TRUNK) != INVALID_MOD && m_Vehicle->GetVariationInstance().GetAudioApply(VMT_TRUNK) > 0.f)
|
|
{
|
|
CCarDoor* trunkDoor = m_Vehicle->GetDoorFromId(VEH_BOOT);
|
|
|
|
if(trunkDoor)
|
|
{
|
|
if(trunkDoor->GetIsIntact(m_Vehicle))
|
|
{
|
|
openness = trunkDoor->GetDoorRatio();
|
|
}
|
|
else
|
|
{
|
|
openness = 1.f;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Party bus has external speakers so is always at full openness
|
|
if (GetVehicleModelNameHash() == ATSTRINGHASH("PBUS2", 0x149BD32A) || GetVehicleModelNameHash() == ATSTRINGHASH("BLIMP3", 0xEDA4ED97) || (GetVehicleModelNameHash() == ATSTRINGHASH("CLUB", 0x82E47E85) && IsRadioUpgraded()))
|
|
{
|
|
openness = 1.f;
|
|
}
|
|
|
|
if(leakage == LEAKAGE_MODDED || leakage == LEAKAGE_PARTYBUS)
|
|
{
|
|
openness = Max(openness, g_ModdedRadioVehicleOpenness);
|
|
}
|
|
|
|
#if RSG_BANK
|
|
if(m_Vehicle && g_OverrideFocusVehicleLeakage && m_Vehicle == CDebugScene::FocusEntities_Get(0))
|
|
{
|
|
leakage = g_OverriddenVehicleRadioLeakage;
|
|
}
|
|
#endif // RSG_BANK
|
|
|
|
//Add a volume offset and modify the source filter cutoff frequency based upon how 'open' this
|
|
//positioned emitter is.
|
|
f32 opennessVolumeOffsetLinear = g_RadioOpennessVols[leakage][0] + (openness * (g_RadioOpennessVols[leakage][1] - g_RadioOpennessVols[leakage][0]));
|
|
float lpfLinear = Lerp(openness, g_RadioLPFLinear[leakage][0], g_RadioLPFLinear[leakage][1]);
|
|
m_RadioLPFCutoff = static_cast<u32>(Clamp<f32>(audDriverUtil::ComputeHzFrequencyFromLinear(lpfLinear), kVoiceFilterLPFMinCutoff, kVoiceFilterLPFMaxCutoff));
|
|
m_RadioRolloffFactor = Lerp(openness, g_RadioRolloffs[leakage][0], g_RadioRolloffs[leakage][1]);
|
|
m_RadioHPFCutoff = g_RadioHPFCutoffs[leakage];
|
|
|
|
#if __BANK
|
|
if(g_OverrideFocusVehicleLeakageParams && m_Vehicle == CDebugScene::FocusEntities_Get(0))
|
|
{
|
|
opennessVolumeOffsetLinear = g_OverridenLeakageVolMin + (openness * (g_OverridenLeakageVolMax - g_OverridenLeakageVolMin));
|
|
lpfLinear = Lerp(openness, g_OverridenLeakageLpfLinearMin, g_OverridenLeakageLpfLinearMax);
|
|
m_RadioRolloffFactor = Lerp(openness, g_OverridenLeakageRolloffMin, g_OverridenLeakageRolloffMax);
|
|
m_RadioHPFCutoff = g_OverridenLeakageHPFCutoff;
|
|
}
|
|
#endif
|
|
|
|
m_RadioLPFCutoff = static_cast<u32>(Clamp<f32>(audDriverUtil::ComputeHzFrequencyFromLinear(lpfLinear), kVoiceFilterLPFMinCutoff, kVoiceFilterLPFMaxCutoff));
|
|
m_RadioOpennessVol = audDriverUtil::ComputeDbVolumeFromLinear(opennessVolumeOffsetLinear);
|
|
|
|
// Keep track of the last valid radio station
|
|
m_LastRadioStation = m_RadioStation;
|
|
|
|
|
|
#if __BANK
|
|
if(g_DebugDrawFocusVehicleRadioOcclusion && m_Vehicle)
|
|
{
|
|
char tempString[512];
|
|
formatf(tempString, "Openness: %.02f", openness);
|
|
safecatf(tempString, "\nLeakage: %s", g_OverrideFocusVehicleLeakageParams? "CUSTOM" : AmbientRadioLeakage_ToString((AmbientRadioLeakage)leakage));
|
|
safecatf(tempString, "\nVolume: %.02f (Min %.02f, Max %.02f)", opennessVolumeOffsetLinear, g_OverrideFocusVehicleLeakageParams? g_OverridenLeakageVolMin : g_RadioOpennessVols[leakage][0], g_OverrideFocusVehicleLeakageParams? g_OverridenLeakageVolMax : g_RadioOpennessVols[leakage][1]);
|
|
safecatf(tempString, "\nLpf Cutoff Linear: %.02f (Min %.02f, Max %.02f)", lpfLinear, g_OverrideFocusVehicleLeakageParams? g_OverridenLeakageLpfLinearMin : g_RadioLPFLinear[leakage][0], g_OverrideFocusVehicleLeakageParams? g_OverridenLeakageLpfLinearMax : g_RadioLPFLinear[leakage][1]);
|
|
safecatf(tempString, "\nHpf Cutoff: %u", g_OverrideFocusVehicleLeakageParams? g_OverridenLeakageHPFCutoff : g_RadioHPFCutoffs[leakage]);
|
|
safecatf(tempString, "\nRoll Off: %.02f (Min %.02f, Max %.02f)", m_RadioRolloffFactor, g_OverrideFocusVehicleLeakageParams? g_OverridenLeakageRolloffMin : g_RadioRolloffs[leakage][0], g_OverrideFocusVehicleLeakageParams? g_OverridenLeakageRolloffMax : g_RadioRolloffs[leakage][1]);
|
|
safecatf(tempString, "\nMax Radius: %.02f (Current distance %.02f)", Sqrtf(g_OverrideFocusVehicleLeakageParams? (g_OverridenLeakageMaxRadius * g_OverridenLeakageMaxRadius) : g_MaxRadiusForAmbientRadio2[leakage]), (VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition() - g_AudioEngine.GetEnvironment().GetVolumeListenerPosition())).Mag());
|
|
grcDebugDraw::Text(m_Vehicle->GetTransform().GetPosition(), CDebugScene::FocusEntities_Get(0) == m_Vehicle? Color32(255,128,128) : Color32(255,255,255), tempString);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
else if(wasRadioValid && m_DrowningRadioSound)
|
|
{
|
|
m_DrowningRadioSound->StopAndForget();
|
|
}
|
|
|
|
#endif // NA_RADIO_ENABLED
|
|
|
|
if(m_RoadNoiseRidged)
|
|
{
|
|
f32 directionMatch = 1.0f;
|
|
f32 previousNodeMatch = 1.0f;
|
|
f32 nextNodeMatch = 1.0f;
|
|
|
|
const Vector3 vVehPosition = VEC3V_TO_VECTOR3(m_Vehicle->GetVehiclePosition());
|
|
const Vector3 vVehForwardDir = VEC3V_TO_VECTOR3(m_Vehicle->GetVehicleForwardDirection());
|
|
|
|
// If we previously had a valid node but have now moved some distance away, clear it. Searching for nodes is expensive so we want to avoid
|
|
// doing it too frequently
|
|
if(!m_NearestNodeAddress.IsEmpty())
|
|
{
|
|
if(m_NearestNodeAddressPos.Dist2(vVehPosition) > 20.0f * 20.0f)
|
|
{
|
|
m_NearestNodeAddress.SetEmpty();
|
|
}
|
|
}
|
|
|
|
// If we don't have a valid node, request one
|
|
if(m_NearestNodeAddress.IsEmpty())
|
|
{
|
|
m_NearestNodeAddress = ThePaths.FindNodeClosestToCoors(vVehPosition, 40.0f);
|
|
m_NearestNodeAddressPos = vVehPosition;
|
|
}
|
|
|
|
// By now we should have a node, so calculate how closely we match its direction
|
|
if(!m_NearestNodeAddress.IsEmpty())
|
|
{
|
|
CPathNode* pNode = ThePaths.FindNodePointerSafe(m_NearestNodeAddress);
|
|
|
|
if(pNode)
|
|
{
|
|
directionMatch = ThePaths.CalcDirectionMatchValue(pNode, vVehForwardDir.x, vVehForwardDir.y, 1.0f);
|
|
|
|
// Occasionally we might get road nodes with very weird orientations compared to the ones infront and behind
|
|
// (eg. at a T junction), so just averaging the match value to make sure that this doesn't totally kill the
|
|
// tyre bumps
|
|
if(pNode->NumLinks() == 2)
|
|
{
|
|
CPathNodeLink& nextLink = ThePaths.GetNodesLink(pNode, 0);
|
|
CPathNodeLink& prevLink = ThePaths.GetNodesLink(pNode, 1);
|
|
|
|
CPathNode* nextNode = ThePaths.FindNodePointerSafe(nextLink.m_OtherNode);
|
|
CPathNode* prevNode = ThePaths.FindNodePointerSafe(prevLink.m_OtherNode);
|
|
|
|
if(nextNode)
|
|
{
|
|
previousNodeMatch = ThePaths.CalcDirectionMatchValue(nextNode, vVehForwardDir.x, vVehForwardDir.y, 1.0f);
|
|
}
|
|
|
|
if(prevNode)
|
|
{
|
|
nextNodeMatch = ThePaths.CalcDirectionMatchValue(prevNode, vVehForwardDir.x, vVehForwardDir.y, 1.0f);
|
|
}
|
|
}
|
|
|
|
directionMatch += previousNodeMatch;
|
|
directionMatch += nextNodeMatch;
|
|
directionMatch *= 0.33f;
|
|
}
|
|
else
|
|
{
|
|
m_NearestNodeAddress.SetEmpty();
|
|
}
|
|
}
|
|
|
|
m_RidgedSurfaceDirectionMatch = directionMatch;
|
|
|
|
#if __BANK
|
|
if(m_IsPlayerVehicle && g_DisplayRidgedSurfaceInfo)
|
|
{
|
|
char tempString[128];
|
|
sprintf(tempString, "Direction Match: %.02f", directionMatch);
|
|
grcDebugDraw::Text(m_NearestNodeAddressPos, Color32(255,255,255), tempString);
|
|
grcDebugDraw::Sphere(m_NearestNodeAddressPos, 2.f, Color32(0,0,255,128));
|
|
grcDebugDraw::Line(m_NearestNodeAddressPos, VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()), Color32(255, 255, 255, 255));
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
m_RidgedSurfaceDirectionMatch = 0.0f;
|
|
}
|
|
|
|
m_VehRainInWaterVol = 1.f;
|
|
|
|
if(m_ForcedGameObjectResetRequired)
|
|
{
|
|
m_PreserveEnvironmentGroupOnShutdown = true;
|
|
Shutdown();
|
|
m_PreserveEnvironmentGroupOnShutdown = false;
|
|
m_IsWaitingToInit = true;
|
|
Init(m_Vehicle);
|
|
m_ForcedGameObjectResetRequired = false;
|
|
}
|
|
|
|
if(m_Vehicle->InheritsFromSubmarineCar())
|
|
{
|
|
((CSubmarineCar*)m_Vehicle)->CheckForAudioModeSwitch(m_IsFocusVehicle BANK_ONLY(, g_ForceAmphibiousBoatMode));
|
|
}
|
|
|
|
if(m_Vehicle->InheritsFromAmphibiousAutomobile())
|
|
{
|
|
((CAmphibiousAutomobile*)m_Vehicle)->CheckForAudioModeSwitch(m_IsFocusVehicle BANK_ONLY(, g_ForceAmphibiousBoatMode));
|
|
}
|
|
}
|
|
|
|
bool audVehicleAudioEntity::ShouldRequestRadio(const AmbientRadioLeakage leakage, bool &shouldStopRadio) const
|
|
{
|
|
const f32 dist2 = (VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition() - g_AudioEngine.GetEnvironment().GetVolumeListenerPosition())).Mag2();
|
|
bool isLocalPlayerInVehicle = m_Vehicle && m_Vehicle->ContainsLocalPlayer();
|
|
|
|
bool followPlayerInVehicle = false;
|
|
if (NetworkInterface::IsGameInProgress() && NetworkInterface::IsLocalPlayerOnSCTVTeam())
|
|
{
|
|
CPed* pFollowPlayer = CGameWorld::FindFollowPlayer();
|
|
if (pFollowPlayer && pFollowPlayer->GetMyVehicle())
|
|
followPlayerInVehicle = true;
|
|
}
|
|
|
|
f32 maxDistance = g_MaxRadiusForAmbientRadio2[leakage];
|
|
|
|
#if RSG_BANK
|
|
if (m_Vehicle && g_OverrideFocusVehicleLeakageParams && m_Vehicle == CDebugScene::FocusEntities_Get(0))
|
|
{
|
|
maxDistance = (g_OverridenLeakageMaxRadius * g_OverridenLeakageMaxRadius);
|
|
}
|
|
#endif
|
|
|
|
shouldStopRadio = !followPlayerInVehicle && (dist2 > maxDistance + 100);
|
|
// Script forced radio means play even with no driver and regardless of distance
|
|
return (m_ScriptForcedRadio || (isLocalPlayerInVehicle || ((m_Vehicle->GetDriver() != NULL || m_IsPersonalVehicle || (m_Vehicle->IsEngineOn() && (GetVehicleModelNameHash() == ATSTRINGHASH("PBUS2", 0x149BD32A) || GetVehicleModelNameHash() == ATSTRINGHASH("BLIMP3", 0xEDA4ED97)))) && dist2 < maxDistance)));
|
|
}
|
|
|
|
AmbientRadioLeakage audVehicleAudioEntity::GetAmbientRadioLeakage() const
|
|
{
|
|
if (IsRadioUpgraded())
|
|
{
|
|
if (GetVehicleModelNameHash() == ATSTRINGHASH("PBUS2", 0x149BD32A) || GetVehicleModelNameHash() == ATSTRINGHASH("BLIMP3", 0xEDA4ED97))
|
|
{
|
|
return LEAKAGE_PARTYBUS;
|
|
}
|
|
else
|
|
{
|
|
return LEAKAGE_MODDED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return m_HasLoudRadio || m_Vehicle->m_nVehicleFlags.bSlowChillinDriver ? LEAKAGE_CRAZY_LOUD : m_RadioLeakage;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// Update any submersible sounds
|
|
// -------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateSubmersible(audVehicleVariables& vehicleVariables, BoatAudioSettings* boatSettings)
|
|
{
|
|
f32 subDiveVelocity = 0.0f;
|
|
CSubmarineHandling* subHandling = m_Vehicle->GetSubHandling();
|
|
|
|
if(m_IsFocusVehicle)
|
|
{
|
|
if(subHandling && subHandling->GetDiveControl() != 0.0f && m_Vehicle->IsEngineOn())
|
|
{
|
|
if(SameSign(subHandling->GetDiveControl(), m_CachedVehicleVelocity.GetZ()))
|
|
{
|
|
subDiveVelocity = abs(m_CachedVehicleVelocity.GetZ() * 0.5f);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (subHandling && GetVehicleModelNameHash() == ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
const f32 submergeLevel = m_Vehicle->m_Buoyancy.GetSubmergedLevel();
|
|
const f32 submarineDiveControl = subHandling->GetDiveControl();
|
|
|
|
if (submarineDiveControl == -1.f)
|
|
{
|
|
m_SubmarineDiveHoldTime += fwTimer::GetTimeStep();
|
|
}
|
|
else
|
|
{
|
|
m_SubmarineDiveHoldTime = 0.f;
|
|
}
|
|
|
|
if (submergeLevel < 0.9f)
|
|
{
|
|
if (!m_HasTriggeredSubmarineSurface)
|
|
{
|
|
m_TriggerDeferredSubmarineSurface = true;
|
|
m_HasTriggeredSubmarineSurface = true;
|
|
}
|
|
}
|
|
else if (submarineDiveControl < 0.f || m_EngineWaterDepth < -10.0f)
|
|
{
|
|
m_HasTriggeredSubmarineSurface = false;
|
|
}
|
|
|
|
if (m_SubmarineDiveHoldTime > g_MinSubDiveHoldTime &&
|
|
submergeLevel >= g_SubDiveHornSubmergeThreshold &&
|
|
subDiveVelocity >= g_SubDiveHornVelocity &&
|
|
Sign(m_CachedVehicleVelocity.GetZ()) < 0)
|
|
{
|
|
if (!m_HasTriggeredSubmarineDiveHorn)
|
|
{
|
|
m_TriggerDeferredSubmarineDiveHorn = true;
|
|
m_HasTriggeredSubmarineDiveHorn = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
f32 diveHornRetriggerThreshold = m_Vehicle->GetDriver() ? g_SubDiveHornSubmergeRetriggerThreshold : g_SubDiveHornSubmergeRetriggerThresholdNoDriver;
|
|
|
|
if (submarineDiveControl >= 0.f && submergeLevel < diveHornRetriggerThreshold)
|
|
{
|
|
m_HasTriggeredSubmarineDiveHorn = false;
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
if (g_DebugSubmarineDiveHorn)
|
|
{
|
|
char tempString[128];
|
|
f32 xCoord = 0.1f;
|
|
f32 yCoord = 0.1f;
|
|
|
|
formatf(tempString, "Has Triggered Dive: %s", m_HasTriggeredSubmarineDiveHorn ? "true" : "false");
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255, 255, 255), tempString);
|
|
yCoord += 0.02f;
|
|
|
|
formatf(tempString, "Has Triggered Surface: %s", m_HasTriggeredSubmarineSurface ? "true" : "false");
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255, 255, 255), tempString);
|
|
yCoord += 0.02f;
|
|
|
|
formatf(tempString, "Dive Hold Time: %.02f", m_SubmarineDiveHoldTime);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255, 255, 255), tempString);
|
|
yCoord += 0.02f;
|
|
|
|
formatf(tempString, "Submerge Level: %.02f", submergeLevel);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255, 255, 255), tempString);
|
|
yCoord += 0.02f;
|
|
|
|
formatf(tempString, "Dive Velocity: %.02f", subDiveVelocity);
|
|
grcDebugDraw::Text(Vector2(xCoord, yCoord), Color32(255, 255, 255), tempString);
|
|
yCoord += 0.02f;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
f32 smoothedDiveVelocity = m_SubDiveVelocitySmoother.CalculateValue(subDiveVelocity);
|
|
f32 volumeLin = m_SubAngularVelocityVolumeSmoother.CalculateValue(m_SubTurningToSweetenerVolume.CalculateValue(Max(m_SubAngularVelocityMag, smoothedDiveVelocity)) * m_SubRevsToSweetenerVolume.CalculateValue(Max(smoothedDiveVelocity, vehicleVariables.rawRevs)));
|
|
s32 pitch = static_cast<s32>(m_SubTurningToSweetenerPitch.CalculateValue(m_SubAngularVelocityMag));
|
|
UpdateLoopWithLinearVolumeAndPitch(&m_SubTurningSweetener, boatSettings->SubTurningSweetenerSound, volumeLin, pitch, m_EnvironmentGroup, NULL, true, false);
|
|
|
|
const bool isKosatka = GetVehicleModelNameHash() == ATSTRINGHASH("Kosatka", 0x4FAF0D70);
|
|
|
|
// Sub extras sound lives in the granular bank, so we need to make sure it is stopped once the waveslot is released or else the bank can't be unloaded
|
|
bool subExtrasValid = (m_IsPlayerVehicle || GetVehicleModelNameHash() == ATSTRINGHASH("Kosatka", 0x4FAF0D70)) && (m_Vehicle->GetIsInWater() REPLAY_ONLY(|| m_ReplayVehiclePhysicsInWater)) && m_Vehicle->m_nVehicleFlags.bEngineOn && m_EngineWaveSlot;
|
|
|
|
if(subExtrasValid)
|
|
{
|
|
if(!m_SubExtrasSound)
|
|
{
|
|
// Sub extras sound just plays while the engine is on - control is all via PTS. Purposefully not updating entity as we want this that same
|
|
// regardless of above/below water status
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
|
|
if (!isKosatka)
|
|
{
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
}
|
|
|
|
CreateAndPlaySound_Persistent(boatSettings->SubExtrasSound, &m_SubExtrasSound, &initParams);
|
|
}
|
|
|
|
if (isKosatka && m_SubExtrasSound)
|
|
{
|
|
m_SubExtrasSound->SetRequestedPosition(ComputeClosestPositionOnVehicleYAxis());
|
|
}
|
|
}
|
|
else if(m_SubExtrasSound)
|
|
{
|
|
m_SubExtrasSound->StopAndForget();
|
|
}
|
|
|
|
// Sub creaks live in the sfx bank, so we need to make sure it is stopped once the waveslot is released or else the bank can't be unloaded
|
|
bool subCreakValid = m_IsPlayerVehicle && (m_Vehicle->GetIsInWater() REPLAY_ONLY(|| m_ReplayVehiclePhysicsInWater)) && Water::IsCameraUnderwater() && m_SFXWaveSlot;
|
|
|
|
if(!m_SubmersibleCreakSound)
|
|
{
|
|
if(subCreakValid)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
CreateAndPlaySound_Persistent(boatSettings->SubmersibleCreaksSound, &m_SubmersibleCreakSound, &initParams);
|
|
}
|
|
}
|
|
else if(!subCreakValid)
|
|
{
|
|
m_SubmersibleCreakSound->StopAndForget();
|
|
}
|
|
|
|
if(m_WaterDiveSound)
|
|
{
|
|
m_WaterDiveSound->SetRequestedVolume(audDriverUtil::ComputeDbVolumeFromLinear(m_DrowningFactor));
|
|
}
|
|
|
|
bool isSubmarineCar = false;
|
|
u32 submarineSoundSetHash = GetSubmarineCarSoundset();
|
|
|
|
if (submarineSoundSetHash != 0u)
|
|
{
|
|
isSubmarineCar = true;
|
|
}
|
|
else if (isKosatka)
|
|
{
|
|
submarineSoundSetHash = ATSTRINGHASH("DLC_Hei4_Kosatka_Sounds", 0xBDDCF962);
|
|
}
|
|
|
|
if(submarineSoundSetHash != 0u)
|
|
{
|
|
f32 rollAngle = m_Vehicle->GetTransform().GetRoll() * 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();
|
|
|
|
if(m_SubExtrasSound)
|
|
{
|
|
m_SubExtrasSound->FindAndSetVariableValue(ATSTRINGHASH("throttleInput", 0x918028C4), m_Vehicle->GetThrottle());
|
|
m_SubExtrasSound->FindAndSetVariableValue(ATSTRINGHASH("rollAngle", 0x94FC4D71), rollAngle);
|
|
m_SubExtrasSound->FindAndSetVariableValue(ATSTRINGHASH("pitchAngle", 0x809A226D), pitchAngle);
|
|
m_SubExtrasSound->FindAndSetVariableValue(ATSTRINGHASH("yawAngle", 0x15DE02B1), yawAngle);
|
|
m_SubExtrasSound->FindAndSetVariableValue(ATSTRINGHASH("angularVelocity", 0xC90EACC2), angularVelocity);
|
|
}
|
|
|
|
if(m_SubTurningSweetener)
|
|
{
|
|
m_SubTurningSweetener->FindAndSetVariableValue(ATSTRINGHASH("throttleInput", 0x918028C4), m_Vehicle->GetThrottle());
|
|
m_SubTurningSweetener->FindAndSetVariableValue(ATSTRINGHASH("rollAngle", 0x94FC4D71), rollAngle);
|
|
m_SubTurningSweetener->FindAndSetVariableValue(ATSTRINGHASH("pitchAngle", 0x809A226D), pitchAngle);
|
|
m_SubTurningSweetener->FindAndSetVariableValue(ATSTRINGHASH("yawAngle", 0x15DE02B1), yawAngle);
|
|
m_SubTurningSweetener->FindAndSetVariableValue(ATSTRINGHASH("angularVelocity", 0xC90EACC2), angularVelocity);
|
|
}
|
|
|
|
f32 maxPropSpeed = 0.f;
|
|
|
|
CSubmarineHandling* subHandling = nullptr;
|
|
|
|
if (isSubmarineCar)
|
|
{
|
|
CSubmarineCar* submarineCar = (CSubmarineCar*)m_Vehicle;
|
|
subHandling = submarineCar->GetSubHandling();
|
|
}
|
|
else
|
|
{
|
|
CSubmarine* submarine = (CSubmarine*)m_Vehicle;
|
|
subHandling = submarine->GetSubHandling();
|
|
}
|
|
|
|
if(subHandling)
|
|
{
|
|
for(u32 i = 0; i < subHandling->GetNumPropellors(); i++)
|
|
{
|
|
maxPropSpeed = Max(maxPropSpeed, Abs(subHandling->GetPropellorSpeed(i)));
|
|
}
|
|
}
|
|
|
|
if(maxPropSpeed > 0.f || (isKosatka && m_Vehicle->GetHealth() > 0.f))
|
|
{
|
|
if(!m_SubPropSound)
|
|
{
|
|
audSoundSet submarineSoundset;
|
|
submarineSoundset.Init(submarineSoundSetHash);
|
|
|
|
if(submarineSoundset.IsInitialised())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
|
|
// We want to do some custom underwater filtering on the Kosatka engine sound, so don't update it as normal
|
|
if (!isKosatka)
|
|
{
|
|
initParams.UpdateEntity = true;
|
|
initParams.u32ClientVar = isSubmarineCar ? AUD_VEHICLE_SOUND_SUBMARINECAR_PROPELLOR : AUD_VEHICLE_SOUND_SUBMARINE_PROPELLOR;
|
|
}
|
|
|
|
CreateAndPlaySound_Persistent(submarineSoundset.Find(ATSTRINGHASH("rotor_loop", 0x3E09EE0)), &m_SubPropSound, &initParams);
|
|
}
|
|
}
|
|
|
|
if(m_SubPropSound)
|
|
{
|
|
if (isKosatka)
|
|
{
|
|
m_SubPropSound->SetRequestedPosition(ComputeClosestPositionOnVehicleYAxis());
|
|
m_SubPropSound->FindAndSetVariableValue(ATSTRINGHASH("enginewaterdepth", 0x620614B8), Max(0.f, m_EngineWaterDepth * -1.f));
|
|
}
|
|
|
|
m_SubPropSound->FindAndSetVariableValue(ATSTRINGHASH("rotorspeed", 0x4F4CEFD4), maxPropSpeed);
|
|
}
|
|
}
|
|
else if(m_SubPropSound)
|
|
{
|
|
m_SubPropSound->StopAndForget(true);
|
|
}
|
|
|
|
if(m_SubExtrasSound)
|
|
{
|
|
m_SubExtrasSound->FindAndSetVariableValue(ATSTRINGHASH("rotorspeed", 0x4F4CEFD4), maxPropSpeed);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a dive sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerWaterDiveSound()
|
|
{
|
|
if(IsSubmersible() && !m_WaterDiveSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
initParams.TrackEntityPosition = true;
|
|
CreateAndPlaySound_Persistent(ATSTRINGHASH("SUBMERSIBLE_WATER_ENTER_MASTER", 0xC9598E64), &m_WaterDiveSound, &initParams);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger the submarine crush sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSubmarineCrushSound()
|
|
{
|
|
// Kosatka has bespoke script triggered crush sounds
|
|
if(IsSubmersible() && GetVehicleModelNameHash() != ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
if(sysThreadType::IsUpdateThread())
|
|
{
|
|
CreateDeferredSound(ATSTRINGHASH("SUB_CREAKS_ONESHOT_MASTER", 0xD67211AE), m_Vehicle, NULL, true, true);
|
|
}
|
|
else
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(ATSTRINGHASH("SUB_CREAKS_ONESHOT_MASTER", 0xD67211AE), &initParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger the implode warning sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSubmarineImplodeWarning(bool fullyImplode)
|
|
{
|
|
// Kosatka has bespoke script triggered crush sounds
|
|
if(IsSubmersible() && GetVehicleModelNameHash() != ATSTRINGHASH("Kosatka", 0x4FAF0D70))
|
|
{
|
|
u32 soundHash = fullyImplode? ATSTRINGHASH("SUB_PRESSURE_DESTROY_MASTER", 0xFF3C6194) : ATSTRINGHASH("SUB_PRESSURE_WARNING_MASTER", 0xE77825EA);
|
|
|
|
if(sysThreadType::IsUpdateThread())
|
|
{
|
|
CreateDeferredSound(soundHash, m_Vehicle, NULL, true, true);
|
|
}
|
|
else
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(soundHash, &initParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity ComputeOutsideWorldOcclusion
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::ComputeOutsideWorldOcclusion()
|
|
{
|
|
f32 occlusion = 0.f;
|
|
// bikes and boats are open
|
|
if((m_Vehicle->GetVehicleType() == VEHICLE_TYPE_CAR && m_Vehicle->CarHasRoof()) || m_Vehicle->GetVehicleType() == VEHICLE_TYPE_HELI || m_Vehicle->GetVehicleType() == VEHICLE_TYPE_AUTOGYRO)
|
|
{
|
|
// factor all doors equally
|
|
f32 doorOpenRatio = 0.f;
|
|
for(u32 i=0; i<g_MaxDoors; i++)
|
|
{
|
|
CCarDoor* pDoor = m_Vehicle->GetDoorFromId(g_DoorHierarchyIds[i]);
|
|
f32 openRatio = 1.0f;
|
|
|
|
if(pDoor)
|
|
{
|
|
if(pDoor->GetIsIntact(NULL))
|
|
{
|
|
openRatio = pDoor->GetDoorRatio();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this door doesn't exist; it's not open
|
|
openRatio = 0.f;
|
|
}
|
|
|
|
doorOpenRatio += openRatio * g_NumDoorsScalar;
|
|
}
|
|
// windows are weighted
|
|
f32 windowOpenRatio = 0.f;
|
|
for(u32 i = 0; i < NumWindowHierarchyIds; i++)
|
|
{
|
|
if(m_Vehicle->HasWindow(audVehicleAudioEntity::sm_WindowHierarchyIds[i]) && !m_HasWindowToSmashCache.IsSet(i))
|
|
{
|
|
windowOpenRatio += g_WindowOpenContribs[i];
|
|
}
|
|
}
|
|
|
|
// overall occlusion - if half of the doors are fully open then so is the car
|
|
occlusion = Min(1.f, 1.f - (doorOpenRatio*2.f + windowOpenRatio));
|
|
}
|
|
|
|
return occlusion;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity GetInteriorSoundOcclusion
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::GetInteriorSoundOcclusion(f32 &volAtten, u32 &cutoffFreq)
|
|
{
|
|
f32 vehicleOpenness = GetOpenness();
|
|
f32 opennessVolumeOffsetLinear = sm_InteriorOpenToVolumeCurve.CalculateValue(vehicleOpenness);
|
|
volAtten = audDriverUtil::ComputeDbVolumeFromLinear(opennessVolumeOffsetLinear);
|
|
cutoffFreq = (u32)sm_InteriorOpenToCutoffCurve.CalculateValue(vehicleOpenness);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if the ped is sat in an external seat
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsPedSatInExternalSeat(CPed* ped) const
|
|
{
|
|
s32 numEnclosedSeats = -1;
|
|
|
|
// GTAV specific fix
|
|
const u32 modelNameHash = GetVehicleModelNameHash();
|
|
switch(modelNameHash)
|
|
{
|
|
case 0xCEEA3F4B: // "BARRACKS"
|
|
numEnclosedSeats = 2;
|
|
break;
|
|
case 0xB6410173: // "DUBSTA3"
|
|
numEnclosedSeats = 4;
|
|
break;
|
|
case 0x9114EADA: // "INSURGENT"
|
|
case 0x8D4B7A8A: // "INSURGENT3"
|
|
numEnclosedSeats = 4;
|
|
break;
|
|
case 0x83051506: // "TECHNICAL"
|
|
case 0x50D4D19F: // "TECHNICAL3"
|
|
numEnclosedSeats = 2;
|
|
break;
|
|
case 0xF34DFB25: // "BARRAGE"
|
|
numEnclosedSeats = 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// End fix
|
|
|
|
// If the player is sat in a vehicle with enclosed front cab but an open rear trailer w/seats,
|
|
// we should to ignore any closed windows/doors when sat in the rear. We also want to ignore them
|
|
// if the player is just hanging onto the vehicle rather than being sat in it (eg. firetrucks and the like)
|
|
if(ped && m_Vehicle->ContainsPed(ped))
|
|
{
|
|
s32 pedSeatIndex = m_Vehicle->GetSeatManager()->GetPedsSeatIndex(ped);
|
|
|
|
if(m_Vehicle->IsSeatIndexValid(pedSeatIndex))
|
|
{
|
|
if(numEnclosedSeats >= 0 && pedSeatIndex >= numEnclosedSeats)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
const CVehicleSeatAnimInfo* seatAnimInfo = m_Vehicle->GetSeatAnimationInfo(pedSeatIndex);
|
|
|
|
if(seatAnimInfo && seatAnimInfo->GetKeepCollisionOnWhenInVehicle())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// audVehicleAudioEntity GetOpenness
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetOpenness(bool cameraRelative)
|
|
{
|
|
f32 openness = 1.0f;
|
|
|
|
#if RSG_BANK
|
|
if(m_Vehicle && m_Vehicle == CDebugScene::FocusEntities_Get(0) && g_OverrideFocusVehicleOpenness)
|
|
{
|
|
return g_OverriddenVehicleOpenness;
|
|
}
|
|
#endif // RSG_BANK
|
|
|
|
// Save having to recalculate openness if we've done it already this frame
|
|
if(!cameraRelative && m_CachedNonCameraRelativeOpenness >= 0.0f)
|
|
{
|
|
return m_CachedNonCameraRelativeOpenness;
|
|
}
|
|
else if(cameraRelative && m_CachedCameraRelativeOpenness >= 0.0f)
|
|
{
|
|
return m_CachedCameraRelativeOpenness;
|
|
}
|
|
|
|
const bool hasRoof = (m_Vehicle->GetVehicleType() == VEHICLE_TYPE_CAR && m_Vehicle->CarHasRoof())
|
|
|| m_Vehicle->GetVehicleType() == VEHICLE_TYPE_PLANE
|
|
|| m_Vehicle->GetVehicleType() == VEHICLE_TYPE_DRAFT
|
|
|| m_Vehicle->GetVehicleType() == VEHICLE_TYPE_SUBMARINECAR
|
|
|| (m_Vehicle->GetVehicleType() == VEHICLE_TYPE_HELI && GetVehicleModelNameHash() != ATSTRINGHASH("Thruster", 0x58CDAF30))
|
|
|| m_Vehicle->GetVehicleType() == VEHICLE_TYPE_BLIMP
|
|
|| m_Vehicle->GetVehicleType() == VEHICLE_TYPE_AUTOGYRO
|
|
|| m_Vehicle->GetVehicleType() == VEHICLE_TYPE_TRAIN;
|
|
|
|
if(m_Vehicle && hasRoof && m_Vehicle->GetSkeleton() && !m_IsPlayerPedInFullyOpenSeat && m_Vehicle->GetFragInst())
|
|
{
|
|
openness = 0.0f;
|
|
|
|
CVehicleModelInfo* modelInfo = (CVehicleModelInfo *)m_Vehicle->GetBaseModelInfo();
|
|
|
|
for(u8 i=0; i<g_MaxDoors; i++)
|
|
{
|
|
CCarDoor* pDoor = m_Vehicle->GetDoorFromId(g_DoorHierarchyIds[i]);
|
|
f32 openAngle = 90.0f;
|
|
|
|
if(pDoor && pDoor->GetIsIntact(NULL))
|
|
{
|
|
openAngle = g_MaxDoorOpenAngle * pDoor->GetDoorRatio();
|
|
}
|
|
|
|
if(openAngle > 0.0f)
|
|
{
|
|
//Generate a vector starting from the centre of the door cavity and pointing outwards along the angle
|
|
//of the open door.
|
|
|
|
|
|
s32 doorBoneIndex = modelInfo->GetBoneIndex(g_DoorHierarchyIds[i]);
|
|
|
|
//Assert(doorBoneIndex > -1);
|
|
//Assert(m_Vehicle->GetSkeleton());
|
|
|
|
if((doorBoneIndex > -1))
|
|
{
|
|
if(cameraRelative)
|
|
{
|
|
Matrix34 doorMatrix = RCC_MATRIX34(m_Vehicle->GetSkeletonData().GetDefaultTransform(doorBoneIndex));
|
|
|
|
//Get the centre of bounding box of (closed) door component.
|
|
Vector3 halfWidthVector, centreVector;
|
|
s32 doorComponent = m_Vehicle->GetFragInst()->GetComponentFromBoneIndex(doorBoneIndex);
|
|
|
|
if(doorComponent != -1 && m_Vehicle->GetFragInst()->GetArchetype()->GetBound()->GetType() == phBound::COMPOSITE)
|
|
{
|
|
phBound *doorBound = ((phBoundComposite *)m_Vehicle->GetFragInst()->GetArchetype()->GetBound())->
|
|
GetBound(doorComponent);
|
|
if(doorBound)
|
|
{
|
|
doorBound->GetBoundingBoxHalfWidthAndCenter(RC_VEC3V(halfWidthVector), RC_VEC3V(centreVector));
|
|
}
|
|
else
|
|
{
|
|
// When the door breaks off the bound is no longer available.
|
|
// I don't think we need the centre of the door cavity in this case, as its fully open?
|
|
centreVector.Zero();
|
|
}
|
|
|
|
doorMatrix.d += centreVector;
|
|
Vector3 doorBackVector = -doorMatrix.b;
|
|
Vector3 doorOutVector = doorMatrix.a * g_DoorOutSign[i];
|
|
|
|
Matrix34 doorMatrixWorld = doorMatrix;
|
|
doorMatrixWorld.Dot(MAT34V_TO_MATRIX34(m_Vehicle->GetMatrix()));
|
|
|
|
//Use the full open angle, as this results in a better inner cone than bisecting this angle.
|
|
f32 openAngleRadians = openAngle * DtoR;
|
|
Vector3 doorOpenVector = (doorBackVector * rage::Cosf(openAngleRadians)) +
|
|
(doorOutVector * rage::Sinf(openAngleRadians));
|
|
Vector3 doorOpenVectorWorld = doorOpenVector;
|
|
doorMatrixWorld.Transform(doorOpenVectorWorld);
|
|
|
|
|
|
audVolumeCone openDoorVolumeCone;
|
|
openDoorVolumeCone.Init(ATSTRINGHASH("LINEAR_RISE", 0xD0E6F19), doorOpenVector, 1.0f, openAngle *
|
|
sm_DoorConeInnerAngleScaling, sm_DoorConeOuterAngle);
|
|
|
|
|
|
const f32 doorOpenness = 1.0f - openDoorVolumeCone.ComputeAttenuation(doorMatrixWorld);
|
|
openness += doorOpenness;
|
|
#if __BANK
|
|
if(g_DebugVehicleOpenness)
|
|
{
|
|
grcDebugDraw::Line(doorMatrixWorld.d, doorOpenVectorWorld, Color32(0, 255, 0, 255));
|
|
char buf[64];
|
|
formatf(buf, sizeof(buf)-1,"%.2f", doorOpenness);
|
|
grcDebugDraw::Text(doorMatrixWorld.d,Color32(0,255,0), buf);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
openness += 0.2f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// windows - only for door-attached windows at the moment
|
|
for(u32 i = 0; i < NumWindowHierarchyIds; i++)
|
|
{
|
|
const s32 windowBoneIndex = modelInfo->GetBoneIndex(audVehicleAudioEntity::sm_WindowHierarchyIds[i]);
|
|
if(windowBoneIndex > -1)
|
|
{
|
|
if(m_Vehicle->HasWindow(audVehicleAudioEntity::sm_WindowHierarchyIds[i]) && !m_HasWindowToSmashCache.IsSet(i))
|
|
{
|
|
if(cameraRelative)
|
|
{
|
|
// first 4 windows are attached to doors; need to dot with door mat
|
|
Matrix34 localWindowMatrix = RCC_MATRIX34(m_Vehicle->GetSkeletonData().GetDefaultTransform(windowBoneIndex));
|
|
Vector3 rightVector;
|
|
rightVector = localWindowMatrix.b;
|
|
if(naVerifyf(i < g_MaxDoors,"Wrong window idx"))
|
|
{
|
|
eHierarchyId doorId = g_DoorHierarchyIds[i];
|
|
if(doorId != VEH_INVALID_ID)
|
|
{
|
|
s32 doorBoneIndex = modelInfo->GetBoneIndex(doorId);
|
|
if(doorBoneIndex > 0)
|
|
{
|
|
Matrix34 doorMatrix = RCC_MATRIX34(m_Vehicle->GetSkeletonData().GetDefaultTransform(doorBoneIndex));
|
|
localWindowMatrix.Dot(doorMatrix);
|
|
rightVector = localWindowMatrix.a;
|
|
}
|
|
else if (audVehicleAudioEntity::sm_WindowHierarchyIds[i] >=VEH_WINDOW_LF)
|
|
{
|
|
rightVector = localWindowMatrix.a;
|
|
}
|
|
}
|
|
else if (audVehicleAudioEntity::sm_WindowHierarchyIds[i] >=VEH_WINDOW_LF)
|
|
{
|
|
rightVector = localWindowMatrix.a;
|
|
}
|
|
|
|
}
|
|
|
|
Matrix34 worldWindowMatrix = localWindowMatrix;
|
|
|
|
worldWindowMatrix.Dot(MAT34V_TO_MATRIX34(m_Vehicle->GetMatrix()));
|
|
|
|
Vector3 windowOpenVector = rightVector * g_WindowOutSign[i];
|
|
|
|
audVolumeCone openWindowVolumeCone;
|
|
openWindowVolumeCone.Init(ATSTRINGHASH("LINEAR_RISE", 0xD0E6F19), windowOpenVector, 1.0f, sm_DoorConeInnerAngleScaling * 90.f, sm_DoorConeOuterAngle);
|
|
const f32 windowOpenness = (1.f - openWindowVolumeCone.ComputeAttenuation(worldWindowMatrix)) * g_WindowOpenContribs[i];
|
|
openness += windowOpenness;
|
|
#if __BANK
|
|
if(g_DebugVehicleOpenness)
|
|
{
|
|
|
|
Vector3 windowOpenVectorWorld = windowOpenVector;
|
|
worldWindowMatrix.Transform(windowOpenVectorWorld);
|
|
|
|
grcDebugDraw::Line(worldWindowMatrix.d, windowOpenVectorWorld, Color32(0, 0, 255),
|
|
Color32(0, 255, 0, 255));
|
|
char buf[64];
|
|
formatf(buf, sizeof(buf)-1,"%.2f", windowOpenness);
|
|
grcDebugDraw::Text(worldWindowMatrix.d,Color32(0,0,255), buf);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// scale non-directional openness by 50%
|
|
openness += g_WindowOpenContribs[i] * 0.5f;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
openness = Max(GetConvertibleRoofOpenness(), openness);
|
|
}
|
|
Assert(openness >= 0.f);
|
|
openness = Clamp(openness, GetMinOpenness(), 1.f);
|
|
|
|
#if __BANK
|
|
if(g_DebugVehicleOpenness)
|
|
{
|
|
char buf[64];
|
|
formatf(buf, "%.2f", openness);
|
|
if(cameraRelative)
|
|
{
|
|
grcDebugDraw::Text(VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition()),Color32(0,255,0), buf);
|
|
}
|
|
else
|
|
{
|
|
grcDebugDraw::Text(m_Vehicle->GetTransform().GetPosition() + Vec3V(0.f,0.f,1.f),Color32(255,0,255), buf);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
if(cameraRelative)
|
|
{
|
|
m_CachedCameraRelativeOpenness = openness;
|
|
}
|
|
else
|
|
{
|
|
m_CachedNonCameraRelativeOpenness = openness;
|
|
}
|
|
|
|
return openness;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// GetConvertibleRoofOpenness
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetConvertibleRoofOpenness() const
|
|
{
|
|
if(m_Vehicle)
|
|
{
|
|
switch(m_Vehicle->GetConvertibleRoofState())
|
|
{
|
|
case CTaskVehicleConvertibleRoof::STATE_RAISING:
|
|
case CTaskVehicleConvertibleRoof::STATE_LOWERING:
|
|
case CTaskVehicleConvertibleRoof::STATE_CLOSING_BOOT:
|
|
{
|
|
return sm_RoofToOpennessCurve.CalculateValue(m_Vehicle->GetMoveVehicle().GetMechanismPhase());
|
|
}
|
|
break;
|
|
case CTaskVehicleConvertibleRoof::STATE_LOWERED:
|
|
case CTaskVehicleConvertibleRoof::STATE_ROOF_STUCK_LOWERED:
|
|
// fully open
|
|
return 1.0f;
|
|
break;
|
|
default:
|
|
return 0.0f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// InitOcclusion
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::InitOcclusion()
|
|
{
|
|
CreateEnvironmentGroup("Vehicle");
|
|
|
|
if (m_EnvironmentGroup)
|
|
{
|
|
m_EnvironmentGroup->Init(this, sm_CheapDistance, 1000);
|
|
m_EnvironmentGroup->SetIsVehicle(true);
|
|
if(audNorthAudioEngine::GetOcclusionManager()->GetIsPortalOcclusionEnabled())
|
|
{
|
|
m_EnvironmentGroup->SetUsePortalOcclusion(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a speed boost sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerStuntRaceSpeedBoost()
|
|
{
|
|
u32 time = fwTimer::GetTimeInMilliseconds();
|
|
|
|
if(time - m_LastStuntRaceSpeedBoostTime < g_StuntBoostIntensityTimeout)
|
|
{
|
|
if(time - m_LastStuntRaceSpeedBoostIntensityIncreaseTime > g_StuntBoostIntensityIncreaseDelay)
|
|
{
|
|
m_SpeedBoostIntensity++;
|
|
m_LastStuntRaceSpeedBoostIntensityIncreaseTime = time;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_SpeedBoostIntensity = 0;
|
|
}
|
|
|
|
audSoundSet stuntBoostSoundset;
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_PLANE || m_VehicleType == AUD_VEHICLE_HELI)
|
|
{
|
|
stuntBoostSoundset.Init(ATSTRINGHASH("DLC_Air_Race_Sounds", 0xD2A9FD4E));
|
|
}
|
|
else
|
|
{
|
|
stuntBoostSoundset.Init(ATSTRINGHASH("DLC_Stunt_Race_Sounds", 0x85CD8A73));
|
|
}
|
|
|
|
if(stuntBoostSoundset.IsInitialised())
|
|
{
|
|
// Needed for fake revs behavior
|
|
AllocateVehicleVariableBlock();
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.SetVariableValue(ATSTRINGHASH("intensity", 0xEFCD993D), (f32)(m_SpeedBoostIntensity - 1));
|
|
u32 boostSound = m_IsFocusVehicle? ATSTRINGHASH("Speed_Up_Player", 0x9096D9FB) : ATSTRINGHASH("Speed_Up_Remote", 0xE1774624);
|
|
CreateDeferredSound(stuntBoostSoundset.Find(boostSound), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(stuntBoostSoundset.GetNameHash(), ATSTRINGHASH("Speed_Up_Remote", 0xE1774624), &initParams, m_Vehicle));
|
|
}
|
|
|
|
if(m_IsFocusVehicle && !sm_StuntRaceSpeedUpScene && SUPERCONDUCTOR.GetVehicleConductor().JumpConductorActive() && NetworkInterface::IsGameInProgress())
|
|
{
|
|
sm_TriggerStuntRaceSpeedBoostScene = true;
|
|
sm_StuntRaceVehicleType = m_VehicleType;
|
|
}
|
|
|
|
audDisplayf("Triggering stunt race boost with intensity %u", m_SpeedBoostIntensity);
|
|
m_LastStuntRaceSpeedBoostTime = time;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a slow down sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerStuntRaceSlowDown()
|
|
{
|
|
m_SpeedBoostIntensity = 0;
|
|
audSoundSet stuntBoostSoundset;
|
|
|
|
if(m_VehicleType == AUD_VEHICLE_PLANE || m_VehicleType == AUD_VEHICLE_HELI)
|
|
{
|
|
stuntBoostSoundset.Init(ATSTRINGHASH("DLC_Air_Race_Sounds", 0xD2A9FD4E));
|
|
}
|
|
else
|
|
{
|
|
stuntBoostSoundset.Init(ATSTRINGHASH("DLC_Stunt_Race_Sounds", 0x85CD8A73));
|
|
}
|
|
|
|
if(stuntBoostSoundset.IsInitialised())
|
|
{
|
|
// Needed for fake revs behavior
|
|
AllocateVehicleVariableBlock();
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
u32 boostSound = m_IsFocusVehicle? ATSTRINGHASH("Slow_Down_Player", 0xC12528C6) : ATSTRINGHASH("Slow_Down_Remote", 0x2E6079D2);
|
|
CreateDeferredSound(stuntBoostSoundset.Find(boostSound), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(stuntBoostSoundset.GetNameHash(), ATSTRINGHASH("Slow_Down_Remote", 0x2E6079D2), &initParams, m_Vehicle));
|
|
}
|
|
|
|
if(m_IsFocusVehicle && !sm_StuntRaceSlowDownScene && SUPERCONDUCTOR.GetVehicleConductor().JumpConductorActive() && NetworkInterface::IsGameInProgress())
|
|
{
|
|
sm_TriggerStuntRaceSlowDownScene = true;
|
|
sm_StuntRaceVehicleType = m_VehicleType;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger missile battery reload sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerMissileBatteryReloadSound()
|
|
{
|
|
audSoundSet missileSoundSet;
|
|
|
|
if(missileSoundSet.Init(ATSTRINGHASH("gr_vehicle_weapon_trailer_missile_sounds", 0x1B9A6F4D)))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateDeferredSound(missileSoundSet.Find(ATSTRINGHASH("Flaps_Close", 0x4EAD5EE9)), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(missileSoundSet.GetNameHash(), ATSTRINGHASH("Flaps_Close", 0x4EAD5EE9), &initParams, m_Vehicle));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger an instant refill sound on cars with a boost mechanism
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerBoostInstantRecharge()
|
|
{
|
|
u32 time = fwTimer::GetTimeInMilliseconds();
|
|
|
|
if(time - m_LastStuntRaceRechargeTime < g_RechargeIntensityTimeout)
|
|
{
|
|
if(time - m_LastRechargeIntensityIncreaseTime > g_RechargeIntensityIncreaseDelay)
|
|
{
|
|
m_RechargeIntensity++;
|
|
m_LastRechargeIntensityIncreaseTime = time;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_RechargeIntensity = 0;
|
|
}
|
|
|
|
audSoundSet rechargeSoundSet;
|
|
|
|
if(rechargeSoundSet.Init(ATSTRINGHASH("DLC_Special_Race_Sounds", 0x99BFF6E)))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.SetVariableValue(ATSTRINGHASH("intensity", 0xEFCD993D), (f32)(m_RechargeIntensity - 1));
|
|
u32 rechargeSound = m_IsFocusVehicle? ATSTRINGHASH("instant_refill_player", 0x24C5D426) : ATSTRINGHASH("instant_refill_remote", 0xD923B0F8);
|
|
CreateDeferredSound(rechargeSoundSet.Find(rechargeSound), m_Vehicle, &initParams, true, true);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(rechargeSoundSet.GetNameHash(), ATSTRINGHASH("instant_refill_remote", 0xD923B0F8), &initParams, m_Vehicle));
|
|
}
|
|
|
|
audDisplayf("Triggering recharge with intensity %u", m_RechargeIntensity);
|
|
m_LastStuntRaceRechargeTime = time;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// SetEnvironmentGroupSettings
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetEnvironmentGroupSettings(const bool useInteriorDistanceMetrics, const u8 maxPathDepth)
|
|
{
|
|
if (m_EnvironmentGroup)
|
|
{
|
|
m_EnvironmentGroup->SetUseInteriorDistanceMetrics(useInteriorDistanceMetrics);
|
|
m_EnvironmentGroup->SetMaxPathDepth(maxPathDepth);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the vehicle model name
|
|
// ----------------------------------------------------------------
|
|
#if !__NO_OUTPUT
|
|
const char *audVehicleAudioEntity::GetVehicleModelName() const
|
|
{
|
|
CVehicleModelInfo *model = (CVehicleModelInfo*)(m_Vehicle->GetBaseModelInfo());
|
|
naAssertf(model, "Couldn't get CVehicleModelInfo for m_vehicle, about to access a null ptr...");
|
|
return model->GetModelName();
|
|
}
|
|
#endif // !__NO_OUTPUT
|
|
|
|
#if NA_RADIO_ENABLED
|
|
// ----------------------------------------------------------------
|
|
// Set radio station from network
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetRadioStationFromNetwork(u8 radioStationIndex, bool bTriggeredByDriver)
|
|
{
|
|
u8 currentStationIndex = GetRadioStation() ? (u8) GetRadioStation()->GetStationIndex() : -1;
|
|
m_NetworkCachedRadioStationIndex = radioStationIndex;
|
|
|
|
if (radioStationIndex != currentStationIndex)
|
|
audDisplayf("Network triggered radio station switch on vehicle %s: station %u, current %u, driver: %s, focus %s", GetVehicleModelName(), radioStationIndex, currentStationIndex, bTriggeredByDriver? "true" : "false", m_IsFocusVehicle? "true" : "false");
|
|
|
|
const bool localPlayerInCar = (CGameWorld::FindLocalPlayerVehicle()==m_Vehicle);
|
|
|
|
bool followPlayerInCar = false;
|
|
if (NetworkInterface::IsGameInProgress() && NetworkInterface::IsLocalPlayerOnSCTVTeam())
|
|
{
|
|
CPed* pFollowPlayer = CGameWorld::FindFollowPlayer();
|
|
if (pFollowPlayer)
|
|
{
|
|
CVehicle* pFollowPlayerVehicle = pFollowPlayer->GetMyVehicle();
|
|
if (pFollowPlayerVehicle)
|
|
{
|
|
followPlayerInCar = (pFollowPlayerVehicle==m_Vehicle);
|
|
|
|
if (followPlayerInCar && NetworkInterface::IsOverrideSpectatedVehicleRadioSet())
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(radioStationIndex == g_NullRadioStation || radioStationIndex == g_OffRadioStation)
|
|
{
|
|
if((radioStationIndex != currentStationIndex) || !m_IsRadioOff)
|
|
{
|
|
audDisplayf("NULL/Off station requested - switching off radio (current: %u new: %u, current status: %s)", currentStationIndex, radioStationIndex, m_IsRadioOff? "OFF" : "ON");
|
|
|
|
if(m_RadioStation)
|
|
{
|
|
g_RadioAudioEntity.StopVehicleRadio(m_Vehicle);
|
|
}
|
|
|
|
if (radioStationIndex == g_OffRadioStation)
|
|
{
|
|
if (localPlayerInCar || followPlayerInCar)
|
|
g_RadioAudioEntity.SwitchOffRadio();
|
|
}
|
|
|
|
SetRadioOffState(true); //off
|
|
m_RadioStation = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Note: bail if radio station is already set as this can cause problems if we keep setting to the same channel
|
|
if (radioStationIndex != currentStationIndex)
|
|
{
|
|
SetRadioOffState(false); //on
|
|
|
|
const audRadioStation *station = audRadioStation::GetStation(radioStationIndex);
|
|
audDisplayf("Valid station selected (%s) - switching on radio. localPlayerInCar: %s, followPlayerInCar: %s", station->GetStationSettings()->Name, localPlayerInCar? "true" : "false", followPlayerInCar? "true" : "false");
|
|
|
|
SetLastRadioStation(station);
|
|
// Only request a radio emitter if we already had one, otherwise let the normal distance/priority logic decide
|
|
if(m_RadioStation || localPlayerInCar || followPlayerInCar || m_IsPersonalVehicle)
|
|
{
|
|
g_RadioAudioEntity.StopVehicleRadio(m_Vehicle);
|
|
m_RadioStation = g_RadioAudioEntity.RequestVehicleRadio(m_Vehicle);
|
|
}
|
|
|
|
// also need to update frontend radio
|
|
if(localPlayerInCar || followPlayerInCar)
|
|
{
|
|
g_RadioAudioEntity.PlayStationSelectSound(true);
|
|
g_RadioAudioEntity.RetuneToStation(station);
|
|
|
|
if(bTriggeredByDriver)
|
|
g_RadioAudioEntity.SetMPDriverTriggeredRadioChange();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void audVehicleAudioEntity::ResetRadioStationFromNetwork()
|
|
{
|
|
audDisplayf("ResetRadioStationFromNetwork");
|
|
SetRadioStationFromNetwork(m_NetworkCachedRadioStationIndex, false);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get Ambient Radio Volume
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetAmbientRadioVolume() const
|
|
{
|
|
if(IsAmbientRadioDisabled())
|
|
{
|
|
return -100.f;
|
|
}
|
|
else
|
|
{
|
|
f32 carVol = GetVehicleModelRadioVolume();
|
|
|
|
if(m_HasLoudRadio)
|
|
{
|
|
carVol += g_LoudVehicleRadioOffset;
|
|
}
|
|
|
|
f32 radioStationVol = (m_RadioStation ? m_RadioStation->GetAmbientVolume():0.f);
|
|
f32 finalVolume = g_AmbientVehicleRadioOffset + carVol + m_RadioOpennessVol + radioStationVol;
|
|
|
|
if(finalVolume > 32.f)
|
|
{
|
|
audWarningf("Vehicle ambient radio volume for station %s is %.02f, seems excessive! AmbientVehicleRadioOffset %.02f, carVol %.02f, radioOpennessVol %.02f, radioStationVol %.02f"
|
|
, m_RadioStation? m_RadioStation->GetName() : "NULL"
|
|
, finalVolume
|
|
, g_AmbientVehicleRadioOffset
|
|
, carVol
|
|
, m_RadioOpennessVol
|
|
, radioStationVol
|
|
);
|
|
}
|
|
|
|
return finalVolume;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get Frontend Radio Volume Offset
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::GetFrontendRadioVolumeOffset()
|
|
{
|
|
static f32 g_LoudVehicleRadioVolume = 0.0f;
|
|
static f32 g_VeryLoudVehicleRadioVolume = 1.0f;
|
|
f32 volume = 0.0f;
|
|
|
|
if(GetVehicleVolumeCategory() == VEHICLE_VOLUME_LOUD)
|
|
{
|
|
volume = g_LoudVehicleRadioVolume;
|
|
}
|
|
else if(GetVehicleVolumeCategory() == VEHICLE_VOLUME_VERY_LOUD)
|
|
{
|
|
volume = g_VeryLoudVehicleRadioVolume;
|
|
}
|
|
|
|
return volume;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// GetHasNormalRadio
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::GetHasNormalRadio() const
|
|
{
|
|
if(m_RadioType == RADIO_TYPE_NORMAL_OFF_MISSION_AND_MP)
|
|
{
|
|
return NetworkInterface::IsGameInProgress() || !CTheScripts::GetPlayerIsOnAMission();
|
|
}
|
|
return (m_RadioType == RADIO_TYPE_NORMAL || (m_RadioType == RADIO_TYPE_EMERGENCY_SERVICES && NetworkInterface::IsGameInProgress()));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// GetHasEmergencyServicesRadio
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::GetHasEmergencyServicesRadio() const
|
|
{
|
|
return (m_RadioType == RADIO_TYPE_EMERGENCY_SERVICES);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// IsAmbientRadioDisabled
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsAmbientRadioDisabled() const
|
|
{
|
|
return m_AmbientRadioDisabled;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if the radio is enabled for this vehicle
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsRadioEnabled() const
|
|
{
|
|
if (g_ScriptAudioEntity.IsFlagSet(audScriptAudioFlags::PlayerOnDLCHeist4Island))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool radioOnEngineOff = false;
|
|
if(m_VehicleType == AUD_VEHICLE_HELI || m_VehicleType == AUD_VEHICLE_PLANE || GetVehicleModelNameHash() == ATSTRINGHASH("TORO", 0x3FD5AA2F) || GetVehicleModelNameHash() == ATSTRINGHASH("TORO2",0x362CAC6D))
|
|
{
|
|
if(m_IsPlayerVehicle && m_IsPlayerSeatedInVehicle && m_Vehicle->GetStatus() != STATUS_WRECKED)
|
|
{
|
|
radioOnEngineOff = true;
|
|
}
|
|
}
|
|
|
|
return ((m_Vehicle->m_nVehicleFlags.bEngineOn || radioOnEngineOff) && !m_RadioDisabled && (m_RadioStation || !IsPlayingStartupSequence()) REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive()));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// SetLoudRadio
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetLoudRadio(const bool loud)
|
|
{
|
|
m_HasLoudRadio = loud;
|
|
}
|
|
|
|
bool audVehicleAudioEntity::HasLoudRadio() const
|
|
{
|
|
if(m_HasLoudRadio)
|
|
return true;
|
|
return m_Vehicle->m_nVehicleFlags.bSlowChillinDriver;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// SetRadioStation
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetRadioStation(u8 radioStationIndex)
|
|
{
|
|
SetRadioStation(audRadioStation::GetStation(radioStationIndex));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// SetRadioStation
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetRadioStation(const audRadioStation *station, const bool alsoRetuneFE /*= true*/, const bool isForcedStation)
|
|
{
|
|
if (m_RadioStation == station)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Don't allow script to set a station on a vehicle with no radio, since the user won't be able to retune
|
|
if(!GetHasNormalRadio())
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if RSG_PC
|
|
// url:bugstar:5172897 - Don't allow retuning to the user radio station on NPC vehicles if we don't have it available on the local machine
|
|
if (station && (station->IsLocked() || station->IsHidden()) && !m_IsPlayerVehicle && NetworkInterface::IsGameInProgress())
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Also retune the player station if this is the player vehicle
|
|
if(alsoRetuneFE && g_RadioAudioEntity.GetLastPlayerVehicle() == m_Vehicle && g_RadioAudioEntity.IsPlayerRadioActive() && g_RadioAudioEntity.GetPlayerRadioStation() != station)
|
|
{
|
|
g_RadioAudioEntity.RetuneToStation(station);
|
|
}
|
|
else
|
|
{
|
|
m_RadioStation = station;
|
|
if(m_RadioStation)
|
|
{
|
|
m_IsRadioOff = false;
|
|
SetLastRadioStation(station);
|
|
|
|
if(g_RadioAudioEntity.GetPlayerVehicle() != m_Vehicle && !isForcedStation)
|
|
{
|
|
bool shouldStopRadio = false;
|
|
if(ShouldRequestRadio(GetAmbientRadioLeakage(), shouldStopRadio))
|
|
{
|
|
m_RadioStation = g_RadioAudioEntity.RequestVehicleRadio(m_Vehicle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we changed the station, check to see if any passengers playing an ambient clip need to reevaluate their base clip. [11/13/2012 mdawe]
|
|
// This is to stop a "dance to music" animation from continuing to play if we've switched to talk radio (for example).
|
|
const int iNumSeats = m_Vehicle->GetSeatManager()->GetMaxSeats();
|
|
for (int iSeat = 0; iSeat < iNumSeats; ++iSeat)
|
|
{
|
|
CPed* pPed = m_Vehicle->GetPedInSeat(iSeat);
|
|
if (pPed)
|
|
{
|
|
//Check base if we're running CTaskAmbientClips.
|
|
CTaskAmbientClips* pAmbientClips = static_cast<CTaskAmbientClips*>(pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_AMBIENT_CLIPS));
|
|
if (pAmbientClips)
|
|
{
|
|
// Force CTaskAmbientClips to update the base clip, which will stop playing it if the conditions on it are no longer met.
|
|
pAmbientClips->TerminateIfBaseConditionsAreNotMet();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// GetVehicleModelNameHash
|
|
// ----------------------------------------------------------------
|
|
u32 audVehicleAudioEntity::GetVehicleModelNameHash() const
|
|
{
|
|
if(m_Vehicle)
|
|
{
|
|
CVehicleModelInfo *model = (CVehicleModelInfo*)(m_Vehicle->GetBaseModelInfo());
|
|
naAssertf(model, "Couldn't get CVehicleModelInfo for m_vehicle, about to access a null ptr...");
|
|
return model->GetModelNameHash();
|
|
}
|
|
|
|
return 0u;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a trailer detach sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerTrailerDetach()
|
|
{
|
|
if(!IsDisabled())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.UpdateEntity = true;
|
|
|
|
if(sysThreadType::IsUpdateThread())
|
|
{
|
|
CreateDeferredSound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("TrailerUnhitch", 0x53130271)), m_Vehicle, &initParams, true);
|
|
}
|
|
else
|
|
{
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("TrailerUnhitch", 0x53130271)), &initParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a windscreen smash sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerWindscreenSmashSound(Vec3V_In position)
|
|
{
|
|
if(m_IsPlayerVehicle && audNorthAudioEngine::IsRenderingFirstPersonVehicleCam())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.Position = VEC3V_TO_VECTOR3(position);
|
|
initParams.UpdateEntity = true;
|
|
CreateDeferredSound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("WindscreenSmash_Interior", 0x4C0BD045)), m_Vehicle, &initParams, true);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a window smash sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerWindowSmashSound(Vec3V_In position)
|
|
{
|
|
if(m_IsPlayerVehicle && audNorthAudioEngine::IsRenderingFirstPersonVehicleCam())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.Position = VEC3V_TO_VECTOR3(position);
|
|
initParams.UpdateEntity = true;
|
|
CreateDeferredSound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("WindowSmash_Interior", 0x4948B2BA)), m_Vehicle, &initParams, true);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a headlight smash
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerHeadlightSmash(const u32 headlightIndex, const Vector3 &localPos)
|
|
{
|
|
if(!IsDisabled() && GetAudioVehicleType() != AUD_VEHICLE_BOAT && !g_NoHeadlightSmashAudio)
|
|
{
|
|
Vector3 pos;
|
|
m_Vehicle->TransformIntoWorldSpace(pos, localPos);
|
|
|
|
u32 soundHash;
|
|
switch(headlightIndex)
|
|
{
|
|
case VEH_HEADLIGHT_L: // 00
|
|
case VEH_HEADLIGHT_R: // 01
|
|
soundHash = ATSTRINGHASH("FRONT_HEADLIGHT_SMASH", 0x4EC863C3);
|
|
break;
|
|
default:
|
|
soundHash = ATSTRINGHASH("REAR_HEADLIGHT_SMASH", 0xEC3A719F);
|
|
break;
|
|
}
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.Position = pos;
|
|
CreateDeferredSound(soundHash, m_Vehicle, &initParams, true);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger tyre puncture
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerTyrePuncture(const eHierarchyId wheelId, bool slowPuncture)
|
|
{
|
|
if(!IsDisabled() && wheelId >= VEH_WHEEL_LF && wheelId <= VEH_WHEEL_RR)
|
|
{
|
|
audSoundInitParams initParams;
|
|
s32 wheel = 0;
|
|
|
|
naAssertf(m_Vehicle, "Sanity check failed! Vehicle audio entity has no vehicle!");
|
|
if(!m_Vehicle)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(;wheel<m_Vehicle->GetNumWheels(); wheel++)
|
|
{
|
|
if(m_Vehicle->GetWheel(wheel) && m_Vehicle->GetWheel(wheel)->GetHierarchyId() == wheelId)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
Vector3 pos;
|
|
GetWheelPosition(wheel, pos);
|
|
initParams.Position = pos;
|
|
initParams.UpdateEntity = true;
|
|
initParams.u32ClientVar = GetWheelSoundUpdateClientVar(wheel);
|
|
CreateDeferredSound(slowPuncture?ATSTRINGHASH("FLAT_TYRE_BLOWOUT", 0xAA624CD4):ATSTRINGHASH("VEH_TYRE_BURST", 0xA9D7073), m_Vehicle, &initParams, true);
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------
|
|
// Get a wheel position - just use the cached value if we've already calculated the position this frame
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::GetCachedWheelPosition(u32 wheelIndex, Vector3 &pos, audVehicleVariables& vehicleVariables)
|
|
{
|
|
naAssertf(wheelIndex < NUM_VEH_CWHEELS_MAX, "Invalid wheel index, will result in null ptr access");
|
|
|
|
audVehicleWheelPositionCache* wheelCache = vehicleVariables.wheelPosCache;
|
|
|
|
if(!wheelCache)
|
|
{
|
|
GetWheelPosition(wheelIndex, pos);
|
|
}
|
|
else if(wheelCache->cachedWheelPositionValid[wheelIndex])
|
|
{
|
|
pos = wheelCache->cachedWheelPositions[wheelIndex];
|
|
}
|
|
else
|
|
{
|
|
GetWheelPosition(wheelIndex, pos);
|
|
wheelCache->cachedWheelPositionValid[wheelIndex] = true;
|
|
wheelCache->cachedWheelPositions[wheelIndex] = pos;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get a wheel position
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::GetWheelPosition(u32 wheelIndex, Vector3 &pos)
|
|
{
|
|
naAssertf(wheelIndex < m_Vehicle->GetNumWheels(), "Invalid wheel index");
|
|
CVehicleModelInfo* modelInfo = (CVehicleModelInfo *)(m_Vehicle->GetBaseModelInfo());
|
|
|
|
if(modelInfo)
|
|
{
|
|
CWheel* wheel = m_Vehicle->GetWheel(wheelIndex);
|
|
|
|
if(wheel)
|
|
{
|
|
s32 boneIndex = modelInfo->GetBoneIndex(m_Vehicle->GetWheel(wheelIndex)->GetHierarchyId());
|
|
Matrix34 matrix = RCC_MATRIX34(m_Vehicle->GetSkeletonData().GetDefaultTransform(boneIndex));
|
|
matrix.d = m_Vehicle->TransformIntoWorldSpace(matrix.d);
|
|
pos = matrix.d;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger an indicator
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerIndicator(const bool isOn)
|
|
{
|
|
if(m_VehicleLOD < AUD_VEHICLE_LOD_DISABLED)
|
|
{
|
|
if(m_DistanceFromListener2LastFrame < 625)
|
|
{
|
|
m_IsIndicatorRequestedOn = isOn;
|
|
m_HasIndicatorRequest = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Called when the rev limiter is hit
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::RevLimiterHit()
|
|
{
|
|
m_LastRevLimiterTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Called when the vehicle is hit by a rocket
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SetHitByRocket()
|
|
{
|
|
m_LastHitByRocketTime = fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a door sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerDoorSound(u32 hash, eHierarchyId doorId, f32 volumeOffset)
|
|
{
|
|
if(!IsDisabled() && hash != g_NullSoundHash REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive()))
|
|
{
|
|
CVehicleModelInfo* modelInfo = (CVehicleModelInfo *)(m_Vehicle->GetBaseModelInfo());
|
|
s32 doorBoneIndex = modelInfo->GetBoneIndex(doorId);
|
|
Matrix34 doorMatrix = RCC_MATRIX34(m_Vehicle->GetSkeletonData().GetDefaultTransform(doorBoneIndex));
|
|
doorMatrix.d = m_Vehicle->TransformIntoWorldSpace(doorMatrix.d);
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.Volume = volumeOffset;
|
|
initParams.Position = doorMatrix.d;
|
|
|
|
if(sysThreadType::IsUpdateThread())
|
|
{
|
|
CreateDeferredSound(hash, m_Vehicle, &initParams, true);
|
|
}
|
|
else
|
|
{
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(hash, &initParams);
|
|
}
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(hash, &initParams, m_Vehicle));
|
|
|
|
CCarDoor *door = m_Vehicle->GetDoorFromId(doorId);
|
|
|
|
if(door)
|
|
{
|
|
door->TriggeredAudio(fwTimer::GetTimeInMilliseconds());
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a landing gear sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerLandingGearSound(const audSoundSet& soundset, const u32 soundFieldHash)
|
|
{
|
|
audMetadataRef soundRef = soundset.Find(soundFieldHash);
|
|
|
|
if(soundRef != g_NullSoundRef)
|
|
{
|
|
// Stop the existing sound if we're triggering a new one
|
|
if(m_LandingGearSound)
|
|
{
|
|
m_LandingGearSound->StopAndForget(true);
|
|
}
|
|
|
|
audSoundInitParams initParams;
|
|
initParams.UpdateEntity = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
|
|
CreateSound_PersistentReference(soundRef, &m_LandingGearSound, &initParams);
|
|
|
|
if(m_LandingGearSound)
|
|
{
|
|
m_LandingGearSound->SetUpdateEntity(true);
|
|
m_LandingGearSound->SetClientVariable((u32)AUD_VEHICLE_SOUND_UNKNOWN);
|
|
m_LandingGearSound->PrepareAndPlay();
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSoundPersistant(soundset.GetNameHash(), soundFieldHash, &initParams, m_LandingGearSound, GetOwningEntity()));
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update Doors
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateDoors()
|
|
{
|
|
for(s32 i = 0; i < m_Vehicle->GetNumDoors(); i++)
|
|
{
|
|
CCarDoor *door = m_Vehicle->GetDoor(i);
|
|
|
|
// Need a way to detect sliding cockpit doors? Adding vehicle type check seems to work ok for all planes
|
|
if(door && (door->GetFlag(CCarDoor::IS_ARTICULATED) || m_Vehicle->GetVehicleType() == VEHICLE_TYPE_PLANE))
|
|
{
|
|
// If we're in the mod shop, suppress door sounds when script open/shut doors as part of the mod shop menu system, as they trigger their own bespoke sounds
|
|
// This allows remote players (possible in the office mod shop) to open/close doors and everyone to hear the regular open/close sounds
|
|
if(fwTimer::GetTimeInMilliseconds() > door->GetLastAudioTime()+250 &&
|
|
(!m_InCarModShop || (m_InCarModShop && NetworkInterface::IsGameInProgress() && fwTimer::GetTimeInMilliseconds() - m_LastScriptDoorModifyTime > g_ModShopDoorRecentlyUsedTime)))
|
|
{
|
|
f32 oldDoorRatio = door->GetOldAudioRatio();
|
|
f32 doorRatio = door->GetDoorRatio();
|
|
|
|
#if __BANK
|
|
if(g_ShowDoorRatios)
|
|
{
|
|
CVehicleModelInfo* modelInfo = (CVehicleModelInfo *)(m_Vehicle->GetBaseModelInfo());
|
|
s32 doorBoneIndex = modelInfo->GetBoneIndex(door->GetHierarchyId());
|
|
Matrix34 doorMatrix = RCC_MATRIX34(m_Vehicle->GetSkeletonData().GetDefaultTransform(doorBoneIndex));
|
|
|
|
char tempString[128];
|
|
sprintf(tempString, "Door Ratio %4.2f Old %4.2f", doorRatio, oldDoorRatio);
|
|
grcDebugDraw::Text(m_Vehicle->TransformIntoWorldSpace(doorMatrix.d), Color_white, tempString);
|
|
}
|
|
#endif
|
|
|
|
// No work to do if the ratios are the same
|
|
if(oldDoorRatio != doorRatio)
|
|
{
|
|
f32 speed = Abs((door->GetOldAudioRatio()-door->GetDoorRatio()) * fwTimer::GetInvTimeStep());
|
|
|
|
static bank_float cargobobRearDoorOpenRatio = 0.76f;
|
|
if(m_Vehicle->GetVehicleType() == VEHICLE_TYPE_PLANE || m_Vehicle->GetVehicleType() == VEHICLE_TYPE_HELI)
|
|
{
|
|
static bank_float startCloseRatio = 0.96f;
|
|
if(m_Vehicle->GetVehicleType() == VEHICLE_TYPE_HELI && door->GetHierarchyId() == VEH_DOOR_DSIDE_R &&
|
|
doorRatio <= 0.7f && doorRatio > 0.6f && oldDoorRatio > doorRatio && speed > 1.0f)
|
|
{
|
|
TriggerDoorStartCloseSound(door->GetHierarchyId());
|
|
}
|
|
else if(m_Vehicle->GetVehicleType() == VEHICLE_TYPE_HELI && door->GetHierarchyId() == VEH_DOOR_DSIDE_R &&
|
|
doorRatio >= cargobobRearDoorOpenRatio && oldDoorRatio < doorRatio && speed > 0.5f)
|
|
{
|
|
TriggerDoorFullyOpenSound(door->GetHierarchyId());
|
|
}
|
|
else if(doorRatio <= startCloseRatio && oldDoorRatio > startCloseRatio)
|
|
{
|
|
//Start to close
|
|
TriggerDoorStartCloseSound(door->GetHierarchyId());
|
|
}
|
|
else if(doorRatio <= 0.1f && oldDoorRatio > 0.1f)
|
|
{
|
|
TriggerDoorCloseSound(door->GetHierarchyId(), speed < 1.f);
|
|
}
|
|
else if(oldDoorRatio <= 0.01f && doorRatio > 0.01f)
|
|
{
|
|
TriggerDoorOpenSound(door->GetHierarchyId());
|
|
TriggerDoorStartOpenSound(door->GetHierarchyId());
|
|
}
|
|
else if(doorRatio >= 0.99f && oldDoorRatio < 0.98f)
|
|
{
|
|
TriggerDoorFullyOpenSound(door->GetHierarchyId());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
f32 doorOpenLimit = 0.01f;
|
|
f32 doorCloseLimit = 0.1f;
|
|
|
|
// HL - Somewhat hacky fix for GTAV B*2187239, where trash compactor rear door isn't triggering consistently.
|
|
// Ideal fix would be to:
|
|
// a) Support doorStartOpen/DoorStartClose sounds on all vehicle types
|
|
// b) Define trigger ratios for each sound type in the vehicle gameobject
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("TRASH2", 0xB527915C) && door->GetHierarchyId() == VEH_BOOT)
|
|
{
|
|
doorOpenLimit = 0.2f;
|
|
doorCloseLimit = 0.8f;
|
|
}
|
|
|
|
// url:bugstar:6185262 - Vagrant - The rear hood door audio occasionally does not fire when it is opened/closed in the Interaction Menu.
|
|
if (GetVehicleModelNameHash() == ATSTRINGHASH("VAGRANT", 0x2C1FEA99) && door->GetHierarchyId() == VEH_BONNET)
|
|
{
|
|
doorOpenLimit = 0.2f;
|
|
doorCloseLimit = 0.8f;
|
|
}
|
|
// End hacky fix.
|
|
|
|
if(m_Vehicle->GetVehicleType() == VEHICLE_TYPE_SUBMARINE && doorRatio < 0.98f && oldDoorRatio > 0.98f)
|
|
{
|
|
TriggerDoorStartCloseSound(door->GetHierarchyId());
|
|
}
|
|
else if(doorRatio < doorCloseLimit && oldDoorRatio >= doorCloseLimit)
|
|
{
|
|
TriggerDoorCloseSound(door->GetHierarchyId(), speed < 1.f);
|
|
}
|
|
else if(oldDoorRatio < doorOpenLimit && doorRatio >= doorOpenLimit)
|
|
{
|
|
TriggerDoorOpenSound(door->GetHierarchyId());
|
|
|
|
//Need to trigger sliding door open sound here, can't tag up get_out animation because can play when door's already open
|
|
if (door->GetFlag(CCarDoor::AXIS_SLIDE_X) || door->GetFlag(CCarDoor::AXIS_SLIDE_Y) || door->GetFlag(CCarDoor::AXIS_SLIDE_Z))
|
|
{
|
|
TriggerDoorSound(ATSTRINGHASH("DLC_LOWRIDER_DOOR_SLIDE_MOVE_OPEN", 0xb8d0c956), door->GetHierarchyId());
|
|
}
|
|
}
|
|
else if(doorRatio >= 0.99f && oldDoorRatio < 0.98f)
|
|
{
|
|
TriggerDoorFullyOpenSound(door->GetHierarchyId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
door->AudioUpdate();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Stop the siren if broken
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::StopSirenIfBroken()
|
|
{
|
|
CPed *player = CGameWorld::FindLocalPlayer();
|
|
CVehicle *playerVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(m_IsSirenFucked && (!playerVeh && player == m_LastVehicleDriver))
|
|
{
|
|
if (m_SirenLoop)
|
|
{
|
|
m_SirenLoop->StopAndForget();
|
|
m_PlaySirenWithNoNetworkPlayerDriver = false;
|
|
m_SirenState = AUD_SIREN_OFF;
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------
|
|
// Smash the siren
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::SmashSiren(bool force)
|
|
{
|
|
if(!m_IsSirenFucked)
|
|
{
|
|
if(m_Vehicle->GetVehicleDamage()->GetSirenHealth() >= 1 && ENTITY_SEED_PROB(m_Vehicle->GetRandomSeed(), 0.1f))
|
|
{
|
|
m_IsSirenFucked = true;
|
|
}
|
|
else if(m_Vehicle->GetVehicleDamage()->GetSirenHealth() >= 2 && ENTITY_SEED_PROB(m_Vehicle->GetRandomSeed(), 0.25f))
|
|
{
|
|
m_IsSirenFucked = true;
|
|
}
|
|
else if (m_Vehicle->GetVehicleDamage()->GetSirenHealth() >= 3 && ENTITY_SEED_PROB(m_Vehicle->GetRandomSeed(), 0.65f))
|
|
{
|
|
m_IsSirenFucked = true;
|
|
}
|
|
|
|
if (force)
|
|
{
|
|
m_IsSirenFucked = force;
|
|
}
|
|
|
|
if(m_IsSirenFucked)
|
|
{
|
|
if(m_SirenLoop && m_SirenState == AUD_SIREN_SLOW && (force || m_Vehicle->GetVehicleDamage()->GetEngineHealth() < g_VehHealthThreshold))
|
|
{
|
|
m_SirenLoop->FindAndSetVariableValue(ATSTRINGHASH("isFucked", 0x82DA7FEC), 1.f);
|
|
m_SirenLoop->StopAndForget();
|
|
}
|
|
else
|
|
{
|
|
if(force || ENTITY_SEED_PROB(m_Vehicle->GetRandomSeed(), 0.5f))
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.RemoveHierarchy = false;
|
|
initParams.SetVariableValue(ATSTRINGHASH("isFucked", 0x82DA7FEC), 1.f);
|
|
|
|
if(sysThreadType::IsUpdateThread())
|
|
{
|
|
CreateDeferredSound(m_VehSirenSounds.Find(ATSTRINGHASH("FUCKED_ONE_SHOT", 0x5417639D)), m_Vehicle, &initParams, true);
|
|
}
|
|
else
|
|
{
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(m_VehSirenSounds.Find(ATSTRINGHASH("FUCKED_ONE_SHOT", 0x5417639D)), &initParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_PlaySirenWithNoNetworkPlayerDriver = false;
|
|
m_SirenState = AUD_SIREN_OFF;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Blip siren
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::BlipSiren()
|
|
{
|
|
if(m_Vehicle)
|
|
{
|
|
if(m_Vehicle->UsesSiren() && !m_SirenLoop && !m_SirenBlip && !m_IsSirenFucked && m_VehSirenSounds.IsInitialised())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateSound_PersistentReference(m_VehSirenSounds.Find(ATSTRINGHASH("BLIP", 0x26D96F23)),&m_SirenBlip,&initParams);
|
|
if(m_SirenBlip)
|
|
{
|
|
m_SirenBlip->PrepareAndPlay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
// Tells the audio entity that a change has been made to the siren state. That helps us decide which sound to play
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::SirenStateChanged(bool on)
|
|
{
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh && pVeh == m_Vehicle)
|
|
{
|
|
if(on)
|
|
{
|
|
if(!m_IsSirenOn)
|
|
{
|
|
// siren just turn on, start checking the time.
|
|
m_TimeToPlaySiren = 0;
|
|
m_WantsToPlaySiren = true;
|
|
m_ShouldPlayPlayerVehSiren = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_IsSirenOn = false;
|
|
m_WantsToPlaySiren = false;
|
|
if(!m_ShouldPlayPlayerVehSiren)
|
|
{
|
|
//We stop the siren before it plays, play the blip instead
|
|
BlipSiren();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
u32 audVehicleAudioEntity::GetVehicleHornSoundHash(bool UNUSED_PARAM(ignoreMods))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Supports audDynamicEntitySound queries
|
|
// ----------------------------------------------------------------
|
|
u32 audVehicleAudioEntity::QuerySoundNameFromObjectAndField(const u32 *objectRefs, u32 numRefs)
|
|
{
|
|
naAssertf(objectRefs, "A null object ref array ptr has been passed into audVehicleAudioEntity::QuerySoundNameFromObjectAndField");
|
|
naAssertf(numRefs >= 2,"The object ref list should always have at least two entries when entering QuerySoundNameFromObjectAndField");
|
|
naAssertf(m_Vehicle, "Tried to QuerySoundNameFromObject but m_Vehicle is invalid which could result in null ptr access");
|
|
|
|
if(numRefs ==2 && m_Vehicle->GetVehicleAudioEntity())
|
|
{
|
|
|
|
if(objectRefs[1] == ATSTRINGHASH("HornSounds", 0xAD9FE71E) || objectRefs[1] == ATSTRINGHASH("HornSound", 0x4DD0098F) )
|
|
{
|
|
u32 hornSound = GetVehicleHornSoundHash();
|
|
CVehicleVariationInstance& variation = m_Vehicle->GetVariationInstance();
|
|
if(variation.GetMods()[VMT_HORN] != 255)
|
|
{
|
|
if(variation.GetKit()->GetStatMods()[variation.GetMods()[VMT_HORN]].GetModifier() != 0)
|
|
{
|
|
hornSound = variation.GetKit()->GetStatMods()[variation.GetMods()[VMT_HORN]].GetModifier();
|
|
}
|
|
}
|
|
|
|
//naDisplayf("HORN : %u", hornSound);
|
|
return hornSound;
|
|
}
|
|
//We're at the end of the object ref chain, see if we have a valid object to query
|
|
else if(*objectRefs == ATSTRINGHASH("CAR", 0x69697274))
|
|
{
|
|
if(m_Vehicle->GetVehicleAudioEntity()->GetAudioVehicleType() == AUD_VEHICLE_CAR)
|
|
{
|
|
++objectRefs;
|
|
return m_Vehicle->GetVehicleAudioEntity()->GetSoundFromObjectData(*objectRefs);
|
|
}
|
|
}
|
|
else if(*objectRefs == ATSTRINGHASH("HELI", 0xD3F50E77))
|
|
{
|
|
if(m_Vehicle->GetVehicleAudioEntity()->GetAudioVehicleType() == AUD_VEHICLE_HELI)
|
|
{
|
|
++objectRefs;
|
|
return m_Vehicle->GetVehicleAudioEntity()->GetSoundFromObjectData(*objectRefs);
|
|
}
|
|
}
|
|
else if(*objectRefs == ATSTRINGHASH("BOAT", 0x6910F770))
|
|
{
|
|
if(m_Vehicle->GetVehicleAudioEntity()->GetAudioVehicleType() == AUD_VEHICLE_BOAT)
|
|
{
|
|
++objectRefs;
|
|
return m_Vehicle->GetVehicleAudioEntity()->GetSoundFromObjectData(*objectRefs);
|
|
}
|
|
}
|
|
else if(*objectRefs == ATSTRINGHASH("BICYCLE", 0x9B943939))
|
|
{
|
|
if(m_Vehicle->GetVehicleAudioEntity()->GetAudioVehicleType() == AUD_VEHICLE_BICYCLE)
|
|
{
|
|
++objectRefs;
|
|
return m_Vehicle->GetVehicleAudioEntity()->GetSoundFromObjectData(*objectRefs);
|
|
}
|
|
}
|
|
else if(*objectRefs == ATSTRINGHASH("PLANE", 0x198530F1))
|
|
{
|
|
if(m_Vehicle->GetVehicleAudioEntity()->GetAudioVehicleType() == AUD_VEHICLE_PLANE)
|
|
{
|
|
++objectRefs;
|
|
return m_Vehicle->GetVehicleAudioEntity()->GetSoundFromObjectData(*objectRefs);
|
|
}
|
|
}
|
|
else if(*objectRefs == ATSTRINGHASH("TRAILER", 0x5C27AA11))
|
|
{
|
|
if(m_Vehicle->GetVehicleAudioEntity()->GetAudioVehicleType() == AUD_VEHICLE_TRAILER)
|
|
{
|
|
++objectRefs;
|
|
return m_Vehicle->GetVehicleAudioEntity()->GetSoundFromObjectData(*objectRefs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
naWarningf("Attempting to query an object field in vehicleaudioentity but object is not a supported type");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
--numRefs;
|
|
if(*objectRefs == ATSTRINGHASH("DRIVER", 0x7CF5B63F))
|
|
{
|
|
++objectRefs;
|
|
CPed *pDriver = m_Vehicle->GetDriver();
|
|
if(pDriver)
|
|
{
|
|
return pDriver->GetPedAudioEntity()->QuerySoundNameFromObjectAndField(objectRefs, numRefs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
naWarningf("Unsupported object type (%d) in reference chain passed into audCarAudioEntity::QuerySoundNameFromObjectAndField", *objectRefs);
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// ScriptAppliedForce
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ScriptAppliedForce(const Vector3 &vecForce)
|
|
{
|
|
const f32 forceMag = vecForce.Mag();
|
|
audSoundInitParams initParams;
|
|
|
|
dev_float magScalar = 1.f/5.f;
|
|
|
|
initParams.Volume = audDriverUtil::ComputeDbVolumeFromLinear(Min(1.f, magScalar * forceMag));
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound(ATSTRINGHASH("SUSPENSION_SCRIPT_FORCE", 0x742C529), &initParams);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a door breaking off
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerDoorBreakOff(const Vector3 &pos, bool isBonnet, fragInst* doorFragInst)
|
|
{
|
|
if(!IsDisabled())
|
|
{
|
|
audSoundInitParams initParams;
|
|
|
|
if(!sysThreadType::IsUpdateThread())
|
|
{
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
}
|
|
|
|
initParams.Position = pos;
|
|
|
|
if(isBonnet)
|
|
{
|
|
if(sysThreadType::IsUpdateThread())
|
|
{
|
|
CreateDeferredSound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("VehicleBonnetBreakOff", 0x37EF7329)), m_Vehicle, &initParams, true);
|
|
}
|
|
else
|
|
{
|
|
CreateAndPlaySound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("VehicleBonnetBreakOff", 0x37EF7329)), &initParams);
|
|
}
|
|
|
|
if(m_IsPlayerVehicle)
|
|
{
|
|
if(doorFragInst)
|
|
{
|
|
m_DetachedBonnetLevelIndex = doorFragInst->GetLevelIndex();
|
|
}
|
|
|
|
m_ShouldPlayBonnetDetachSound = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(sysThreadType::IsUpdateThread())
|
|
{
|
|
CreateDeferredSound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("VehicleDoorBreakOff", 0xA432CD83)), m_Vehicle, &initParams, true);
|
|
}
|
|
else
|
|
{
|
|
CreateAndPlaySound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("VehicleDoorBreakOff", 0xA432CD83)), &initParams);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update the bonnet loop
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateDetachedBonnetSound(bool firstFrame)
|
|
{
|
|
if(m_ShouldPlayBonnetDetachSound)
|
|
{
|
|
if(!m_DetachedBonnetSound)
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
CreateAndPlaySound_Persistent(sm_ExtrasSoundSet.Find(ATSTRINGHASH("VehicleBonnetFlyPast", 0xC334DF01)), &m_DetachedBonnetSound, &initParams);
|
|
}
|
|
|
|
m_ShouldPlayBonnetDetachSound = false;
|
|
}
|
|
|
|
if(m_DetachedBonnetSound)
|
|
{
|
|
phCollider* pBonnetCollider = CPhysics::GetSimulator()->GetCollider(m_DetachedBonnetLevelIndex);
|
|
|
|
if(pBonnetCollider && (firstFrame || MagSquared(pBonnetCollider->GetVelocity()).Getf() > 1.0f))
|
|
{
|
|
m_DetachedBonnetSound->SetRequestedPosition(pBonnetCollider->GetPosition());
|
|
}
|
|
else
|
|
{
|
|
m_DetachedBonnetSound->StopAndForget();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Check if this is a sea plane or not
|
|
// ----------------------------------------------------------------
|
|
bool audVehicleAudioEntity::IsSeaPlane() const
|
|
{
|
|
if(m_VehicleType == AUD_VEHICLE_PLANE || m_VehicleType == AUD_VEHICLE_HELI)
|
|
{
|
|
if(m_Vehicle)
|
|
{
|
|
if(m_Vehicle->pHandling && m_Vehicle->pHandling->GetSeaPlaneHandlingData())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a splash
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerBoatEntrySplash(bool goneIntoWater, bool comeOutOfWater)
|
|
{
|
|
// Boats don't normally trigger entry splashes, but the APC is an exception
|
|
if(GetVehicleModelNameHash() == ATSTRINGHASH("APC", 0x2189D250))
|
|
{
|
|
float downwardSpeed = Max(0.0f, -m_Vehicle->GetVelocity().z);
|
|
|
|
// get the vfx vehicle info
|
|
CVfxVehicleInfo* pVfxVehicleInfo = g_vfxVehicleInfoMgr.GetInfo(m_Vehicle);
|
|
if (pVfxVehicleInfo)
|
|
{
|
|
// play all other water vfx (in/out/wade) if the camera is above or close to the water surface
|
|
if (goneIntoWater)
|
|
{
|
|
TriggerSplash(downwardSpeed);
|
|
}
|
|
else if (comeOutOfWater)
|
|
{
|
|
TriggerSplash(downwardSpeed,true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a splash
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerSplash(const f32 downSpeed,bool outOfWater)
|
|
{
|
|
if(!IsDisabled() && !IsSeaPlane())
|
|
{
|
|
if(fwTimer::GetTimeInMilliseconds()>m_LastSplashTime+1000 REPLAY_ONLY(|| CReplayMgr::IsEditModeActive()) )
|
|
{
|
|
f32 sqdDistance = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition() - g_AudioEngine.GetEnvironment().GetVolumeListenerPosition()).Mag2();
|
|
if (sqdDistance <= g_DistThresholdToTriggerVehSplashes)
|
|
{
|
|
audMetadataRef soundRef = g_NullSoundRef;
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Tracker = m_Vehicle->GetPlaceableTracker();
|
|
if (!outOfWater)
|
|
{
|
|
f32 velocity = fabs(m_CachedVehicleVelocity.Mag());
|
|
if ( downSpeed >= sm_DownSpeedThreshold || m_JustCameOutOfWater)
|
|
{
|
|
/*f32 mass = m_Vehicle->pHandling->m_fMass;
|
|
f32 volume = size * (m_Vehicle->GetBoundingBoxMax().z - m_Vehicle->GetBoundingBoxMin().z);*/
|
|
//initParams.SetVariableValue(ATSTRINGHASH("DownSpeed", 0x4756096),downSpeed);
|
|
//initParams.SetVariableValue(ATSTRINGHASH("Size", 0xC052DEA7),size);
|
|
//initParams.SetVariableValue(ATSTRINGHASH("Mass", 0x4BC594CB),mass);
|
|
//initParams.SetVariableValue(ATSTRINGHASH("Volume", 0x691362F2),volume);
|
|
if((m_Vehicle && m_Vehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE) || m_JustCameOutOfWater)
|
|
{
|
|
if ( velocity * downSpeed < sm_BicycleCombineSpeedMediumThreshold)
|
|
{
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("BICYCLE_SMALL", 0x2DB76DC1) : ATSTRINGHASH("BICYCLE_SMALL_UNDERWATER", 0xA1C9F0DE) );
|
|
}
|
|
else if (velocity * downSpeed < sm_BicycleCombineSpeedBigThreshold)
|
|
{
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("BICYCLE_MEDIUM", 0xD05884B2) : ATSTRINGHASH("BICYCLE_MEDIUM_UNDERWATER", 0xE7997D8B) );
|
|
}
|
|
else
|
|
{
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("BICYCLE_HEAVY", 0x344D5A48) : ATSTRINGHASH("BICYCLE_HEAVY_UNDERWATER", 0x1152764D) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
f32 size = (m_Vehicle->GetBoundingBoxMax().x - m_Vehicle->GetBoundingBoxMin().x)
|
|
* (m_Vehicle->GetBoundingBoxMax().y - m_Vehicle->GetBoundingBoxMin().y);
|
|
if ( (size < sm_SizeThreshold) || m_JustCameOutOfWater)
|
|
{
|
|
// trigger small splash.
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("SMALL", 0xB7F05D20) : ATSTRINGHASH("UNDERWATER_SMALL", 0xCB87A7DC) );
|
|
}
|
|
else
|
|
{
|
|
if ((velocity * downSpeed < sm_CombineSpeedThreshold) && size < sm_BigSizeThreshold)
|
|
{
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("MEDIUM", 0x74E06FAC) : ATSTRINGHASH("UNDERWATER_MEDIUM", 0x9B393786) );
|
|
}
|
|
else
|
|
{
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("HEAVY", 0xB1AEBE06) : ATSTRINGHASH("UNDERWATER_HEAVY", 0xC6055D14) );
|
|
}
|
|
}
|
|
|
|
//naDisplayf("[Velocity %f] [downSpeed %f] [combined %f] [size %f] [mass %f] [volume %f] ",velocity,downSpeed,velocity*downSpeed,size,mass,volume);
|
|
}
|
|
m_JustCameOutOfWater = false;
|
|
}
|
|
else if( velocity > sm_FwdSpeedThreshold )
|
|
{
|
|
if(m_Vehicle && m_Vehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE)
|
|
{
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("BICYCLE_SMALL", 0x2DB76DC1) : ATSTRINGHASH("BICYCLE_SMALL_UNDERWATER", 0xA1C9F0DE) );
|
|
}
|
|
else
|
|
{
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("SHALLOW", 0x8448CEF5) : ATSTRINGHASH("UNDERWATER_SHALLOW", 0x34F89C97) );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_Vehicle && m_Vehicle->GetVehicleType() == VEHICLE_TYPE_BICYCLE)
|
|
{
|
|
soundRef= sm_VehiclesInWaterSoundset.Find(!Water::IsCameraUnderwater() ? ATSTRINGHASH("BICYCLE_SMALL", 0x2DB76DC1) : ATSTRINGHASH("BICYCLE_SMALL_UNDERWATER", 0xA1C9F0DE) );
|
|
}
|
|
else
|
|
{
|
|
soundRef= sm_ExtrasSoundSet.Find(ATSTRINGHASH("VehicleComingOutOfWater", 0xC618DCC4));
|
|
}
|
|
m_JustCameOutOfWater = true;
|
|
}
|
|
m_LastSplashTime = fwTimer::GetTimeInMilliseconds();
|
|
CreateAndPlaySound(soundRef, &initParams);
|
|
#if GTA_REPLAY
|
|
if(CReplayMgr::ShouldRecord())
|
|
{
|
|
CReplayMgr::RecordFx<CPacketVehicleSplashPacket>(
|
|
CPacketVehicleSplashPacket(downSpeed, outOfWater), GetOwningEntity());
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void audVehicleAudioEntity::TriggerHeliRotorSplash()
|
|
{
|
|
if(!IsDisabled())
|
|
{
|
|
|
|
if(fwTimer::GetTimeInMilliseconds()>m_LastHeliRotorSplashTime+500)
|
|
{
|
|
audSoundInitParams initParams;
|
|
|
|
m_LastHeliRotorSplashTime = fwTimer::GetTimeInMilliseconds();
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.Position = VEC3V_TO_VECTOR3(m_Vehicle->GetTransform().GetPosition());
|
|
CreateAndPlaySound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("HeliRotorHittingWater", 0xC7147B73)), &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(sm_ExtrasSoundSet.GetNameHash(), ATSTRINGHASH("HeliRotorHittingWater", 0xC7147B73), &initParams, GetOwningEntity()));
|
|
}
|
|
}
|
|
}
|
|
// ----------------------------------------------------------------
|
|
// This function supports dynamic sound creation from collisions
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerDynamicImpactSounds(f32 volume)
|
|
{
|
|
if(!IsDisabled())
|
|
{
|
|
u32 soundhash = 0;
|
|
audSoundInitParams initParams;
|
|
if(volume <= g_LowerVehDynamicImpactThreshold)
|
|
{
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
soundhash = ATSTRINGHASH("VEH_DYNAMIC_IMPACTS_LOW", 0x2AA0D9E0);
|
|
}
|
|
else if(volume <= g_UpperVehDynamicImpactThreshold)
|
|
{
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
soundhash = ATSTRINGHASH("VEH_DYNAMIC_IMPACTS_MEDIUM", 0x5BC85E0D);
|
|
}
|
|
else
|
|
{
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
soundhash = ATSTRINGHASH("VEH_DYNAMIC_IMPACTS_HIGH", 0xC6E79F96);
|
|
}
|
|
|
|
CreateAndPlaySound(soundhash, &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(soundhash, &initParams, GetOwningEntity()));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a towing hook attach sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerTowingHookAttachSound()
|
|
{
|
|
if(!IsDisabled())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateAndPlaySound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("TowTruck_HookAttach", 0xA8A8FF30)), &initParams);
|
|
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(sm_ExtrasSoundSet.GetNameHash(), ATSTRINGHASH("TowTruck_HookAttach", 0xA8A8FF30), &initParams, GetOwningEntity()));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Trigger a towing hook detach sound
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerTowingHookDetachSound()
|
|
{
|
|
if(!IsDisabled())
|
|
{
|
|
audSoundInitParams initParams;
|
|
initParams.EnvironmentGroup = m_EnvironmentGroup;
|
|
initParams.TrackEntityPosition = true;
|
|
CreateAndPlaySound(sm_ExtrasSoundSet.Find(ATSTRINGHASH("TowTruck_HookRelease", 0xA10E2691)), &initParams);
|
|
REPLAY_ONLY(CReplayMgr::ReplayRecordSound(sm_ExtrasSoundSet.GetNameHash(), ATSTRINGHASH("TowTruck_HookRelease", 0xA10E2691), &initParams, GetOwningEntity()));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get any trailer attached to this vehicle
|
|
// ----------------------------------------------------------------
|
|
audTrailerAudioEntity* audVehicleAudioEntity::GetTrailer()
|
|
{
|
|
for(int i = 0; i < m_Vehicle->GetNumberOfVehicleGadgets(); i++)
|
|
{
|
|
CVehicleGadget *pVehicleGadget = m_Vehicle->GetVehicleGadget(i);
|
|
|
|
if(pVehicleGadget->GetType() == VGT_TRAILER_ATTACH_POINT)
|
|
{
|
|
CVehicleTrailerAttachPoint *pTrailerAttachPoint = static_cast<CVehicleTrailerAttachPoint*>(pVehicleGadget);
|
|
CTrailer *pTrailer = pTrailerAttachPoint->GetAttachedTrailer(m_Vehicle);
|
|
|
|
if(pTrailer && pTrailer->GetVehicleAudioEntity() &&
|
|
pTrailer->GetVehicleAudioEntity()->GetAudioVehicleType() == AUD_VEHICLE_TRAILER)
|
|
{
|
|
return ((audTrailerAudioEntity*)pTrailer->GetVehicleAudioEntity());
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// This function supports dynamic sound creation from explosions
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::TriggerDynamicExplosionSounds(bool isUnderwater)
|
|
{
|
|
VehicleExploded();
|
|
|
|
m_LastTimeExploded = g_AudioEngine.GetSoundManager().GetTimeInMilliseconds(0);
|
|
audSoundInitParams initParams;
|
|
BANK_ONLY( initParams.IsAuditioning = g_AuditionVehExplosions; );
|
|
if(m_VehicleType == AUD_VEHICLE_BICYCLE)
|
|
{
|
|
return;
|
|
}
|
|
if(!isUnderwater)
|
|
{
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
CreateAndPlaySound(ATSTRINGHASH("VEH_DYNAMIC_EXPLOSION", 0xED136850), &initParams);
|
|
}
|
|
else
|
|
{
|
|
initParams.TrackEntityPosition = true;
|
|
initParams.EnvironmentGroup = m_Vehicle->GetAudioEnvironmentGroup();
|
|
CreateAndPlaySound(ATSTRINGHASH("VEH_DYNAMIC_EXPLOSION_UNDERWATER", 0xDB101148), &initParams);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Get the wave slot
|
|
// ----------------------------------------------------------------
|
|
audWaveSlot* audVehicleAudioEntity::GetWaveSlot()
|
|
{
|
|
if(m_EngineWaveSlot)
|
|
{
|
|
return m_EngineWaveSlot->waveSlot;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Compute proximity ratio to exhaust
|
|
// ----------------------------------------------------------------
|
|
f32 audVehicleAudioEntity::ComputeProximityEffectRatio()
|
|
{
|
|
const Vec3V camPos = g_AudioEngine.GetEnvironment().GetVolumeListenerPosition(0);
|
|
const Vec3V exhaustPos = m_Vehicle->TransformIntoWorldSpace(m_ExhaustOffsetPos);
|
|
const Vec3V camToCar = (exhaustPos-camPos);
|
|
f32 factor = Min((MagSquared(camToCar)/ScalarV(g_ExhaustProximityEffectRange*g_ExhaustProximityEffectRange)).Getf(), 1.0f);
|
|
if(fwTimer::GetTimeWarp() < 0.9f)
|
|
{
|
|
// disable proximity effect when in slowmo as it causes distortion
|
|
factor = 1.f;
|
|
}
|
|
|
|
return 1.0f-factor;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Update loop with linear volume/pitch
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateLoopWithLinearVolumeAndPitchRatio(audSound **sound, const u32 soundHash, f32 linVolume, f32 pitchRatio, audEnvironmentGroupInterface *occlusionGroup, audCategory *category, bool stopWhenSilent, bool smoothPitch, f32 environmentalLoudness, bool trackPosition)
|
|
{
|
|
s32 pitch = audDriverUtil::ConvertRatioToPitch(pitchRatio);
|
|
UpdateLoopWithLinearVolumeAndPitch(sound, soundHash, linVolume, pitch, occlusionGroup, category, stopWhenSilent, smoothPitch, environmentalLoudness, trackPosition);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Force this vehicle to use a particular game object
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::ForceUseGameObject(u32 gameObject)
|
|
{
|
|
m_ForcedGameObject = gameObject;
|
|
m_ForcedGameObjectResetRequired = true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::StopHorn(bool checkForCarModShop, bool onlyStopIfPlayer)
|
|
{
|
|
if(!checkForCarModShop || (checkForCarModShop && (!m_InCarModShop || m_Vehicle->UsesSiren())))
|
|
{
|
|
if(!onlyStopIfPlayer || (onlyStopIfPlayer && m_PlayerHornOn))
|
|
{
|
|
if(m_HornSound)
|
|
{
|
|
m_HornSound->StopAndForget(true);
|
|
#if GTA_REPLAY
|
|
if(CReplayMgr::ShouldRecord())
|
|
{
|
|
CReplayMgr::RecordFx<CPacketVehicleHornStop>(
|
|
CPacketVehicleHornStop(),
|
|
m_Vehicle);
|
|
}
|
|
#endif // GTA_REPLAY
|
|
}
|
|
m_PlayerHornOn = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateBulletHits()
|
|
{
|
|
if(!m_Vehicle->GetDriver() || (m_Vehicle->GetDriver() && !m_Vehicle->GetDriver()->IsPlayer()))
|
|
{
|
|
m_BulletHitCount ++;
|
|
m_TimeSinceLastBulletHit = 0;
|
|
}
|
|
}
|
|
#if __BANK
|
|
bool audVehicleAudioEntity::ShouldRenderRecording(const s32 index)
|
|
{
|
|
bool shouldRenderRecording = true;
|
|
if(sm_EnableCREditor)
|
|
{
|
|
CarRecordingAudioSettings *CRSettings = NULL;
|
|
CRSettings = audNorthAudioEngine::GetObject<CarRecordingAudioSettings>(CVehicleRecordingMgr::GetRecordingHash(index));
|
|
|
|
if(CRSettings)
|
|
{
|
|
if(g_CRFilter[0] != 0 && !audAmbientAudioEntity::MatchName(audNorthAudioEngine::GetMetadataManager().GetObjectName(CRSettings->NameTableOffset,0),g_CRFilter))
|
|
{
|
|
shouldRenderRecording = false;
|
|
}
|
|
}
|
|
}
|
|
return shouldRenderRecording;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::SkipTo()
|
|
{
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh))
|
|
{
|
|
s32 playBackSlot = CVehicleRecordingMgr::GetPlaybackSlot(pVeh);
|
|
sm_ManualTimeSet = false;
|
|
f32 desireTime = (sm_CRCurrentTime - CVehicleRecordingMgr::GetPlaybackRunningTime(playBackSlot));
|
|
CVehicleRecordingMgr::SkipTimeForwardInRecording(pVeh,desireTime);
|
|
for(u32 i = 0; i<sm_DebugCarRecording.eventList.GetCount();i++)
|
|
{
|
|
if(sm_DebugCarRecording.eventList[i].time > sm_CRCurrentTime)
|
|
{
|
|
sm_DebugCarRecording.eventList[i].processed = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::FwdCR()
|
|
{
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh))
|
|
{
|
|
sm_CRCurrentTime += sm_CRJumpTimeInMs;
|
|
audVehicleAudioEntity::SkipTo();
|
|
}
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::RewindCR()
|
|
{
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh))
|
|
{
|
|
sm_CRCurrentTime -= sm_CRJumpTimeInMs;
|
|
audVehicleAudioEntity::SkipTo();
|
|
}
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateProgressBar()
|
|
{
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh))
|
|
{
|
|
s32 index = CVehicleRecordingMgr::GetPlaybackSlot(pVeh);
|
|
if(sm_EnableCREditor)
|
|
{
|
|
if(sm_ManualTimeSet)
|
|
{
|
|
sm_CRProgress = (f32)(sm_CRCurrentTime / (f32) CVehicleRecordingMgr::GetEndTimeOfRecording(index)) * 100.f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::UpdateTimeBar()
|
|
{
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh))
|
|
{
|
|
s32 index = CVehicleRecordingMgr::GetPlaybackSlot(pVeh);
|
|
if(sm_EnableCREditor)
|
|
{
|
|
if(sm_ManualTimeSet)
|
|
{
|
|
sm_CRCurrentTime = (f32) CVehicleRecordingMgr::GetEndTimeOfRecording(index) * 0.01f * sm_CRProgress;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::LoadCRAudioSettings()
|
|
{
|
|
if(sm_EnableCREditor && !sm_UpdateCRTime)
|
|
{
|
|
sm_UpdateCRTime = true;
|
|
if(naVerifyf(strlen(sm_CRAudioSettingsCreator) != 0 ,"Please in order to enable the Car Recording audio editor, select one."))
|
|
{
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh))
|
|
{
|
|
|
|
bkBank* bank = BANKMGR.FindBank("Audio");
|
|
if( sm_CRWidgetGroup )
|
|
{
|
|
bank->DeleteGroup(*sm_CRWidgetGroup);
|
|
sm_CRWidgetGroup = NULL;
|
|
}
|
|
bank->SetCurrentGroup(*CVehicleRecordingMgr::sm_WidgetGroup);
|
|
sm_CRWidgetGroup = bank->PushGroup("Current recording editor",true);
|
|
s32 index = CVehicleRecordingMgr::GetPlaybackSlot(pVeh);
|
|
bank->AddToggle("Manual time/progress set up ",&sm_ManualTimeSet);
|
|
bank->AddSlider("Current time",&sm_CRCurrentTime,0.f,(f32) CVehicleRecordingMgr::GetEndTimeOfRecording(index),0.1f,CFA(UpdateProgressBar));
|
|
bank->AddSlider("Progress bar",&sm_CRProgress,0.f,100.f,0.1f,CFA(UpdateTimeBar));
|
|
bank->AddButton("Skip to selected time/progress", CFA(SkipTo));
|
|
bank->AddSlider("Jump time in ms",&sm_CRJumpTimeInMs,0.f,10000.f,0.1f);
|
|
bank->AddButton("Forward", CFA(FwdCR));
|
|
bank->AddButton("Rewind", CFA(RewindCR));
|
|
bank->PopGroup();
|
|
bank->UnSetCurrentGroup(*CVehicleRecordingMgr::sm_WidgetGroup);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (sm_EnableCREditor)
|
|
{
|
|
for(u32 i = 0; i<sm_DebugCarRecording.eventList.GetCount();i++)
|
|
{
|
|
sm_DebugCarRecording.eventList[i].processed = false;
|
|
}
|
|
}
|
|
}
|
|
void audVehicleAudioEntity::CancelCRAudioSettings()
|
|
{
|
|
formatf(sm_CRAudioSettingsCreator,sizeof(sm_CRAudioSettingsCreator),"");
|
|
formatf(CVehicleRecordingMgr::ms_debug_RecordingNameToPlayWith,sizeof(CVehicleRecordingMgr::ms_debug_RecordingNameToPlayWith),"");
|
|
CVehicleRecordingMgr::ms_debug_RecordingNumToPlayWith = 0;
|
|
sm_DebugCarRecording.nameHash.Clear();
|
|
sm_DebugCarRecording.eventList.Reset();
|
|
sm_DebugCarRecording.settings = NULL;
|
|
sm_DebugCarRecording.modelId = 0;
|
|
sm_CRCurrentTime = 0.f;
|
|
sm_CRProgress = 0.f;
|
|
sm_ManualTimeSet = false;
|
|
sm_DrawCREvents = false;
|
|
sm_DrawCRName = false;
|
|
sm_LoadExistingCR = false;
|
|
sm_UpdateCRTime = false;
|
|
sm_VehCreated = false;
|
|
g_pFocusEntity = NULL;
|
|
CVehicle* pVeh = CGameWorld::FindLocalPlayerVehicle();
|
|
if(pVeh)
|
|
{
|
|
if(CVehicleRecordingMgr::IsPlaybackGoingOnForCar(pVeh))
|
|
{
|
|
CVehicleRecordingMgr::StopPlaybackRecordedCar(pVeh);
|
|
}
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::CreateAudioSettings()
|
|
{
|
|
if(sm_DebugCarRecording.nameHash.IsNotNull())
|
|
{
|
|
char xmlMsg[8192];
|
|
FormatCRAudioSettingsXml(xmlMsg,sizeof(xmlMsg), sm_DebugCarRecording.nameHash.GetCStr());
|
|
naAssertf(g_AudioEngine.GetRemoteControl().SendXmlMessage(xmlMsg, istrlen(xmlMsg)), "Failed to send xml message to rave");
|
|
naAssertf(g_AudioEngine.GetRemoteControl().SendXmlMessage(xmlMsg, istrlen(xmlMsg)), "Failed to send xml message to rave");
|
|
}
|
|
}
|
|
void audVehicleAudioEntity::CreateCREvent()
|
|
{
|
|
if(sm_DebugCarRecording.nameHash.IsNotNull())
|
|
{
|
|
audioRecordingEvent event;
|
|
event.time = sm_CRCurrentTime;
|
|
event.hashEvent = g_NullSoundHash;
|
|
event.processed = false;
|
|
//Add the event in order.
|
|
atArray<audioRecordingEvent> eventListCached;
|
|
eventListCached.Reset();
|
|
u32 i = 0;
|
|
if(sm_DebugCarRecording.eventList.GetCount())
|
|
{
|
|
bool added = false;
|
|
while (i < sm_DebugCarRecording.eventList.GetCount())
|
|
{
|
|
if(added || sm_DebugCarRecording.eventList[i].time <= event.time)
|
|
{
|
|
eventListCached.PushAndGrow(sm_DebugCarRecording.eventList[i]);
|
|
i++;
|
|
}
|
|
else if(!added)
|
|
{
|
|
eventListCached.PushAndGrow(event);
|
|
added = true;
|
|
}
|
|
}
|
|
if(!added)
|
|
{
|
|
eventListCached.PushAndGrow(event);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eventListCached.PushAndGrow(event);
|
|
}
|
|
sm_DebugCarRecording.eventList.Reset();
|
|
for (u32 i = 0; i < eventListCached.GetCount();i++)
|
|
{
|
|
sm_DebugCarRecording.eventList.PushAndGrow(eventListCached[i]);
|
|
}
|
|
char xmlMsg[8192];
|
|
FormatCRAudioSettingsXml(xmlMsg,sizeof(xmlMsg), sm_DebugCarRecording.nameHash.GetCStr());
|
|
naAssertf(g_AudioEngine.GetRemoteControl().SendXmlMessage(xmlMsg, istrlen(xmlMsg)), "Failed to send xml message to rave");
|
|
naAssertf(g_AudioEngine.GetRemoteControl().SendXmlMessage(xmlMsg, istrlen(xmlMsg)), "Failed to send xml message to rave");
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
void audVehicleAudioEntity::FormatCRAudioSettingsXml(char * xmlMsg, const size_t bufferSize,const char * settingsName)
|
|
{
|
|
atString upperSettings(settingsName);
|
|
upperSettings.Uppercase();
|
|
|
|
formatf(xmlMsg,bufferSize, "<RAVEMessage>\n");
|
|
char tmpBuf[256] = {0};
|
|
//CarRecordingAudioSettings
|
|
formatf(tmpBuf, "<EditObjects metadataType=\"GAMEOBJECTS\" chunkNameHash=\"%u\">\n", ATSTRINGHASH("BASE", 0x44E21C90));
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "<CarRecordingAudioSettings name=\"%s\">\n", &upperSettings[0]);
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
// Keep current events
|
|
for (s32 i = 0; i< sm_DebugCarRecording.eventList.GetCount(); i++)
|
|
{
|
|
formatf(tmpBuf, "<Event>\n");
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "<Time>%f</Time>\n", sm_DebugCarRecording.eventList[i].time);
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "<Sound>%s</Sound>\n", SOUNDFACTORY.GetMetadataManager().GetObjectName(sm_DebugCarRecording.eventList[i].hashEvent));
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "</Event>\n");
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
}
|
|
formatf(tmpBuf, "<VehicleModelId>%u</VehicleModelId>\n", sm_DebugCarRecording.modelId);
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "<Description/>\n");
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "<VehicleModel/>\n");
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "</CarRecordingAudioSettings>\n");
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "</EditObjects>\n");
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
formatf(tmpBuf, "</RAVEMessage>\n");
|
|
safecat(xmlMsg, tmpBuf,bufferSize);
|
|
}
|
|
|
|
#if __BANK
|
|
// ----------------------------------------------------------------
|
|
// Draw Bounding Box
|
|
// ----------------------------------------------------------------
|
|
void audVehicleAudioEntity::DrawBoundingBox(const Color32 color)
|
|
{
|
|
const Vector3 & vMin = m_Vehicle->GetBoundingBoxMin();
|
|
const Vector3 & vMax = m_Vehicle->GetBoundingBoxMax();
|
|
CDebugScene::Draw3DBoundingBox(vMin, vMax, MAT34V_TO_MATRIX34(m_Vehicle->GetMatrix()), color);
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------
|
|
// Add widgets
|
|
// ----------------------------------------------------------------
|
|
void LoadExistingCR()
|
|
{
|
|
if(naVerifyf(strlen(audVehicleAudioEntity::sm_CRAudioSettingsCreator) != 0 ,"Please in order to load a Car Recording , write the name of the object in the 'Current Car Recording' field"))
|
|
{
|
|
audVehicleAudioEntity::sm_DebugCarRecording.settings = audNorthAudioEngine::GetObject<CarRecordingAudioSettings>(audVehicleAudioEntity::sm_CRAudioSettingsCreator);
|
|
if(naVerifyf(audVehicleAudioEntity::sm_DebugCarRecording.settings, "there is no existing settings for %s",audVehicleAudioEntity::sm_CRAudioSettingsCreator))
|
|
{
|
|
audVehicleAudioEntity::sm_LoadExistingCR = true;
|
|
audVehicleAudioEntity::sm_VehCreated = false;
|
|
}
|
|
}
|
|
}
|
|
void CreatePlaybackVehicleCB()
|
|
{
|
|
CVehicleFactory::CreateCar(audVehicleAudioEntity::GetPlayBackVehModelIndex());
|
|
}
|
|
void CreateDefaultPlaybackVehicleCB()
|
|
{
|
|
CVehicleFactory::CreateCar(audVehicleAudioEntity::GetDefaultPlayBackVehModelIndex());
|
|
}
|
|
void WarpPlayerToPlaybackVehicleCB()
|
|
{
|
|
CVehicleFactory::WarpPlayerOutOfCar();
|
|
CVehicleFactory::WarpPlayerIntoRecentCar();
|
|
}
|
|
|
|
bool audVehicleAudioEntity::AddCarRecordingWidgets(bkBank *bank)
|
|
{
|
|
bank->AddSeparator();
|
|
sm_EnableCREditor = true;
|
|
bank->SetCurrentGroup(*CVehicleRecordingMgr::sm_WidgetGroup);
|
|
bank->AddText("Current Car Recording Audio GO", sm_CRAudioSettingsCreator, sizeof(sm_CRAudioSettingsCreator), false);
|
|
bank->AddButton("Load existing CR", CFA(LoadExistingCR));
|
|
bank->AddButton("Create playback veh", CFA(CreatePlaybackVehicleCB));
|
|
bank->AddButton("Create default playback veh (tailgater) ", CFA(CreateDefaultPlaybackVehicleCB));
|
|
bank->AddButton("Warp player to playback veh", CFA(WarpPlayerToPlaybackVehicleCB));
|
|
bank->AddToggle("Draw events",&sm_DrawCREvents);
|
|
bank->AddToggle("Draw recording name",&sm_DrawCRName);
|
|
bank->AddText("Filter by Name", g_CRFilter, sizeof(g_CRFilter));
|
|
bank->AddToggle("Pause Game",&sm_PauseGame);
|
|
bank->AddButton("Create audio settings", CFA(CreateAudioSettings));
|
|
bank->AddButton("Create current event", CFA(CreateCREvent));
|
|
bank->AddButton("Finish current work ", CFA(CancelCRAudioSettings));
|
|
bank->AddButton("Cancel ", CFA(CancelCRAudioSettings));
|
|
bank->UnSetCurrentGroup(*CVehicleRecordingMgr::sm_WidgetGroup);
|
|
return true;
|
|
}
|
|
void audVehicleAudioEntity::AddWidgets(bkBank &bank)
|
|
{
|
|
bank.AddToggle("DebugVehicleSkids", &g_DebugVehicleSkids);
|
|
bank.AddToggle("Understeer Affects Skid Vol", &g_UndersteerAffectsMainSkidVol);
|
|
bank.AddToggle("Show cars playing rain loops", &g_ShowCarsPlayingRainLoops);
|
|
bank.AddSlider("Override Skid Pitch", &g_OverridenSkidPitchOffset, -24000, 24000, 100);
|
|
bank.AddToggle("g_AuditionVehExplosions",&g_AuditionVehExplosions);
|
|
bank.AddSlider("Delta fwd speed for collision", &audVehicleAudioEntity::sm_VehDeltaSpeedForCollision, 0.f, 100.f, 0.1f);
|
|
bank.AddSlider("Time to play player's veh siren",&g_TimeToPlaySiren,0,5000,10 );
|
|
bank.AddSlider("sm_AlarmIntervalInMs",&sm_AlarmIntervalInMs,0,5000,10 );
|
|
bank.AddSlider("Mod Shop Door Recently Used Time",&g_ModShopDoorRecentlyUsedTime,0,5000,10 );
|
|
|
|
bank.PushGroup("Submarine Dive Horn", false);
|
|
bank.AddToggle("Debug Draw", &g_DebugSubmarineDiveHorn);
|
|
bank.AddToggle("Trigger", &g_ForceTriggerSubmarineDiveHorn);
|
|
bank.AddSlider("Min Dive Button Hold Time", &g_MinSubDiveHoldTime, 0.f, 10.0f, 0.01f);
|
|
bank.AddSlider("Submerge Threshold", &g_SubDiveHornSubmergeThreshold, 0.f, 1.0f, 0.01f);
|
|
bank.AddSlider("Submerge Retrigger Threshold", &g_SubDiveHornSubmergeRetriggerThreshold, 0.f, 1.0f, 0.01f);
|
|
bank.AddSlider("Submerge Retrigger (No Driver)", &g_SubDiveHornSubmergeRetriggerThresholdNoDriver, 0.f, 1.0f, 0.01f);
|
|
bank.AddSlider("Sub Dive Velocity", &g_SubDiveHornVelocity, 0.f, 100.0f, 0.01f);
|
|
bank.PopGroup();
|
|
|
|
bank.PushGroup("Sirens", false);
|
|
bank.AddToggle("Enable Player Stereo Sirens", &g_EnableStereoSirens);
|
|
bank.AddToggle("Smash Player Siren", &g_SmashPlayerSiren);
|
|
bank.AddToggle("Fix Player Siren", &g_FixPlayerSiren);
|
|
bank.AddSlider("C&C Siren Smash Damage", &g_CopsAndCrooksForceSirenSmashDamage, 0.f, 1.0f, 0.01f);
|
|
bank.AddSlider("C&C Siren Smash Probability", &g_CopsAndCrooksForceSirenSmashProbability, 0.f, 1.0f, 0.01f);
|
|
bank.PopGroup();
|
|
bank.PushGroup("Missile Lock", false);
|
|
bank.AddToggle("Debug Missile Status", &g_DebugMissileLockStatus);
|
|
bank.AddToggle("Override Missile Status", &g_OverrideMissileStatus);
|
|
bank.AddCombo("Missile Status", &g_SimulatedMissileState, 5, &g_MissileLockOnStates[0], 0, NullCB, "" );
|
|
bank.AddSlider("Simulated Missile Distance", &g_SimulatedMissileDistance, 0.0f, 1.0f, 0.01f);
|
|
bank.PopGroup();
|
|
bank.PushGroup("Vehicle High Speed Effect", false);
|
|
bank.AddToggle("Debug High Speed Effect", &g_DebugHighSpeedEffect);
|
|
bank.AddSlider("Minimum Vehicle Top Speed", &audVehicleAudioEntity::sm_HighSpeedReqVehicleVelocity, 0.0f, 100.f, 1.0f);
|
|
bank.AddSlider("Num Valid Gears (below top gear)", &audVehicleAudioEntity::sm_HighSpeedMaxGearOffset, 0, 10, 1);
|
|
bank.AddSlider("Min Forward Speed Ratio", &audVehicleAudioEntity::sm_HighSpeedApplyStart, 0.0f, 1.0, 0.01f);
|
|
bank.AddSlider("Max Forward Speed Ratio", &audVehicleAudioEntity::sm_HighSpeedApplyEnd, 0.0f, 1.0, 0.01f);
|
|
bank.AddSlider("1/Smoother Increase Rate", &audVehicleAudioEntity::sm_InvHighSpeedSmootherIncreaseRate, 0, 100000000, 10);
|
|
bank.AddSlider("1/Smoother Decrease Rate", &audVehicleAudioEntity::sm_InvHighSpeedSmootherDecreaseRate, 0, 100000000, 10);
|
|
bank.PopGroup();
|
|
bank.PushGroup("Vehicle water splashes");
|
|
bank.AddSlider("sm_DownSpeedThreshold", &sm_DownSpeedThreshold, 0.f, 1000.f,0.1f);
|
|
bank.AddSlider("sm_FwdSpeedThreshold", &sm_FwdSpeedThreshold, 0.f, 1000.f,0.1f);
|
|
bank.AddSlider("sm_SizeThreshold", &sm_SizeThreshold, 0.f, 1000.f,0.1f);
|
|
bank.AddSlider("sm_BigSizeThreshold", &sm_BigSizeThreshold, 0.f, 1000.f,0.1f);
|
|
bank.AddSlider("sm_CombineSpeedThreshold", &sm_CombineSpeedThreshold, 0.f, 1000.f,0.1f);
|
|
bank.AddSlider("sm_BicycleCombineSpeedMediumThreshold", &sm_BicycleCombineSpeedMediumThreshold, 0.f, 1000.f,0.1f);
|
|
bank.AddSlider("sm_BicycleCombineSpeedBigThreshold", &sm_BicycleCombineSpeedBigThreshold, 0.f, 1000.f,0.1f);
|
|
bank.AddSlider("g_DistThresholdToTriggerVehSplashes", &g_DistThresholdToTriggerVehSplashes,0.f, 10000.f,0.1f);
|
|
bank.AddSlider("g_SqdDistThresholdForWaveImpact", &g_SqdDistThresholdForWaveImpact,0.f, 10000.f,0.1f);
|
|
bank.PopGroup();
|
|
|
|
bank.PushGroup("Amphibious Vehicles");
|
|
bank.AddToggle("Force Amphibious Boat Mode", &g_ForceAmphibiousBoatMode);
|
|
bank.PopGroup();
|
|
|
|
bank.PushGroup("Radio occlusion");
|
|
bank.AddToggle("Debug Draw Radio Occlusion", &g_DebugDrawFocusVehicleRadioOcclusion);
|
|
bank.AddToggle("Force Upgrade Radio", &g_ForceUpgradeRadio);
|
|
bank.AddToggle("Positioned Player Vehicle Radio Enabled", &g_PositionedPlayerVehicleRadioEnabled);
|
|
bank.AddToggle("Override Focus Vehicle Openness", &g_OverrideFocusVehicleOpenness);
|
|
bank.AddSlider("Overridden Openness", &g_OverriddenVehicleOpenness, 0.f, 1.f, 0.001f);
|
|
bank.AddSlider("Modded Radio Min Openness", &g_ModdedRadioVehicleOpenness, 0.f, 1.f, 0.001f);
|
|
const char *leakageNames[NUM_AMBIENTRADIOLEAKAGE];
|
|
for(s32 l = LEAKAGE_BASSY_LOUD; l < NUM_AMBIENTRADIOLEAKAGE; l++)
|
|
{
|
|
leakageNames[l] = AmbientRadioLeakage_ToString((AmbientRadioLeakage)l);
|
|
}
|
|
bank.AddToggle("Override Focus Vehicle Leakage", &g_OverrideFocusVehicleLeakage);
|
|
bank.AddCombo("Overridden Vehicle Leakage", (s32*)&g_OverriddenVehicleRadioLeakage, NUM_AMBIENTRADIOLEAKAGE, leakageNames);
|
|
bank.AddToggle("Override Focus Vehicle Leakage Params", &g_OverrideFocusVehicleLeakageParams);
|
|
bank.AddToggle("Copy Overriden Leakage Params from Selected Settings", &g_CopyOverridenLeakageFromCurrentSettings);
|
|
bank.AddSlider("Volume Min", &g_OverridenLeakageVolMin, 0.f, 20.f, 0.001f);
|
|
bank.AddSlider("Volume Max", &g_OverridenLeakageVolMax, 0.f, 20.f, 0.001f);
|
|
bank.AddSlider("Lpf Cutoff Linear Min", &g_OverridenLeakageLpfLinearMin, 0.f, 1.f, 0.001f);
|
|
bank.AddSlider("Lpf Cutoff Linear Max", &g_OverridenLeakageLpfLinearMax, 0.f, 1.f, 0.001f);
|
|
bank.AddSlider("Rolloff Min", &g_OverridenLeakageRolloffMin, 0.f, 200.f, 0.1f);
|
|
bank.AddSlider("Rolloff Max", &g_OverridenLeakageRolloffMax, 0.f, 200.f, 0.1f);
|
|
bank.AddSlider("Hpf Cutoff", &g_OverridenLeakageHPFCutoff, 0, kVoiceFilterHPFMaxCutoff, 1);
|
|
bank.AddSlider("Max Radius", &g_OverridenLeakageMaxRadius, 0, 10000, 100);
|
|
bank.PopGroup();
|
|
}
|
|
#endif
|